From 2a9c1dba1b804ba4f92e56cff7df79eb41f60972 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 28 Aug 2018 14:35:02 +0100 Subject: [PATCH 0001/1995] ASoC: dapm: Remove clock framework ifdefs The clock code now has stub functions defined in its header files so the ifdefs around clocking code should no longer be necessary. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit d78b1e43e2182640b33d1c39245965d9231f0130) --- sound/soc/soc-dapm.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 461d951917c056..78ab6965af55ce 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1320,14 +1320,13 @@ int dapm_clock_event(struct snd_soc_dapm_widget *w, soc_dapm_async_complete(w->dapm); -#ifdef CONFIG_HAVE_CLK if (SND_SOC_DAPM_EVENT_ON(event)) { return clk_prepare_enable(w->clk); } else { clk_disable_unprepare(w->clk); return 0; } -#endif + return 0; } EXPORT_SYMBOL_GPL(dapm_clock_event); @@ -3498,7 +3497,6 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, } break; case snd_soc_dapm_clock_supply: -#ifdef CONFIG_CLKDEV_LOOKUP w->clk = devm_clk_get(dapm->dev, w->name); if (IS_ERR(w->clk)) { ret = PTR_ERR(w->clk); @@ -3508,9 +3506,6 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, w->name, ret); return NULL; } -#else - return NULL; -#endif break; default: break; From 59b8cafe96a365f2b0c53757476b43c2cfbe14b2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 28 Aug 2018 14:35:03 +0100 Subject: [PATCH 0002/1995] ASoC: dapm: Don't fail creating new DAPM control on NULL pinctrl devm_pinctrl_get will only return NULL in the case that pinctrl is not built into the kernel and all the pinctrl functions used by the DAPM core are appropriately stubbed for that case. There is no need to error out of snd_soc_dapm_new_control_unlocked if pinctrl isn't built into the kernel, so change the IS_ERR_OR_NULL to just an IS_ERR. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit a5cd7e9cf587f51a84b86c828b4e1c7b392f448e) --- sound/soc/soc-dapm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 78ab6965af55ce..d7be3981f0269d 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3487,7 +3487,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, break; case snd_soc_dapm_pinctrl: w->pinctrl = devm_pinctrl_get(dapm->dev); - if (IS_ERR_OR_NULL(w->pinctrl)) { + if (IS_ERR(w->pinctrl)) { ret = PTR_ERR(w->pinctrl); if (ret == -EPROBE_DEFER) return ERR_PTR(ret); From 1188377616b82d39f6e739ad15fba4997aa1fb7b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 27 Aug 2018 14:26:47 +0100 Subject: [PATCH 0003/1995] ASoC: dpcm: Properly initialise hw->rate_max If the CPU DAI does not initialise rate_max, say if using using KNOT or CONTINUOUS, then the rate_max field will be initialised to 0. A value of zero in the rate_max field of the hardware runtime will cause the sound card to support no sample rates at all. Obviously this is not desired, just a different mechanism is being used to apply the constraints. As such update the setting of rate_max in dpcm_init_runtime_hw to be consistent with the non-DPCM cases and set rate_max to UINT_MAX if nothing is defined on the CPU DAI. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit e33ffbd9cd39da09831ce62c11025d830bf78d9e) --- sound/soc/soc-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index e8b98bfd4cf13b..eb6f4f1b65a92b 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1680,7 +1680,7 @@ static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime, struct snd_soc_pcm_stream *stream) { runtime->hw.rate_min = stream->rate_min; - runtime->hw.rate_max = stream->rate_max; + runtime->hw.rate_max = min_not_zero(stream->rate_max, UINT_MAX); runtime->hw.channels_min = stream->channels_min; runtime->hw.channels_max = stream->channels_max; if (runtime->hw.formats) From 7a3f4905770c9239060bbf9f833d6d78ba34bbbe Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Fri, 24 Aug 2018 10:51:51 +0800 Subject: [PATCH 0004/1995] ASoC: rt5682: Update calibration function New calibration sequence allows rt5682 do calibration without MCLK. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown (cherry picked from commit 513792c2554bdece11d82568ea25501a555abd34) --- sound/soc/codecs/rt5682.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index afe7d5b193133a..731c6a849f69bc 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2454,27 +2454,15 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682) regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2bf); usleep_range(15000, 20000); regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2bf); - regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380); - regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8001); - regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000); - regmap_write(rt5682->regmap, RT5682_STO1_DAC_MIXER, 0x2080); - regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x4040); - regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0069); + regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0300); + regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x8000); + regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0100); regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x3000); - regmap_write(rt5682->regmap, RT5682_HP_CTRL_2, 0x6000); - regmap_write(rt5682->regmap, RT5682_HP_CHARGE_PUMP_1, 0x0f26); - regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x7f05); - regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x686c); - regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0d0d); - regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_9, 0x000f); - regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8d01); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_2, 0x0321); regmap_write(rt5682->regmap, RT5682_HP_LOGIC_CTRL_2, 0x0004); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_3, 0x06a1); - regmap_write(rt5682->regmap, RT5682_A_DAC1_MUX, 0x0311); - regmap_write(rt5682->regmap, RT5682_RESET_HPF_CTRL, 0x0000); - regmap_write(rt5682->regmap, RT5682_ADC_STO1_HP_CTRL_1, 0x3320); + regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0xfc00); @@ -2490,7 +2478,7 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682) pr_err("HP Calibration Failure\n"); /* restore settings */ - regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4); + regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x0000); regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0000); mutex_unlock(&rt5682->calibrate_mutex); From e7c5835495232e5e28ab50b8d4d6b4f3d277303c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 Aug 2018 15:24:57 -0500 Subject: [PATCH 0005/1995] ALSA: hda: move hda_codec.h to include/sound As suggested by Takashi, move this header file to make it easier to include from e.g. the Intel Skylake driver in follow-up patches Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit b4af16d617add4f6380d6651473b8efba13ca8ca) --- {sound/pci/hda => include/sound}/hda_codec.h | 0 sound/pci/hda/hda_auto_parser.c | 2 +- sound/pci/hda/hda_beep.h | 2 +- sound/pci/hda/hda_bind.c | 2 +- sound/pci/hda/hda_codec.c | 2 +- sound/pci/hda/hda_controller.h | 2 +- sound/pci/hda/hda_eld.c | 2 +- sound/pci/hda/hda_generic.c | 2 +- sound/pci/hda/hda_hwdep.c | 2 +- sound/pci/hda/hda_intel.c | 2 +- sound/pci/hda/hda_jack.c | 2 +- sound/pci/hda/hda_proc.c | 2 +- sound/pci/hda/hda_sysfs.c | 2 +- sound/pci/hda/hda_tegra.c | 2 +- sound/pci/hda/patch_analog.c | 2 +- sound/pci/hda/patch_ca0110.c | 2 +- sound/pci/hda/patch_ca0132.c | 2 +- sound/pci/hda/patch_cirrus.c | 2 +- sound/pci/hda/patch_cmedia.c | 2 +- sound/pci/hda/patch_conexant.c | 2 +- sound/pci/hda/patch_hdmi.c | 2 +- sound/pci/hda/patch_realtek.c | 2 +- sound/pci/hda/patch_si3054.c | 2 +- sound/pci/hda/patch_sigmatel.c | 2 +- sound/pci/hda/patch_via.c | 2 +- 25 files changed, 24 insertions(+), 24 deletions(-) rename {sound/pci/hda => include/sound}/hda_codec.h (100%) diff --git a/sound/pci/hda/hda_codec.h b/include/sound/hda_codec.h similarity index 100% rename from sound/pci/hda/hda_codec.h rename to include/sound/hda_codec.h diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index b9a6b66aeb0ef7..df0d636145f819 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -13,7 +13,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h index d1a6a9c1329a06..f1457c6b39695b 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h @@ -9,7 +9,7 @@ #ifndef __SOUND_HDA_BEEP_H #define __SOUND_HDA_BEEP_H -#include "hda_codec.h" +#include #define HDA_BEEP_MODE_OFF 0 #define HDA_BEEP_MODE_ON 1 diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index d361bb77ca00d1..2222b47d4ec4fb 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -11,7 +11,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" /* diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 26d348b47867d6..0957813939e5cf 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -27,7 +27,7 @@ #include #include #include -#include "hda_codec.h" +#include #include #include #include diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index a68e75b00ea3bd..55760e5231e62b 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -20,7 +20,7 @@ #include #include #include -#include "hda_codec.h" +#include #include #define AZX_MAX_CODECS HDA_MAX_CODECS diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index ba7fe9b6655c1f..806b12ed44a233 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -27,7 +27,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" enum eld_versions { diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 579984ecdec301..276150f29cda90 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index cc009a4a3d1d20..268bba6ec985a7 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -23,7 +23,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include #include diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index aa4c672dbaf730..4b7666e0374cb2 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -63,7 +63,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_controller.h" #include "hda_intel.h" diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index a33234e04d4f7a..c499727920e61c 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -15,7 +15,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index c6b778b2580c12..a657404196502e 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -25,7 +25,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" static int dump_coef = -1; diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c index 6ec79c58d48de7..c154b19a0c4594 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_sysfs.c @@ -14,7 +14,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include #include diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 0621920f7617f9..4bc5232eac1cb4 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -35,7 +35,7 @@ #include #include -#include "hda_codec.h" +#include #include "hda_controller.h" /* Defines for Nvidia Tegra HDA support */ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index fd476fb40e1b45..ebfd0be885b316 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -24,7 +24,7 @@ #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_beep.h" diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c index c2d9ee9cfdc009..21d0f06109131a 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -22,7 +22,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 0166a3d7cd5557..a585d0ec6d7729 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index a7f91be4519468..64fa5a82bb9f28 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -23,7 +23,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 1b2195dd2b2658..52642ba3e2c0d3 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -25,7 +25,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index cfd4e4f97f8ff2..5592557fe50e4e 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -27,7 +27,7 @@ #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_beep.h" diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index cb587dce67a90c..67099cbb6be2f2 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -41,7 +41,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 3ac7ba9b342d24..69283633ae9108 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index f63acb1b965c0e..c49d25bcd7f2a9 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -27,7 +27,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" /* si3054 verbs */ diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 046705b4691afa..d16a25a395c95c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -32,7 +32,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_beep.h" diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 6b9617aee0e69a..9f6f13e25145ec 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -52,7 +52,7 @@ #include #include #include -#include "hda_codec.h" +#include #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" From 71c2d2d0507488d7187b799271905432da4e8c31 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 Aug 2018 15:24:58 -0500 Subject: [PATCH 0006/1995] ASoC: Intel: common: add table for HDA-based platforms Expose a table containing machine driver information for HDAudio-based platforms handled by ASoC on Intel hardware. We only set constant values that are valid across multiple platforms. The firmware name used by the DSP will be set dynamically for each platform. The table is made of a single entry for now, if we need more complicated set-up where HDAudio is mixed with ACPI-enumerated devices (I2C, SoundWire) then we'd expect the differentiation to be handled through information provided by the BIOS (as done for KBL Chromebooks). Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 8dce1d026da4588382ed8c03e791c7c9b37b22e8) --- include/sound/soc-acpi-intel-match.h | 6 +++ sound/soc/intel/common/Makefile | 3 +- .../intel/common/soc-acpi-intel-hda-match.c | 40 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/common/soc-acpi-intel-hda-match.c diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index bb1d24b703fb05..f48f59e5b7b02b 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -25,4 +25,10 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[]; +/* + * generic table used for HDA codec-based platforms, possibly with + * additional ACPI-enumerated codecs + */ +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[]; + #endif diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 915a34cdc8acbb..c1f50a079d34aa 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -7,7 +7,8 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-hsw-bdw-match.o \ soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ - soc-acpi-intel-cnl-match.o + soc-acpi-intel-cnl-match.o \ + soc-acpi-intel-hda-match.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o diff --git a/sound/soc/intel/common/soc-acpi-intel-hda-match.c b/sound/soc/intel/common/soc-acpi-intel-hda-match.c new file mode 100644 index 00000000000000..533c1064f84b33 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-hda-match.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018, Intel Corporation. + +/* + * soc-apci-intel-hda-match.c - tables and support for HDA+ACPI enumeration. + * + */ + +#include +#include +#include "../skylake/skl.h" + +static struct skl_machine_pdata hda_pdata = { + .use_tplg_pcm = true, +}; + +struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[] = { + { + /* .id is not used in this file */ + .drv_name = "skl_hda_dsp_generic", + + /* .fw_filename is dynamically set in skylake driver */ + + /* .sof_fw_filename is dynamically set in sof/intel driver */ + + .sof_tplg_filename = "intel/sof-hda-generic.tplg", + + /* + * .machine_quirk and .quirk_data are not used here but + * can be used if we need a more complicated machine driver + * combining HDA+other device (e.g. DMIC). + */ + .pdata = &hda_pdata, + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_hda_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); From eada546a111a03bab6af3ce70dde01606527fd69 Mon Sep 17 00:00:00 2001 From: Rakesh Ughreja Date: Wed, 22 Aug 2018 15:24:59 -0500 Subject: [PATCH 0007/1995] ASoC: Intel: Boards: Machine driver for SKL+ w/ HDAudio codecs Add machine driver for Intel platforms (SKL/KBL/BXT/APL) with HDA and iDisp codecs. This patch adds support for only iDisp (HDMI/DP) codec. In the following patches support for HDA codecs will be added. This should work for other Intel platforms as well e.g. GLK,CNL however this series is not tested on all the platforms. Signed-off-by: Rakesh Ughreja Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7c33b5f16915a7bc3d3b81a9a041bdc562f71dfb) --- sound/soc/intel/boards/Kconfig | 8 ++ sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/skl_hda_dsp_common.c | 103 +++++++++++++ sound/soc/intel/boards/skl_hda_dsp_common.h | 38 +++++ sound/soc/intel/boards/skl_hda_dsp_generic.c | 144 +++++++++++++++++++ sound/soc/intel/skylake/skl.h | 2 + 6 files changed, 297 insertions(+) create mode 100644 sound/soc/intel/boards/skl_hda_dsp_common.c create mode 100644 sound/soc/intel/boards/skl_hda_dsp_common.h create mode 100644 sound/soc/intel/boards/skl_hda_dsp_generic.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index cccda87f4b34f1..0f0d578595558f 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -279,6 +279,14 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH This adds support for ASoC Onboard Codec I2S machine driver. This will create an alsa sound card for DA7219 + MAX98357A I2S audio codec. Say Y if you have such a device. + +config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH + tristate "SKL/KBL/BXT/APL with HDA Codecs" + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC machine driver for Intel platforms + SKL/KBL/BXT/APL with iDisp, HDA audio codecs. + Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 87ef8b4058e583..6e88373cbe355b 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -20,6 +20,7 @@ snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o snd-soc-skl_rt286-objs := skl_rt286.o +snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o @@ -46,3 +47,4 @@ obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt566 obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o +obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c new file mode 100644 index 00000000000000..f9917e0f2ba8c3 --- /dev/null +++ b/sound/soc/intel/boards/skl_hda_dsp_common.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2015-18 Intel Corporation. + +/* + * Common functions used in different Intel machine drivers + */ +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/hdac_hdmi.h" +#include "../skylake/skl.h" +#include "skl_hda_dsp_common.h" + +#define NAME_SIZE 32 + +int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device) +{ + struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); + struct skl_hda_hdmi_pcm *pcm; + char dai_name[NAME_SIZE]; + + pcm = devm_kzalloc(card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + snprintf(dai_name, sizeof(dai_name), "intel-hdmi-hifi%d", + ctx->dai_index); + pcm->codec_dai = snd_soc_card_get_codec_dai(card, dai_name); + if (!pcm->codec_dai) + return -EINVAL; + + pcm->device = device; + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +/* skl_hda_digital audio interface glue - connects codec <--> CPU */ +struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = { + /* Back End DAI links */ + { + .name = "iDisp1", + .id = 1, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .id = 2, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .id = 3, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +int skl_hda_hdmi_jack_init(struct snd_soc_card *card) +{ + struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component = NULL; + struct skl_hda_hdmi_pcm *pcm; + char jack_name[NAME_SIZE]; + int err; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &pcm->hdmi_jack, + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &pcm->hdmi_jack); + if (err < 0) + return err; + } + + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); +} diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h new file mode 100644 index 00000000000000..b6c79696bfba1b --- /dev/null +++ b/sound/soc/intel/boards/skl_hda_dsp_common.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(c) 2015-18 Intel Corporation. + */ + +/* + * This file defines data structures used in Machine Driver for Intel + * platforms with HDA Codecs. + */ + +#ifndef __SOUND_SOC_HDA_DSP_COMMON_H +#define __SOUND_SOC_HDA_DSP_COMMON_H +#include +#include +#include +#include + +#define HDA_DSP_MAX_BE_DAI_LINKS 3 + +struct skl_hda_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + struct snd_soc_jack hdmi_jack; + int device; +}; + +struct skl_hda_private { + struct list_head hdmi_pcm_list; + int pcm_count; + int dai_index; + const char *platform_name; +}; + +extern struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS]; +int skl_hda_hdmi_jack_init(struct snd_soc_card *card); +int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device); + +#endif /* __SOUND_SOC_HDA_DSP_COMMON_H */ diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c new file mode 100644 index 00000000000000..920bc2ce22aa37 --- /dev/null +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2015-18 Intel Corporation. + +/* + * Machine Driver for SKL+ platforms with DSP and iDisp, HDA Codecs + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/hdac_hdmi.h" +#include "../skylake/skl.h" +#include "skl_hda_dsp_common.h" + +static const struct snd_soc_dapm_route skl_hda_map[] = { + { "hifi3", NULL, "iDisp3 Tx"}, + { "iDisp3 Tx", NULL, "iDisp3_out"}, + { "hifi2", NULL, "iDisp2 Tx"}, + { "iDisp2 Tx", NULL, "iDisp2_out"}, + { "hifi1", NULL, "iDisp1 Tx"}, + { "iDisp1 Tx", NULL, "iDisp1_out"}, +}; + +static int skl_hda_card_late_probe(struct snd_soc_card *card) +{ + return skl_hda_hdmi_jack_init(card); +} + +static int +skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) +{ + struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); + int ret = 0; + + dev_dbg(card->dev, "%s: dai link name - %s\n", __func__, link->name); + link->platform_name = ctx->platform_name; + link->nonatomic = 1; + + if (strstr(link->name, "HDMI")) { + ret = skl_hda_hdmi_add_pcm(card, ctx->pcm_count); + + if (ret < 0) + return ret; + + ctx->dai_index++; + } + + ctx->pcm_count++; + return ret; +} + +static struct snd_soc_card hda_soc_card = { + .name = "skl_hda_card", + .owner = THIS_MODULE, + .dai_link = skl_hda_be_dai_links, + .dapm_routes = skl_hda_map, + .add_dai_link = skl_hda_add_dai_link, + .fully_routed = true, + .late_probe = skl_hda_card_late_probe, +}; + +#define IDISP_DAI_COUNT 3 +/* there are two routes per iDisp output */ +#define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2) +#define IDISP_CODEC_MASK 0x4 + +static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) +{ + struct snd_soc_card *card = &hda_soc_card; + u32 codec_count, codec_mask; + int i, num_links, num_route; + + codec_mask = pdata->codec_mask; + codec_count = hweight_long(codec_mask); + + if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) { + num_links = IDISP_DAI_COUNT; + num_route = IDISP_ROUTE_COUNT; + } else { + return -EINVAL; + } + + card->num_links = num_links; + card->num_dapm_routes = num_route; + + for (i = 0; i < num_links; i++) + skl_hda_be_dai_links[i].platform_name = pdata->platform; + + return 0; +} + +static int skl_hda_audio_probe(struct platform_device *pdev) +{ + struct skl_machine_pdata *pdata; + struct skl_hda_private *ctx; + int ret; + + dev_dbg(&pdev->dev, "%s: entry\n", __func__); + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + pdata = dev_get_drvdata(&pdev->dev); + if (!pdata) + return -EINVAL; + + ret = skl_hda_fill_card_info(pdata); + if (ret < 0) { + dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n"); + return ret; + } + + ctx->pcm_count = hda_soc_card.num_links; + ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */ + ctx->platform_name = pdata->platform; + + hda_soc_card.dev = &pdev->dev; + snd_soc_card_set_drvdata(&hda_soc_card, ctx); + + return devm_snd_soc_register_card(&pdev->dev, &hda_soc_card); +} + +static struct platform_driver skl_hda_audio = { + .probe = skl_hda_audio_probe, + .driver = { + .name = "skl_hda_dsp_generic", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(skl_hda_audio) + +/* Module information */ +MODULE_DESCRIPTION("SKL/KBL/BXT/APL HDA Generic Machine driver"); +MODULE_AUTHOR("Rakesh Ughreja "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:skl_hda_dsp_generic"); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 78aa8bdcb61929..4105a9371b6425 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -117,6 +117,8 @@ struct skl_dma_params { struct skl_machine_pdata { u32 dmic_num; bool use_tplg_pcm; /* use dais and dai links from topology */ + const char *platform; + u32 codec_mask; }; struct skl_dsp_ops { From 9b7f0a7148d361bab29c654b7b81722a243a192b Mon Sep 17 00:00:00 2001 From: Rakesh Ughreja Date: Wed, 22 Aug 2018 15:25:00 -0500 Subject: [PATCH 0008/1995] ASoC: Intel: Skylake: use HDAudio if ACPI enumeration fails When no I2S based codec entries are found in the BIOS, check if there are any HDA codecs detected on the bus. Based on the number of codecs found take appropriate action in machine driver. If there are two HDA codecs i.e. iDisp + HDA found on the bus, register DAIs and DAI links for both. If only one codec i.e. iDisp is found then load only iDisp machine driver. Signed-off-by: Rakesh Ughreja Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 9cdae4352cba3f66d39a4ef78bb726940ae1e513) --- sound/soc/intel/skylake/skl.c | 38 ++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 1d17be0f78a089..7e0ae0a591b023 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -472,6 +472,25 @@ static struct skl_ssp_clk skl_ssp_clks[] = { {.name = "ssp5_sclkfs"}, }; +static struct snd_soc_acpi_mach *skl_find_hda_machine(struct skl *skl, + struct snd_soc_acpi_mach *machines) +{ + struct hdac_bus *bus = skl_to_bus(skl); + struct snd_soc_acpi_mach *mach; + + /* check if we have any codecs detected on bus */ + if (bus->codec_mask == 0) + return NULL; + + /* point to common table */ + mach = snd_soc_acpi_intel_hda_machines; + + /* all entries in the machine table use the same firmware */ + mach->fw_filename = machines->fw_filename; + + return mach; +} + static int skl_find_machine(struct skl *skl, void *driver_data) { struct hdac_bus *bus = skl_to_bus(skl); @@ -479,9 +498,13 @@ static int skl_find_machine(struct skl *skl, void *driver_data) struct skl_machine_pdata *pdata; mach = snd_soc_acpi_find_machine(mach); - if (mach == NULL) { - dev_err(bus->dev, "No matching machine driver found\n"); - return -ENODEV; + if (!mach) { + dev_dbg(bus->dev, "No matching I2S machine driver found\n"); + mach = skl_find_hda_machine(skl, driver_data); + if (!mach) { + dev_err(bus->dev, "No matching machine driver found\n"); + return -ENODEV; + } } skl->mach = mach; @@ -498,8 +521,9 @@ static int skl_find_machine(struct skl *skl, void *driver_data) static int skl_machine_device_register(struct skl *skl) { - struct hdac_bus *bus = skl_to_bus(skl); struct snd_soc_acpi_mach *mach = skl->mach; + struct hdac_bus *bus = skl_to_bus(skl); + struct skl_machine_pdata *pdata; struct platform_device *pdev; int ret; @@ -516,8 +540,12 @@ static int skl_machine_device_register(struct skl *skl) return -EIO; } - if (mach->pdata) + if (mach->pdata) { + pdata = (struct skl_machine_pdata *)mach->pdata; + pdata->platform = dev_name(bus->dev); + pdata->codec_mask = bus->codec_mask; dev_set_drvdata(&pdev->dev, mach->pdata); + } skl->i2s_dev = pdev; From c22515b33c04330f3cda18ae5525b106181193c2 Mon Sep 17 00:00:00 2001 From: Rakesh Ughreja Date: Wed, 22 Aug 2018 15:25:01 -0500 Subject: [PATCH 0009/1995] ASoC: Intel: Skylake: add HDA BE DAIs Add support for HDA BE DAIs in SKL platform driver. Signed-off-by: Rakesh Ughreja Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 3d17871349d5cec0a37ce9407ba72fdbf8572cfd) --- sound/soc/intel/skylake/skl-pcm.c | 70 +++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 823e39103edd30..00b7a91b18c9a5 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -32,6 +32,7 @@ #define HDA_MONO 1 #define HDA_STEREO 2 #define HDA_QUAD 4 +#define HDA_MAX 8 static const struct snd_pcm_hardware azx_pcm_hw = { .info = (SNDRV_PCM_INFO_MMAP | @@ -569,7 +570,10 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, stream_tag = hdac_stream(link_dev)->stream_tag; /* set the stream tag in the codec dai dma params */ - snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0); + else + snd_soc_dai_set_tdm_slot(codec_dai, 0, stream_tag, 0, 0); p_params.s_fmt = snd_pcm_format_width(params_format(params)); p_params.ch = params_channels(params); @@ -995,21 +999,63 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { }, }, { - .name = "HD-Codec Pin", + .name = "Analog CPU DAI", .ops = &skl_link_dai_ops, .playback = { - .stream_name = "HD-Codec Tx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .stream_name = "Analog CPU Playback", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, }, .capture = { - .stream_name = "HD-Codec Rx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .stream_name = "Analog CPU Capture", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, +}, +{ + .name = "Alt Analog CPU DAI", + .ops = &skl_link_dai_ops, + .playback = { + .stream_name = "Alt Analog CPU Playback", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "Alt Analog CPU Capture", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, +}, +{ + .name = "Digital CPU DAI", + .ops = &skl_link_dai_ops, + .playback = { + .stream_name = "Digital CPU Playback", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .stream_name = "Digital CPU Capture", + .channels_min = HDA_MONO, + .channels_max = HDA_MAX, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, }, }, }; From 8b0723b59a8f46c26377dc584fb26b79479f252d Mon Sep 17 00:00:00 2001 From: Rakesh Ughreja Date: Wed, 22 Aug 2018 15:25:02 -0500 Subject: [PATCH 0010/1995] ASoC: Intel: Skylake: use hda_bus instead of hdac_bus Use hda_bus instead of hdac_bus in the SKL ASoC platform driver to enable reuse of legacy HDA codec drivers. Signed-off-by: Rakesh Ughreja Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 00deadb5d86a3c1e691aaa073a8852a198595099) --- sound/soc/intel/skylake/skl.c | 11 +++++++++-- sound/soc/intel/skylake/skl.h | 10 +++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 7e0ae0a591b023..9952fa5c07eba7 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "skl.h" #include "skl-sst-dsp.h" #include "skl-sst-ipc.h" @@ -673,7 +674,7 @@ static int probe_codec(struct hdac_bus *bus, int addr) mutex_unlock(&bus->cmd_mutex); if (res == -1) return -EIO; - dev_dbg(bus->dev, "codec #%d probed OK\n", addr); + dev_dbg(bus->dev, "codec #%d probed OK: %x\n", addr, res); hdev = devm_kzalloc(&skl->pci->dev, sizeof(*hdev), GFP_KERNEL); if (!hdev) @@ -816,7 +817,7 @@ static int skl_create(struct pci_dev *pci, { struct skl *skl; struct hdac_bus *bus; - + struct hda_bus *hbus; int err; *rskl = NULL; @@ -831,6 +832,7 @@ static int skl_create(struct pci_dev *pci, return -ENOMEM; } + hbus = skl_to_hbus(skl); bus = skl_to_bus(skl); snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, NULL); bus->use_posbuf = 1; @@ -838,6 +840,11 @@ static int skl_create(struct pci_dev *pci, INIT_WORK(&skl->probe_work, skl_probe_work); bus->bdl_pos_adj = 0; + mutex_init(&hbus->prepare_mutex); + hbus->pci = pci; + hbus->mixer_assigned = -1; + hbus->modelname = "sklbus"; + *rskl = skl; return 0; diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 4105a9371b6425..8d48cd7c56c835 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -23,6 +23,7 @@ #include #include +#include #include #include "skl-nhlt.h" #include "skl-ssp-clk.h" @@ -71,7 +72,7 @@ struct skl_fw_config { }; struct skl { - struct hdac_bus hbus; + struct hda_bus hbus; struct pci_dev *pci; unsigned int init_done:1; /* delayed init status */ @@ -105,8 +106,11 @@ struct skl { struct snd_soc_acpi_mach *mach; }; -#define skl_to_bus(s) (&(s)->hbus) -#define bus_to_skl(bus) container_of(bus, struct skl, hbus) +#define skl_to_bus(s) (&(s)->hbus.core) +#define bus_to_skl(bus) container_of(bus, struct skl, hbus.core) + +#define skl_to_hbus(s) (&(s)->hbus) +#define hbus_to_skl(hbus) container_of((hbus), struct skl, (hbus)) /* to pass dai dma data */ struct skl_dma_params { From b4a2cf4161710cb61552af7dab539e0a2a936fc1 Mon Sep 17 00:00:00 2001 From: Rakesh Ughreja Date: Wed, 22 Aug 2018 15:25:03 -0500 Subject: [PATCH 0011/1995] ASoC: hdac_hda: add asoc extension for legacy HDA codec drivers This patch adds a kernel module which is used by the legacy HDA codec drivers as library. This implements hdac_ext_bus_ops to enable the reuse of legacy HDA codec drivers with ASoC platform drivers. Signed-off-by: Rakesh Ughreja Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 6bae5ea9498926440ffc883f3dbceb0adc65e492) --- sound/pci/hda/hda_bind.c | 12 + sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/hdac_hda.c | 484 +++++++++++++++++++ sound/soc/codecs/hdac_hda.h | 24 + sound/soc/intel/boards/Kconfig | 1 + sound/soc/intel/boards/skl_hda_dsp_common.c | 24 + sound/soc/intel/boards/skl_hda_dsp_common.h | 2 +- sound/soc/intel/boards/skl_hda_dsp_generic.c | 38 ++ sound/soc/intel/skylake/skl.c | 47 +- 10 files changed, 634 insertions(+), 5 deletions(-) create mode 100644 sound/soc/codecs/hdac_hda.c create mode 100644 sound/soc/codecs/hdac_hda.h diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index 2222b47d4ec4fb..9174f1b3a987f3 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -81,6 +81,12 @@ static int hda_codec_driver_probe(struct device *dev) hda_codec_patch_t patch; int err; + if (codec->bus->core.ext_ops) { + if (WARN_ON(!codec->bus->core.ext_ops->hdev_attach)) + return -EINVAL; + return codec->bus->core.ext_ops->hdev_attach(&codec->core); + } + if (WARN_ON(!codec->preset)) return -EINVAL; @@ -134,6 +140,12 @@ static int hda_codec_driver_remove(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); + if (codec->bus->core.ext_ops) { + if (WARN_ON(!codec->bus->core.ext_ops->hdev_detach)) + return -EINVAL; + return codec->bus->core.ext_ops->hdev_detach(&codec->core); + } + if (codec->patch_ops.free) codec->patch_ops.free(codec); snd_hda_codec_cleanup_for_unbind(codec); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index efb095dbcd7145..bf0b949eb7e82a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -82,6 +82,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_ES7241 select SND_SOC_GTM601 select SND_SOC_HDAC_HDMI + select SND_SOC_HDAC_HDA select SND_SOC_ICS43432 select SND_SOC_INNO_RK3036 select SND_SOC_ISABELLE if I2C @@ -615,6 +616,10 @@ config SND_SOC_HDAC_HDMI select SND_PCM_ELD select HDMI +config SND_SOC_HDAC_HDA + tristate + select SND_HDA + config SND_SOC_ICS43432 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 7ae7c85e8219f5..3046b33ca9d308 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -78,6 +78,7 @@ snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o snd-soc-gtm601-objs := gtm601.o snd-soc-hdac-hdmi-objs := hdac_hdmi.o +snd-soc-hdac-hda-objs := hdac_hda.o snd-soc-ics43432-objs := ics43432.o snd-soc-inno-rk3036-objs := inno_rk3036.o snd-soc-isabelle-objs := isabelle.o @@ -338,6 +339,7 @@ obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o +obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c new file mode 100644 index 00000000000000..8c25a1332fa7ee --- /dev/null +++ b/sound/soc/codecs/hdac_hda.c @@ -0,0 +1,484 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2015-18 Intel Corporation. + +/* + * hdac_hda.c - ASoC extensions to reuse the legacy HDA codec drivers + * with ASoC platform drivers. These APIs are called by the legacy HDA + * codec drivers using hdac_ext_bus_ops ops. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hdac_hda.h" + +#define HDAC_ANALOG_DAI_ID 0 +#define HDAC_DIGITAL_DAI_ID 1 +#define HDAC_ALT_ANALOG_DAI_ID 2 + +#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_U8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_U16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_U24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE | \ + SNDRV_PCM_FMTBIT_U32_LE | \ + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) + +static int hdac_hda_dai_open(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +static void hdac_hda_dai_close(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width); +static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, + struct snd_soc_dai *dai); + +static struct snd_soc_dai_ops hdac_hda_dai_ops = { + .startup = hdac_hda_dai_open, + .shutdown = hdac_hda_dai_close, + .prepare = hdac_hda_dai_prepare, + .hw_free = hdac_hda_dai_hw_free, + .set_tdm_slot = hdac_hda_dai_set_tdm_slot, +}; + +static struct snd_soc_dai_driver hdac_hda_dais[] = { +{ + .id = HDAC_ANALOG_DAI_ID, + .name = "Analog Codec DAI", + .ops = &hdac_hda_dai_ops, + .playback = { + .stream_name = "Analog Codec Playback", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, + .capture = { + .stream_name = "Analog Codec Capture", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, +}, +{ + .id = HDAC_DIGITAL_DAI_ID, + .name = "Digital Codec DAI", + .ops = &hdac_hda_dai_ops, + .playback = { + .stream_name = "Digital Codec Playback", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, + .capture = { + .stream_name = "Digital Codec Capture", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, +}, +{ + .id = HDAC_ALT_ANALOG_DAI_ID, + .name = "Alt Analog Codec DAI", + .ops = &hdac_hda_dai_ops, + .playback = { + .stream_name = "Alt Analog Codec Playback", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, + .capture = { + .stream_name = "Alt Analog Codec Capture", + .channels_min = 1, + .channels_max = 16, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, +} + +}; + +static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_component *component = dai->component; + struct hdac_hda_priv *hda_pvt; + struct hdac_hda_pcm *pcm; + + hda_pvt = snd_soc_component_get_drvdata(component); + pcm = &hda_pvt->pcm[dai->id]; + if (tx_mask) + pcm[dai->id].stream_tag[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask; + else + pcm[dai->id].stream_tag[SNDRV_PCM_STREAM_CAPTURE] = rx_mask; + + return 0; +} + +static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct hdac_hda_priv *hda_pvt; + struct hda_pcm_stream *hda_stream; + struct hda_pcm *pcm; + + hda_pvt = snd_soc_component_get_drvdata(component); + pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai); + if (!pcm) + return -EINVAL; + + hda_stream = &pcm->stream[substream->stream]; + snd_hda_codec_cleanup(&hda_pvt->codec, hda_stream, substream); + + return 0; +} + +static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct hdac_hda_priv *hda_pvt; + struct snd_pcm_runtime *runtime = substream->runtime; + struct hdac_device *hdev; + struct hda_pcm_stream *hda_stream; + unsigned int format_val; + struct hda_pcm *pcm; + unsigned int stream; + int ret = 0; + + hda_pvt = snd_soc_component_get_drvdata(component); + hdev = &hda_pvt->codec.core; + pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai); + if (!pcm) + return -EINVAL; + + hda_stream = &pcm->stream[substream->stream]; + + format_val = snd_hdac_calc_stream_format(runtime->rate, + runtime->channels, + runtime->format, + hda_stream->maxbps, + 0); + if (!format_val) { + dev_err(&hdev->dev, + "invalid format_val, rate=%d, ch=%d, format=%d\n", + runtime->rate, runtime->channels, runtime->format); + return -EINVAL; + } + + stream = hda_pvt->pcm[dai->id].stream_tag[substream->stream]; + + ret = snd_hda_codec_prepare(&hda_pvt->codec, hda_stream, + stream, format_val, substream); + if (ret < 0) + dev_err(&hdev->dev, "codec prepare failed %d\n", ret); + + return ret; +} + +static int hdac_hda_dai_open(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct hdac_hda_priv *hda_pvt; + struct hda_pcm_stream *hda_stream; + struct hda_pcm *pcm; + int ret; + + hda_pvt = snd_soc_component_get_drvdata(component); + pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai); + if (!pcm) + return -EINVAL; + + snd_hda_codec_pcm_get(pcm); + + hda_stream = &pcm->stream[substream->stream]; + + ret = hda_stream->ops.open(hda_stream, &hda_pvt->codec, substream); + if (ret < 0) + snd_hda_codec_pcm_put(pcm); + + return ret; +} + +static void hdac_hda_dai_close(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct hdac_hda_priv *hda_pvt; + struct hda_pcm_stream *hda_stream; + struct hda_pcm *pcm; + + hda_pvt = snd_soc_component_get_drvdata(component); + pcm = snd_soc_find_pcm_from_dai(hda_pvt, dai); + if (!pcm) + return; + + hda_stream = &pcm->stream[substream->stream]; + + hda_stream->ops.close(hda_stream, &hda_pvt->codec, substream); + + snd_hda_codec_pcm_put(pcm); +} + +static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, + struct snd_soc_dai *dai) +{ + struct hda_codec *hcodec = &hda_pvt->codec; + struct hda_pcm *cpcm; + const char *pcm_name; + + switch (dai->id) { + case HDAC_ANALOG_DAI_ID: + pcm_name = "Analog"; + break; + case HDAC_DIGITAL_DAI_ID: + pcm_name = "Digital"; + break; + case HDAC_ALT_ANALOG_DAI_ID: + pcm_name = "Alt Analog"; + break; + default: + dev_err(&hcodec->core.dev, "invalid dai id %d\n", dai->id); + return NULL; + } + + list_for_each_entry(cpcm, &hcodec->pcm_list_head, list) { + if (strpbrk(cpcm->name, pcm_name)) + return cpcm; + } + + dev_err(&hcodec->core.dev, "didn't find PCM for DAI %s\n", dai->name); + return NULL; +} + +static int hdac_hda_codec_probe(struct snd_soc_component *component) +{ + struct hdac_hda_priv *hda_pvt = + snd_soc_component_get_drvdata(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct hdac_device *hdev = &hda_pvt->codec.core; + struct hda_codec *hcodec = &hda_pvt->codec; + struct hdac_ext_link *hlink; + hda_codec_patch_t patch; + int ret; + + hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); + if (!hlink) { + dev_err(&hdev->dev, "hdac link not found\n"); + return -EIO; + } + + snd_hdac_ext_bus_link_get(hdev->bus, hlink); + + ret = snd_hda_codec_device_new(hcodec->bus, component->card->snd_card, + hdev->addr, hcodec); + if (ret < 0) { + dev_err(&hdev->dev, "failed to create hda codec %d\n", ret); + goto error_no_pm; + } + + /* + * snd_hda_codec_device_new decrements the usage count so call get pm + * else the device will be powered off + */ + pm_runtime_get_noresume(&hdev->dev); + + hcodec->bus->card = dapm->card->snd_card; + + ret = snd_hda_codec_set_name(hcodec, hcodec->preset->name); + if (ret < 0) { + dev_err(&hdev->dev, "name failed %s\n", hcodec->preset->name); + goto error; + } + + ret = snd_hdac_regmap_init(&hcodec->core); + if (ret < 0) { + dev_err(&hdev->dev, "regmap init failed\n"); + goto error; + } + + patch = (hda_codec_patch_t)hcodec->preset->driver_data; + if (patch) { + ret = patch(hcodec); + if (ret < 0) { + dev_err(&hdev->dev, "patch failed %d\n", ret); + goto error; + } + } else { + dev_dbg(&hdev->dev, "no patch file found\n"); + } + + ret = snd_hda_codec_parse_pcms(hcodec); + if (ret < 0) { + dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret); + goto error; + } + + ret = snd_hda_codec_build_controls(hcodec); + if (ret < 0) { + dev_err(&hdev->dev, "unable to create controls %d\n", ret); + goto error; + } + + hcodec->core.lazy_cache = true; + + /* + * hdac_device core already sets the state to active and calls + * get_noresume. So enable runtime and set the device to suspend. + * pm_runtime_enable is also called during codec registeration + */ + pm_runtime_put(&hdev->dev); + pm_runtime_suspend(&hdev->dev); + + return 0; + +error: + pm_runtime_put(&hdev->dev); +error_no_pm: + snd_hdac_ext_bus_link_put(hdev->bus, hlink); + return ret; +} + +static void hdac_hda_codec_remove(struct snd_soc_component *component) +{ + struct hdac_hda_priv *hda_pvt = + snd_soc_component_get_drvdata(component); + struct hdac_device *hdev = &hda_pvt->codec.core; + struct hdac_ext_link *hlink = NULL; + + hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); + if (!hlink) { + dev_err(&hdev->dev, "hdac link not found\n"); + return; + } + + snd_hdac_ext_bus_link_put(hdev->bus, hlink); + pm_runtime_disable(&hdev->dev); +} + +static const struct snd_soc_dapm_route hdac_hda_dapm_routes[] = { + {"AIF1TX", NULL, "Codec Input Pin1"}, + {"AIF2TX", NULL, "Codec Input Pin2"}, + {"AIF3TX", NULL, "Codec Input Pin3"}, + + {"Codec Output Pin1", NULL, "AIF1RX"}, + {"Codec Output Pin2", NULL, "AIF2RX"}, + {"Codec Output Pin3", NULL, "AIF3RX"}, +}; + +static const struct snd_soc_dapm_widget hdac_hda_dapm_widgets[] = { + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "Analog Codec Playback", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2RX", "Digital Codec Playback", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF3RX", "Alt Analog Codec Playback", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "Analog Codec Capture", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2TX", "Digital Codec Capture", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF3TX", "Alt Analog Codec Capture", 0, + SND_SOC_NOPM, 0, 0), + + /* Input Pins */ + SND_SOC_DAPM_INPUT("Codec Input Pin1"), + SND_SOC_DAPM_INPUT("Codec Input Pin2"), + SND_SOC_DAPM_INPUT("Codec Input Pin3"), + + /* Output Pins */ + SND_SOC_DAPM_OUTPUT("Codec Output Pin1"), + SND_SOC_DAPM_OUTPUT("Codec Output Pin2"), + SND_SOC_DAPM_OUTPUT("Codec Output Pin3"), +}; + +static const struct snd_soc_component_driver hdac_hda_codec = { + .probe = hdac_hda_codec_probe, + .remove = hdac_hda_codec_remove, + .idle_bias_on = false, + .dapm_widgets = hdac_hda_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(hdac_hda_dapm_widgets), + .dapm_routes = hdac_hda_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(hdac_hda_dapm_routes), +}; + +static int hdac_hda_dev_probe(struct hdac_device *hdev) +{ + struct hdac_ext_link *hlink; + struct hdac_hda_priv *hda_pvt; + int ret; + + /* hold the ref while we probe */ + hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); + if (!hlink) { + dev_err(&hdev->dev, "hdac link not found\n"); + return -EIO; + } + snd_hdac_ext_bus_link_get(hdev->bus, hlink); + + hda_pvt = hdac_to_hda_priv(hdev); + if (!hda_pvt) + return -ENOMEM; + + /* ASoC specific initialization */ + ret = snd_soc_register_component(&hdev->dev, + &hdac_hda_codec, hdac_hda_dais, + ARRAY_SIZE(hdac_hda_dais)); + if (ret < 0) { + dev_err(&hdev->dev, "failed to register HDA codec %d\n", ret); + return ret; + } + + dev_set_drvdata(&hdev->dev, hda_pvt); + snd_hdac_ext_bus_link_put(hdev->bus, hlink); + + return ret; +} + +static int hdac_hda_dev_remove(struct hdac_device *hdev) +{ + snd_soc_unregister_component(&hdev->dev); + return 0; +} + +static struct hdac_ext_bus_ops hdac_ops = { + .hdev_attach = hdac_hda_dev_probe, + .hdev_detach = hdac_hda_dev_remove, +}; + +struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void) +{ + return &hdac_ops; +} +EXPORT_SYMBOL_GPL(snd_soc_hdac_hda_get_ops); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ASoC Extensions for legacy HDA Drivers"); +MODULE_AUTHOR("Rakesh Ughreja"); diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h new file mode 100644 index 00000000000000..e444ef5933606c --- /dev/null +++ b/sound/soc/codecs/hdac_hda.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(c) 2015-18 Intel Corporation. + */ + +#ifndef __HDAC_HDA_H__ +#define __HDAC_HDA_H__ + +struct hdac_hda_pcm { + int stream_tag[2]; +}; + +struct hdac_hda_priv { + struct hda_codec codec; + struct hdac_hda_pcm pcm[2]; +}; + +#define hdac_to_hda_priv(_hdac) \ + container_of(_hdac, struct hdac_hda_priv, codec.core) +#define hdac_to_hda_codec(_hdac) container_of(_hdac, struct hda_codec, core) + +struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void); + +#endif /* __HDAC_HDA_H__ */ diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 0f0d578595558f..88e4b4284738ab 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -283,6 +283,7 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH tristate "SKL/KBL/BXT/APL with HDA Codecs" select SND_SOC_HDAC_HDMI + select SND_SOC_HDAC_HDA help This adds support for ASoC machine driver for Intel platforms SKL/KBL/BXT/APL with iDisp, HDA audio codecs. diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c index f9917e0f2ba8c3..3fdbf239da741b 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.c +++ b/sound/soc/intel/boards/skl_hda_dsp_common.c @@ -69,6 +69,30 @@ struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = { .dpcm_playback = 1, .no_pcm = 1, }, + { + .name = "Analog Playback and Capture", + .id = 4, + .cpu_dai_name = "Analog CPU DAI", + .codec_name = "ehdaudio0D0", + .codec_dai_name = "Analog Codec DAI", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = NULL, + .no_pcm = 1, + }, + { + .name = "Digital Playback and Capture", + .id = 5, + .cpu_dai_name = "Digital CPU DAI", + .codec_name = "ehdaudio0D0", + .codec_dai_name = "Digital Codec DAI", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = NULL, + .no_pcm = 1, + }, }; int skl_hda_hdmi_jack_init(struct snd_soc_card *card) diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h index b6c79696bfba1b..87c50aff56cdd7 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.h +++ b/sound/soc/intel/boards/skl_hda_dsp_common.h @@ -15,7 +15,7 @@ #include #include -#define HDA_DSP_MAX_BE_DAI_LINKS 3 +#define HDA_DSP_MAX_BE_DAI_LINKS 5 struct skl_hda_hdmi_pcm { struct list_head head; diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 920bc2ce22aa37..b213e9b47505fb 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -16,6 +16,15 @@ #include "../skylake/skl.h" #include "skl_hda_dsp_common.h" +static const struct snd_soc_dapm_widget skl_hda_widgets[] = { + SND_SOC_DAPM_HP("Analog Out", NULL), + SND_SOC_DAPM_MIC("Analog In", NULL), + SND_SOC_DAPM_HP("Alt Analog Out", NULL), + SND_SOC_DAPM_MIC("Alt Analog In", NULL), + SND_SOC_DAPM_SPK("Digital Out", NULL), + SND_SOC_DAPM_MIC("Digital In", NULL), +}; + static const struct snd_soc_dapm_route skl_hda_map[] = { { "hifi3", NULL, "iDisp3 Tx"}, { "iDisp3 Tx", NULL, "iDisp3_out"}, @@ -23,6 +32,29 @@ static const struct snd_soc_dapm_route skl_hda_map[] = { { "iDisp2 Tx", NULL, "iDisp2_out"}, { "hifi1", NULL, "iDisp1 Tx"}, { "iDisp1 Tx", NULL, "iDisp1_out"}, + + { "Analog Out", NULL, "Codec Output Pin1" }, + { "Digital Out", NULL, "Codec Output Pin2" }, + { "Alt Analog Out", NULL, "Codec Output Pin3" }, + + { "Codec Input Pin1", NULL, "Analog In" }, + { "Codec Input Pin2", NULL, "Digital In" }, + { "Codec Input Pin3", NULL, "Alt Analog In" }, + + /* CODEC BE connections */ + { "Analog Codec Playback", NULL, "Analog CPU Playback" }, + { "Analog CPU Playback", NULL, "codec0_out" }, + { "Digital Codec Playback", NULL, "Digital CPU Playback" }, + { "Digital CPU Playback", NULL, "codec1_out" }, + { "Alt Analog Codec Playback", NULL, "Alt Analog CPU Playback" }, + { "Alt Analog CPU Playback", NULL, "codec2_out" }, + + { "codec0_in", NULL, "Analog CPU Capture" }, + { "Analog CPU Capture", NULL, "Analog Codec Capture" }, + { "codec1_in", NULL, "Digital CPU Capture" }, + { "Digital CPU Capture", NULL, "Digital Codec Capture" }, + { "codec2_in", NULL, "Alt Analog CPU Capture" }, + { "Alt Analog CPU Capture", NULL, "Alt Analog Codec Capture" }, }; static int skl_hda_card_late_probe(struct snd_soc_card *card) @@ -57,6 +89,7 @@ static struct snd_soc_card hda_soc_card = { .name = "skl_hda_card", .owner = THIS_MODULE, .dai_link = skl_hda_be_dai_links, + .dapm_widgets = skl_hda_widgets, .dapm_routes = skl_hda_map, .add_dai_link = skl_hda_add_dai_link, .fully_routed = true, @@ -80,6 +113,11 @@ static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) { num_links = IDISP_DAI_COUNT; num_route = IDISP_ROUTE_COUNT; + } else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) { + num_links = ARRAY_SIZE(skl_hda_be_dai_links); + num_route = ARRAY_SIZE(skl_hda_map), + card->dapm_widgets = skl_hda_widgets; + card->num_dapm_widgets = ARRAY_SIZE(skl_hda_widgets); } else { return -EINVAL; } diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 9952fa5c07eba7..29225623b4b40d 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -37,6 +37,7 @@ #include "skl.h" #include "skl-sst-dsp.h" #include "skl-sst-ipc.h" +#include "../../../soc/codecs/hdac_hda.h" /* * initialize the PCI registers @@ -657,6 +658,24 @@ static void skl_clock_device_unregister(struct skl *skl) platform_device_unregister(skl->clk_dev); } +#define IDISP_INTEL_VENDOR_ID 0x80860000 + +/* + * load the legacy codec driver + */ +static void load_codec_module(struct hda_codec *codec) +{ +#ifdef MODULE + char modalias[MODULE_NAME_LEN]; + const char *mod = NULL; + + snd_hdac_codec_modalias(&codec->core, modalias, sizeof(modalias)); + mod = modalias; + dev_dbg(&codec->core.dev, "loading %s codec module\n", mod); + request_module(mod); +#endif +} + /* * Probe the given codec address */ @@ -666,7 +685,9 @@ static int probe_codec(struct hdac_bus *bus, int addr) (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; unsigned int res = -1; struct skl *skl = bus_to_skl(bus); + struct hdac_hda_priv *hda_codec; struct hdac_device *hdev; + int err; mutex_lock(&bus->cmd_mutex); snd_hdac_bus_send_cmd(bus, cmd); @@ -676,11 +697,24 @@ static int probe_codec(struct hdac_bus *bus, int addr) return -EIO; dev_dbg(bus->dev, "codec #%d probed OK: %x\n", addr, res); - hdev = devm_kzalloc(&skl->pci->dev, sizeof(*hdev), GFP_KERNEL); - if (!hdev) + hda_codec = devm_kzalloc(&skl->pci->dev, sizeof(*hda_codec), + GFP_KERNEL); + if (!hda_codec) return -ENOMEM; - return snd_hdac_ext_bus_device_init(bus, addr, hdev); + hda_codec->codec.bus = skl_to_hbus(skl); + hdev = &hda_codec->codec.core; + + err = snd_hdac_ext_bus_device_init(bus, addr, hdev); + if (err < 0) + return err; + + /* use legacy bus only for HDA codecs, idisp uses ext bus */ + if ((res & 0xFFFF0000) != IDISP_INTEL_VENDOR_ID) { + hdev->type = HDA_DEV_LEGACY; + load_codec_module(&hda_codec->codec); + } + return 0; } /* Codec initialization */ @@ -815,6 +849,7 @@ static int skl_create(struct pci_dev *pci, const struct hdac_io_ops *io_ops, struct skl **rskl) { + struct hdac_ext_bus_ops *ext_ops = NULL; struct skl *skl; struct hdac_bus *bus; struct hda_bus *hbus; @@ -834,7 +869,11 @@ static int skl_create(struct pci_dev *pci, hbus = skl_to_hbus(skl); bus = skl_to_bus(skl); - snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, NULL); + +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDA) + ext_ops = snd_soc_hdac_hda_get_ops(); +#endif + snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, ext_ops); bus->use_posbuf = 1; skl->pci = pci; INIT_WORK(&skl->probe_work, skl_probe_work); From 358466f81ade5685e12291bec84cdf0e702b7a32 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 21 Aug 2018 13:43:35 +0200 Subject: [PATCH 0012/1995] ASoC: rt5670: Add quirk for Thinkpad 8 tablet The Thinkpad 8 needs a quirk for jack-detect and the internal mic to work correctly. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit 818838e6bfa4ddc6c76703237028dcffb80d6496) --- sound/soc/codecs/rt5670.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 732ef928b25d9c..455fe7cff700bd 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2875,6 +2875,18 @@ static const struct dmi_system_id dmi_platform_intel_quirks[] = { RT5670_DEV_GPIO | RT5670_JD_MODE1), }, + { + .callback = rt5670_quirk_cb, + .ident = "Lenovo Thinkpad Tablet 8", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"), + }, + .driver_data = (unsigned long *)(RT5670_DMIC_EN | + RT5670_DMIC2_INR | + RT5670_DEV_GPIO | + RT5670_JD_MODE1), + }, { .callback = rt5670_quirk_cb, .ident = "Lenovo Thinkpad Tablet 10", From ba4cca0383a77f95242116525a17e5acce3bff98 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 21 Aug 2018 13:43:36 +0200 Subject: [PATCH 0013/1995] ASoC: Intel: common: Add quirk for Thinkpad 8 tablet The Thinkpad 8 tablet uses 10EC5640 as ACPI HID, but it has a rt5670 codec add a quirk for this. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit 2ca426a24dd75e775ece1466ae45e019f0035b8d) --- sound/soc/intel/common/soc-acpi-intel-byt-match.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 4daa8a4f0c0c69..097dc06377baaf 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -30,6 +30,13 @@ static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id) static const struct dmi_system_id byt_table[] = { + { + .callback = byt_thinkpad10_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 8"), + }, + }, { .callback = byt_thinkpad10_quirk_cb, .matches = { From 6ed5656209cc51ec0cb2658677cbd843eca84d2c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 21 Aug 2018 13:43:37 +0200 Subject: [PATCH 0014/1995] ASoC: Intel: cht-bsw-rt5672: Add key-mappings for the headset buttons Having the headset buttons send BTN_0, BTN_1 and BTN_2 events is not really useful. Add mappings to PLAYPAUSE VOLUME_UP and VOLUME_DOWN like we do in other Intel machine drivers. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit f8fc397e13107f925186ee742e9e8dfbfe9a3d03) --- sound/soc/intel/boards/cht_bsw_rt5672.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index e5aa13058dd738..e054318185ea36 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -16,6 +16,7 @@ * General Public License for more details. */ +#include #include #include #include @@ -212,6 +213,10 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) if (ret) return ret; + snd_jack_set_key(ctx->headset.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(ctx->headset.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(ctx->headset.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + rt5670_set_jack_detect(component, &ctx->headset); if (ctx->mclk) { /* From 498cd6554b618bcabfc65e2b96b6b2b6dbde9280 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 29 Aug 2018 17:00:49 +0200 Subject: [PATCH 0015/1995] ASoC: dmic: add DT module alias Before this patch the only alias provided by the dmic module is: alias: platform:dmic-codec Device instantiated from DT will not probe automatically with this After this patch, here is the new alias list: alias: platform:dmic-codec alias: of:N*T*Cdmic-codecC* alias: of:N*T*Cdmic-codec Now the dmic codec probes automatically when instantiated from DT. Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown (cherry picked from commit cb06a037f8362e250a6e61872ffa01ab086ec9e2) --- sound/soc/codecs/dmic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index 8c4926df92862f..71322e0410ee76 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -148,6 +148,7 @@ static const struct of_device_id dmic_dev_match[] = { {.compatible = "dmic-codec"}, {} }; +MODULE_DEVICE_TABLE(of, dmic_dev_match); static struct platform_driver dmic_driver = { .driver = { From 9cb26a62c45b7269b796ef3b3f0f25c62b0374ad Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 31 Aug 2018 03:10:08 +0000 Subject: [PATCH 0016/1995] ASoC: soc-core: use snd_soc_dai_link_component for platform Current struct snd_soc_dai_link is supporting multicodec, and it is supporting legacy style of codec_name codec_of_node code_dai_name This is handled as single entry of multicodec. We don't have multicpu support yet, but in the future we will. In such case, we can use snd_soc_dai_link_component for both cpu/codec. Then the code will be more simple and readble. As next step, we want to use it for platform, too. This patch adds snd_soc_dai_link_component style for platform. We might have multiplatform support in the future, but we don't know yet. To avoid un-known issue / complex code, this patch supports just single-platform as 1st step. If we could use snd_soc_dai_link_component for all CPU/Codec/Platform, we will switch to new style, and remove legacy code. This is prepare for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit daecf46ee0e5f0fb2349e20af53c4653e2afc440) --- include/sound/soc.h | 2 ++ sound/soc/soc-core.c | 48 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 41cec42fb456a5..96c19aabf21b82 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -915,6 +915,8 @@ struct snd_soc_dai_link { */ const char *platform_name; struct device_node *platform_of_node; + struct snd_soc_dai_link_component *platform; + int id; /* optional ID for machine driver link identification */ const struct snd_soc_pcm_stream *params; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 473eefe8658e9a..2a73630d06804a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -892,8 +892,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->codec_dai = codec_dais[0]; /* if there's no platform we match on the empty platform */ - platform_name = dai_link->platform_name; - if (!platform_name && !dai_link->platform_of_node) + platform_name = dai_link->platform->name; + if (!platform_name && !dai_link->platform->of_node) platform_name = "snd-soc-dummy"; /* find one from the set of registered platforms */ @@ -902,8 +902,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card, if (!platform_of_node && component->dev->parent->of_node) platform_of_node = component->dev->parent->of_node; - if (dai_link->platform_of_node) { - if (platform_of_node != dai_link->platform_of_node) + if (dai_link->platform->of_node) { + if (platform_of_node != dai_link->platform->of_node) continue; } else { if (strcmp(component->name, platform_name)) @@ -1015,6 +1015,31 @@ static void soc_remove_dai_links(struct snd_soc_card *card) } } +static int snd_soc_init_platform(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) +{ + /* + * FIXME + * + * this function should be removed in the future + */ + /* convert Legacy platform link */ + if (dai_link->platform) + return 0; + + dai_link->platform = devm_kzalloc(card->dev, + sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!dai_link->platform) + return -ENOMEM; + + dai_link->platform->name = dai_link->platform_name; + dai_link->platform->of_node = dai_link->platform_of_node; + dai_link->platform->dai_name = NULL; + + return 0; +} + static int snd_soc_init_multicodec(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { @@ -1047,6 +1072,12 @@ static int soc_init_dai_link(struct snd_soc_card *card, { int i, ret; + ret = snd_soc_init_platform(card, link); + if (ret) { + dev_err(card->dev, "ASoC: failed to init multiplatform\n"); + return ret; + } + ret = snd_soc_init_multicodec(card, link); if (ret) { dev_err(card->dev, "ASoC: failed to init multicodec\n"); @@ -1076,13 +1107,12 @@ static int soc_init_dai_link(struct snd_soc_card *card, * Platform may be specified by either name or OF node, but * can be left unspecified, and a dummy platform will be used. */ - if (link->platform_name && link->platform_of_node) { + if (link->platform->name && link->platform->of_node) { dev_err(card->dev, "ASoC: Both platform name/of_node are set for %s\n", link->name); return -EINVAL; } - /* * CPU device may be specified by either name or OF node, but * can be left unspecified, and will be matched based on DAI @@ -1917,7 +1947,11 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) card->dai_link[i].name); /* override platform component */ - dai_link->platform_name = component->name; + if (snd_soc_init_platform(card, dai_link) < 0) { + dev_err(card->dev, "init platform error"); + continue; + } + dai_link->platform->name = component->name; /* convert non BE into BE */ dai_link->no_pcm = 1; From 0ce23a31c4f400e6f21d5f68323c2027298167ce Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 2 Sep 2018 19:38:10 -0700 Subject: [PATCH 0017/1995] ASoC: fix soc-core.c kernel-doc warning Fix kernel-doc warning: ../sound/soc/soc-core.c:2918: warning: Excess function parameter 'legacy_dai_naming' description in 'snd_soc_register_dais' Signed-off-by: Randy Dunlap Signed-off-by: Mark Brown (cherry picked from commit 63a886f38dd96868e33488eccee8ed427144d397) --- sound/soc/soc-core.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2a73630d06804a..e9c2304afaf192 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2944,8 +2944,6 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, * @component: The component the DAIs are registered for * @dai_drv: DAI driver to use for the DAIs * @count: Number of DAIs - * @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the - * parent's name. */ static int snd_soc_register_dais(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv, size_t count) From 165215f1f62e2b438bb20e3f402d2e56d57b957b Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 17 Aug 2018 16:35:43 +0100 Subject: [PATCH 0018/1995] ASoC: core: Don't schedule DAPM work if already in target state When dapm_power_widgets() is called, the dapm_pre_sequence_async() and dapm_post_sequence_async() functions are scheduled for all DAPM contexts (apart from the card DAPM context) regardless of whether the DAPM context is already in the desired state. The overhead of this is not insignificant and the more DAPM contexts there are the more overhead there is. For example, on the Tegra124 Jetson TK1, when profiling the time taken to execute the dapm_power_widgets() the following times were observed. Times for function dapm_power_widgets() are (us): Min 23, Ave 190, Max 434, Count 39 Here 'Count' is the number of times that dapm_power_widgets() has been called. Please note that the above time were measured using ktime_get() to log the time on entry and exit from dapm_power_widgets(). So it should be noted that these times may not be purely the time take to execute this function if it is preempted. However, after applying this patch and measuring the time taken to execute dapm_power_widgets() again a significant improvement is seen as shown below. Times for function dapm_power_widgets() are (us): Min 4, Ave 16, Max 82, Count 39 Therefore, optimise the dapm_power_widgets() function by only scheduling the dapm_pre/post_sequence_async() work if the DAPM context is not in the desired state. Signed-off-by: Jon Hunter Reviewed-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit e03546ddd3db5352a74dec247dbdaa29889e93f7) --- sound/soc/soc-dapm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d7be3981f0269d..9feccd2e7c1175 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1952,7 +1952,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) dapm_pre_sequence_async(&card->dapm, 0); /* Run other bias changes in parallel */ list_for_each_entry(d, &card->dapm_list, list) { - if (d != &card->dapm) + if (d != &card->dapm && d->bias_level != d->target_bias_level) async_schedule_domain(dapm_pre_sequence_async, d, &async_domain); } @@ -1976,7 +1976,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) /* Run all the bias changes in parallel */ list_for_each_entry(d, &card->dapm_list, list) { - if (d != &card->dapm) + if (d != &card->dapm && d->bias_level != d->target_bias_level) async_schedule_domain(dapm_post_sequence_async, d, &async_domain); } From af041ffa77f26ec781ce6d9864205193ca539b22 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 3 Sep 2018 02:12:40 +0000 Subject: [PATCH 0019/1995] ASoC: add for_each_link_codecs() macro ALSA SoC snd_soc_dai_link has snd_soc_dai_link_component array for codecs. To be more readable code, this patch adds new for_each_link_codecs() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 3db769f17714ae65f2faf44ff2bae9d52f4bd46b) --- include/sound/soc.h | 4 ++++ sound/soc/meson/axg-card.c | 5 +++-- sound/soc/soc-core.c | 17 ++++++++--------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 96c19aabf21b82..ce42c578fe8226 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -978,6 +978,10 @@ struct snd_soc_dai_link { struct list_head list; /* DAI link list of the soc card */ struct snd_soc_dobj dobj; /* For topology */ }; +#define for_each_link_codecs(link, i, codec) \ + for ((i) = 0; \ + ((i) < link->num_codecs) && ((codec) = &link->codecs[i]); \ + (i)++) struct snd_soc_codec_conf { /* diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index 2914ba0d965bd8..b6c1596c4e4c2f 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -97,14 +97,15 @@ static void axg_card_clean_references(struct axg_card *priv) { struct snd_soc_card *card = &priv->card; struct snd_soc_dai_link *link; + struct snd_soc_dai_link_component *codec; int i, j; if (card->dai_link) { for (i = 0; i < card->num_links; i++) { link = &card->dai_link[i]; of_node_put(link->cpu_of_node); - for (j = 0; j < link->num_codecs; j++) - of_node_put(link->codecs[j].of_node); + for_each_link_codecs(link, j, codec) + of_node_put(codec->of_node); } } diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e9c2304afaf192..eeab492e954fd8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1071,6 +1071,7 @@ static int soc_init_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) { int i, ret; + struct snd_soc_dai_link_component *codec; ret = snd_soc_init_platform(card, link); if (ret) { @@ -1084,19 +1085,19 @@ static int soc_init_dai_link(struct snd_soc_card *card, return ret; } - for (i = 0; i < link->num_codecs; i++) { + for_each_link_codecs(link, i, codec) { /* * Codec must be specified by 1 of name or OF node, * not both or neither. */ - if (!!link->codecs[i].name == - !!link->codecs[i].of_node) { + if (!!codec->name == + !!codec->of_node) { dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n", link->name); return -EINVAL; } /* Codec DAI name must be specified */ - if (!link->codecs[i].dai_name) { + if (!codec->dai_name) { dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n", link->name); return -EINVAL; @@ -3796,10 +3797,10 @@ EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); */ void snd_soc_of_put_dai_link_codecs(struct snd_soc_dai_link *dai_link) { - struct snd_soc_dai_link_component *component = dai_link->codecs; + struct snd_soc_dai_link_component *component; int index; - for (index = 0; index < dai_link->num_codecs; index++, component++) { + for_each_link_codecs(dai_link, index, component) { if (!component->of_node) break; of_node_put(component->of_node); @@ -3851,9 +3852,7 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev, dai_link->num_codecs = num_codecs; /* Parse the list */ - for (index = 0, component = dai_link->codecs; - index < dai_link->num_codecs; - index++, component++) { + for_each_link_codecs(dai_link, index, component) { ret = of_parse_phandle_with_args(of_node, name, "#sound-dai-cells", index, &args); From afb967df150a2441156622f851c63b5f556256da Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 3 Sep 2018 02:12:56 +0000 Subject: [PATCH 0020/1995] ASoC: add for_each_rtd_codec_dai() macro ALSA SoC snd_soc_pcm_runtime has snd_soc_dai array for codec_dai. To be more readable code, this patch adds new for_each_rtd_codec_dai() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 0b7990e38971da403ce223d8bdc758a817eb72f8) --- include/sound/soc.h | 7 + sound/soc/intel/boards/kbl_rt5663_max98927.c | 5 +- .../intel/boards/kbl_rt5663_rt5514_max98927.c | 5 +- .../mediatek/mt8173/mt8173-rt5650-rt5514.c | 5 +- .../mediatek/mt8173/mt8173-rt5650-rt5676.c | 5 +- sound/soc/mediatek/mt8173/mt8173-rt5650.c | 5 +- sound/soc/meson/axg-card.c | 6 +- sound/soc/soc-core.c | 38 ++--- sound/soc/soc-dapm.c | 14 +- sound/soc/soc-pcm.c | 154 ++++++++---------- 10 files changed, 118 insertions(+), 126 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index ce42c578fe8226..6b68b31e314013 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1158,6 +1158,13 @@ struct snd_soc_pcm_runtime { unsigned int dev_registered:1; unsigned int pop_wait:1; }; +#define for_each_rtd_codec_dai(rtd, i, dai)\ + for ((i) = 0; \ + ((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \ + (i)++) +#define for_each_rtd_codec_dai_reverse(rtd, i, dai) \ + for (; ((i--) >= 0) && ((dai) = rtd->codec_dais[i]);) + /* mixer control */ struct soc_mixer_control { diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index 21a6490746a6f9..99e1320c485ff2 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -488,11 +488,10 @@ static int kabylake_ssp0_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; int ret = 0, j; - for (j = 0; j < rtd->num_codecs; j++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; - + for_each_rtd_codec_dai(rtd, j, codec_dai) { if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { /* * Use channel 4 and 5 for the first amp diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index a892b37eab7c92..a737c915d46a83 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -353,11 +353,10 @@ static int kabylake_ssp0_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; int ret = 0, j; - for (j = 0; j < rtd->num_codecs; j++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; - + for_each_rtd_codec_dai(rtd, j, codec_dai) { if (!strcmp(codec_dai->component->name, RT5514_DEV_NAME)) { ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0, 8, 16); if (ret < 0) { diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index 582174d98c6c9c..5b4e90180827a7 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -44,11 +44,10 @@ static int mt8173_rt5650_rt5514_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; int i, ret; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; - + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* pll from mclk 12.288M */ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS, params_rate(params) * 512); diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index b3670c8a5b8de1..82675ed057dee9 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -48,11 +48,10 @@ static int mt8173_rt5650_rt5676_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; int i, ret; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; - + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* pll from mclk 12.288M */ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS, params_rate(params) * 512); diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index 7a89b4aad182fb..ef05fbc40c324f 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -59,6 +59,7 @@ static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; unsigned int mclk_clock; + struct snd_soc_dai *codec_dai; int i, ret; switch (mt8173_rt5650_priv.pll_from) { @@ -76,9 +77,7 @@ static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream, break; } - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; - + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* pll from mclk */ ret = snd_soc_dai_set_pll(codec_dai, 0, 0, mclk_clock, params_rate(params) * 512); diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index b6c1596c4e4c2f..b9163970ab7af7 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -168,8 +168,7 @@ static int axg_card_tdm_be_hw_params(struct snd_pcm_substream *substream, if (be->mclk_fs) { mclk = params_rate(params) * be->mclk_fs; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN); if (ret && ret != -ENOTSUPP) @@ -197,8 +196,7 @@ static int axg_card_tdm_dai_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dai *codec_dai; int ret, i; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { ret = snd_soc_dai_set_tdm_slot(codec_dai, be->codec_masks[i].tx, be->codec_masks[i].rx, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index eeab492e954fd8..390da15c4a8b9d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -452,12 +452,12 @@ int snd_soc_suspend(struct device *dev) /* mute any active DACs */ list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *dai; if (rtd->dai_link->ignore_suspend) continue; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, dai) { struct snd_soc_dai_driver *drv = dai->driver; if (drv->ops->digital_mute && dai->playback_active) @@ -625,12 +625,12 @@ static void soc_resume_deferred(struct work_struct *work) /* unmute any active DACs */ list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *dai; if (rtd->dai_link->ignore_suspend) continue; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, dai) { struct snd_soc_dai_driver *drv = dai->driver; if (drv->ops->digital_mute && dai->playback_active) @@ -674,15 +674,14 @@ int snd_soc_resume(struct device *dev) /* activate pins from sleep state */ list_for_each_entry(rtd, &card->rtd_list, list) { - struct snd_soc_dai **codec_dais = rtd->codec_dais; + struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int j; if (cpu_dai->active) pinctrl_pm_select_default_state(cpu_dai->dev); - for (j = 0; j < rtd->num_codecs; j++) { - struct snd_soc_dai *codec_dai = codec_dais[j]; + for_each_rtd_codec_dai(rtd, j, codec_dai) { if (codec_dai->active) pinctrl_pm_select_default_state(codec_dai->dev); } @@ -877,6 +876,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ + /* we can use for_each_rtd_codec_dai() after this */ codec_dais = rtd->codec_dais; for (i = 0; i < rtd->num_codecs; i++) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); @@ -959,6 +959,7 @@ static void soc_remove_link_dais(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, int order) { int i; + struct snd_soc_dai *codec_dai; /* unregister the rtd device */ if (rtd->dev_registered) { @@ -967,8 +968,8 @@ static void soc_remove_link_dais(struct snd_soc_card *card, } /* remove the CODEC DAI */ - for (i = 0; i < rtd->num_codecs; i++) - soc_remove_dai(rtd->codec_dais[i], order); + for_each_rtd_codec_dai(rtd, i, codec_dai) + soc_remove_dai(codec_dai, order); soc_remove_dai(rtd->cpu_dai, order); } @@ -1511,6 +1512,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_component *component; + struct snd_soc_dai *codec_dai; int i, ret, num; dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", @@ -1524,8 +1526,8 @@ static int soc_probe_link_dais(struct snd_soc_card *card, return ret; /* probe the CODEC DAI */ - for (i = 0; i < rtd->num_codecs; i++) { - ret = soc_probe_dai(rtd->codec_dais[i], order); + for_each_rtd_codec_dai(rtd, i, codec_dai) { + ret = soc_probe_dai(codec_dai, order); if (ret) return ret; } @@ -1712,14 +1714,12 @@ static void soc_remove_aux_devices(struct snd_soc_card *card) int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, unsigned int dai_fmt) { - struct snd_soc_dai **codec_dais = rtd->codec_dais; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; unsigned int i; int ret; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = codec_dais[i]; - + for_each_rtd_codec_dai(rtd, i, codec_dai) { ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt); if (ret != 0 && ret != -ENOTSUPP) { dev_warn(codec_dai->dev, @@ -2266,11 +2266,11 @@ int snd_soc_poweroff(struct device *dev) /* deactivate pins to sleep state */ list_for_each_entry(rtd, &card->rtd_list, list) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; int i; pinctrl_pm_select_sleep_state(cpu_dai->dev); - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { pinctrl_pm_select_sleep_state(codec_dai->dev); } } @@ -2776,10 +2776,10 @@ int snd_soc_register_card(struct snd_soc_card *card) /* deactivate pins to sleep state */ list_for_each_entry(rtd, &card->rtd_list, list) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; int j; - for (j = 0; j < rtd->num_codecs; j++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; + for_each_rtd_codec_dai(rtd, j, codec_dai) { if (!codec_dai->active) pinctrl_pm_select_sleep_state(codec_dai->dev); } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 9feccd2e7c1175..0a738cb439becf 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2370,12 +2370,13 @@ static ssize_t dapm_widget_show(struct device *dev, struct device_attribute *attr, char *buf) { struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); + struct snd_soc_dai *codec_dai; int i, count = 0; mutex_lock(&rtd->card->dapm_mutex); - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_component *cmpnt = rtd->codec_dais[i]->component; + for_each_rtd_codec_dai(rtd, i, codec_dai) { + struct snd_soc_component *cmpnt = codec_dai->component; count += dapm_widget_show_component(cmpnt, buf + count); } @@ -4110,11 +4111,11 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; struct snd_soc_dapm_widget *sink, *source; int i; - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* connect BE DAI playback if widgets are valid */ if (codec_dai->playback_widget && cpu_dai->playback_widget) { @@ -4202,11 +4203,12 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, int event) { + struct snd_soc_dai *codec_dai; int i; soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event); - for (i = 0; i < rtd->num_codecs; i++) - soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event); + for_each_rtd_codec_dai(rtd, i, codec_dai) + soc_dapm_dai_stream_event(codec_dai, stream, event); dapm_power_widgets(rtd->card, event); } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index eb6f4f1b65a92b..79f5dd541d2997 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -59,25 +59,26 @@ static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream) void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; int i; lockdep_assert_held(&rtd->pcm_mutex); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { cpu_dai->playback_active++; - for (i = 0; i < rtd->num_codecs; i++) - rtd->codec_dais[i]->playback_active++; + for_each_rtd_codec_dai(rtd, i, codec_dai) + codec_dai->playback_active++; } else { cpu_dai->capture_active++; - for (i = 0; i < rtd->num_codecs; i++) - rtd->codec_dais[i]->capture_active++; + for_each_rtd_codec_dai(rtd, i, codec_dai) + codec_dai->capture_active++; } cpu_dai->active++; cpu_dai->component->active++; - for (i = 0; i < rtd->num_codecs; i++) { - rtd->codec_dais[i]->active++; - rtd->codec_dais[i]->component->active++; + for_each_rtd_codec_dai(rtd, i, codec_dai) { + codec_dai->active++; + codec_dai->component->active++; } } @@ -94,25 +95,26 @@ void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; int i; lockdep_assert_held(&rtd->pcm_mutex); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { cpu_dai->playback_active--; - for (i = 0; i < rtd->num_codecs; i++) - rtd->codec_dais[i]->playback_active--; + for_each_rtd_codec_dai(rtd, i, codec_dai) + codec_dai->playback_active--; } else { cpu_dai->capture_active--; - for (i = 0; i < rtd->num_codecs; i++) - rtd->codec_dais[i]->capture_active--; + for_each_rtd_codec_dai(rtd, i, codec_dai) + codec_dai->capture_active--; } cpu_dai->active--; cpu_dai->component->active--; - for (i = 0; i < rtd->num_codecs; i++) { - rtd->codec_dais[i]->component->active--; - rtd->codec_dais[i]->active--; + for_each_rtd_codec_dai(rtd, i, codec_dai) { + codec_dai->component->active--; + codec_dai->active--; } } @@ -253,6 +255,7 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; unsigned int rate, channels, sample_bits, symmetry, i; rate = params_rate(params); @@ -263,8 +266,8 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, symmetry = cpu_dai->driver->symmetric_rates || rtd->dai_link->symmetric_rates; - for (i = 0; i < rtd->num_codecs; i++) - symmetry |= rtd->codec_dais[i]->driver->symmetric_rates; + for_each_rtd_codec_dai(rtd, i, codec_dai) + symmetry |= codec_dai->driver->symmetric_rates; if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) { dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n", @@ -275,8 +278,8 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, symmetry = cpu_dai->driver->symmetric_channels || rtd->dai_link->symmetric_channels; - for (i = 0; i < rtd->num_codecs; i++) - symmetry |= rtd->codec_dais[i]->driver->symmetric_channels; + for_each_rtd_codec_dai(rtd, i, codec_dai) + symmetry |= codec_dai->driver->symmetric_channels; if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) { dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n", @@ -287,8 +290,8 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, symmetry = cpu_dai->driver->symmetric_samplebits || rtd->dai_link->symmetric_samplebits; - for (i = 0; i < rtd->num_codecs; i++) - symmetry |= rtd->codec_dais[i]->driver->symmetric_samplebits; + for_each_rtd_codec_dai(rtd, i, codec_dai) + symmetry |= codec_dai->driver->symmetric_samplebits; if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) { dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n", @@ -304,17 +307,18 @@ static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver; struct snd_soc_dai_link *link = rtd->dai_link; + struct snd_soc_dai *codec_dai; unsigned int symmetry, i; symmetry = cpu_driver->symmetric_rates || link->symmetric_rates || cpu_driver->symmetric_channels || link->symmetric_channels || cpu_driver->symmetric_samplebits || link->symmetric_samplebits; - for (i = 0; i < rtd->num_codecs; i++) + for_each_rtd_codec_dai(rtd, i, codec_dai) symmetry = symmetry || - rtd->codec_dais[i]->driver->symmetric_rates || - rtd->codec_dais[i]->driver->symmetric_channels || - rtd->codec_dais[i]->driver->symmetric_samplebits; + codec_dai->driver->symmetric_rates || + codec_dai->driver->symmetric_channels || + codec_dai->driver->symmetric_samplebits; return symmetry; } @@ -342,8 +346,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream) unsigned int bits = 0, cpu_bits; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->playback.sig_bits == 0) { bits = 0; break; @@ -352,8 +355,7 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream) } cpu_bits = cpu_dai->driver->playback.sig_bits; } else { - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->capture.sig_bits == 0) { bits = 0; break; @@ -372,6 +374,7 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hardware *hw = &runtime->hw; struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai; struct snd_soc_dai_driver *cpu_dai_drv = rtd->cpu_dai->driver; struct snd_soc_dai_driver *codec_dai_drv; struct snd_soc_pcm_stream *codec_stream; @@ -388,7 +391,7 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream) cpu_stream = &cpu_dai_drv->capture; /* first calculate min/max only for CODECs in the DAI link */ - for (i = 0; i < rtd->num_codecs; i++) { + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* * Skip CODECs which don't support the current stream type. @@ -399,11 +402,11 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream) * bailed out on a higher level, since there would be no * CODEC to support the transfer direction in that case. */ - if (!snd_soc_dai_stream_valid(rtd->codec_dais[i], + if (!snd_soc_dai_stream_valid(codec_dai, substream->stream)) continue; - codec_dai_drv = rtd->codec_dais[i]->driver; + codec_dai_drv = codec_dai->driver; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) codec_stream = &codec_dai_drv->playback; else @@ -482,8 +485,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) int i, ret = 0; pinctrl_pm_select_default_state(cpu_dai->dev); - for (i = 0; i < rtd->num_codecs; i++) - pinctrl_pm_select_default_state(rtd->codec_dais[i]->dev); + for_each_rtd_codec_dai(rtd, i, codec_dai) + pinctrl_pm_select_default_state(codec_dai->dev); for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -520,8 +523,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } component = NULL; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->startup) { ret = codec_dai->driver->ops->startup(substream, codec_dai); @@ -588,10 +590,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) goto config_err; } - for (i = 0; i < rtd->num_codecs; i++) { - if (rtd->codec_dais[i]->active) { - ret = soc_pcm_apply_symmetry(substream, - rtd->codec_dais[i]); + for_each_rtd_codec_dai(rtd, i, codec_dai) { + if (codec_dai->active) { + ret = soc_pcm_apply_symmetry(substream, codec_dai); if (ret != 0) goto config_err; } @@ -620,8 +621,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) i = rtd->num_codecs; codec_dai_err: - while (--i >= 0) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai_reverse(rtd, i, codec_dai) { if (codec_dai->driver->ops->shutdown) codec_dai->driver->ops->shutdown(substream, codec_dai); } @@ -641,9 +641,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) pm_runtime_put_autosuspend(component->dev); } - for (i = 0; i < rtd->num_codecs; i++) { - if (!rtd->codec_dais[i]->active) - pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev); + for_each_rtd_codec_dai(rtd, i, codec_dai) { + if (!codec_dai->active) + pinctrl_pm_select_sleep_state(codec_dai->dev); } if (!cpu_dai->active) pinctrl_pm_select_sleep_state(cpu_dai->dev); @@ -701,8 +701,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) if (!cpu_dai->active) cpu_dai->rate = 0; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (!codec_dai->active) codec_dai->rate = 0; } @@ -712,8 +711,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) if (cpu_dai->driver->ops->shutdown) cpu_dai->driver->ops->shutdown(substream, cpu_dai); - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->shutdown) codec_dai->driver->ops->shutdown(substream, codec_dai); } @@ -751,9 +749,9 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) pm_runtime_put_autosuspend(component->dev); } - for (i = 0; i < rtd->num_codecs; i++) { - if (!rtd->codec_dais[i]->active) - pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev); + for_each_rtd_codec_dai(rtd, i, codec_dai) { + if (!codec_dai->active) + pinctrl_pm_select_sleep_state(codec_dai->dev); } if (!cpu_dai->active) pinctrl_pm_select_sleep_state(cpu_dai->dev); @@ -801,8 +799,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } } - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->prepare) { ret = codec_dai->driver->ops->prepare(substream, codec_dai); @@ -834,8 +831,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) snd_soc_dapm_stream_event(rtd, substream->stream, SND_SOC_DAPM_STREAM_START); - for (i = 0; i < rtd->num_codecs; i++) - snd_soc_dai_digital_mute(rtd->codec_dais[i], 0, + for_each_rtd_codec_dai(rtd, i, codec_dai) + snd_soc_dai_digital_mute(codec_dai, 0, substream->stream); snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream); @@ -920,6 +917,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; int i, ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -932,8 +930,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } } - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { struct snd_pcm_hw_params codec_params; /* @@ -1018,8 +1015,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, i = rtd->num_codecs; codec_err: - while (--i >= 0) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai_reverse(rtd, i, codec_dai) { if (codec_dai->driver->ops->hw_free) codec_dai->driver->ops->hw_free(substream, codec_dai); codec_dai->rate = 0; @@ -1052,8 +1048,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) cpu_dai->sample_bits = 0; } - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->active == 1) { codec_dai->rate = 0; codec_dai->channels = 0; @@ -1062,10 +1057,10 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) } /* apply codec digital mute */ - for (i = 0; i < rtd->num_codecs; i++) { - if ((playback && rtd->codec_dais[i]->playback_active == 1) || - (!playback && rtd->codec_dais[i]->capture_active == 1)) - snd_soc_dai_digital_mute(rtd->codec_dais[i], 1, + for_each_rtd_codec_dai(rtd, i, codec_dai) { + if ((playback && codec_dai->playback_active == 1) || + (!playback && codec_dai->capture_active == 1)) + snd_soc_dai_digital_mute(codec_dai, 1, substream->stream); } @@ -1077,8 +1072,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) soc_pcm_components_hw_free(substream, NULL); /* now free hw params for the DAIs */ - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->hw_free) codec_dai->driver->ops->hw_free(substream, codec_dai); } @@ -1099,8 +1093,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_soc_dai *codec_dai; int i, ret; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->trigger) { ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai); @@ -1144,8 +1137,7 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai; int i, ret; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->bespoke_trigger) { ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai); @@ -1199,8 +1191,7 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) if (cpu_dai->driver->ops->delay) delay += cpu_dai->driver->ops->delay(substream, cpu_dai); - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->ops->delay) codec_delay = max(codec_delay, codec_dai->driver->ops->delay(substream, @@ -1388,6 +1379,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, { struct snd_soc_card *card = widget->dapm->card; struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *dai; int i; if (dir == SND_SOC_DAPM_DIR_OUT) { @@ -1398,8 +1390,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, if (rtd->cpu_dai->playback_widget == widget) return true; - for (i = 0; i < rtd->num_codecs; ++i) { - struct snd_soc_dai *dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, dai) { if (dai->playback_widget == widget) return true; } @@ -1412,8 +1403,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, if (rtd->cpu_dai->capture_widget == widget) return true; - for (i = 0; i < rtd->num_codecs; ++i) { - struct snd_soc_dai *dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, dai) { if (dai->capture_widget == widget) return true; } @@ -1907,6 +1897,7 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, struct snd_pcm_substream *be_substream = snd_soc_dpcm_get_substream(be, stream); struct snd_soc_pcm_runtime *rtd = be_substream->private_data; + struct snd_soc_dai *codec_dai; int i; if (rtd->dai_link->be_hw_params_fixup) @@ -1923,10 +1914,10 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, return err; } - for (i = 0; i < rtd->num_codecs; i++) { - if (rtd->codec_dais[i]->active) { + for_each_rtd_codec_dai(rtd, i, codec_dai) { + if (codec_dai->active) { err = soc_pcm_apply_symmetry(fe_substream, - rtd->codec_dais[i]); + codec_dai); if (err < 0) return err; } @@ -3041,8 +3032,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) playback = rtd->dai_link->dpcm_playback; capture = rtd->dai_link->dpcm_capture; } else { - for (i = 0; i < rtd->num_codecs; i++) { - codec_dai = rtd->codec_dais[i]; + for_each_rtd_codec_dai(rtd, i, codec_dai) { if (codec_dai->driver->playback.channels_min) playback = 1; if (codec_dai->driver->capture.channels_min) From d7433ad634da86bd85440332f3e102f16712e20d Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Sep 2018 15:20:58 +0100 Subject: [PATCH 0021/1995] ASoC: dapm: Move error handling to snd_soc_dapm_new_control_unlocked Currently DAPM has a lot of similar code to handle errors from snd_soc_dapm_new_control_unlocked, and much of this code does not really accurately reflect what the function returns. Firstly, most places will check for a return value of -EPROBE_DEFER and silence any error messages in that case. The one notable exception here being dapm_kcontrol_data_alloc which does currently print any error messages in the case of snd_soc_dapm_new_control_unlocked returning NULL or an error. Additionally the error prints being silenced in these case are redundant as snd_soc_dapm_new_control_unlocked can only return -EPROBE_DEFER or NULL when failing. Secondly, most places will treat a return value of NULL as an -ENOMEM. This is not correct either since any error except EPROBE_DEFER will cause a return value of NULL from snd_soc_dapm_new_control_unlocked. Centralise this handling and the error messages within snd_soc_dapm_new_control_unlocked and update the callers to simply check IS_ERR and return. Note that this update is slightly simpler in the case of dapm_kcontrol_data_alloc where that is fairly close to the handling that was already in place. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit 3bbf5d34fd4a0c41246290b70338095ae291851b) --- sound/soc/soc-dapm.c | 118 +++++++-------------------------------- sound/soc/soc-topology.c | 11 ---- 2 files changed, 19 insertions(+), 110 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 0a738cb439becf..d13a25ce127559 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -364,10 +364,6 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, ret = PTR_ERR(data->widget); goto err_data; } - if (!data->widget) { - ret = -ENOMEM; - goto err_data; - } } break; case snd_soc_dapm_demux: @@ -402,10 +398,6 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, ret = PTR_ERR(data->widget); goto err_data; } - if (!data->widget) { - ret = -ENOMEM; - goto err_data; - } snd_soc_dapm_add_path(widget->dapm, data->widget, widget, NULL, NULL); @@ -3433,23 +3425,8 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); w = snd_soc_dapm_new_control_unlocked(dapm, widget); - /* Do not nag about probe deferrals */ - if (IS_ERR(w)) { - int ret = PTR_ERR(w); - - if (ret != -EPROBE_DEFER) - dev_err(dapm->dev, - "ASoC: Failed to create DAPM control %s (%d)\n", - widget->name, ret); - goto out_unlock; - } - if (!w) - dev_err(dapm->dev, - "ASoC: Failed to create DAPM control %s\n", - widget->name); - -out_unlock: mutex_unlock(&dapm->card->dapm_mutex); + return w; } EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); @@ -3464,24 +3441,20 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, int ret; if ((w = dapm_cnew_widget(widget)) == NULL) - return NULL; + return ERR_PTR(-ENOMEM); switch (w->id) { case snd_soc_dapm_regulator_supply: w->regulator = devm_regulator_get(dapm->dev, w->name); if (IS_ERR(w->regulator)) { ret = PTR_ERR(w->regulator); - if (ret == -EPROBE_DEFER) - return ERR_PTR(ret); - dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", - w->name, ret); - return NULL; + goto request_failed; } if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) { ret = regulator_allow_bypass(w->regulator, true); if (ret != 0) - dev_warn(w->dapm->dev, + dev_warn(dapm->dev, "ASoC: Failed to bypass %s: %d\n", w->name, ret); } @@ -3490,22 +3463,14 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, w->pinctrl = devm_pinctrl_get(dapm->dev); if (IS_ERR(w->pinctrl)) { ret = PTR_ERR(w->pinctrl); - if (ret == -EPROBE_DEFER) - return ERR_PTR(ret); - dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", - w->name, ret); - return NULL; + goto request_failed; } break; case snd_soc_dapm_clock_supply: w->clk = devm_clk_get(dapm->dev, w->name); if (IS_ERR(w->clk)) { ret = PTR_ERR(w->clk); - if (ret == -EPROBE_DEFER) - return ERR_PTR(ret); - dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", - w->name, ret); - return NULL; + goto request_failed; } break; default: @@ -3519,7 +3484,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, w->name = kstrdup_const(widget->name, GFP_KERNEL); if (w->name == NULL) { kfree(w); - return NULL; + return ERR_PTR(-ENOMEM); } switch (w->id) { @@ -3596,6 +3561,13 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, /* machine layer sets up unconnected pins and insertions */ w->connected = 1; return w; + +request_failed: + if (ret != -EPROBE_DEFER) + dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", + w->name, ret); + + return ERR_PTR(ret); } /** @@ -3621,19 +3593,6 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, w = snd_soc_dapm_new_control_unlocked(dapm, widget); if (IS_ERR(w)) { ret = PTR_ERR(w); - /* Do not nag about probe deferrals */ - if (ret == -EPROBE_DEFER) - break; - dev_err(dapm->dev, - "ASoC: Failed to create DAPM control %s (%d)\n", - widget->name, ret); - break; - } - if (!w) { - dev_err(dapm->dev, - "ASoC: Failed to create DAPM control %s\n", - widget->name); - ret = -ENOMEM; break; } widget++; @@ -3944,21 +3903,8 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name); w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template); - if (IS_ERR(w)) { - ret = PTR_ERR(w); - /* Do not nag about probe deferrals */ - if (ret != -EPROBE_DEFER) - dev_err(card->dev, - "ASoC: Failed to create %s widget (%d)\n", - link_name, ret); - goto outfree_kcontrol_news; - } - if (!w) { - dev_err(card->dev, "ASoC: Failed to create %s widget\n", - link_name); - ret = -ENOMEM; + if (IS_ERR(w)) goto outfree_kcontrol_news; - } w->params = params; w->num_params = num_params; @@ -3999,21 +3945,8 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, template.name); w = snd_soc_dapm_new_control_unlocked(dapm, &template); - if (IS_ERR(w)) { - int ret = PTR_ERR(w); - - /* Do not nag about probe deferrals */ - if (ret != -EPROBE_DEFER) - dev_err(dapm->dev, - "ASoC: Failed to create %s widget (%d)\n", - dai->driver->playback.stream_name, ret); - return ret; - } - if (!w) { - dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", - dai->driver->playback.stream_name); - return -ENOMEM; - } + if (IS_ERR(w)) + return PTR_ERR(w); w->priv = dai; dai->playback_widget = w; @@ -4028,21 +3961,8 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, template.name); w = snd_soc_dapm_new_control_unlocked(dapm, &template); - if (IS_ERR(w)) { - int ret = PTR_ERR(w); - - /* Do not nag about probe deferrals */ - if (ret != -EPROBE_DEFER) - dev_err(dapm->dev, - "ASoC: Failed to create %s widget (%d)\n", - dai->driver->playback.stream_name, ret); - return ret; - } - if (!w) { - dev_err(dapm->dev, "ASoC: Failed to create %s widget\n", - dai->driver->capture.stream_name); - return -ENOMEM; - } + if (IS_ERR(w)) + return PTR_ERR(w); w->priv = dai; dai->capture_widget = w; diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 66e77e020745b2..17f81b9a575448 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1565,17 +1565,6 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, widget = snd_soc_dapm_new_control_unlocked(dapm, &template); if (IS_ERR(widget)) { ret = PTR_ERR(widget); - /* Do not nag about probe deferrals */ - if (ret != -EPROBE_DEFER) - dev_err(tplg->dev, - "ASoC: failed to create widget %s controls (%d)\n", - w->name, ret); - goto hdr_err; - } - if (widget == NULL) { - dev_err(tplg->dev, "ASoC: failed to create widget %s controls\n", - w->name); - ret = -ENOMEM; goto hdr_err; } From 4e3c25e8cd47290904b0e74a4ce7ddf8cdba29fa Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Sep 2018 15:20:59 +0100 Subject: [PATCH 0022/1995] ASoC: dapm: Cosmetic tidy up of snd_soc_dapm_new_control Move the function snd_soc_dapm_new_control to be next to snd_soc_dapm_new_controls and add some kernel doc for it. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit 94e630a35d3383b42f12a873a5404bdf61e38e42) --- sound/soc/soc-dapm.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d13a25ce127559..c111e69b9a094e 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3417,20 +3417,6 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); -struct snd_soc_dapm_widget * -snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget) -{ - struct snd_soc_dapm_widget *w; - - mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - w = snd_soc_dapm_new_control_unlocked(dapm, widget); - mutex_unlock(&dapm->card->dapm_mutex); - - return w; -} -EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); - struct snd_soc_dapm_widget * snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget) @@ -3570,6 +3556,29 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, return ERR_PTR(ret); } +/** + * snd_soc_dapm_new_control - create new dapm control + * @dapm: DAPM context + * @widget: widget template + * + * Creates new DAPM control based upon a template. + * + * Returns a widget pointer on success or an error pointer on failure + */ +struct snd_soc_dapm_widget * +snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, + const struct snd_soc_dapm_widget *widget) +{ + struct snd_soc_dapm_widget *w; + + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + w = snd_soc_dapm_new_control_unlocked(dapm, widget); + mutex_unlock(&dapm->card->dapm_mutex); + + return w; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); + /** * snd_soc_dapm_new_controls - create new dapm controls * @dapm: DAPM context From 692ae8a6e66945df681b8cc856fce9c4dd496ea9 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Sep 2018 15:21:00 +0100 Subject: [PATCH 0023/1995] ASoC: dapm: Move connection of CODEC to CODEC DAIs Currently, snd_soc_dapm_connect_dai_link_widgets connects up the routes representing normal DAIs, however CODEC to CODEC links are hooked up through separate infrastructure in soc_link_dai_widgets. Improve the consistency of the code by using snd_soc_dapm_connect_dai_link for both types of DAIs. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit 778ff5bb8689eb4fd05a72a409e32a3a34e23faf) --- include/sound/soc-dapm.h | 6 --- sound/soc/soc-core.c | 47 ------------------ sound/soc/soc-dapm.c | 103 +++++++++++++++++++++++++-------------- 3 files changed, 66 insertions(+), 90 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index fdaaafdc7a0039..cb177fa21ce7e0 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -406,12 +406,6 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, struct snd_soc_dai *dai); int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card); void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card); -int snd_soc_dapm_new_pcm(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd, - const struct snd_soc_pcm_stream *params, - unsigned int num_params, - struct snd_soc_dapm_widget *source, - struct snd_soc_dapm_widget *sink); /* dapm path setup */ int snd_soc_dapm_new_widgets(struct snd_soc_card *card); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 390da15c4a8b9d..4e9367aacc0c9c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1463,48 +1463,6 @@ static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, return 0; } -static int soc_link_dai_widgets(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_link, - struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dapm_widget *sink, *source; - int ret; - - if (rtd->num_codecs > 1) - dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n"); - - /* link the DAI widgets */ - sink = codec_dai->playback_widget; - source = cpu_dai->capture_widget; - if (sink && source) { - ret = snd_soc_dapm_new_pcm(card, rtd, dai_link->params, - dai_link->num_params, - source, sink); - if (ret != 0) { - dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", - sink->name, source->name, ret); - return ret; - } - } - - sink = cpu_dai->playback_widget; - source = codec_dai->capture_widget; - if (sink && source) { - ret = snd_soc_dapm_new_pcm(card, rtd, dai_link->params, - dai_link->num_params, - source, sink); - if (ret != 0) { - dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", - sink->name, source->name, ret); - return ret; - } - } - - return 0; -} - static int soc_probe_link_dais(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, int order) { @@ -1606,11 +1564,6 @@ static int soc_probe_link_dais(struct snd_soc_card *card, } else { INIT_DELAYED_WORK(&rtd->delayed_work, codec2codec_close_delayed_work); - - /* link the DAI widgets */ - ret = soc_link_dai_widgets(card, dai_link, rtd); - if (ret) - return ret; } } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c111e69b9a094e..bbfcb7fc05cc6d 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3860,12 +3860,10 @@ snd_soc_dapm_alloc_kcontrol(struct snd_soc_card *card, return NULL; } -int snd_soc_dapm_new_pcm(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd, - const struct snd_soc_pcm_stream *params, - unsigned int num_params, - struct snd_soc_dapm_widget *source, - struct snd_soc_dapm_widget *sink) +static struct snd_soc_dapm_widget * +snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) { struct snd_soc_dapm_widget template; struct snd_soc_dapm_widget *w; @@ -3877,7 +3875,7 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s", source->name, sink->name); if (!link_name) - return -ENOMEM; + return ERR_PTR(-ENOMEM); memset(&template, 0, sizeof(template)); template.reg = SND_SOC_NOPM; @@ -3889,9 +3887,10 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, template.kcontrol_news = NULL; /* allocate memory for control, only in case of multiple configs */ - if (num_params > 1) { - w_param_text = devm_kcalloc(card->dev, num_params, - sizeof(char *), GFP_KERNEL); + if (rtd->dai_link->num_params > 1) { + w_param_text = devm_kcalloc(card->dev, + rtd->dai_link->num_params, + sizeof(char *), GFP_KERNEL); if (!w_param_text) { ret = -ENOMEM; goto param_fail; @@ -3900,7 +3899,9 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, template.num_kcontrols = 1; template.kcontrol_news = snd_soc_dapm_alloc_kcontrol(card, - link_name, params, num_params, + link_name, + rtd->dai_link->params, + rtd->dai_link->num_params, w_param_text, &private_value); if (!template.kcontrol_news) { ret = -ENOMEM; @@ -3915,23 +3916,19 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, if (IS_ERR(w)) goto outfree_kcontrol_news; - w->params = params; - w->num_params = num_params; + w->params = rtd->dai_link->params; + w->num_params = rtd->dai_link->num_params; w->priv = rtd; - ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL); - if (ret) - goto outfree_w; - return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL); + return w; -outfree_w: - devm_kfree(card->dev, w); outfree_kcontrol_news: devm_kfree(card->dev, (void *)template.kcontrol_news); - snd_soc_dapm_free_kcontrol(card, &private_value, num_params, w_param_text); + snd_soc_dapm_free_kcontrol(card, &private_value, + rtd->dai_link->num_params, w_param_text); param_fail: devm_kfree(card->dev, link_name); - return ret; + return ERR_PTR(ret); } int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, @@ -4041,33 +4038,65 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; - struct snd_soc_dapm_widget *sink, *source; + struct snd_soc_dapm_widget *playback = NULL, *capture = NULL; + struct snd_soc_dapm_widget *codec, *playback_cpu, *capture_cpu; int i; + if (rtd->dai_link->params) { + if (rtd->num_codecs > 1) + dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n"); + + playback_cpu = cpu_dai->capture_widget; + capture_cpu = cpu_dai->playback_widget; + } else { + playback = cpu_dai->playback_widget; + capture = cpu_dai->capture_widget; + playback_cpu = playback; + capture_cpu = capture; + } + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* connect BE DAI playback if widgets are valid */ - if (codec_dai->playback_widget && cpu_dai->playback_widget) { - source = cpu_dai->playback_widget; - sink = codec_dai->playback_widget; + codec = codec_dai->playback_widget; + + if (playback_cpu && codec) { + if (!playback) { + playback = snd_soc_dapm_new_dai(card, rtd, + playback_cpu, + codec); + + snd_soc_dapm_add_path(&card->dapm, playback_cpu, + playback, NULL, NULL); + } + dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", - cpu_dai->component->name, source->name, - codec_dai->component->name, sink->name); + cpu_dai->component->name, playback_cpu->name, + codec_dai->component->name, codec->name); - snd_soc_dapm_add_path(&card->dapm, source, sink, - NULL, NULL); + snd_soc_dapm_add_path(&card->dapm, playback, codec, + NULL, NULL); } /* connect BE DAI capture if widgets are valid */ - if (codec_dai->capture_widget && cpu_dai->capture_widget) { - source = codec_dai->capture_widget; - sink = cpu_dai->capture_widget; + codec = codec_dai->capture_widget; + + if (codec && capture_cpu) { + if (!capture) { + capture = snd_soc_dapm_new_dai(card, rtd, + codec, + capture_cpu); + + snd_soc_dapm_add_path(&card->dapm, capture, + capture_cpu, NULL, NULL); + } + dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n", - codec_dai->component->name, source->name, - cpu_dai->component->name, sink->name); + codec_dai->component->name, codec->name, + cpu_dai->component->name, capture_cpu->name); - snd_soc_dapm_add_path(&card->dapm, source, sink, - NULL, NULL); + snd_soc_dapm_add_path(&card->dapm, codec, capture, + NULL, NULL); } } } @@ -4122,7 +4151,7 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) * dynamic FE links have no fixed DAI mapping. * CODEC<->CODEC links have no direct connection. */ - if (rtd->dai_link->dynamic || rtd->dai_link->params) + if (rtd->dai_link->dynamic) continue; dapm_connect_dai_link_widgets(card, rtd); From d19c141dc7c6cbd532f99d669dfd897d3a2faa06 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Sep 2018 15:21:01 +0100 Subject: [PATCH 0024/1995] ASoC: dapm: Add support for multi-CODEC CODEC to CODEC links Currently multi-CODEC is not supported on CODEC to CODEC links. There are common applications where this would be useful, such as connecting two mono amplifiers to an audio CODEC. Adding support simply requires an update of snd_soc_dai_link_event to loop over the attached CODEC DAIs. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit 4a75aae17b2a802a7267206414050408392c374c) --- sound/soc/soc-dapm.c | 123 ++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 53 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index bbfcb7fc05cc6d..40f27c95da614c 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3614,7 +3614,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { - struct snd_soc_dapm_path *source_p, *sink_p; + struct snd_soc_dapm_path *path; struct snd_soc_dai *source, *sink; struct snd_soc_pcm_runtime *rtd = w->priv; const struct snd_soc_pcm_stream *config = w->params + w->params_select; @@ -3629,17 +3629,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) return -EINVAL; - /* We only support a single source and sink, pick the first */ - source_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_OUT], - struct snd_soc_dapm_path, - list_node[SND_SOC_DAPM_DIR_OUT]); - sink_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_IN], - struct snd_soc_dapm_path, - list_node[SND_SOC_DAPM_DIR_IN]); - - source = source_p->source->priv; - sink = sink_p->sink->priv; - /* Be a little careful as we don't want to overflow the mask array */ if (config->formats) { fmt = ffs(config->formats) - 1; @@ -3681,59 +3670,90 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: substream.stream = SNDRV_PCM_STREAM_CAPTURE; - if (source->driver->ops->startup) { - ret = source->driver->ops->startup(&substream, source); - if (ret < 0) { - dev_err(source->dev, - "ASoC: startup() failed: %d\n", ret); - goto out; + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; + + if (source->driver->ops->startup) { + ret = source->driver->ops->startup(&substream, + source); + if (ret < 0) { + dev_err(source->dev, + "ASoC: startup() failed: %d\n", + ret); + goto out; + } + source->active++; } - source->active++; + ret = soc_dai_hw_params(&substream, params, source); + if (ret < 0) + goto out; } - ret = soc_dai_hw_params(&substream, params, source); - if (ret < 0) - goto out; substream.stream = SNDRV_PCM_STREAM_PLAYBACK; - if (sink->driver->ops->startup) { - ret = sink->driver->ops->startup(&substream, sink); - if (ret < 0) { - dev_err(sink->dev, - "ASoC: startup() failed: %d\n", ret); - goto out; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + + if (sink->driver->ops->startup) { + ret = sink->driver->ops->startup(&substream, + sink); + if (ret < 0) { + dev_err(sink->dev, + "ASoC: startup() failed: %d\n", + ret); + goto out; + } + sink->active++; } - sink->active++; + ret = soc_dai_hw_params(&substream, params, sink); + if (ret < 0) + goto out; } - ret = soc_dai_hw_params(&substream, params, sink); - if (ret < 0) - goto out; break; case SND_SOC_DAPM_POST_PMU: - ret = snd_soc_dai_digital_mute(sink, 0, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret != 0 && ret != -ENOTSUPP) - dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret); - ret = 0; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + + ret = snd_soc_dai_digital_mute(sink, 0, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret != 0 && ret != -ENOTSUPP) + dev_warn(sink->dev, + "ASoC: Failed to unmute: %d\n", ret); + ret = 0; + } break; case SND_SOC_DAPM_PRE_PMD: - ret = snd_soc_dai_digital_mute(sink, 1, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret != 0 && ret != -ENOTSUPP) - dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret); - ret = 0; + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + + ret = snd_soc_dai_digital_mute(sink, 1, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret != 0 && ret != -ENOTSUPP) + dev_warn(sink->dev, + "ASoC: Failed to mute: %d\n", ret); + ret = 0; + } + + snd_soc_dapm_widget_for_each_source_path(w, path) { + source = path->source->priv; - source->active--; - if (source->driver->ops->shutdown) { - substream.stream = SNDRV_PCM_STREAM_CAPTURE; - source->driver->ops->shutdown(&substream, source); + source->active--; + if (source->driver->ops->shutdown) { + substream.stream = SNDRV_PCM_STREAM_CAPTURE; + source->driver->ops->shutdown(&substream, + source); + } } - sink->active--; - if (sink->driver->ops->shutdown) { - substream.stream = SNDRV_PCM_STREAM_PLAYBACK; - sink->driver->ops->shutdown(&substream, sink); + snd_soc_dapm_widget_for_each_sink_path(w, path) { + sink = path->sink->priv; + + sink->active--; + if (sink->driver->ops->shutdown) { + substream.stream = SNDRV_PCM_STREAM_PLAYBACK; + sink->driver->ops->shutdown(&substream, sink); + } } break; @@ -4043,9 +4063,6 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, int i; if (rtd->dai_link->params) { - if (rtd->num_codecs > 1) - dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n"); - playback_cpu = cpu_dai->capture_widget; capture_cpu = cpu_dai->playback_widget; } else { From cd99d7aba2c456fae8b296c52caa04309f50b8ac Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 5 Sep 2018 15:21:02 +0100 Subject: [PATCH 0025/1995] ASoC: dapm: Move CODEC to CODEC params from the widget to the runtime Larger CODECs may contain many several hundred widgets and which set of parameters is selected only needs to be recorded on a per DAI basis. As such move the selected CODEC to CODEC link params to be stored in the runtime rather than the DAPM widget, to save some memory. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit 243bcfafcd9a23a20867fd488dc3a35264918d87) --- include/sound/soc-dapm.h | 3 --- include/sound/soc.h | 2 ++ sound/soc/soc-dapm.c | 19 +++++++++++-------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index cb177fa21ce7e0..bd8163f151cb85 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -584,9 +584,6 @@ struct snd_soc_dapm_widget { void *priv; /* widget specific data */ struct regulator *regulator; /* attached regulator */ struct pinctrl *pinctrl; /* attached pinctrl */ - const struct snd_soc_pcm_stream *params; /* params for dai links */ - unsigned int num_params; /* number of params for dai links */ - unsigned int params_select; /* currently selected param for dai link */ /* dapm control */ int reg; /* negative reg = no direct dapm */ diff --git a/include/sound/soc.h b/include/sound/soc.h index 6b68b31e314013..821bf99992b865 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1130,6 +1130,8 @@ struct snd_soc_pcm_runtime { enum snd_soc_pcm_subclass pcm_subclass; struct snd_pcm_ops ops; + unsigned int params_select; /* currently selected param for dai link */ + /* Dynamic PCM BE runtime data */ struct snd_soc_dpcm_runtime dpcm[2]; int fe_compr; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 40f27c95da614c..9f4edcd19e022b 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1018,9 +1018,10 @@ static int dapm_new_dai_link(struct snd_soc_dapm_widget *w) struct snd_kcontrol *kcontrol; struct snd_soc_dapm_context *dapm = w->dapm; struct snd_card *card = dapm->card->snd_card; + struct snd_soc_pcm_runtime *rtd = w->priv; /* create control for links with > 1 config */ - if (w->num_params <= 1) + if (rtd->dai_link->num_params <= 1) return 0; /* add kcontrol */ @@ -3617,13 +3618,15 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, struct snd_soc_dapm_path *path; struct snd_soc_dai *source, *sink; struct snd_soc_pcm_runtime *rtd = w->priv; - const struct snd_soc_pcm_stream *config = w->params + w->params_select; + const struct snd_soc_pcm_stream *config; struct snd_pcm_substream substream; struct snd_pcm_hw_params *params = NULL; struct snd_pcm_runtime *runtime = NULL; unsigned int fmt; int ret; + config = rtd->dai_link->params + rtd->params_select; + if (WARN_ON(!config) || WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) @@ -3772,8 +3775,9 @@ static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol); + struct snd_soc_pcm_runtime *rtd = w->priv; - ucontrol->value.enumerated.item[0] = w->params_select; + ucontrol->value.enumerated.item[0] = rtd->params_select; return 0; } @@ -3782,18 +3786,19 @@ static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol); + struct snd_soc_pcm_runtime *rtd = w->priv; /* Can't change the config when widget is already powered */ if (w->power) return -EBUSY; - if (ucontrol->value.enumerated.item[0] == w->params_select) + if (ucontrol->value.enumerated.item[0] == rtd->params_select) return 0; - if (ucontrol->value.enumerated.item[0] >= w->num_params) + if (ucontrol->value.enumerated.item[0] >= rtd->dai_link->num_params) return -EINVAL; - w->params_select = ucontrol->value.enumerated.item[0]; + rtd->params_select = ucontrol->value.enumerated.item[0]; return 0; } @@ -3936,8 +3941,6 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, if (IS_ERR(w)) goto outfree_kcontrol_news; - w->params = rtd->dai_link->params; - w->num_params = rtd->dai_link->num_params; w->priv = rtd; return w; From 2fcc8a3be80b0bf76b188e6e163d59154abf67fd Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 6 Sep 2018 10:39:01 +0100 Subject: [PATCH 0026/1995] ASoC: hdac_hdmi: remove redundant check for !port condition The !port check is redundant as it being performed in the following check. Remove it. Signed-off-by: Colin Ian King Signed-off-by: Mark Brown (cherry picked from commit c24fb71fa4f764f02c17cbf88a969f109794e602) --- sound/soc/codecs/hdac_hdmi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 7b8533abf63731..dc6a0dfea0502d 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1961,9 +1961,6 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx) port = list_first_entry(&pcm->port_list, struct hdac_hdmi_port, head); - if (!port) - return 0; - if (!port || !port->eld.eld_valid) return 0; From ee162843d2fa787a742d38bcd222f94eedcb8c17 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 6 Sep 2018 17:41:55 +0100 Subject: [PATCH 0027/1995] ASoC: dapm: Avoid uninitialised variable warning Commit 4a75aae17b2a ("ASoC: dapm: Add support for multi-CODEC CODEC to CODEC links") adds loops that iterate over multiple CODECs in snd_soc_dai_link_event. This also introduced a compiler warning for a potentially uninitialised variable in the case no CODECs are present. This should never be the case as the DAI link must by definition contain at least 1 CODEC however probably best to avoid the compiler warning by initialising ret to zero. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit fc269c0396448cabe1afd648c0b335669aa347b7) --- sound/soc/soc-dapm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 9f4edcd19e022b..e496bc642c990c 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3623,7 +3623,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, struct snd_pcm_hw_params *params = NULL; struct snd_pcm_runtime *runtime = NULL; unsigned int fmt; - int ret; + int ret = 0; config = rtd->dai_link->params + rtd->params_select; From 71cb00120a0c846f7769f16da9133133caefa8e3 Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Tue, 7 Aug 2018 12:19:16 -0500 Subject: [PATCH 0028/1995] ASoC: Intel: hdac_hdmi: Limit sampling rates at dai creation Playback of 44.1Khz contents with HDMI plugged returns "Invalid pipe config" because HDMI paths in the FW topology are configured to operate at 48Khz. This patch filters out sampling rates not supported at hdac_hdmi_create_dais() to let user space SRC to do the converting. Signed-off-by: Yong Zhi Reviewed-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 3b857472f34faa7d11001afa5e158833812c98d7) --- sound/soc/codecs/hdac_hdmi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index dc6a0dfea0502d..41d90dc6ebf701 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1410,6 +1410,12 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdev, if (ret) return ret; + /* Filter out 44.1, 88.2 and 176.4Khz */ + rates &= ~(SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_176400); + if (!rates) + return -EINVAL; + sprintf(dai_name, "intel-hdmi-hifi%d", i+1); hdmi_dais[i].name = devm_kstrdup(&hdev->dev, dai_name, GFP_KERNEL); From cfbbc58278297d6f6b4a723cc338062792ddeec3 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Thu, 6 Sep 2018 17:27:28 -0700 Subject: [PATCH 0029/1995] ASoC: max98373: usleep_range() needs include/delay.h Commit ca917f9fe1a0fab added use of usleep_range() but not the corresponding "include ". The result is with Chrome OS won't build because warnings are forced to be errors: mnt/host/source/src/third_party/kernel/v4.4/sound/soc/codecs/max98373.c:734:2: error: implicit declaration of function 'usleep_range' [-Werror,-Wimplicit-function-declaration] usleep_range(10000, 11000); ^ Including delay.h "fixes" this. Signed-off-by: Grant Grundler Reviewed-by: Benson Leung Signed-off-by: Mark Brown (cherry picked from commit 3004136b90bedc9e254ff659adb7a60299e9495e) --- sound/soc/codecs/max98373.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 1093f766d0d2c7..d6868c9a9ce632 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -2,6 +2,7 @@ // Copyright (c) 2017, Maxim Integrated #include +#include #include #include #include From 12354e34e5ee761bd3959e6cc3c9282d074b9165 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 7 Sep 2018 22:40:33 +0300 Subject: [PATCH 0030/1995] ASoC: dapm: Fix a couple uninitialized ret variables Smatch complains that these variables could be uninitialized. The first one in snd_soc_dai_link_event() is probably a false positive, because probably we know the lists are not empty. I would normally ignore the warning, but GCC complains here as well so I just silenced the warning. The "ret" in snd_soc_dapm_new_dai() does need to be initialized or it leads to a bogus dereference in the caller. Fixes: 3bbf5d34fd4a ("ASoC: dapm: Move error handling to snd_soc_dapm_new_control_unlocked") Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown (cherry picked from commit 2e558a8127de7b2ed3302f9adcf332ba3feeadb2) --- sound/soc/soc-dapm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index e496bc642c990c..0dcdcc23dcfde1 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3938,8 +3938,10 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name); w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template); - if (IS_ERR(w)) + if (IS_ERR(w)) { + ret = PTR_ERR(w); goto outfree_kcontrol_news; + } w->priv = rtd; From 7a81df9fa79bdcf560d527ac4d30b0281dde1ad4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:01:19 +0000 Subject: [PATCH 0031/1995] ASoC: hdac_hda: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 10ccaa39d7628470a3de4aae9d2346a55cbee46e) --- sound/soc/codecs/hdac_hda.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 8c25a1332fa7ee..2aaa83028e55f2 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -448,7 +448,7 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev) return -ENOMEM; /* ASoC specific initialization */ - ret = snd_soc_register_component(&hdev->dev, + ret = devm_snd_soc_register_component(&hdev->dev, &hdac_hda_codec, hdac_hda_dais, ARRAY_SIZE(hdac_hda_dais)); if (ret < 0) { @@ -464,7 +464,6 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev) static int hdac_hda_dev_remove(struct hdac_device *hdev) { - snd_soc_unregister_component(&hdev->dev); return 0; } From 4b6a649690a8344b1d443dc9804106c486584762 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 7 Sep 2018 01:01:34 +0000 Subject: [PATCH 0032/1995] ASoC: rt5668: use devm_snd_soc_register_component() Now we have devm_snd_soc_register_component(). Let's use it instead of snd_soc_register_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 4fe1984ebc086ee39dd57983a7fee84c96c954a7) --- sound/soc/codecs/rt5668.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index 3c19d03f2446b5..4412cd2910cd58 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -2587,14 +2587,12 @@ static int rt5668_i2c_probe(struct i2c_client *i2c, } - return snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5668, + return devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5668, rt5668_dai, ARRAY_SIZE(rt5668_dai)); } static int rt5668_i2c_remove(struct i2c_client *i2c) { - snd_soc_unregister_component(&i2c->dev); - return 0; } From 0f8eb2f40f70068d7cfb3b02c6fc4ebd0d4e7514 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Sat, 8 Sep 2018 16:36:20 +0800 Subject: [PATCH 0033/1995] ASoC: skl-topology: Use kmemdup to replace kzalloc + memcpy kmemdup has implemented the function that kzalloc() + memcpy() will do. and we prefer to kmemdup rather than the open coded implementation. Signed-off-by: zhong jiang Signed-off-by: Mark Brown (cherry picked from commit ca92cc4636fdedf0d7ee88a5e50cd2b85c246a3b) --- sound/soc/intel/skylake/skl-topology.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 2620d77729c52e..52a9915da0f5cc 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -898,11 +898,10 @@ static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, bc = (struct skl_algo_data *)sb->dobj.private; if (bc->set_params == SKL_PARAM_BIND) { - params = kzalloc(bc->max, GFP_KERNEL); + params = kmemdup(bc->params, bc->max, GFP_KERNEL); if (!params) return -ENOMEM; - memcpy(params, bc->params, bc->max); skl_fill_sink_instance_id(ctx, params, bc->max, mconfig); From ff1c4ba3c15778b0b9d95c01532f58296c7b4f10 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 10 Sep 2018 15:28:39 +0100 Subject: [PATCH 0034/1995] ASoC: dapm: Add missing return value check for snd_soc_dapm_new_dai snd_soc_dapm_new_dai may return an error pointer and currently this isn't checked for in dapm_connect_dai_link_widgets. Add code to check the return value and not add routes in that case. Fixes: 778ff5bb8689 ("ASoC: dapm: Move connection of CODEC to CODEC DAIs") Reported-by: Dan Carpenter Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit e36a1d0d249aa09f94d551cadf043a7f9f7fae00) --- sound/soc/soc-dapm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 0dcdcc23dcfde1..43983c69f6aad8 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -4087,6 +4087,13 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, playback = snd_soc_dapm_new_dai(card, rtd, playback_cpu, codec); + if (IS_ERR(playback)) { + dev_err(rtd->dev, + "ASoC: Failed to create DAI %s: %ld\n", + codec_dai->name, + PTR_ERR(playback)); + continue; + } snd_soc_dapm_add_path(&card->dapm, playback_cpu, playback, NULL, NULL); @@ -4099,7 +4106,9 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, snd_soc_dapm_add_path(&card->dapm, playback, codec, NULL, NULL); } + } + for_each_rtd_codec_dai(rtd, i, codec_dai) { /* connect BE DAI capture if widgets are valid */ codec = codec_dai->capture_widget; @@ -4108,6 +4117,13 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, capture = snd_soc_dapm_new_dai(card, rtd, codec, capture_cpu); + if (IS_ERR(capture)) { + dev_err(rtd->dev, + "ASoC: Failed to create DAI %s: %ld\n", + codec_dai->name, + PTR_ERR(capture)); + continue; + } snd_soc_dapm_add_path(&card->dapm, capture, capture_cpu, NULL, NULL); From 56a467438c274e0c7d7b89c5d382fbfab449073d Mon Sep 17 00:00:00 2001 From: Rohit kumar Date: Tue, 11 Sep 2018 14:59:21 +0530 Subject: [PATCH 0035/1995] ASoC: Fix UBSAN warning at snd_soc_get/put_volsw_sx() In functions snd_soc_get_volsw_sx() or snd_soc_put_volsw_sx(), if the result of (min + max) is negative, then fls() returns signed integer with value as 32. This leads to signed integer overflow as complete operation is considered as signed integer. UBSAN: Undefined behaviour in sound/soc/soc-ops.c:382:50 signed integer overflow: -2147483648 - 1 cannot be represented in type 'int' Call trace: [] __dump_stack lib/dump_stack.c:15 [inline] [] dump_stack+0xec/0x158 lib/dump_stack.c:51 [] ubsan_epilogue+0x18/0x50 lib/ubsan.c:164 [] handle_overflow+0xf8/0x130 lib/ubsan.c:195 [] __ubsan_handle_sub_overflow+0x34/0x44 lib/ubsan.c:211 [] snd_soc_get_volsw_sx+0x1a8/0x1f8 sound/soc/soc-ops.c:382 Typecast the operation to unsigned int to fix the issue. Signed-off-by: Rohit kumar Signed-off-by: Mark Brown (cherry picked from commit ae7d1247d8673ebfd686b17e759d4be391165368) --- sound/soc/soc-ops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index 592efb370c4493..f4dc3d445aae9e 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -373,7 +373,7 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, unsigned int rshift = mc->rshift; int max = mc->max; int min = mc->min; - unsigned int mask = (1 << (fls(min + max) - 1)) - 1; + unsigned int mask = (1U << (fls(min + max) - 1)) - 1; unsigned int val; int ret; @@ -418,7 +418,7 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, unsigned int rshift = mc->rshift; int max = mc->max; int min = mc->min; - unsigned int mask = (1 << (fls(min + max) - 1)) - 1; + unsigned int mask = (1U << (fls(min + max) - 1)) - 1; int err = 0; unsigned int val, val_mask, val2 = 0; From 32821bf14d826f7096e633476f683db13b364f21 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 07:02:04 +0000 Subject: [PATCH 0036/1995] ASoC: rt5668: remove empty rt5668_i2c_remove() rt5668_i2c_remove() is empty, and no longer needed. Let's remove it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit a6ebf4c9770e918e601aa9bf4bc3cf4001dd3d4d) --- sound/soc/codecs/rt5668.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index 4412cd2910cd58..85ba04d6e7aef4 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -2591,11 +2591,6 @@ static int rt5668_i2c_probe(struct i2c_client *i2c, rt5668_dai, ARRAY_SIZE(rt5668_dai)); } -static int rt5668_i2c_remove(struct i2c_client *i2c) -{ - return 0; -} - static void rt5668_i2c_shutdown(struct i2c_client *client) { struct rt5668_priv *rt5668 = i2c_get_clientdata(client); @@ -2626,7 +2621,6 @@ static struct i2c_driver rt5668_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5668_acpi_match), }, .probe = rt5668_i2c_probe, - .remove = rt5668_i2c_remove, .shutdown = rt5668_i2c_shutdown, .id_table = rt5668_i2c_id, }; From 9a0040577c1a2f404256c35aec48f008b5a56d96 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 06:54:26 +0000 Subject: [PATCH 0037/1995] ASoC: soc-core: avoid nested code on soc_remove_dai() Nested code is not readable. This patch avoid it on soc_remove_dai(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 2eda3cb108b699a6ff78a87e25143c153bc88e41) --- sound/soc/soc-core.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4e9367aacc0c9c..dde9b70b58b59d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -942,17 +942,18 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order) { int err; - if (dai && dai->probed && - dai->driver->remove_order == order) { - if (dai->driver->remove) { - err = dai->driver->remove(dai); - if (err < 0) - dev_err(dai->dev, - "ASoC: failed to remove %s: %d\n", - dai->name, err); - } - dai->probed = 0; + if (!dai || !dai->probed || + dai->driver->remove_order != order) + return; + + if (dai->driver->remove) { + err = dai->driver->remove(dai); + if (err < 0) + dev_err(dai->dev, + "ASoC: failed to remove %s: %d\n", + dai->name, err); } + dai->probed = 0; } static void soc_remove_link_dais(struct snd_soc_card *card, From 18560c2972910164591d56d12c5b7f327527fc0e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 06:59:01 +0000 Subject: [PATCH 0038/1995] ASoC: soc-core: remove unused num_dai_links ALSA SoC is counting card->dai_link_list user, but no-one is using it. Let's remove it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 4f1b327e65a9516a46ea491ce72a5161be176af8) --- include/sound/soc.h | 1 - sound/soc/soc-core.c | 4 ---- 2 files changed, 5 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 821bf99992b865..e17a7ae9a155c4 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1060,7 +1060,6 @@ struct snd_soc_card { struct snd_soc_dai_link *dai_link; /* predefined links only */ int num_links; /* predefined links only */ struct list_head dai_link_list; /* all links */ - int num_dai_links; struct list_head rtd_list; int num_rtd; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index dde9b70b58b59d..7e18937c221443 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1013,7 +1013,6 @@ static void soc_remove_dai_links(struct snd_soc_card *card) link->name); list_del(&link->list); - card->num_dai_links--; } } @@ -1182,7 +1181,6 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, card->add_dai_link(card, dai_link); list_add_tail(&dai_link->list, &card->dai_link_list); - card->num_dai_links++; return 0; } @@ -1220,7 +1218,6 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card, list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { if (link == dai_link) { list_del(&link->list); - card->num_dai_links--; return; } } @@ -2712,7 +2709,6 @@ int snd_soc_register_card(struct snd_soc_card *card) snd_soc_initialize_card_lists(card); INIT_LIST_HEAD(&card->dai_link_list); - card->num_dai_links = 0; INIT_LIST_HEAD(&card->rtd_list); card->num_rtd = 0; From 6594ae4774b98dd4beec1318cf20b32ea6e3d466 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 12 Sep 2018 10:15:00 +0100 Subject: [PATCH 0039/1995] ASoC: core: add support to card rebind Current behaviour of ASoC core w.r.t to component removal is that it unregisters dependent sound card totally. There is no support to rebind the card if the component comes back. Typical use case is DSP restart or kernel modules itself. With this patch, core now maintains list of cards that are unbind due to any of its depended components are removed and card not unregistered yet. This list is cleared when the card is rebind successfully or when the card is unregistered from machine driver. This list of unbind cards are tried to bind once again after every new component is successfully added, giving a fair chance for card bind to be successful. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown (cherry picked from commit e894efef9ac7c10b7727798dcc711cccf07569f9) --- include/sound/soc.h | 2 ++ sound/soc/soc-core.c | 85 ++++++++++++++++++++++++++++++-------------- 2 files changed, 60 insertions(+), 27 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index e17a7ae9a155c4..1e093b399bc0da 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1097,6 +1097,7 @@ struct snd_soc_card { /* lists of probed devices belonging to this card */ struct list_head component_dev_list; + struct list_head list; struct list_head widgets; struct list_head paths; @@ -1373,6 +1374,7 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card) INIT_LIST_HEAD(&card->dapm_list); INIT_LIST_HEAD(&card->aux_comp_list); INIT_LIST_HEAD(&card->component_dev_list); + INIT_LIST_HEAD(&card->list); } static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7e18937c221443..807f112fad80b3 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -52,6 +52,7 @@ EXPORT_SYMBOL_GPL(snd_soc_debugfs_root); static DEFINE_MUTEX(client_mutex); static LIST_HEAD(component_list); +static LIST_HEAD(unbind_card_list); /* * This is a timeout to do a DAPM powerdown after a stream is closed(). @@ -2679,6 +2680,33 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, } EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); +static int snd_soc_bind_card(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + int ret; + + ret = snd_soc_instantiate_card(card); + if (ret != 0) + return ret; + + /* deactivate pins to sleep state */ + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai; + int j; + + for_each_rtd_codec_dai(rtd, j, codec_dai) { + if (!codec_dai->active) + pinctrl_pm_select_sleep_state(codec_dai->dev); + } + + if (!cpu_dai->active) + pinctrl_pm_select_sleep_state(cpu_dai->dev); + } + + return ret; +} + /** * snd_soc_register_card - Register a card with the ASoC core * @@ -2688,7 +2716,6 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); int snd_soc_register_card(struct snd_soc_card *card) { int i, ret; - struct snd_soc_pcm_runtime *rtd; if (!card->name || !card->dev) return -EINVAL; @@ -2719,28 +2746,23 @@ int snd_soc_register_card(struct snd_soc_card *card) mutex_init(&card->mutex); mutex_init(&card->dapm_mutex); - ret = snd_soc_instantiate_card(card); - if (ret != 0) - return ret; - - /* deactivate pins to sleep state */ - list_for_each_entry(rtd, &card->rtd_list, list) { - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai; - int j; - - for_each_rtd_codec_dai(rtd, j, codec_dai) { - if (!codec_dai->active) - pinctrl_pm_select_sleep_state(codec_dai->dev); - } + return snd_soc_bind_card(card); +} +EXPORT_SYMBOL_GPL(snd_soc_register_card); - if (!cpu_dai->active) - pinctrl_pm_select_sleep_state(cpu_dai->dev); +static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) +{ + if (card->instantiated) { + card->instantiated = false; + snd_soc_dapm_shutdown(card); + soc_cleanup_card_resources(card); + if (!unregister) + list_add(&card->list, &unbind_card_list); + } else { + if (unregister) + list_del(&card->list); } - - return ret; } -EXPORT_SYMBOL_GPL(snd_soc_register_card); /** * snd_soc_unregister_card - Unregister a card with the ASoC core @@ -2750,12 +2772,8 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card); */ int snd_soc_unregister_card(struct snd_soc_card *card) { - if (card->instantiated) { - card->instantiated = false; - snd_soc_dapm_shutdown(card); - soc_cleanup_card_resources(card); - dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); - } + snd_soc_unbind_card(card, true); + dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); return 0; } @@ -3099,7 +3117,7 @@ static void snd_soc_component_del_unlocked(struct snd_soc_component *component) struct snd_soc_card *card = component->card; if (card) - snd_soc_unregister_card(card); + snd_soc_unbind_card(card, false); list_del(&component->list); } @@ -3139,6 +3157,18 @@ static void convert_endianness_formats(struct snd_soc_pcm_stream *stream) stream->formats |= endianness_format_map[i]; } +static void snd_soc_try_rebind_card(void) +{ + struct snd_soc_card *card, *c; + + if (!list_empty(&unbind_card_list)) { + list_for_each_entry_safe(card, c, &unbind_card_list, list) { + if (!snd_soc_bind_card(card)) + list_del(&card->list); + } + } +} + int snd_soc_add_component(struct device *dev, struct snd_soc_component *component, const struct snd_soc_component_driver *component_driver, @@ -3166,6 +3196,7 @@ int snd_soc_add_component(struct device *dev, } snd_soc_component_add(component); + snd_soc_try_rebind_card(); return 0; From 8d5a8dac13c2c766f7221cf8b5e10dd5c9e36a7e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 15:50:27 +0900 Subject: [PATCH 0040/1995] ASoC: soc-core: remove dai->driver NULL check It is strange if it has "dai" but doesn't have "dai->driver". And more over "dai->driver->xxx" is used everywhere without "dai->driver" pointer NULL checking. It got Oops already if "dai->driver" was NULL. Let's remove un-needed "dai->driver" NULL check. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit a7c439d6128de2cbc087ae7524b47f613ff8bc6c) --- sound/soc/soc-core.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 807f112fad80b3..325dc1964850c8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2519,8 +2519,6 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio); */ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - if (dai->driver == NULL) - return -EINVAL; if (dai->driver->ops->set_fmt == NULL) return -ENOTSUPP; return dai->driver->ops->set_fmt(dai, fmt); @@ -2667,9 +2665,6 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, int direction) { - if (!dai->driver) - return -ENOTSUPP; - if (dai->driver->ops->mute_stream) return dai->driver->ops->mute_stream(dai, mute, direction); else if (direction == SNDRV_PCM_STREAM_PLAYBACK && From 4e5b3de391bb765bd721bae1524b8e0881fb074c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 06:51:14 +0000 Subject: [PATCH 0041/1995] ASoC: soc-core: manage platform name under snd_soc_init_platform() Now "platform" is controlled by snd_soc_dai_link_component, thus its "name" can be initialized in snd_soc_init_platform(), instead of soc_bind_dai_link() local. This patch do it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 4a9ed39477bd1635cf23b49e10f9e364329bbe46) --- sound/soc/soc-core.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 325dc1964850c8..d856b08f5f993a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -845,7 +845,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_component *component; struct snd_soc_dai **codec_dais; struct device_node *platform_of_node; - const char *platform_name; int i; if (dai_link->ignore) @@ -892,11 +891,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card, /* Single codec links expect codec and codec_dai in runtime data */ rtd->codec_dai = codec_dais[0]; - /* if there's no platform we match on the empty platform */ - platform_name = dai_link->platform->name; - if (!platform_name && !dai_link->platform->of_node) - platform_name = "snd-soc-dummy"; - /* find one from the set of registered platforms */ list_for_each_entry(component, &component_list, list) { platform_of_node = component->dev->of_node; @@ -907,7 +901,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, if (platform_of_node != dai_link->platform->of_node) continue; } else { - if (strcmp(component->name, platform_name)) + if (strcmp(component->name, dai_link->platform->name)) continue; } @@ -1020,24 +1014,31 @@ static void soc_remove_dai_links(struct snd_soc_card *card) static int snd_soc_init_platform(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { + struct snd_soc_dai_link_component *platform = dai_link->platform; + /* * FIXME * * this function should be removed in the future */ /* convert Legacy platform link */ - if (dai_link->platform) - return 0; - - dai_link->platform = devm_kzalloc(card->dev, + if (!platform) { + platform = devm_kzalloc(card->dev, sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); - if (!dai_link->platform) - return -ENOMEM; + if (!platform) + return -ENOMEM; - dai_link->platform->name = dai_link->platform_name; - dai_link->platform->of_node = dai_link->platform_of_node; - dai_link->platform->dai_name = NULL; + dai_link->platform = platform; + platform->name = dai_link->platform_name; + platform->of_node = dai_link->platform_of_node; + platform->dai_name = NULL; + } + + /* if there's no platform we match on the empty platform */ + if (!platform->name && + !platform->of_node) + platform->name = "snd-soc-dummy"; return 0; } From 77e8d226c56f31a207b9995dfc5e423c3bba9231 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 11 Sep 2018 06:51:45 +0000 Subject: [PATCH 0042/1995] ASoC: soc-core: add snd_soc_is_matching_component() To find (CPU/)Codec/Platform, we need to find component first (= on CPU/Codec/Platform), and find DAI from it (= CPU/Codec). These are similar operation but difficult to be simple, and has many duplicate code to finding component. This patch adds new snd_soc_is_matching_component(), and reduce duplicate codes. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit be6ac0a9ced99403c435b2b2fe9ac4bd55749823) --- sound/soc/soc-core.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d856b08f5f993a..da2b2a758b6d1b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -737,6 +737,24 @@ static struct snd_soc_component *soc_find_component( return NULL; } +static int snd_soc_is_matching_component( + const struct snd_soc_dai_link_component *dlc, + struct snd_soc_component *component) +{ + struct device_node *component_of_node; + + component_of_node = component->dev->of_node; + if (!component_of_node && component->dev->parent) + component_of_node = component->dev->parent->of_node; + + if (dlc->of_node && component_of_node != dlc->of_node) + return 0; + if (dlc->name && strcmp(component->name, dlc->name)) + return 0; + + return 1; +} + /** * snd_soc_find_dai - Find a registered DAI * @@ -753,19 +771,12 @@ struct snd_soc_dai *snd_soc_find_dai( { struct snd_soc_component *component; struct snd_soc_dai *dai; - struct device_node *component_of_node; lockdep_assert_held(&client_mutex); /* Find CPU DAI from registered DAIs*/ list_for_each_entry(component, &component_list, list) { - component_of_node = component->dev->of_node; - if (!component_of_node && component->dev->parent) - component_of_node = component->dev->parent->of_node; - - if (dlc->of_node && component_of_node != dlc->of_node) - continue; - if (dlc->name && strcmp(component->name, dlc->name)) + if (!snd_soc_is_matching_component(dlc, component)) continue; list_for_each_entry(dai, &component->dai_list, list) { if (dlc->dai_name && strcmp(dai->name, dlc->dai_name) @@ -844,7 +855,6 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; struct snd_soc_dai **codec_dais; - struct device_node *platform_of_node; int i; if (dai_link->ignore) @@ -893,17 +903,9 @@ static int soc_bind_dai_link(struct snd_soc_card *card, /* find one from the set of registered platforms */ list_for_each_entry(component, &component_list, list) { - platform_of_node = component->dev->of_node; - if (!platform_of_node && component->dev->parent->of_node) - platform_of_node = component->dev->parent->of_node; - - if (dai_link->platform->of_node) { - if (platform_of_node != dai_link->platform->of_node) - continue; - } else { - if (strcmp(component->name, dai_link->platform->name)) - continue; - } + if (!snd_soc_is_matching_component(dai_link->platform, + component)) + continue; snd_soc_rtdcom_add(rtd, component); } From 1f9085aba29b0544a53eec5da72840763dfd69f2 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 17 Sep 2018 19:03:09 +0800 Subject: [PATCH 0043/1995] ASoC: rt5514-spi: Get the period_bytes in the copy work to make sure the value correctly The value of period_bytes will get the zero before the hw_params() is not run completely. Move the function snd_pcm_lib_period_bytes() to copy work, and make sure that is not zero. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown (cherry picked from commit fbb673f7c6555d5434ad005f86b0d4368b1203d9) --- sound/soc/codecs/rt5514-spi.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 6478d10c4f4af3..4d46f4567c3a8c 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -91,6 +91,14 @@ static void rt5514_spi_copy_work(struct work_struct *work) runtime = rt5514_dsp->substream->runtime; period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream); + if (!period_bytes) { + schedule_delayed_work(&rt5514_dsp->copy_work, 5); + goto done; + } + + if (rt5514_dsp->buf_size % period_bytes) + rt5514_dsp->buf_size = (rt5514_dsp->buf_size / period_bytes) * + period_bytes; if (rt5514_dsp->get_size >= rt5514_dsp->buf_size) { rt5514_spi_burst_read(RT5514_BUFFER_VOICE_WP, (u8 *)&buf, @@ -149,13 +157,11 @@ static void rt5514_spi_copy_work(struct work_struct *work) static void rt5514_schedule_copy(struct rt5514_dsp *rt5514_dsp) { - size_t period_bytes; u8 buf[8]; if (!rt5514_dsp->substream) return; - period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream); rt5514_dsp->get_size = 0; /** @@ -183,10 +189,6 @@ static void rt5514_schedule_copy(struct rt5514_dsp *rt5514_dsp) rt5514_dsp->buf_size = rt5514_dsp->buf_limit - rt5514_dsp->buf_base; - if (rt5514_dsp->buf_size % period_bytes) - rt5514_dsp->buf_size = (rt5514_dsp->buf_size / period_bytes) * - period_bytes; - if (rt5514_dsp->buf_base && rt5514_dsp->buf_limit && rt5514_dsp->buf_rp && rt5514_dsp->buf_size) schedule_delayed_work(&rt5514_dsp->copy_work, 0); From 9e1a23d67448054ac4f266c5c42cbbd92e4c2d1f Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Tue, 18 Sep 2018 16:16:24 +0800 Subject: [PATCH 0044/1995] ASoC: remove redundant include module.h already contained moduleparam.h, so it is safe to remove the redundant include. The issue is detected with the help of Coccinelle. Signed-off-by: zhong jiang Acked-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit 29ca7d32d7f10737e8d165fcf40fe31d44b06bee) --- sound/soc/codecs/rt5651.c | 1 - sound/soc/codecs/wm8904.c | 1 - sound/soc/codecs/wm8974.c | 1 - sound/soc/soc-dapm.c | 1 - 4 files changed, 4 deletions(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 985852fd972387..b613103d801b51 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 1965635ec07c70..2a3e5fbd04e46f 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -13,7 +13,6 @@ #include #include -#include #include #include #include diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 43edaf8cd27624..593a1196088896 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -11,7 +11,6 @@ */ #include -#include #include #include #include diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 43983c69f6aad8..ee6b9758ec15f8 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -18,7 +18,6 @@ // device reopen. #include -#include #include #include #include From 5c470bc3bfea2e15f745d9707f98da627a232d67 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 18 Sep 2018 19:51:08 +0800 Subject: [PATCH 0045/1995] ASoC: rt5682: Improve HP performance We change the settings while HP power-up for better performance. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown (cherry picked from commit bf0fa00fd8410b377a3403adb58e32fc703e86e8) --- sound/soc/codecs/rt5682.c | 32 +++++++++++++++++++++++++++++--- sound/soc/codecs/rt5682.h | 14 ++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 731c6a849f69bc..83202e9e5abd37 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -1437,6 +1437,28 @@ static const struct snd_kcontrol_new hpor_switch = SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5682_HP_CTRL_1, RT5682_R_MUTE_SFT, 1, 1); +static int rt5682_charge_pump_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_update_bits(component, + RT5682_HP_CHARGE_PUMP_1, RT5682_PM_HP_MASK, RT5682_PM_HP_HV); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_update_bits(component, + RT5682_HP_CHARGE_PUMP_1, RT5682_PM_HP_MASK, RT5682_PM_HP_LV); + break; + default: + return 0; + } + + return 0; +} + static int rt5682_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -1449,8 +1471,6 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w, RT5682_HP_LOGIC_CTRL_2, 0x0012); snd_soc_component_write(component, RT5682_HP_CTRL_2, 0x6000); - snd_soc_component_update_bits(component, RT5682_STO_NG2_CTRL_1, - RT5682_NG2_EN_MASK, RT5682_NG2_EN); snd_soc_component_update_bits(component, RT5682_DEPOP_1, 0x60, 0x60); break; @@ -1723,7 +1743,8 @@ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("HP Amp R", RT5682_PWR_ANLG_1, RT5682_PWR_HA_R_BIT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, RT5682_DEPOP_1, - RT5682_PUMP_EN_SFT, 0, NULL, 0), + RT5682_PUMP_EN_SFT, 0, rt5682_charge_pump_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY_S("Capless", 2, RT5682_DEPOP_1, RT5682_CAPLESS_EN_SFT, 0, NULL, 0), @@ -1884,6 +1905,7 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = { {"HP Amp", NULL, "Charge Pump"}, {"HP Amp", NULL, "CLKDET SYS"}, {"HP Amp", NULL, "CBJ Power"}, + {"HP Amp", NULL, "Vref1"}, {"HP Amp", NULL, "Vref2"}, {"HPOL Playback", "Switch", "HP Amp"}, {"HPOR Playback", "Switch", "HP Amp"}, @@ -2607,6 +2629,10 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, RT5682_GP4_PIN_MASK | RT5682_GP5_PIN_MASK, RT5682_GP4_PIN_ADCDAT1 | RT5682_GP5_PIN_DACDAT1); regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000); + regmap_update_bits(rt5682->regmap, RT5682_BIAS_CUR_CTRL_8, + RT5682_HPA_CP_BIAS_CTRL_MASK, RT5682_HPA_CP_BIAS_3UA); + regmap_update_bits(rt5682->regmap, RT5682_CHARGE_PUMP_1, + RT5682_CP_CLK_HP_MASK, RT5682_CP_CLK_HP_300KHZ); INIT_DELAYED_WORK(&rt5682->jack_detect_work, rt5682_jack_detect_handler); diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h index 8068140ebe3f19..d82a8301fd745c 100644 --- a/sound/soc/codecs/rt5682.h +++ b/sound/soc/codecs/rt5682.h @@ -1214,6 +1214,20 @@ #define RT5682_JDH_NO_PLUG (0x1 << 4) #define RT5682_JDH_PLUG (0x0 << 4) +/* Bias current control 8 (0x0111) */ +#define RT5682_HPA_CP_BIAS_CTRL_MASK (0x3 << 2) +#define RT5682_HPA_CP_BIAS_2UA (0x0 << 2) +#define RT5682_HPA_CP_BIAS_3UA (0x1 << 2) +#define RT5682_HPA_CP_BIAS_4UA (0x2 << 2) +#define RT5682_HPA_CP_BIAS_6UA (0x3 << 2) + +/* Charge Pump Internal Register1 (0x0125) */ +#define RT5682_CP_CLK_HP_MASK (0x3 << 4) +#define RT5682_CP_CLK_HP_100KHZ (0x0 << 4) +#define RT5682_CP_CLK_HP_200KHZ (0x1 << 4) +#define RT5682_CP_CLK_HP_300KHZ (0x2 << 4) +#define RT5682_CP_CLK_HP_600KHZ (0x3 << 4) + /* Chopper and Clock control for DAC (0x013a)*/ #define RT5682_CKXEN_DAC1_MASK (0x1 << 13) #define RT5682_CKXEN_DAC1_SFT 13 From 8666ffff424ef42bfd62c7e82764b3b73c8aa378 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 18 Sep 2018 19:51:24 +0800 Subject: [PATCH 0046/1995] ASoC: rt5682: Remove HP volume control This patch removed Headphone Playback Volume control. Due to codec settings, we don't want the user to change HP analog gain. The user could use DAC1 Playback Volume control to change playback volume. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown (cherry picked from commit 3f24f37adbc9a1059420a9c8f857e3490a4bce5e) --- sound/soc/codecs/rt5682.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 83202e9e5abd37..7213b1cfb18ac0 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -749,7 +749,6 @@ static bool rt5682_readable_register(struct device *dev, unsigned int reg) } } -static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2250, 150, 0); static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0); static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); @@ -1108,10 +1107,6 @@ static void rt5682_jack_detect_handler(struct work_struct *work) } static const struct snd_kcontrol_new rt5682_snd_controls[] = { - /* Headphone Output Volume */ - SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5682_HPL_GAIN, - RT5682_HPR_GAIN, RT5682_G_HP_SFT, 15, 1, hp_vol_tlv), - /* DAC Digital Volume */ SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5682_DAC1_DIG_VOL, RT5682_L_VOL_SFT + 1, RT5682_R_VOL_SFT + 1, 86, 0, dac_vol_tlv), From 7d2ac3618bce316e6a120648a7ce244cd246a594 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 18 Sep 2018 19:50:38 +0800 Subject: [PATCH 0047/1995] ASoC: rt5682: Update calibration function The ADC/DAC path should open while calibration process. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown (cherry picked from commit afd603e4ded0fad9e3102d514020af8494da1604) --- sound/soc/codecs/rt5682.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 7213b1cfb18ac0..2725eb72fb1b26 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2468,17 +2468,22 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682) mutex_lock(&rt5682->calibrate_mutex); rt5682_reset(rt5682->regmap); - regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2bf); + regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2af); usleep_range(15000, 20000); - regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2bf); + regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2af); regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0300); regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x8000); regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0100); + regmap_write(rt5682->regmap, RT5682_HP_IMP_SENS_CTRL_19, 0x3800); regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x3000); + regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x7005); + regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x686c); + regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0d0d); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_2, 0x0321); regmap_write(rt5682->regmap, RT5682_HP_LOGIC_CTRL_2, 0x0004); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_3, 0x06a1); + regmap_write(rt5682->regmap, RT5682_A_DAC1_MUX, 0x0311); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00); regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0xfc00); @@ -2495,8 +2500,12 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682) pr_err("HP Calibration Failure\n"); /* restore settings */ + regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0x02af); + regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0080); regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x0000); regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0000); + regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x2000); + regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x2005); mutex_unlock(&rt5682->calibrate_mutex); From 68e6fb6ed176297e232cfe746e89ee121fa5c917 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 18 Sep 2018 19:51:38 +0800 Subject: [PATCH 0048/1995] ASoC: rt5682: Fix the boost volume at the begining of playback This patch fixed the boost volume at the begining of playback while DAC volume set to lower level. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown (cherry picked from commit 28b20dde5e1c943ab899549a655ac4935cffccbb) --- sound/soc/codecs/rt5682.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 2725eb72fb1b26..18099668e96062 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -68,6 +68,7 @@ struct rt5682_priv { static const struct reg_sequence patch_list[] = { {0x01c1, 0x1000}, + {RT5682_DAC_ADC_DIG_VOL1, 0xa020}, }; static const struct reg_default rt5682_reg[] = { @@ -1468,6 +1469,8 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w, RT5682_HP_CTRL_2, 0x6000); snd_soc_component_update_bits(component, RT5682_DEPOP_1, 0x60, 0x60); + snd_soc_component_update_bits(component, + RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0080); break; case SND_SOC_DAPM_POST_PMD: @@ -1475,6 +1478,8 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w, RT5682_DEPOP_1, 0x60, 0x0); snd_soc_component_write(component, RT5682_HP_CTRL_2, 0x0000); + snd_soc_component_update_bits(component, + RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0000); break; default: From 75706feff918f8f283401cbde3ff0e81f0161cd7 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 18 Sep 2018 19:51:53 +0800 Subject: [PATCH 0049/1995] ASoC: rt5682: Minor code modification Minor code changes are: - improve the readability in patch list - add i2c remove function - regmap_register_patch changes to regmap_multi_reg_write Signed-off-by: Shuming Fan Signed-off-by: Mark Brown (cherry picked from commit 37efe23dcca3c59cee662f1c28835020bef31cc0) --- sound/soc/codecs/rt5682.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 18099668e96062..340f90497d072a 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -67,7 +67,7 @@ struct rt5682_priv { }; static const struct reg_sequence patch_list[] = { - {0x01c1, 0x1000}, + {RT5682_HP_IMP_SENS_CTRL_19, 0x1000}, {RT5682_DAC_ADC_DIG_VOL1, 0xa020}, }; @@ -2584,7 +2584,7 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, rt5682_calibrate(rt5682); - ret = regmap_register_patch(rt5682->regmap, patch_list, + ret = regmap_multi_reg_write(rt5682->regmap, patch_list, ARRAY_SIZE(patch_list)); if (ret != 0) dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); @@ -2659,11 +2659,17 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, } - return devm_snd_soc_register_component(&i2c->dev, - &soc_component_dev_rt5682, + return snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5682, rt5682_dai, ARRAY_SIZE(rt5682_dai)); } +static int rt5682_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_component(&i2c->dev); + + return 0; +} + static void rt5682_i2c_shutdown(struct i2c_client *client) { struct rt5682_priv *rt5682 = i2c_get_clientdata(client); @@ -2694,6 +2700,7 @@ static struct i2c_driver rt5682_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5682_acpi_match), }, .probe = rt5682_i2c_probe, + .remove = rt5682_i2c_remove, .shutdown = rt5682_i2c_shutdown, .id_table = rt5682_i2c_id, }; From 2b3bc1ad2130e5564b341d52e47c090bf678ec78 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 18 Sep 2018 12:11:57 -0700 Subject: [PATCH 0050/1995] ASoC: rt5677-spi: Drop unused GPIO include This SPI driver does not use the legacy GPIO header so just delete it. Signed-off-by: Linus Walleij Signed-off-by: Mark Brown (cherry picked from commit 65ba4dd5200a537eae0f6b29e120f3971eac5a4d) --- sound/soc/codecs/rt5677-spi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index bd51f3655ee3e5..84501c2020c786 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include From bcb6b303ec915bfdf5a60e80924e3c9d32236dc1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:28:04 +0000 Subject: [PATCH 0051/1995] ASoC: convert for_each_rtd_codec_dai() for missing part commit 0b7990e38971 ("ASoC: add for_each_rtd_codec_dai() macro") added for_each_rtd_codec_dai(), but it didn't convert few loop which is not using "rtd". This patch fixup it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 7afecb3073e357ebfe4087e4ab8bb493c32bb652) --- sound/soc/soc-pcm.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 79f5dd541d2997..e387fff352c8fe 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1301,6 +1301,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, struct snd_soc_dapm_widget *widget, int stream) { struct snd_soc_pcm_runtime *be; + struct snd_soc_dai *dai; int i; dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name); @@ -1318,8 +1319,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, if (be->cpu_dai->playback_widget == widget) return be; - for (i = 0; i < be->num_codecs; i++) { - struct snd_soc_dai *dai = be->codec_dais[i]; + for_each_rtd_codec_dai(be, i, dai) { if (dai->playback_widget == widget) return be; } @@ -1338,8 +1338,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, if (be->cpu_dai->capture_widget == widget) return be; - for (i = 0; i < be->num_codecs; i++) { - struct snd_soc_dai *dai = be->codec_dais[i]; + for_each_rtd_codec_dai(be, i, dai) { if (dai->capture_widget == widget) return be; } @@ -1435,6 +1434,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, struct snd_soc_dpcm *dpcm; struct snd_soc_dapm_widget_list *list = *list_; struct snd_soc_dapm_widget *widget; + struct snd_soc_dai *dai; int prune = 0; /* Destroy any old FE <--> BE connections */ @@ -1449,8 +1449,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, continue; /* is there a valid CODEC DAI widget for this BE */ - for (i = 0; i < dpcm->be->num_codecs; i++) { - struct snd_soc_dai *dai = dpcm->be->codec_dais[i]; + for_each_rtd_codec_dai(dpcm->be, i, dai) { widget = dai_get_widget(dai, stream); /* prune the BE if it's no longer in our active list */ @@ -1685,6 +1684,7 @@ static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *fe = substream->private_data; struct snd_soc_dpcm *dpcm; + struct snd_soc_dai *dai; int stream = substream->stream; if (!fe->dai_link->dpcm_merged_format) @@ -1701,16 +1701,15 @@ static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream, struct snd_soc_pcm_stream *codec_stream; int i; - for (i = 0; i < be->num_codecs; i++) { + for_each_rtd_codec_dai(be, i, dai) { /* * Skip CODECs which don't support the current stream * type. See soc_pcm_init_runtime_hw() for more details */ - if (!snd_soc_dai_stream_valid(be->codec_dais[i], - stream)) + if (!snd_soc_dai_stream_valid(dai, stream)) continue; - codec_dai_drv = be->codec_dais[i]->driver; + codec_dai_drv = dai->driver; if (stream == SNDRV_PCM_STREAM_PLAYBACK) codec_stream = &codec_dai_drv->playback; else @@ -1795,6 +1794,7 @@ static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream, struct snd_soc_dai_driver *codec_dai_drv; struct snd_soc_pcm_stream *codec_stream; struct snd_soc_pcm_stream *cpu_stream; + struct snd_soc_dai *dai; int i; if (stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -1806,16 +1806,15 @@ static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream, *rate_max = min_not_zero(*rate_max, cpu_stream->rate_max); *rates = snd_pcm_rate_mask_intersect(*rates, cpu_stream->rates); - for (i = 0; i < be->num_codecs; i++) { + for_each_rtd_codec_dai(be, i, dai) { /* * Skip CODECs which don't support the current stream * type. See soc_pcm_init_runtime_hw() for more details */ - if (!snd_soc_dai_stream_valid(be->codec_dais[i], - stream)) + if (!snd_soc_dai_stream_valid(dai, stream)) continue; - codec_dai_drv = be->codec_dais[i]->driver; + codec_dai_drv = dai->driver; if (stream == SNDRV_PCM_STREAM_PLAYBACK) codec_stream = &codec_dai_drv->playback; else @@ -2784,6 +2783,7 @@ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) struct snd_soc_dpcm *dpcm; struct list_head *clients = &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients; + struct snd_soc_dai *dai; list_for_each_entry(dpcm, clients, list_be) { @@ -2793,8 +2793,7 @@ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) if (be->dai_link->ignore_suspend) continue; - for (i = 0; i < be->num_codecs; i++) { - struct snd_soc_dai *dai = be->codec_dais[i]; + for_each_rtd_codec_dai(be, i, dai) { struct snd_soc_dai_driver *drv = dai->driver; dev_dbg(be->dev, "ASoC: BE digital mute %s\n", From ed8f2478cdfd0ef0e6eea890879b458f3ca1aa7f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:28:30 +0000 Subject: [PATCH 0052/1995] ASoC: rename for_each_rtd_codec_dai_reverse to rollback commit 0b7990e38971 ("ASoC: add for_each_rtd_codec_dai() macro") added for_each_rtd_codec_dai_reverse(). but _rollback() is better naming than _reverse(). This patch rename it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 6d11b12879144da5f5aa08071a8a7f95f3b5a4e8) --- include/sound/soc.h | 2 +- sound/soc/soc-pcm.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 1e093b399bc0da..ec1ae9f4feebd0 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1164,7 +1164,7 @@ struct snd_soc_pcm_runtime { for ((i) = 0; \ ((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \ (i)++) -#define for_each_rtd_codec_dai_reverse(rtd, i, dai) \ +#define for_each_rtd_codec_dai_rollback(rtd, i, dai) \ for (; ((i--) >= 0) && ((dai) = rtd->codec_dais[i]);) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index e387fff352c8fe..1eff1dbb0d002a 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -621,7 +621,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) i = rtd->num_codecs; codec_dai_err: - for_each_rtd_codec_dai_reverse(rtd, i, codec_dai) { + for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) { if (codec_dai->driver->ops->shutdown) codec_dai->driver->ops->shutdown(substream, codec_dai); } @@ -1015,7 +1015,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, i = rtd->num_codecs; codec_err: - for_each_rtd_codec_dai_reverse(rtd, i, codec_dai) { + for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) { if (codec_dai->driver->ops->hw_free) codec_dai->driver->ops->hw_free(substream, codec_dai); codec_dai->rate = 0; From 8dd30650240dc2ba0f200e1fecf5bcb3cfea3e9b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:28:49 +0000 Subject: [PATCH 0053/1995] ASoC: add for_each_card_prelinks() macro To be more readable code, this patch adds new for_each_card_prelinks() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 7fe072b4df5d0cc832eb758c1eed243c145a2dfc) --- include/sound/soc.h | 4 ++++ sound/soc/fsl/pcm030-audio-fabric.c | 5 +++-- sound/soc/generic/simple-card-utils.c | 6 ++---- sound/soc/intel/boards/skl_hda_dsp_generic.c | 5 +++-- sound/soc/mediatek/mt2701/mt2701-cs42448.c | 13 +++++++------ sound/soc/mediatek/mt2701/mt2701-wm8960.c | 13 +++++++------ sound/soc/mediatek/mt6797/mt6797-mt6351.c | 13 +++++++------ sound/soc/mediatek/mt8173/mt8173-max98090.c | 13 +++++++------ sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c | 7 ++++--- sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c | 7 ++++--- sound/soc/mediatek/mt8173/mt8173-rt5650.c | 7 ++++--- sound/soc/meson/axg-card.c | 3 +-- sound/soc/qcom/apq8096.c | 7 +++---- sound/soc/qcom/sdm845.c | 7 +++---- sound/soc/samsung/tm2_wm5110.c | 13 +++++++------ sound/soc/soc-core.c | 16 +++++++--------- 16 files changed, 73 insertions(+), 66 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index ec1ae9f4feebd0..f94b989e7a1a1b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1120,6 +1120,10 @@ struct snd_soc_card { void *drvdata; }; +#define for_each_card_prelinks(card, i, link) \ + for ((i) = 0; \ + ((i) < (card)->num_links) && ((link) = &(card)->dai_link[i]); \ + (i)++) /* SoC machine DAI configuration, glues a codec and cpu DAI together */ struct snd_soc_pcm_runtime { diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c index ec731223cab3d7..e339f36cea9565 100644 --- a/sound/soc/fsl/pcm030-audio-fabric.c +++ b/sound/soc/fsl/pcm030-audio-fabric.c @@ -57,6 +57,7 @@ static int pcm030_fabric_probe(struct platform_device *op) struct device_node *platform_np; struct snd_soc_card *card = &pcm030_card; struct pcm030_audio_data *pdata; + struct snd_soc_dai_link *dai_link; int ret; int i; @@ -78,8 +79,8 @@ static int pcm030_fabric_probe(struct platform_device *op) return -ENODEV; } - for (i = 0; i < card->num_links; i++) - card->dai_link[i].platform_of_node = platform_np; + for_each_card_prelinks(card, i, dai_link) + dai_link->platform_of_node = platform_np; ret = request_module("snd-soc-wm9712"); if (ret) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index d3f3f0fec74c09..5091d5201c54fd 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -367,11 +367,9 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_cpu); int asoc_simple_card_clean_reference(struct snd_soc_card *card) { struct snd_soc_dai_link *dai_link; - int num_links; + int i; - for (num_links = 0, dai_link = card->dai_link; - num_links < card->num_links; - num_links++, dai_link++) { + for_each_card_prelinks(card, i, dai_link) { of_node_put(dai_link->cpu_of_node); of_node_put(dai_link->codec_of_node); } diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index b213e9b47505fb..b415dd4c85f5ac 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -104,6 +104,7 @@ static struct snd_soc_card hda_soc_card = { static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) { struct snd_soc_card *card = &hda_soc_card; + struct snd_soc_dai_link *dai_link; u32 codec_count, codec_mask; int i, num_links, num_route; @@ -125,8 +126,8 @@ static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) card->num_links = num_links; card->num_dapm_routes = num_route; - for (i = 0; i < num_links; i++) - skl_hda_be_dai_links[i].platform_name = pdata->platform; + for_each_card_prelinks(card, i, dai_link) + dai_link->platform_name = pdata->platform; return 0; } diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c index 666282b865a8af..875f8469153519 100644 --- a/sound/soc/mediatek/mt2701/mt2701-cs42448.c +++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c @@ -299,6 +299,7 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) devm_kzalloc(&pdev->dev, sizeof(struct mt2701_cs42448_private), GFP_KERNEL); struct device *dev = &pdev->dev; + struct snd_soc_dai_link *dai_link; if (!priv) return -ENOMEM; @@ -309,10 +310,10 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt2701_cs42448_dai_links[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_links->platform_name) continue; - mt2701_cs42448_dai_links[i].platform_of_node = platform_node; + dai_links->platform_of_node = platform_node; } card->dev = dev; @@ -324,10 +325,10 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) "Property 'audio-codec' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt2701_cs42448_dai_links[i].codec_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_links->codec_name) continue; - mt2701_cs42448_dai_links[i].codec_of_node = codec_node; + dai_links->codec_of_node = codec_node; } codec_node_bt_mrg = of_parse_phandle(pdev->dev.of_node, diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c index 89f34efd974729..9c7773f288a8c9 100644 --- a/sound/soc/mediatek/mt2701/mt2701-wm8960.c +++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c @@ -97,6 +97,7 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt2701_wm8960_card; struct device_node *platform_node, *codec_node; + struct snd_soc_dai_link *dai_link; int ret, i; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -105,10 +106,10 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt2701_wm8960_dai_links[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_links->platform_name) continue; - mt2701_wm8960_dai_links[i].platform_of_node = platform_node; + dai_links->platform_of_node = platform_node; } card->dev = &pdev->dev; @@ -120,10 +121,10 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) "Property 'audio-codec' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt2701_wm8960_dai_links[i].codec_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_links->codec_name) continue; - mt2701_wm8960_dai_links[i].codec_of_node = codec_node; + dai_links->codec_of_node = codec_node; } ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); diff --git a/sound/soc/mediatek/mt6797/mt6797-mt6351.c b/sound/soc/mediatek/mt6797/mt6797-mt6351.c index b1558c57b9ca7a..b569b452c54154 100644 --- a/sound/soc/mediatek/mt6797/mt6797-mt6351.c +++ b/sound/soc/mediatek/mt6797/mt6797-mt6351.c @@ -158,6 +158,7 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt6797_mt6351_card; struct device_node *platform_node, *codec_node; + struct snd_soc_dai_link *dai_link; int ret, i; card->dev = &pdev->dev; @@ -168,10 +169,10 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt6797_mt6351_dai_links[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platform_name) continue; - mt6797_mt6351_dai_links[i].platform_of_node = platform_node; + dai_links->platform_of_node = platform_node; } codec_node = of_parse_phandle(pdev->dev.of_node, @@ -181,10 +182,10 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) "Property 'audio-codec' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt6797_mt6351_dai_links[i].codec_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_links->codec_name) continue; - mt6797_mt6351_dai_links[i].codec_of_node = codec_node; + dai_links->codec_of_node = codec_node; } ret = devm_snd_soc_register_card(&pdev->dev, card); diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c index 902d111016d6f5..4d6596d5cb0796 100644 --- a/sound/soc/mediatek/mt8173/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c @@ -137,6 +137,7 @@ static int mt8173_max98090_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt8173_max98090_card; struct device_node *codec_node, *platform_node; + struct snd_soc_dai_link *dai_link; int ret, i; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -145,10 +146,10 @@ static int mt8173_max98090_dev_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt8173_max98090_dais[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platform_name) continue; - mt8173_max98090_dais[i].platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } codec_node = of_parse_phandle(pdev->dev.of_node, @@ -158,10 +159,10 @@ static int mt8173_max98090_dev_probe(struct platform_device *pdev) "Property 'audio-codec' missing or invalid\n"); return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt8173_max98090_dais[i].codec_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->codec_name) continue; - mt8173_max98090_dais[i].codec_of_node = codec_node; + dai_link->codec_of_node = codec_node; } card->dev = &pdev->dev; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index 5b4e90180827a7..da5b58ce791bbb 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -178,6 +178,7 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt8173_rt5650_rt5514_card; struct device_node *platform_node; + struct snd_soc_dai_link *dai_link; int i, ret; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -187,10 +188,10 @@ static int mt8173_rt5650_rt5514_dev_probe(struct platform_device *pdev) return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt8173_rt5650_rt5514_dais[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platform_name) continue; - mt8173_rt5650_rt5514_dais[i].platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } mt8173_rt5650_rt5514_codecs[0].of_node = diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index 82675ed057dee9..d83cd039b413b3 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -224,6 +224,7 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) { struct snd_soc_card *card = &mt8173_rt5650_rt5676_card; struct device_node *platform_node; + struct snd_soc_dai_link *dai_link; int i, ret; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -233,10 +234,10 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt8173_rt5650_rt5676_dais[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platform_name) continue; - mt8173_rt5650_rt5676_dais[i].platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } mt8173_rt5650_rt5676_codecs[0].of_node = diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index ef05fbc40c324f..7edf250c8fb139 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -239,6 +239,7 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) struct device_node *platform_node; struct device_node *np; const char *codec_capture_dai; + struct snd_soc_dai_link *dai_link; int i, ret; platform_node = of_parse_phandle(pdev->dev.of_node, @@ -248,10 +249,10 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) return -EINVAL; } - for (i = 0; i < card->num_links; i++) { - if (mt8173_rt5650_dais[i].platform_name) + for_each_card_prelinks(card, i, dai_link) { + if (dai_link->platform_name) continue; - mt8173_rt5650_dais[i].platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } mt8173_rt5650_codecs[0].of_node = diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c index b9163970ab7af7..7861b408a4b9e7 100644 --- a/sound/soc/meson/axg-card.c +++ b/sound/soc/meson/axg-card.c @@ -101,8 +101,7 @@ static void axg_card_clean_references(struct axg_card *priv) int i, j; if (card->dai_link) { - for (i = 0; i < card->num_links; i++) { - link = &card->dai_link[i]; + for_each_card_prelinks(card, i, link) { of_node_put(link->cpu_of_node); for_each_link_codecs(link, j, codec) of_node_put(codec->of_node); diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c index 1543e85629f803..fb45f396ab4a74 100644 --- a/sound/soc/qcom/apq8096.c +++ b/sound/soc/qcom/apq8096.c @@ -25,13 +25,12 @@ static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, static void apq8096_add_be_ops(struct snd_soc_card *card) { - struct snd_soc_dai_link *link = card->dai_link; - int i, num_links = card->num_links; + struct snd_soc_dai_link *link; + int i; - for (i = 0; i < num_links; i++) { + for_each_card_prelinks(card, i, link) { if (link->no_pcm == 1) link->be_hw_params_fixup = apq8096_be_hw_params_fixup; - link++; } } diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c index 2a781d87ee65e1..9effbecc571f6b 100644 --- a/sound/soc/qcom/sdm845.c +++ b/sound/soc/qcom/sdm845.c @@ -195,15 +195,14 @@ static int sdm845_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, static void sdm845_add_be_ops(struct snd_soc_card *card) { - struct snd_soc_dai_link *link = card->dai_link; - int i, num_links = card->num_links; + struct snd_soc_dai_link *link; + int i; - for (i = 0; i < num_links; i++) { + for_each_card_prelinks(card, i, link) { if (link->no_pcm == 1) { link->ops = &sdm845_be_ops; link->be_hw_params_fixup = sdm845_be_hw_params_fixup; } - link++; } } diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c index 43332c32d7e9b4..dc93941e01c3b8 100644 --- a/sound/soc/samsung/tm2_wm5110.c +++ b/sound/soc/samsung/tm2_wm5110.c @@ -491,6 +491,7 @@ static int tm2_probe(struct platform_device *pdev) struct snd_soc_card *card = &tm2_card; struct tm2_machine_priv *priv; struct of_phandle_args args; + struct snd_soc_dai_link *dai_link; int num_codecs, ret, i; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -558,18 +559,18 @@ static int tm2_probe(struct platform_device *pdev) } /* Initialize WM5110 - I2S and HDMI - I2S1 DAI links */ - for (i = 0; i < card->num_links; i++) { + for_each_card_prelinks(card, i, dai_link) { unsigned int dai_index = 0; /* WM5110 */ - card->dai_link[i].cpu_name = NULL; - card->dai_link[i].platform_name = NULL; + dai_link->cpu_name = NULL; + dai_link->platform_name = NULL; if (num_codecs > 1 && i == card->num_links - 1) dai_index = 1; /* HDMI */ - card->dai_link[i].codec_of_node = codec_dai_node[dai_index]; - card->dai_link[i].cpu_of_node = cpu_dai_node[dai_index]; - card->dai_link[i].platform_of_node = cpu_dai_node[dai_index]; + dai_link->codec_of_node = codec_dai_node[dai_index]; + dai_link->cpu_of_node = cpu_dai_node[dai_index]; + dai_link->platform_of_node = cpu_dai_node[dai_index]; } if (num_codecs > 1) { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index da2b2a758b6d1b..532d8c59ed1e36 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1889,9 +1889,7 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) continue; /* machine matches, so override the rtd data */ - for (i = 0; i < card->num_links; i++) { - - dai_link = &card->dai_link[i]; + for_each_card_prelinks(card, i, dai_link) { /* ignore this FE */ if (dai_link->dynamic) { @@ -1955,8 +1953,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) soc_check_tplg_fes(card); /* bind DAIs */ - for (i = 0; i < card->num_links; i++) { - ret = soc_bind_dai_link(card, &card->dai_link[i]); + for_each_card_prelinks(card, i, dai_link) { + ret = soc_bind_dai_link(card, dai_link); if (ret != 0) goto base_error; } @@ -1969,8 +1967,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } /* add predefined DAI links to the list */ - for (i = 0; i < card->num_links; i++) - snd_soc_add_dai_link(card, card->dai_link+i); + for_each_card_prelinks(card, i, dai_link) + snd_soc_add_dai_link(card, dai_link); /* card bind complete so register a sound card */ ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, @@ -2714,12 +2712,12 @@ static int snd_soc_bind_card(struct snd_soc_card *card) int snd_soc_register_card(struct snd_soc_card *card) { int i, ret; + struct snd_soc_dai_link *link; if (!card->name || !card->dev) return -EINVAL; - for (i = 0; i < card->num_links; i++) { - struct snd_soc_dai_link *link = &card->dai_link[i]; + for_each_card_prelinks(card, i, link) { ret = soc_init_dai_link(card, link); if (ret) { From 6d4c665fb9a9692f70aac529691b49b9d582d3be Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:29:16 +0000 Subject: [PATCH 0054/1995] ASoC: add for_each_card_links() macro To be more readable code, this patch adds new for_each_card_links() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 98061fdbfccc02aa0fd6637c67a0524aab385b8d) --- include/sound/soc.h | 6 ++++++ sound/soc/soc-core.c | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index f94b989e7a1a1b..1fffbaa819d9dd 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1125,6 +1125,12 @@ struct snd_soc_card { ((i) < (card)->num_links) && ((link) = &(card)->dai_link[i]); \ (i)++) +#define for_each_card_links(card, link) \ + list_for_each_entry(dai_link, &(card)->dai_link_list, list) +#define for_each_card_links_safe(card, link, _link) \ + list_for_each_entry_safe(link, _link, &(card)->dai_link_list, list) + + /* SoC machine DAI configuration, glues a codec and cpu DAI together */ struct snd_soc_pcm_runtime { struct device *dev; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 532d8c59ed1e36..4951736356421c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -816,7 +816,7 @@ struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, lockdep_assert_held(&client_mutex); - list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { + for_each_card_links_safe(card, link, _link) { if (link->id != id) continue; @@ -1004,7 +1004,7 @@ static void soc_remove_dai_links(struct snd_soc_card *card) soc_remove_link_components(card, rtd, order); } - list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { + for_each_card_links_safe(card, link, _link) { if (link->dobj.type == SND_SOC_DOBJ_DAI_LINK) dev_warn(card->dev, "Topology forgot to remove link %s?\n", link->name); @@ -1219,7 +1219,7 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card, if (dai_link->dobj.type && card->remove_dai_link) card->remove_dai_link(card, dai_link); - list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { + for_each_card_links_safe(card, link, _link) { if (link == dai_link) { list_del(&link->list); return; @@ -2033,7 +2033,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* Find new DAI links added during probing components and bind them. * Components with topology may bring new DAIs and DAI links. */ - list_for_each_entry(dai_link, &card->dai_link_list, list) { + for_each_card_links(card, dai_link) { if (soc_is_dai_link_bound(card, dai_link)) continue; From 1b84adc23e8ddfae68aa1d09a88f92e914ea5def Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:29:35 +0000 Subject: [PATCH 0055/1995] ASoC: add for_each_card_rtds() macro To be more readable code, this patch adds new for_each_card_rtds() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit bcb1fd1fcd6507ba5a1f8610550135dc367aedb7) --- include/sound/soc.h | 4 ++ sound/soc/codecs/hdac_hdmi.c | 2 +- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 4 +- sound/soc/soc-core.c | 48 ++++++++++---------- sound/soc/soc-dapm.c | 2 +- sound/soc/soc-pcm.c | 12 ++--- 6 files changed, 38 insertions(+), 34 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 1fffbaa819d9dd..164418dbf40e27 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1130,6 +1130,10 @@ struct snd_soc_card { #define for_each_card_links_safe(card, link, _link) \ list_for_each_entry_safe(link, _link, &(card)->dai_link_list, list) +#define for_each_card_rtds(card, rtd) \ + list_for_each_entry(rtd, &(card)->rtd_list, list) +#define for_each_card_rtds_safe(card, rtd, _rtd) \ + list_for_each_entry_safe(rtd, _rtd, &(card)->rtd_list, list) /* SoC machine DAI configuration, glues a codec and cpu DAI together */ struct snd_soc_pcm_runtime { diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 41d90dc6ebf701..4e9854889a9570 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1604,7 +1604,7 @@ static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, { struct snd_soc_pcm_runtime *rtd; - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->pcm && (rtd->pcm->device == device)) return rtd->pcm; } diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 6c36da56087759..afc5598660955a 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -765,7 +765,7 @@ static int sst_soc_prepare(struct device *dev) snd_soc_poweroff(drv->soc_card->dev); /* set the SSPs to idle */ - list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) { + for_each_card_rtds(drv->soc_card, rtd) { struct snd_soc_dai *dai = rtd->cpu_dai; if (dai->active) { @@ -786,7 +786,7 @@ static void sst_soc_complete(struct device *dev) return; /* restart SSPs */ - list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) { + for_each_card_rtds(drv->soc_card, rtd) { struct snd_soc_dai *dai = rtd->cpu_dai; if (dai->active) { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4951736356421c..7efcf3475d6f92 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -342,7 +342,7 @@ struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, { struct snd_soc_pcm_runtime *rtd; - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->dai_link->no_pcm && !strcmp(rtd->dai_link->name, dai_link)) return rtd->pcm->streams[stream].substream; @@ -399,7 +399,7 @@ static void soc_remove_pcm_runtimes(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd, *_rtd; - list_for_each_entry_safe(rtd, _rtd, &card->rtd_list, list) { + for_each_card_rtds_safe(card, rtd, _rtd) { list_del(&rtd->list); soc_free_pcm_runtime(rtd); } @@ -412,7 +412,7 @@ struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, { struct snd_soc_pcm_runtime *rtd; - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (!strcmp(rtd->dai_link->name, dai_link)) return rtd; } @@ -452,7 +452,7 @@ int snd_soc_suspend(struct device *dev) snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot); /* mute any active DACs */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *dai; if (rtd->dai_link->ignore_suspend) @@ -467,7 +467,7 @@ int snd_soc_suspend(struct device *dev) } /* suspend all pcms */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->dai_link->ignore_suspend) continue; @@ -477,7 +477,7 @@ int snd_soc_suspend(struct device *dev) if (card->suspend_pre) card->suspend_pre(card); - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; if (rtd->dai_link->ignore_suspend) @@ -488,10 +488,10 @@ int snd_soc_suspend(struct device *dev) } /* close any waiting streams */ - list_for_each_entry(rtd, &card->rtd_list, list) + for_each_card_rtds(card, rtd) flush_delayed_work(&rtd->delayed_work); - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->dai_link->ignore_suspend) continue; @@ -548,7 +548,7 @@ int snd_soc_suspend(struct device *dev) } } - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; if (rtd->dai_link->ignore_suspend) @@ -592,7 +592,7 @@ static void soc_resume_deferred(struct work_struct *work) card->resume_pre(card); /* resume control bus DAIs */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; if (rtd->dai_link->ignore_suspend) @@ -610,7 +610,7 @@ static void soc_resume_deferred(struct work_struct *work) } } - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->dai_link->ignore_suspend) continue; @@ -625,7 +625,7 @@ static void soc_resume_deferred(struct work_struct *work) } /* unmute any active DACs */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *dai; if (rtd->dai_link->ignore_suspend) @@ -639,7 +639,7 @@ static void soc_resume_deferred(struct work_struct *work) } } - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; if (rtd->dai_link->ignore_suspend) @@ -674,7 +674,7 @@ int snd_soc_resume(struct device *dev) return 0; /* activate pins from sleep state */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int j; @@ -694,7 +694,7 @@ int snd_soc_resume(struct device *dev) * have that problem and may take a substantial amount of time to resume * due to I/O costs and anti-pop so handle them out of line. */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; bus_control |= cpu_dai->driver->bus_control; } @@ -839,7 +839,7 @@ static bool soc_is_dai_link_bound(struct snd_soc_card *card, { struct snd_soc_pcm_runtime *rtd; - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (rtd->dai_link == dai_link) return true; } @@ -994,13 +994,13 @@ static void soc_remove_dai_links(struct snd_soc_card *card) for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - list_for_each_entry(rtd, &card->rtd_list, list) + for_each_card_rtds(card, rtd) soc_remove_link_dais(card, rtd, order); } for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - list_for_each_entry(rtd, &card->rtd_list, list) + for_each_card_rtds(card, rtd) soc_remove_link_components(card, rtd, order); } @@ -2014,7 +2014,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* probe all components used by DAI links on this card */ for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { ret = soc_probe_link_components(card, rtd, order); if (ret < 0) { dev_err(card->dev, @@ -2048,7 +2048,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* probe all DAI links on this card */ for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { ret = soc_probe_link_dais(card, rtd, order); if (ret < 0) { dev_err(card->dev, @@ -2169,7 +2169,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) struct snd_soc_pcm_runtime *rtd; /* make sure any delayed work runs */ - list_for_each_entry(rtd, &card->rtd_list, list) + for_each_card_rtds(card, rtd) flush_delayed_work(&rtd->delayed_work); /* free the ALSA card at first; this syncs with pending operations */ @@ -2211,13 +2211,13 @@ int snd_soc_poweroff(struct device *dev) /* Flush out pmdown_time work - we actually do want to run it * now, we're shutting down so no imminent restart. */ - list_for_each_entry(rtd, &card->rtd_list, list) + for_each_card_rtds(card, rtd) flush_delayed_work(&rtd->delayed_work); snd_soc_dapm_shutdown(card); /* deactivate pins to sleep state */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; int i; @@ -2686,7 +2686,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card) return ret; /* deactivate pins to sleep state */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; int j; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index ee6b9758ec15f8..8c5b065c888062 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -4183,7 +4183,7 @@ void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) struct snd_soc_pcm_runtime *rtd; /* for each BE DAI link... */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { /* * dynamic FE links have no fixed DAI mapping. * CODEC<->CODEC links have no direct connection. diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 1eff1dbb0d002a..09d0f668c78e6d 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1307,7 +1307,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, dev_dbg(card->dev, "ASoC: find BE for widget %s\n", widget->name); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - list_for_each_entry(be, &card->rtd_list, list) { + for_each_card_rtds(card, be) { if (!be->dai_link->no_pcm) continue; @@ -1326,7 +1326,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, } } else { - list_for_each_entry(be, &card->rtd_list, list) { + for_each_card_rtds(card, be) { if (!be->dai_link->no_pcm) continue; @@ -1382,7 +1382,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, int i; if (dir == SND_SOC_DAPM_DIR_OUT) { - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (!rtd->dai_link->no_pcm) continue; @@ -1395,7 +1395,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, } } } else { /* SND_SOC_DAPM_DIR_IN */ - list_for_each_entry(rtd, &card->rtd_list, list) { + for_each_card_rtds(card, rtd) { if (!rtd->dai_link->no_pcm) continue; @@ -2761,14 +2761,14 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card) mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); /* shutdown all old paths first */ - list_for_each_entry(fe, &card->rtd_list, list) { + for_each_card_rtds(card, fe) { ret = soc_dpcm_fe_runtime_update(fe, 0); if (ret) goto out; } /* bring new paths up */ - list_for_each_entry(fe, &card->rtd_list, list) { + for_each_card_rtds(card, fe) { ret = soc_dpcm_fe_runtime_update(fe, 1); if (ret) goto out; From b3a651e4e9f665fa352c2fa73e9513f58d508d0f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:29:55 +0000 Subject: [PATCH 0056/1995] ASoC: add for_each_card_components() macro To be more readable code, this patch adds new for_each_card_components() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit f70f18f7d459b7958a4d3944396e2bc4a9f7ed72) --- include/sound/soc.h | 3 +++ sound/soc/intel/boards/broadwell.c | 4 ++-- sound/soc/intel/boards/bytcr_rt5640.c | 4 ++-- sound/soc/intel/boards/bytcr_rt5651.c | 4 ++-- sound/soc/intel/boards/cht_bsw_rt5672.c | 4 ++-- sound/soc/soc-core.c | 5 +++-- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 164418dbf40e27..34efab6baff632 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1135,6 +1135,9 @@ struct snd_soc_card { #define for_each_card_rtds_safe(card, rtd, _rtd) \ list_for_each_entry_safe(rtd, _rtd, &(card)->rtd_list, list) +#define for_each_card_components(card, component) \ + list_for_each_entry(component, &(card)->component_dev_list, card_list) + /* SoC machine DAI configuration, glues a codec and cpu DAI together */ struct snd_soc_pcm_runtime { struct device *dev; diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 7b0ee67b4fc8b0..68e6543e6cb026 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -223,7 +223,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { static int broadwell_suspend(struct snd_soc_card *card){ struct snd_soc_component *component; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, "i2c-INT343A:00")) { dev_dbg(component->dev, "disabling jack detect before going to suspend.\n"); @@ -237,7 +237,7 @@ static int broadwell_suspend(struct snd_soc_card *card){ static int broadwell_resume(struct snd_soc_card *card){ struct snd_soc_component *component; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, "i2c-INT343A:00")) { dev_dbg(component->dev, "enabling jack detect for resume.\n"); diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index b6dc524830b21a..8587bd3d1cc17d 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1048,7 +1048,7 @@ static int byt_rt5640_suspend(struct snd_soc_card *card) if (!BYT_RT5640_JDSRC(byt_rt5640_quirk)) return 0; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, byt_rt5640_codec_name)) { dev_dbg(component->dev, "disabling jack detect before suspend\n"); snd_soc_component_set_jack(component, NULL, NULL); @@ -1067,7 +1067,7 @@ static int byt_rt5640_resume(struct snd_soc_card *card) if (!BYT_RT5640_JDSRC(byt_rt5640_quirk)) return 0; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, byt_rt5640_codec_name)) { dev_dbg(component->dev, "re-enabling jack detect after resume\n"); snd_soc_component_set_jack(component, &priv->jack, NULL); diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index f8a68bdb388581..8dffeecda55b88 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -742,7 +742,7 @@ static int byt_rt5651_suspend(struct snd_soc_card *card) if (!BYT_RT5651_JDSRC(byt_rt5651_quirk)) return 0; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, byt_rt5651_codec_name)) { dev_dbg(component->dev, "disabling jack detect before suspend\n"); snd_soc_component_set_jack(component, NULL, NULL); @@ -761,7 +761,7 @@ static int byt_rt5651_resume(struct snd_soc_card *card) if (!BYT_RT5651_JDSRC(byt_rt5651_quirk)) return 0; - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strcmp(component->name, byt_rt5651_codec_name)) { dev_dbg(component->dev, "re-enabling jack detect after resume\n"); snd_soc_component_set_jack(component, &priv->jack, NULL); diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index e054318185ea36..51f0d45d6f8f9d 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -347,7 +347,7 @@ static int cht_suspend_pre(struct snd_soc_card *card) struct snd_soc_component *component; struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strncmp(component->name, ctx->codec_name, sizeof(ctx->codec_name))) { @@ -364,7 +364,7 @@ static int cht_resume_post(struct snd_soc_card *card) struct snd_soc_component *component; struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (!strncmp(component->name, ctx->codec_name, sizeof(ctx->codec_name))) { diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7efcf3475d6f92..673a694ede3ec2 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -510,7 +510,7 @@ int snd_soc_suspend(struct device *dev) snd_soc_dapm_sync(&card->dapm); /* suspend all COMPONENTs */ - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); /* If there are paths active then the COMPONENT will be held with @@ -602,7 +602,7 @@ static void soc_resume_deferred(struct work_struct *work) cpu_dai->driver->resume(cpu_dai); } - list_for_each_entry(component, &card->component_dev_list, card_list) { + for_each_card_components(card, component) { if (component->suspended) { if (component->driver->resume) component->driver->resume(component); @@ -1354,6 +1354,7 @@ static int soc_probe_component(struct snd_soc_card *card, component->driver->num_dapm_routes); list_add(&dapm->list, &card->dapm_list); + /* see for_each_card_components */ list_add(&component->card_list, &card->component_dev_list); return 0; From 4d16e7d583e3e71652f0117d955ad5ce5f849e8c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:30:41 +0000 Subject: [PATCH 0057/1995] ASoC: add for_each_comp_order() macro To be more readable code, this patch adds new for_each_comp_order() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 1a1035a9854fd893d487a84edccc1d5804e1d716) --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 18 ++++++------------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 34efab6baff632..93aa894a57ef02 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -372,6 +372,11 @@ #define SND_SOC_COMP_ORDER_LATE 1 #define SND_SOC_COMP_ORDER_LAST 2 +#define for_each_comp_order(order) \ + for (order = SND_SOC_COMP_ORDER_FIRST; \ + order <= SND_SOC_COMP_ORDER_LAST; \ + order++) + /* * Bias levels * diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 673a694ede3ec2..d8625ac2b20150 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -992,14 +992,12 @@ static void soc_remove_dai_links(struct snd_soc_card *card) struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link *link, *_link; - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { for_each_card_rtds(card, rtd) soc_remove_link_dais(card, rtd, order); } - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { for_each_card_rtds(card, rtd) soc_remove_link_components(card, rtd, order); } @@ -1617,8 +1615,7 @@ static int soc_probe_aux_devices(struct snd_soc_card *card) int order; int ret; - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { list_for_each_entry(comp, &card->aux_comp_list, card_aux_list) { if (comp->driver->probe_order == order) { ret = soc_probe_component(card, comp); @@ -1640,8 +1637,7 @@ static void soc_remove_aux_devices(struct snd_soc_card *card) struct snd_soc_component *comp, *_comp; int order; - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { list_for_each_entry_safe(comp, _comp, &card->aux_comp_list, card_aux_list) { @@ -2013,8 +2009,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } /* probe all components used by DAI links on this card */ - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { for_each_card_rtds(card, rtd) { ret = soc_probe_link_components(card, rtd, order); if (ret < 0) { @@ -2047,8 +2042,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } /* probe all DAI links on this card */ - for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; - order++) { + for_each_comp_order(order) { for_each_card_rtds(card, rtd) { ret = soc_probe_link_dais(card, rtd, order); if (ret < 0) { From 7131ebc23f73854ed7dc802e7bc5bf6815f8ab51 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:30:54 +0000 Subject: [PATCH 0058/1995] ASoC: add for_each_dpcm_fe() macro To be more readable code, this patch adds new for_each_dpcm_fe() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit d2e24d64652bf9d272e5496ae8a562bc64facff3) --- include/sound/soc-dpcm.h | 3 +++ sound/soc/soc-pcm.c | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h index 9bb92f187af87a..f130de6cfe8e6c 100644 --- a/include/sound/soc-dpcm.h +++ b/include/sound/soc-dpcm.h @@ -103,6 +103,9 @@ struct snd_soc_dpcm_runtime { int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */ }; +#define for_each_dpcm_fe(be, stream, dpcm) \ + list_for_each_entry(dpcm, &(be)->dpcm[stream].fe_clients, list_fe) + /* can this BE stop and free */ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, struct snd_soc_pcm_runtime *be, int stream); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 09d0f668c78e6d..e7916630e6fadd 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1252,7 +1252,7 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe, be_substream = snd_soc_dpcm_get_substream(be, stream); - list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { + for_each_dpcm_fe(be, stream, dpcm) { if (dpcm->fe == fe) continue; @@ -3219,7 +3219,7 @@ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, struct snd_soc_dpcm *dpcm; int state; - list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { + for_each_dpcm_fe(be, stream, dpcm) { if (dpcm->fe == fe) continue; @@ -3246,7 +3246,7 @@ int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe, struct snd_soc_dpcm *dpcm; int state; - list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) { + for_each_dpcm_fe(be, stream, dpcm) { if (dpcm->fe == fe) continue; From 8664e7491e7af26bede9cd2b0639f862525df916 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Sep 2018 01:31:09 +0000 Subject: [PATCH 0059/1995] ASoC: add for_each_dpcm_be() macro To be more readable code, this patch adds new for_each_dpcm_be() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 8d6258a4dd267838e2f10643c3d91b79fe75ef6e) --- include/sound/soc-dpcm.h | 7 ++++++ sound/soc/fsl/fsl_asrc_dma.c | 2 +- sound/soc/sh/rcar/ctu.c | 2 +- sound/soc/sh/rcar/src.c | 2 +- sound/soc/soc-compress.c | 4 +-- sound/soc/soc-pcm.c | 48 +++++++++++++++++------------------- 6 files changed, 35 insertions(+), 30 deletions(-) diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h index f130de6cfe8e6c..4be3a2b7c10611 100644 --- a/include/sound/soc-dpcm.h +++ b/include/sound/soc-dpcm.h @@ -106,6 +106,13 @@ struct snd_soc_dpcm_runtime { #define for_each_dpcm_fe(be, stream, dpcm) \ list_for_each_entry(dpcm, &(be)->dpcm[stream].fe_clients, list_fe) +#define for_each_dpcm_be(fe, stream, dpcm) \ + list_for_each_entry(dpcm, &(fe)->dpcm[stream].be_clients, list_be) +#define for_each_dpcm_be_safe(fe, stream, dpcm, _dpcm) \ + list_for_each_entry_safe(dpcm, _dpcm, &(fe)->dpcm[stream].be_clients, list_be) +#define for_each_dpcm_be_rollback(fe, stream, dpcm) \ + list_for_each_entry_continue_reverse(dpcm, &(fe)->dpcm[stream].be_clients, list_be) + /* can this BE stop and free */ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, struct snd_soc_pcm_runtime *be, int stream); diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index 1033ac6631b08a..01052a0808b0bd 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -151,7 +151,7 @@ static int fsl_asrc_dma_hw_params(struct snd_pcm_substream *substream, int ret; /* Fetch the Back-End dma_data from DPCM */ - list_for_each_entry(dpcm, &rtd->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(rtd, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *substream_be; struct snd_soc_dai *dai = be->cpu_dai; diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 6a55aa75300313..ad702377a6c33c 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -258,7 +258,7 @@ static int rsnd_ctu_hw_params(struct rsnd_mod *mod, struct snd_pcm_hw_params *be_params; int stream = substream->stream; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { be_params = &dpcm->hw_params; if (params_channels(fe_params) != params_channels(be_params)) ctu->channels = params_channels(be_params); diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index beccfbac7581ce..cd38a43b976fae 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -158,7 +158,7 @@ static int rsnd_src_hw_params(struct rsnd_mod *mod, struct snd_soc_dpcm *dpcm; struct snd_pcm_hw_params *be_params; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { be_params = &dpcm->hw_params; if (params_rate(fe_params) != params_rate(be_params)) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 409d082e80d15b..699397a091670d 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -157,7 +157,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) ret = dpcm_be_dai_startup(fe, stream); if (ret < 0) { /* clean up all links */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + for_each_dpcm_be(fe, stream, dpcm) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; dpcm_be_disconnect(fe, stream); @@ -321,7 +321,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) ret = dpcm_be_dai_shutdown(fe, stream); /* mark FE's links ready to prune */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + for_each_dpcm_be(fe, stream, dpcm) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index e7916630e6fadd..03f36e534050f4 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -174,7 +174,7 @@ int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, { struct snd_soc_dpcm *dpcm; - list_for_each_entry(dpcm, &fe->dpcm[dir].be_clients, list_be) { + for_each_dpcm_be(fe, dir, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; @@ -1211,7 +1211,7 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, struct snd_soc_dpcm *dpcm; /* only add new dpcms */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { if (dpcm->be == be && dpcm->fe == fe) return 0; } @@ -1272,7 +1272,7 @@ void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm, *d; - list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be_safe(fe, stream, dpcm, d) { dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n", stream ? "capture" : "playback", dpcm->be->dai_link->name); @@ -1438,7 +1438,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, int prune = 0; /* Destroy any old FE <--> BE connections */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { unsigned int i; /* is there a valid CPU DAI widget for this BE */ @@ -1544,7 +1544,7 @@ void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + for_each_dpcm_be(fe, stream, dpcm) dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; } @@ -1555,7 +1555,7 @@ static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, struct snd_soc_dpcm *dpcm; /* disable any enabled and non active backends */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -1584,7 +1584,7 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) int err, count = 0; /* only startup BE DAIs that are either sinks or sources to this FE DAI */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -1638,7 +1638,7 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) unwind: /* disable any enabled and non active backends */ - list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be_rollback(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = snd_soc_dpcm_get_substream(be, stream); @@ -1695,7 +1695,7 @@ static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream, * if FE want to use it (= dpcm_merged_format) */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_soc_dai_driver *codec_dai_drv; struct snd_soc_pcm_stream *codec_stream; @@ -1736,7 +1736,7 @@ static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream, * if FE want to use it (= dpcm_merged_chan) */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver; struct snd_soc_dai_driver *codec_dai_drv; @@ -1788,7 +1788,7 @@ static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream, * if FE want to use it (= dpcm_merged_chan) */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver; struct snd_soc_dai_driver *codec_dai_drv; @@ -1891,7 +1891,7 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, } /* apply symmetry for BE */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = snd_soc_dpcm_get_substream(be, stream); @@ -1976,7 +1976,7 @@ int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream) struct snd_soc_dpcm *dpcm; /* only shutdown BEs that are either sinks or sources to this FE DAI */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -2040,7 +2040,7 @@ int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) /* only hw_params backends that are either sinks or sources * to this frontend DAI */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -2109,7 +2109,7 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) struct snd_soc_dpcm *dpcm; int ret; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -2160,7 +2160,7 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) unwind: /* disable any enabled and non active backends */ - list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be_rollback(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = snd_soc_dpcm_get_substream(be, stream); @@ -2240,7 +2240,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, struct snd_soc_dpcm *dpcm; int ret = 0; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -2426,7 +2426,7 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) struct snd_soc_dpcm *dpcm; int ret = 0; - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = @@ -2636,7 +2636,7 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) dpcm_be_dai_shutdown(fe, stream); disconnect: /* disconnect any non started BEs */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; @@ -2781,11 +2781,9 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card) int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) { struct snd_soc_dpcm *dpcm; - struct list_head *clients = - &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients; struct snd_soc_dai *dai; - list_for_each_entry(dpcm, clients, list_be) { + for_each_dpcm_be(fe, SNDRV_PCM_STREAM_PLAYBACK, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; int i; @@ -2834,7 +2832,7 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) ret = dpcm_fe_dai_startup(fe_substream); if (ret < 0) { /* clean up all links */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + for_each_dpcm_be(fe, stream, dpcm) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; dpcm_be_disconnect(fe, stream); @@ -2857,7 +2855,7 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) ret = dpcm_fe_dai_shutdown(fe_substream); /* mark FE's links ready to prune */ - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) + for_each_dpcm_be(fe, stream, dpcm) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; dpcm_be_disconnect(fe, stream); @@ -3326,7 +3324,7 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, goto out; } - list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; params = &dpcm->hw_params; From e33c6d1b7948d9e0934bb48698ca5b805b4b2374 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Wed, 19 Sep 2018 09:56:47 +0800 Subject: [PATCH 0060/1995] ASoC: rt5663: Remove the boost volume in the beginning of playback The patch removes the boost volume in the beginning of playback while the DAC volume set to lower. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown (cherry picked from commit fc795bf7224efda8c35e505966c2757856064247) --- sound/soc/codecs/rt5663.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 9bd24ad4224071..2444fad7c2dfec 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -72,6 +72,7 @@ struct rt5663_priv { static const struct reg_sequence rt5663_patch_list[] = { { 0x002a, 0x8020 }, { 0x0086, 0x0028 }, + { 0x0100, 0xa020 }, { 0x0117, 0x0f28 }, { 0x02fb, 0x8089 }, }; @@ -580,7 +581,7 @@ static const struct reg_default rt5663_reg[] = { { 0x00fd, 0x0001 }, { 0x00fe, 0x10ec }, { 0x00ff, 0x6406 }, - { 0x0100, 0xa0a0 }, + { 0x0100, 0xa020 }, { 0x0108, 0x4444 }, { 0x0109, 0x4444 }, { 0x010a, 0xaaaa }, @@ -2337,6 +2338,8 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, 0x8000); snd_soc_component_update_bits(component, RT5663_DEPOP_1, 0x3000, 0x3000); + snd_soc_component_update_bits(component, + RT5663_DIG_VOL_ZCD, 0x00c0, 0x0080); } break; @@ -2351,6 +2354,8 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_EN); snd_soc_component_update_bits(component, RT5663_DACREF_LDO, 0x3e0e, 0); + snd_soc_component_update_bits(component, + RT5663_DIG_VOL_ZCD, 0x00c0, 0); } break; From 375ce662b9ac1b7b1ba49286a364fb715b9d270e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 21 Sep 2018 05:23:01 +0000 Subject: [PATCH 0061/1995] ASoC: add for_each_component() macro To be more readable code, this patch adds new for_each_component() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 368dee9459472b44f760a35cd07a6f3b90b3e549) --- sound/soc/soc-core.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d8625ac2b20150..b9b33c8cac2ed8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -54,6 +54,9 @@ static DEFINE_MUTEX(client_mutex); static LIST_HEAD(component_list); static LIST_HEAD(unbind_card_list); +#define for_each_component(component) \ + list_for_each_entry(component, &component_list, list) + /* * This is a timeout to do a DAPM powerdown after a stream is closed(). * It can be used to eliminate pops between different playback streams, e.g. @@ -176,7 +179,7 @@ static int dai_list_show(struct seq_file *m, void *v) mutex_lock(&client_mutex); - list_for_each_entry(component, &component_list, list) + for_each_component(component) list_for_each_entry(dai, &component->dai_list, list) seq_printf(m, "%s\n", dai->name); @@ -192,7 +195,7 @@ static int component_list_show(struct seq_file *m, void *v) mutex_lock(&client_mutex); - list_for_each_entry(component, &component_list, list) + for_each_component(component) seq_printf(m, "%s\n", component->name); mutex_unlock(&client_mutex); @@ -725,7 +728,7 @@ static struct snd_soc_component *soc_find_component( lockdep_assert_held(&client_mutex); - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { if (of_node) { if (component->dev->of_node == of_node) return component; @@ -775,7 +778,7 @@ struct snd_soc_dai *snd_soc_find_dai( lockdep_assert_held(&client_mutex); /* Find CPU DAI from registered DAIs*/ - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { if (!snd_soc_is_matching_component(dlc, component)) continue; list_for_each_entry(dai, &component->dai_list, list) { @@ -902,7 +905,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->codec_dai = codec_dais[0]; /* find one from the set of registered platforms */ - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { if (!snd_soc_is_matching_component(dai_link->platform, component)) continue; @@ -1874,7 +1877,7 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) struct snd_soc_dai_link *dai_link; int i; - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { /* does this component override FEs ? */ if (!component->driver->ignore_machine) @@ -3091,6 +3094,7 @@ static void snd_soc_component_add(struct snd_soc_component *component) snd_soc_component_setup_regmap(component); } + /* see for_each_component */ list_add(&component->list, &component_list); INIT_LIST_HEAD(&component->dobj_list); @@ -3226,7 +3230,7 @@ static int __snd_soc_unregister_component(struct device *dev) int found = 0; mutex_lock(&client_mutex); - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { if (dev != component->dev) continue; @@ -3258,7 +3262,7 @@ struct snd_soc_component *snd_soc_lookup_component(struct device *dev, ret = NULL; mutex_lock(&client_mutex); - list_for_each_entry(component, &component_list, list) { + for_each_component(component) { if (dev != component->dev) continue; @@ -3658,7 +3662,7 @@ int snd_soc_get_dai_id(struct device_node *ep) */ ret = -ENOTSUPP; mutex_lock(&client_mutex); - list_for_each_entry(pos, &component_list, list) { + for_each_component(pos) { struct device_node *component_of_node = pos->dev->of_node; if (!component_of_node && pos->dev->parent) @@ -3688,7 +3692,7 @@ int snd_soc_get_dai_name(struct of_phandle_args *args, int ret = -EPROBE_DEFER; mutex_lock(&client_mutex); - list_for_each_entry(pos, &component_list, list) { + for_each_component(pos) { component_of_node = pos->dev->of_node; if (!component_of_node && pos->dev->parent) component_of_node = pos->dev->parent->of_node; From 908a51f1103f08ad5e95011804ab75c4f24d5838 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 21 Sep 2018 05:23:17 +0000 Subject: [PATCH 0062/1995] ASoC: add for_each_component_dais() macro To be more readable code, this patch adds new for_each_component_dais() macro, and replace existing code to it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 15a0c64572463eddf59e80aa643d3a87809a7d9b) --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 11 ++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 93aa894a57ef02..f1dab1f4b194d4 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -864,6 +864,11 @@ struct snd_soc_component { #endif }; +#define for_each_component_dais(component, dai)\ + list_for_each_entry(dai, &(component)->dai_list, list) +#define for_each_component_dais_safe(component, dai, _dai)\ + list_for_each_entry_safe(dai, _dai, &(component)->dai_list, list) + struct snd_soc_rtdcom_list { struct snd_soc_component *component; struct list_head list; /* rtd::component_list */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b9b33c8cac2ed8..62e8e36062df05 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -180,7 +180,7 @@ static int dai_list_show(struct seq_file *m, void *v) mutex_lock(&client_mutex); for_each_component(component) - list_for_each_entry(dai, &component->dai_list, list) + for_each_component_dais(component, dai) seq_printf(m, "%s\n", dai->name); mutex_unlock(&client_mutex); @@ -781,7 +781,7 @@ struct snd_soc_dai *snd_soc_find_dai( for_each_component(component) { if (!snd_soc_is_matching_component(dlc, component)) continue; - list_for_each_entry(dai, &component->dai_list, list) { + for_each_component_dais(component, dai) { if (dlc->dai_name && strcmp(dai->name, dlc->dai_name) && (!dai->driver->name || strcmp(dai->driver->name, dlc->dai_name))) @@ -1312,7 +1312,7 @@ static int soc_probe_component(struct snd_soc_card *card, } } - list_for_each_entry(dai, &component->dai_list, list) { + for_each_component_dais(component, dai) { ret = snd_soc_dapm_new_dai_widgets(dapm, dai); if (ret != 0) { dev_err(component->dev, @@ -2842,7 +2842,7 @@ static void snd_soc_unregister_dais(struct snd_soc_component *component) { struct snd_soc_dai *dai, *_dai; - list_for_each_entry_safe(dai, _dai, &component->dai_list, list) { + for_each_component_dais_safe(component, dai, _dai) { dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n", dai->name); list_del(&dai->list); @@ -2894,6 +2894,7 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, if (!dai->driver->ops) dai->driver->ops = &null_dai_ops; + /* see for_each_component_dais */ list_add_tail(&dai->list, &component->dai_list); component->num_dai++; @@ -3728,7 +3729,7 @@ int snd_soc_get_dai_name(struct of_phandle_args *args, ret = 0; /* find target DAI */ - list_for_each_entry(dai, &pos->dai_list, list) { + for_each_component_dais(pos, dai) { if (id == 0) break; id--; From 2fdf01a90ee685df25339f1f12c14ece8619a23c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Tue, 25 Sep 2018 16:23:49 +0200 Subject: [PATCH 0063/1995] ASoC: max98088: add OF support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MAX98088 is an older version of the MAX98089 device. Signed-off-by: Andreas Färber [m.felsch@pengutronix.de: add CONFIG_OF compile switch] [m.felsch@pengutronix.de: adapt commit message] Signed-off-by: Marco Felsch Signed-off-by: Mark Brown (cherry picked from commit 85aa0fe73edd856365d074a5aa38c614c8b2ca45) --- sound/soc/codecs/max98088.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index fb515aaa54fcd7..9450d5d9c49235 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -1742,9 +1742,19 @@ static const struct i2c_device_id max98088_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, max98088_i2c_id); +#if defined(CONFIG_OF) +static const struct of_device_id max98088_of_match[] = { + { .compatible = "maxim,max98088" }, + { .compatible = "maxim,max98089" }, + { } +}; +MODULE_DEVICE_TABLE(of, max98088_of_match); +#endif + static struct i2c_driver max98088_i2c_driver = { .driver = { .name = "max98088", + .of_match_table = of_match_ptr(max98088_of_match), }, .probe = max98088_i2c_probe, .id_table = max98088_i2c_id, From c6967255cf5b7388c415986891336287cd50d619 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 25 Sep 2018 11:09:14 -0700 Subject: [PATCH 0064/1995] ASoC: soc-utils: Rename dummy_dma_ops to snd_dummy_dma_ops The symbols 'dummy_dma_ops' is declared with different data types by sound/soc/soc-utils.c and arch/arm64/include/asm/dma-mapping.h. This leads to conflicts when soc-utils.c (indirectly) includes dma-mapping.h: sound/soc/soc-utils.c:282:33: error: conflicting types for 'dummy_dma_ops' static const struct snd_pcm_ops dummy_dma_ops = { ^ ... arch/arm64/include/asm/dma-mapping.h:27:33: note: previous declaration of 'dummy_dma_ops' was here extern const struct dma_map_ops dummy_dma_ops; ^ Rename the symbol in soc-utils.c to 'snd_dummy_dma_ops' to avoid the conflict. Signed-off-by: Matthias Kaehlcke Signed-off-by: Mark Brown (cherry picked from commit 42cfb412e24ffbb46d6de9590293bc44f921a0fb) --- sound/soc/soc-utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index e0c93496c0cda6..e3b9dd634c6db3 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -273,13 +273,13 @@ static int dummy_dma_open(struct snd_pcm_substream *substream) return 0; } -static const struct snd_pcm_ops dummy_dma_ops = { +static const struct snd_pcm_ops snd_dummy_dma_ops = { .open = dummy_dma_open, .ioctl = snd_pcm_lib_ioctl, }; static const struct snd_soc_component_driver dummy_platform = { - .ops = &dummy_dma_ops, + .ops = &snd_dummy_dma_ops, }; static const struct snd_soc_component_driver dummy_codec = { From 01318e75feee40b27cff004cdd5357ffe088aa90 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 3 Oct 2018 19:31:44 +0200 Subject: [PATCH 0065/1995] ASoC: intel: skylake: Add missing break in skl_tplg_get_token() skl_tplg_get_token() misses a break in the big switch() block for SKL_TKN_U8_CORE_ID entry. Spotted nicely by -Wimplicit-fallthrough compiler option. Fixes: 6277e83292a2 ("ASoC: Intel: Skylake: Parse vendor tokens to build module data") Cc: Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 9c80c5a8831471e0a3e139aad1b0d4c0fdc50b2f) --- sound/soc/intel/skylake/skl-topology.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 52a9915da0f5cc..cf8848b779dcc2 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -2460,6 +2460,7 @@ static int skl_tplg_get_token(struct device *dev, case SKL_TKN_U8_CORE_ID: mconfig->core_id = tkn_elem->value; + break; case SKL_TKN_U8_MOD_TYPE: mconfig->m_type = tkn_elem->value; From 9ddf42cdd3c73fac3e1b44d33ca95721db0ba944 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 20:30:04 +0200 Subject: [PATCH 0066/1995] ASoC: rt274: Add fall-through annotations As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, add the "fall through" annotations in rt274 driver. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 0beeb4baf56bd9deb920712a4034541fb33bbbe0) --- sound/soc/codecs/rt274.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index d88e6734108352..0ef966d56bac30 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -755,6 +755,7 @@ static int rt274_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, break; default: dev_warn(component->dev, "invalid pll source, use BCLK\n"); + /* fall through */ case RT274_PLL2_S_BCLK: snd_soc_component_update_bits(component, RT274_PLL2_CTRL, RT274_PLL2_SRC_MASK, RT274_PLL2_SRC_BCLK); @@ -782,6 +783,7 @@ static int rt274_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, break; default: dev_warn(component->dev, "invalid freq_in, assume 4.8M\n"); + /* fall through */ case 100: snd_soc_component_write(component, 0x7a, 0xaab6); snd_soc_component_write(component, 0x7b, 0x0301); From 2072f260de32d7a8b86960d3f00fb2dd1725efc4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 20:30:05 +0200 Subject: [PATCH 0067/1995] ASoC: intel: skylake: Add fall-through annotation As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, add the "fall through" annotation in Intel SST skylake driver. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit e4bfd61571f5db5c69a7a49de401543cc7d6c87c) --- sound/soc/intel/skylake/skl-pcm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 00b7a91b18c9a5..557f80c0bfe530 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -495,6 +495,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, stream->lpib); snd_hdac_ext_stream_set_lpib(stream, stream->lpib); } + /* fall through */ case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: From 0f9ea3fba1828ae2284126f5a127992d2c6f3cfe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 20:30:06 +0200 Subject: [PATCH 0068/1995] ASoC: topology: Use the standard fall-through annotations As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, replace with the standard "fall through" annotation. gcc can't understand the mixed texts, unfortunately. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 9c6c4d961e634413add345ee030e108e6d19cea2) --- sound/soc/soc-topology.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 17f81b9a575448..045ef136903d63 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -993,7 +993,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, kfree(se); continue; } - /* fall through and create texts */ + /* fall through */ case SND_SOC_TPLG_CTL_ENUM: case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: @@ -1310,7 +1310,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( ec->hdr.name); goto err_se; } - /* fall through to create texts */ + /* fall through */ case SND_SOC_TPLG_CTL_ENUM: case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: From 14d1ad367b8a25aa34707c363361715672722e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Fri, 5 Oct 2018 09:58:11 +0200 Subject: [PATCH 0069/1995] ASoC: max98088: Add master clock handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If master clock is provided through device tree, then update the master clock frequency during set_sysclk. Cc: Tushar Behera Signed-off-by: Andreas Färber Acked-by: Tushar Behera Reviewed-by: Javier Martinez Canillas [m.felsch@pengutronix.de: move mclk request to i2c_probe] [m.felsch@pengutronix.de: make use of snd_soc_component_get_bias_level()] Signed-off-by: Marco Felsch Signed-off-by: Mark Brown (cherry picked from commit 62a7fc32a6289dce88787da03f893deab08158c3) --- sound/soc/codecs/max98088.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 9450d5d9c49235..ca172a4b68491c 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ struct max98088_priv { struct regmap *regmap; enum max98088_type devtype; struct max98088_pdata *pdata; + struct clk *mclk; unsigned int sysclk; struct max98088_cdata dai[2]; int eq_textcnt; @@ -1103,6 +1105,11 @@ static int max98088_dai_set_sysclk(struct snd_soc_dai *dai, if (freq == max98088->sysclk) return 0; + if (!IS_ERR(max98088->mclk)) { + freq = clk_round_rate(max98088->mclk, freq); + clk_set_rate(max98088->mclk, freq); + } + /* Setup clocks for slave mode, and using the PLL * PSCLK = 0x01 (when master clk is 10MHz to 20MHz) * 0x02 (when master clk is 20MHz to 30MHz).. @@ -1310,6 +1317,20 @@ static int max98088_set_bias_level(struct snd_soc_component *component, break; case SND_SOC_BIAS_PREPARE: + /* + * SND_SOC_BIAS_PREPARE is called while preparing for a + * transition to ON or away from ON. If current bias_level + * is SND_SOC_BIAS_ON, then it is preparing for a transition + * away from ON. Disable the clock in that case, otherwise + * enable it. + */ + if (!IS_ERR(max98088->mclk)) { + if (snd_soc_component_get_bias_level(component) == + SND_SOC_BIAS_ON) + clk_disable_unprepare(max98088->mclk); + else + clk_prepare_enable(max98088->mclk); + } break; case SND_SOC_BIAS_STANDBY: @@ -1725,6 +1746,11 @@ static int max98088_i2c_probe(struct i2c_client *i2c, if (IS_ERR(max98088->regmap)) return PTR_ERR(max98088->regmap); + max98088->mclk = devm_clk_get(&i2c->dev, "mclk"); + if (IS_ERR(max98088->mclk)) + if (PTR_ERR(max98088->mclk) == -EPROBE_DEFER) + return PTR_ERR(max98088->mclk); + max98088->devtype = id->driver_data; i2c_set_clientdata(i2c, max98088); From c5c720a082aef865b384f73aaec8b59375f4502f Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 10 Oct 2018 23:26:06 +0000 Subject: [PATCH 0070/1995] ASoC: max98373: Sort Digital Volume in reverse order Signed-off-by: Ryan Lee Signed-off-by: Mark Brown (cherry picked from commit 4cbbc91609846c09a8350080cd7e6f7764fb2ec1) --- sound/soc/codecs/max98373.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index d6868c9a9ce632..9b7ccd351caeb0 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -455,7 +455,7 @@ SND_SOC_DAPM_SIGGEN("IMON"), SND_SOC_DAPM_SIGGEN("FBMON"), }; -static DECLARE_TLV_DB_SCALE(max98373_digital_tlv, 0, -50, 0); +static DECLARE_TLV_DB_SCALE(max98373_digital_tlv, -6350, 50, 1); static const DECLARE_TLV_DB_RANGE(max98373_spk_tlv, 0, 8, TLV_DB_SCALE_ITEM(0, 50, 0), 9, 10, TLV_DB_SCALE_ITEM(500, 100, 0), @@ -605,7 +605,7 @@ SOC_SINGLE("Dither Switch", MAX98373_R203F_AMP_DSP_CFG, SOC_SINGLE("DC Blocker Switch", MAX98373_R203F_AMP_DSP_CFG, MAX98373_AMP_DSP_CFG_DCBLK_SHIFT, 1, 0), SOC_SINGLE_TLV("Digital Volume", MAX98373_R203D_AMP_DIG_VOL_CTRL, - 0, 0x7F, 0, max98373_digital_tlv), + 0, 0x7F, 1, max98373_digital_tlv), SOC_SINGLE_TLV("Speaker Volume", MAX98373_R203E_AMP_PATH_GAIN, MAX98373_SPK_DIGI_GAIN_SHIFT, 10, 0, max98373_spk_tlv), SOC_SINGLE_TLV("FS Max Volume", MAX98373_R203E_AMP_PATH_GAIN, From 1408fe9caaeffc27fa9967acd8ba9c72c0d66089 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 10 Oct 2018 23:26:10 +0000 Subject: [PATCH 0071/1995] ASoC: max98373: Sort BDE Limiter Thresh Volume in reverse order Signed-off-by: Ryan Lee Signed-off-by: Mark Brown (cherry picked from commit 6c3beeca424a0c8d6c79184a880a8954bd498d57) --- sound/soc/codecs/max98373.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 9b7ccd351caeb0..38871677cbae10 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -479,7 +479,7 @@ static const DECLARE_TLV_DB_RANGE(max98373_dht_rotation_point_tlv, 14, 15, TLV_DB_SCALE_ITEM(-2500, -500, 0), ); static const DECLARE_TLV_DB_RANGE(max98373_limiter_thresh_tlv, - 0, 15, TLV_DB_SCALE_ITEM(0, -100, 0), + 0, 15, TLV_DB_SCALE_ITEM(-1500, 100, 0), ); static const DECLARE_TLV_DB_RANGE(max98373_bde_gain_tlv, @@ -670,13 +670,13 @@ SOC_SINGLE_TLV("BDE LVL3 Clip Reduction Volume", MAX98373_R20B0_BDE_L3_CFG_3, SOC_SINGLE_TLV("BDE LVL4 Clip Reduction Volume", MAX98373_R20B3_BDE_L4_CFG_3, 0, 0x3C, 0, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL1 Limiter Thresh Volume", MAX98373_R20A8_BDE_L1_CFG_1, - 0, 0xF, 0, max98373_limiter_thresh_tlv), + 0, 0xF, 1, max98373_limiter_thresh_tlv), SOC_SINGLE_TLV("BDE LVL2 Limiter Thresh Volume", MAX98373_R20AB_BDE_L2_CFG_1, - 0, 0xF, 0, max98373_limiter_thresh_tlv), + 0, 0xF, 1, max98373_limiter_thresh_tlv), SOC_SINGLE_TLV("BDE LVL3 Limiter Thresh Volume", MAX98373_R20AE_BDE_L3_CFG_1, - 0, 0xF, 0, max98373_limiter_thresh_tlv), + 0, 0xF, 1, max98373_limiter_thresh_tlv), SOC_SINGLE_TLV("BDE LVL4 Limiter Thresh Volume", MAX98373_R20B1_BDE_L4_CFG_1, - 0, 0xF, 0, max98373_limiter_thresh_tlv), + 0, 0xF, 1, max98373_limiter_thresh_tlv), /* Limiter */ SOC_SINGLE("Limiter Switch", MAX98373_R20E2_LIMITER_EN, MAX98373_LIMITER_EN_SHIFT, 1, 0), From 709f78192435cb3036c36c8bd2fca4ad5cacad7e Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 10 Oct 2018 23:26:13 +0000 Subject: [PATCH 0072/1995] ASoC: max98373: Sort max98373_bde_gain_tlv in reverse order Signed-off-by: Ryan Lee Signed-off-by: Mark Brown (cherry picked from commit d34c8f37c75b739efc26383145a43497143ada88) --- sound/soc/codecs/max98373.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 38871677cbae10..37f8bcdd8e350a 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -483,7 +483,7 @@ static const DECLARE_TLV_DB_RANGE(max98373_limiter_thresh_tlv, ); static const DECLARE_TLV_DB_RANGE(max98373_bde_gain_tlv, - 0, 60, TLV_DB_SCALE_ITEM(0, -25, 0), + 0, 60, TLV_DB_SCALE_ITEM(-1500, 25, 0), ); static bool max98373_readable_register(struct device *dev, unsigned int reg) @@ -654,21 +654,21 @@ SOC_SINGLE("BDE Hold Time", MAX98373_R2090_BDE_LVL_HOLD, 0, 0xFF, 0), SOC_SINGLE("BDE Attack Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 4, 0xF, 0), SOC_SINGLE("BDE Release Rate", MAX98373_R2091_BDE_GAIN_ATK_REL_RATE, 0, 0xF, 0), SOC_SINGLE_TLV("BDE LVL1 Clip Thresh Volume", MAX98373_R20A9_BDE_L1_CFG_2, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL2 Clip Thresh Volume", MAX98373_R20AC_BDE_L2_CFG_2, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL3 Clip Thresh Volume", MAX98373_R20AF_BDE_L3_CFG_2, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL4 Clip Thresh Volume", MAX98373_R20B2_BDE_L4_CFG_2, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL1 Clip Reduction Volume", MAX98373_R20AA_BDE_L1_CFG_3, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL2 Clip Reduction Volume", MAX98373_R20AD_BDE_L2_CFG_3, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL3 Clip Reduction Volume", MAX98373_R20B0_BDE_L3_CFG_3, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL4 Clip Reduction Volume", MAX98373_R20B3_BDE_L4_CFG_3, - 0, 0x3C, 0, max98373_bde_gain_tlv), + 0, 0x3C, 1, max98373_bde_gain_tlv), SOC_SINGLE_TLV("BDE LVL1 Limiter Thresh Volume", MAX98373_R20A8_BDE_L1_CFG_1, 0, 0xF, 1, max98373_limiter_thresh_tlv), SOC_SINGLE_TLV("BDE LVL2 Limiter Thresh Volume", MAX98373_R20AB_BDE_L2_CFG_1, From 43501cd9939bf413d52b801055519e0dade4a797 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Wed, 10 Oct 2018 23:26:17 +0000 Subject: [PATCH 0073/1995] ASoC: max98373: Sort DHT Rot Pnt Volume in reverse order Signed-off-by: Ryan Lee Signed-off-by: Mark Brown (cherry picked from commit a23f5dc8448694a0ffe2127a04aa5787b9cf9e5f) --- sound/soc/codecs/max98373.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 37f8bcdd8e350a..a09d01318f793d 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -471,12 +471,12 @@ static const DECLARE_TLV_DB_RANGE(max98373_dht_spkgain_min_tlv, 0, 9, TLV_DB_SCALE_ITEM(800, 100, 0), ); static const DECLARE_TLV_DB_RANGE(max98373_dht_rotation_point_tlv, - 0, 1, TLV_DB_SCALE_ITEM(-50, -50, 0), - 2, 7, TLV_DB_SCALE_ITEM(-200, -100, 0), - 8, 9, TLV_DB_SCALE_ITEM(-1000, -200, 0), - 10, 11, TLV_DB_SCALE_ITEM(-1500, -300, 0), - 12, 13, TLV_DB_SCALE_ITEM(-2000, -200, 0), - 14, 15, TLV_DB_SCALE_ITEM(-2500, -500, 0), + 0, 1, TLV_DB_SCALE_ITEM(-3000, 500, 0), + 2, 4, TLV_DB_SCALE_ITEM(-2200, 200, 0), + 5, 6, TLV_DB_SCALE_ITEM(-1500, 300, 0), + 7, 9, TLV_DB_SCALE_ITEM(-1000, 200, 0), + 10, 13, TLV_DB_SCALE_ITEM(-500, 100, 0), + 14, 15, TLV_DB_SCALE_ITEM(-100, 50, 0), ); static const DECLARE_TLV_DB_RANGE(max98373_limiter_thresh_tlv, 0, 15, TLV_DB_SCALE_ITEM(-1500, 100, 0), @@ -617,7 +617,7 @@ SOC_SINGLE("DHT Switch", MAX98373_R20D4_DHT_EN, SOC_SINGLE_TLV("DHT Min Volume", MAX98373_R20D1_DHT_CFG, MAX98373_DHT_SPK_GAIN_MIN_SHIFT, 9, 0, max98373_dht_spkgain_min_tlv), SOC_SINGLE_TLV("DHT Rot Pnt Volume", MAX98373_R20D1_DHT_CFG, - MAX98373_DHT_ROT_PNT_SHIFT, 15, 0, max98373_dht_rotation_point_tlv), + MAX98373_DHT_ROT_PNT_SHIFT, 15, 1, max98373_dht_rotation_point_tlv), SOC_SINGLE_TLV("DHT Attack Step Volume", MAX98373_R20D2_DHT_ATTACK_CFG, MAX98373_DHT_ATTACK_STEP_SHIFT, 4, 0, max98373_dht_step_size_tlv), SOC_SINGLE_TLV("DHT Release Step Volume", MAX98373_R20D3_DHT_RELEASE_CFG, From aadc9c0aeac54b593abf4ff14ba0eecaabb710d0 Mon Sep 17 00:00:00 2001 From: Mac Chiang Date: Tue, 9 Oct 2018 15:35:47 +0800 Subject: [PATCH 0074/1995] ASoC: Intel: Boards: Add KBL Dialog Maxim I2S machine driver This patch adds Kabylake I2S machine driver with: DA7219 audio codec(SSP1) and MAXIM98927(SSP0) speaker amplifier. Signed-off-by: Mac Chiang Signed-off-by: Mark Brown (cherry picked from commit bca0ac1d96739c07ee1a158e4b1202260ad7480e) --- sound/soc/intel/boards/Kconfig | 13 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/kbl_da7219_max98927.c | 983 +++++++++++++++++++ 3 files changed, 998 insertions(+) create mode 100644 sound/soc/intel/boards/kbl_da7219_max98927.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 88e4b4284738ab..73ca1350aa3124 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -280,6 +280,19 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH create an alsa sound card for DA7219 + MAX98357A I2S audio codec. Say Y if you have such a device. +config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH + tristate "KBL with DA7219 and MAX98927 in I2S Mode" + depends on MFD_INTEL_LPSS && I2C && ACPI + select SND_SOC_DA7219 + select SND_SOC_MAX98927 + select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC Onboard Codec I2S machine driver. This will + create an alsa sound card for DA7219 + MAX98927 I2S audio codec. + Say Y if you have such a device. + If unsure select "N". + config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH tristate "SKL/KBL/BXT/APL with HDA Codecs" select SND_SOC_HDAC_HDMI diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 6e88373cbe355b..5381e27df9cc76 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -17,6 +17,7 @@ snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o +snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o snd-soc-skl_rt286-objs := skl_rt286.o @@ -42,6 +43,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max98357a.o +obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c new file mode 100644 index 00000000000000..3ab96ee7bd3c55 --- /dev/null +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -0,0 +1,983 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2018 Intel Corporation. + +/* + * Intel Kabylake I2S Machine Driver with MAX98927 & DA7219 Codecs + * + * Modified from: + * Intel Kabylake I2S Machine driver supporting MAX98927 and + * RT5663 codecs + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/da7219.h" +#include "../../codecs/hdac_hdmi.h" +#include "../skylake/skl.h" +#include "../../codecs/da7219-aad.h" + +#define KBL_DIALOG_CODEC_DAI "da7219-hifi" +#define MAX98927_CODEC_DAI "max98927-aif1" +#define MAXIM_DEV0_NAME "i2c-MX98927:00" +#define MAXIM_DEV1_NAME "i2c-MX98927:01" +#define DUAL_CHANNEL 2 +#define QUAD_CHANNEL 4 +#define NAME_SIZE 32 + +static struct snd_soc_card *kabylake_audio_card; +static struct snd_soc_jack kabylake_hdmi[3]; + +struct kbl_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct kbl_codec_private { + struct snd_soc_jack kabylake_headset; + struct list_head hdmi_pcm_list; +}; + +enum { + KBL_DPCM_AUDIO_PB = 0, + KBL_DPCM_AUDIO_CP, + KBL_DPCM_AUDIO_ECHO_REF_CP, + KBL_DPCM_AUDIO_REF_CP, + KBL_DPCM_AUDIO_DMIC_CP, + KBL_DPCM_AUDIO_HDMI1_PB, + KBL_DPCM_AUDIO_HDMI2_PB, + KBL_DPCM_AUDIO_HDMI3_PB, + KBL_DPCM_AUDIO_HS_PB, +}; + +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + int ret = 0; + + codec_dai = snd_soc_card_get_codec_dai(card, KBL_DIALOG_CODEC_DAI); + if (!codec_dai) { + dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n"); + return -EIO; + } + + /* Configure sysclk for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24576000, + SND_SOC_CLOCK_IN); + if (ret) { + dev_err(card->dev, "can't set codec sysclk configuration\n"); + return ret; + } + + 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_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 kabylake_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), +}; + +static const struct snd_soc_dapm_widget kabylake_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), + SND_SOC_DAPM_MIC("SoC DMIC", NULL), + SND_SOC_DAPM_SPK("DP", NULL), + SND_SOC_DAPM_SPK("HDMI", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route kabylake_map[] = { + /* speaker */ + { "Left Spk", NULL, "Left BE_OUT" }, + { "Right Spk", NULL, "Right BE_OUT" }, + + /* other jacks */ + { "DMic", NULL, "SoC DMIC" }, + + { "HDMI", NULL, "hif5 Output" }, + { "DP", NULL, "hif6 Output" }, + + /* CODEC BE connections */ + { "Left HiFi Playback", NULL, "ssp0 Tx" }, + { "Right HiFi Playback", NULL, "ssp0 Tx" }, + { "ssp0 Tx", NULL, "spk_out" }, + + /* IV feedback path */ + { "codec0_fb_in", NULL, "ssp0 Rx"}, + { "ssp0 Rx", NULL, "Left HiFi Capture" }, + { "ssp0 Rx", NULL, "Right HiFi Capture" }, + + /* AEC capture path */ + { "echo_ref_out", NULL, "ssp0 Rx" }, + + /* DMIC */ + { "dmic01_hifi", NULL, "DMIC01 Rx" }, + { "DMIC01 Rx", NULL, "DMIC AIF" }, + + { "hifi1", NULL, "iDisp1 Tx" }, + { "iDisp1 Tx", NULL, "iDisp1_out" }, + { "hifi2", NULL, "iDisp2 Tx" }, + { "iDisp2 Tx", NULL, "iDisp2_out" }, + { "hifi3", NULL, "iDisp3 Tx"}, + { "iDisp3 Tx", NULL, "iDisp3_out"}, +}; + +static const struct snd_soc_dapm_route kabylake_ssp1_map[] = { + { "Headphone Jack", NULL, "HPL" }, + { "Headphone Jack", NULL, "HPR" }, + + /* other jacks */ + { "MIC", NULL, "Headset Mic" }, + + /* CODEC BE connections */ + { "Playback", NULL, "ssp1 Tx" }, + { "ssp1 Tx", NULL, "codec1_out" }, + + { "hs_in", NULL, "ssp1 Rx" }, + { "ssp1 Rx", NULL, "Capture" }, + + { "Headphone Jack", NULL, "Platform Clock" }, + { "Headset Mic", NULL, "Platform Clock" }, +}; + +static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *runtime = substream->private_data; + int ret = 0, j; + + for (j = 0; j < runtime->num_codecs; j++) { + struct snd_soc_dai *codec_dai = runtime->codec_dais[j]; + + if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); + if (ret < 0) { + dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret); + return ret; + } + } + if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); + if (ret < 0) { + dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret); + return ret; + } + } + } + + return 0; +} + +static struct snd_soc_ops kabylake_ssp0_ops = { + .hw_params = kabylake_ssp0_hw_params, +}; + +static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + struct snd_soc_dpcm *dpcm = container_of( + params, struct snd_soc_dpcm, hw_params); + struct snd_soc_dai_link *fe_dai_link = dpcm->fe->dai_link; + struct snd_soc_dai_link *be_dai_link = dpcm->be->dai_link; + + /* + * The ADSP will convert the FE rate to 48k, stereo, 24 bit + */ + if (!strcmp(fe_dai_link->name, "Kbl Audio Port") || + !strcmp(fe_dai_link->name, "Kbl Audio Headset Playback") || + !strcmp(fe_dai_link->name, "Kbl Audio Capture Port")) { + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + snd_mask_none(fmt); + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + } + + /* + * The speaker on the SSP0 supports S16_LE and not S24_LE. + * thus changing the mask here + */ + if (!strcmp(be_dai_link->name, "SSP0-Codec")) + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE); + + return 0; +} + +static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_component *component = rtd->codec_dai->component; + struct snd_soc_jack *jack; + struct snd_soc_card *card = rtd->card; + int ret; + + + ret = snd_soc_dapm_add_routes(&card->dapm, + kabylake_ssp1_map, + ARRAY_SIZE(kabylake_ssp1_map)); + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new(kabylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, + &ctx->kabylake_headset, NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + jack = &ctx->kabylake_headset; + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + + da7219_aad_jack_det(component, &ctx->kabylake_headset); + + ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); + if (ret) + dev_err(rtd->dev, "SoC DMIC - Ignore suspend failed %d\n", ret); + + return ret; +} + +static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) +{ + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct kbl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = device; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); +} + +static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); +} + +static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); +} + +static int kabylake_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dapm_context *dapm; + struct snd_soc_component *component = rtd->cpu_dai->component; + + dapm = snd_soc_component_get_dapm(component); + snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); + + return 0; +} + +static const unsigned int rates[] = { + 48000, +}; + +static const struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; + +static const unsigned int channels[] = { + DUAL_CHANNEL, +}; + +static const struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, +}; + +static unsigned int channels_quad[] = { + QUAD_CHANNEL, +}; + +static struct snd_pcm_hw_constraint_list constraints_channels_quad = { + .count = ARRAY_SIZE(channels_quad), + .list = channels_quad, + .mask = 0, +}; + +static int kbl_fe_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + /* + * On this platform for PCM device we support, + * 48Khz + * stereo + * 16 bit audio + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + + return 0; +} + +static const struct snd_soc_ops kabylake_da7219_fe_ops = { + .startup = kbl_fe_startup, +}; + +static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + /* + * set BE channel constraint as user FE channels + */ + + if (params_channels(params) == 2) + channels->min = channels->max = 2; + else + channels->min = channels->max = 4; + + return 0; +} + +static int kabylake_dmic_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels_quad); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); +} + +static struct snd_soc_ops kabylake_dmic_ops = { + .startup = kabylake_dmic_startup, +}; + +static const unsigned int rates_16000[] = { + 16000, +}; + +static const struct snd_pcm_hw_constraint_list constraints_16000 = { + .count = ARRAY_SIZE(rates_16000), + .list = rates_16000, +}; + +static const unsigned int ch_mono[] = { + 1, +}; +static const struct snd_pcm_hw_constraint_list constraints_refcap = { + .count = ARRAY_SIZE(ch_mono), + .list = ch_mono, +}; + +static int kabylake_refcap_startup(struct snd_pcm_substream *substream) +{ + substream->runtime->hw.channels_max = 1; + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_refcap); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_16000); +} + + +static struct snd_soc_ops skylaye_refcap_ops = { + .startup = kabylake_refcap_startup, +}; + +static struct snd_soc_codec_conf max98927_codec_conf[] = { + + { + .dev_name = MAXIM_DEV0_NAME, + .name_prefix = "Right", + }, + + { + .dev_name = MAXIM_DEV1_NAME, + .name_prefix = "Left", + }, +}; + +static struct snd_soc_dai_link_component ssp0_codec_components[] = { + { /* Left */ + .name = MAXIM_DEV0_NAME, + .dai_name = MAX98927_CODEC_DAI, + }, + + { /* For Right */ + .name = MAXIM_DEV1_NAME, + .dai_name = MAX98927_CODEC_DAI, + }, + +}; + +/* kabylake digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link kabylake_dais[] = { + /* Front End DAI links */ + [KBL_DPCM_AUDIO_PB] = { + .name = "Kbl Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .init = kabylake_da7219_fe_init, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &kabylake_da7219_fe_ops, + }, + [KBL_DPCM_AUDIO_CP] = { + .name = "Kbl Audio Capture Port", + .stream_name = "Audio Record", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_capture = 1, + .ops = &kabylake_da7219_fe_ops, + }, + [KBL_DPCM_AUDIO_ECHO_REF_CP] = { + .name = "Kbl Audio Echo Reference cap", + .stream_name = "Echoreference Capture", + .cpu_dai_name = "Echoref Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .capture_only = 1, + .nonatomic = 1, + }, + [KBL_DPCM_AUDIO_REF_CP] = { + .name = "Kbl Audio Reference cap", + .stream_name = "Wake on Voice", + .cpu_dai_name = "Reference Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylaye_refcap_ops, + }, + [KBL_DPCM_AUDIO_DMIC_CP] = { + .name = "Kbl Audio DMIC cap", + .stream_name = "dmiccap", + .cpu_dai_name = "DMIC Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &kabylake_dmic_ops, + }, + [KBL_DPCM_AUDIO_HDMI1_PB] = { + .name = "Kbl HDMI Port1", + .stream_name = "Hdmi1", + .cpu_dai_name = "HDMI1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI2_PB] = { + .name = "Kbl HDMI Port2", + .stream_name = "Hdmi2", + .cpu_dai_name = "HDMI2 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI3_PB] = { + .name = "Kbl HDMI Port3", + .stream_name = "Hdmi3", + .cpu_dai_name = "HDMI3 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .init = NULL, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HS_PB] = { + .name = "Kbl Audio Headset Playback", + .stream_name = "Headset Audio", + .cpu_dai_name = "System Pin2", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .nonatomic = 1, + .dynamic = 1, + .init = kabylake_da7219_fe_init, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .ops = &kabylake_da7219_fe_ops, + + }, + + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .id = 0, + .cpu_dai_name = "SSP0 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codecs = ssp0_codec_components, + .num_codecs = ARRAY_SIZE(ssp0_codec_components), + .dai_fmt = SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp_fixup, + .ops = &kabylake_ssp0_ops, + }, + { + /* SSP1 - Codec */ + .name = "SSP1-Codec", + .id = 1, + .cpu_dai_name = "SSP1 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codec_name = "i2c-DLGS7219:00", + .codec_dai_name = KBL_DIALOG_CODEC_DAI, + .init = kabylake_da7219_codec_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp_fixup, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + { + .name = "dmic01", + .id = 2, + .cpu_dai_name = "DMIC01 Pin", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", + .platform_name = "0000:00:1f.3", + .be_hw_params_fixup = kabylake_dmic_fixup, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + }, + { + .name = "iDisp1", + .id = 3, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = kabylake_hdmi1_init, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .id = 4, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi2_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .id = 5, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi3_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +/* kabylake digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link kabylake_max98927_dais[] = { + /* Front End DAI links */ + [KBL_DPCM_AUDIO_PB] = { + .name = "Kbl Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .init = kabylake_da7219_fe_init, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &kabylake_da7219_fe_ops, + }, + [KBL_DPCM_AUDIO_CP] = { + .name = "Kbl Audio Capture Port", + .stream_name = "Audio Record", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_capture = 1, + .ops = &kabylake_da7219_fe_ops, + }, + [KBL_DPCM_AUDIO_ECHO_REF_CP] = { + .name = "Kbl Audio Echo Reference cap", + .stream_name = "Echoreference Capture", + .cpu_dai_name = "Echoref Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .capture_only = 1, + .nonatomic = 1, + }, + [KBL_DPCM_AUDIO_REF_CP] = { + .name = "Kbl Audio Reference cap", + .stream_name = "Wake on Voice", + .cpu_dai_name = "Reference Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylaye_refcap_ops, + }, + [KBL_DPCM_AUDIO_DMIC_CP] = { + .name = "Kbl Audio DMIC cap", + .stream_name = "dmiccap", + .cpu_dai_name = "DMIC Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &kabylake_dmic_ops, + }, + [KBL_DPCM_AUDIO_HDMI1_PB] = { + .name = "Kbl HDMI Port1", + .stream_name = "Hdmi1", + .cpu_dai_name = "HDMI1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI2_PB] = { + .name = "Kbl HDMI Port2", + .stream_name = "Hdmi2", + .cpu_dai_name = "HDMI2 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI3_PB] = { + .name = "Kbl HDMI Port3", + .stream_name = "Hdmi3", + .cpu_dai_name = "HDMI3 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .init = NULL, + .nonatomic = 1, + .dynamic = 1, + }, + + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .id = 0, + .cpu_dai_name = "SSP0 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codecs = ssp0_codec_components, + .num_codecs = ARRAY_SIZE(ssp0_codec_components), + .dai_fmt = SND_SOC_DAIFMT_DSP_B | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp_fixup, + .ops = &kabylake_ssp0_ops, + }, + { + .name = "dmic01", + .id = 1, + .cpu_dai_name = "DMIC01 Pin", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", + .platform_name = "0000:00:1f.3", + .be_hw_params_fixup = kabylake_dmic_fixup, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + }, + { + .name = "iDisp1", + .id = 2, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = kabylake_hdmi1_init, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .id = 3, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi2_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .id = 4, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi3_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +static int kabylake_card_late_probe(struct snd_soc_card *card) +{ + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); + struct kbl_hdmi_pcm *pcm; + struct snd_soc_component *component = NULL; + int err, i = 0; + char jack_name[NAME_SIZE]; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &kabylake_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &kabylake_hdmi[i]); + if (err < 0) + return err; + + i++; + } + + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); + + return 0; +} + +/* kabylake audio machine driver for SPT + DA7219 */ +static struct snd_soc_card kbl_audio_card_da7219_m98927 = { + .name = "kblda7219m98927", + .owner = THIS_MODULE, + .dai_link = kabylake_dais, + .num_links = ARRAY_SIZE(kabylake_dais), + .controls = kabylake_controls, + .num_controls = ARRAY_SIZE(kabylake_controls), + .dapm_widgets = kabylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), + .dapm_routes = kabylake_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_map), + .codec_conf = max98927_codec_conf, + .num_configs = ARRAY_SIZE(max98927_codec_conf), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + +/* kabylake audio machine driver for Maxim98927 */ +static struct snd_soc_card kbl_audio_card_max98927 = { + .name = "kblmax98927", + .owner = THIS_MODULE, + .dai_link = kabylake_max98927_dais, + .num_links = ARRAY_SIZE(kabylake_max98927_dais), + .controls = kabylake_controls, + .num_controls = ARRAY_SIZE(kabylake_controls), + .dapm_widgets = kabylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), + .dapm_routes = kabylake_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_map), + .codec_conf = max98927_codec_conf, + .num_configs = ARRAY_SIZE(max98927_codec_conf), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + +static int kabylake_audio_probe(struct platform_device *pdev) +{ + struct kbl_codec_private *ctx; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + kabylake_audio_card = + (struct snd_soc_card *)pdev->id_entry->driver_data; + + kabylake_audio_card->dev = &pdev->dev; + snd_soc_card_set_drvdata(kabylake_audio_card, ctx); + + return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); +} + +static const struct platform_device_id kbl_board_ids[] = { + { + .name = "kbl_da7219_max98927", + .driver_data = + (kernel_ulong_t)&kbl_audio_card_da7219_m98927, + }, + { + .name = "kbl_max98927", + .driver_data = + (kernel_ulong_t)&kbl_audio_card_max98927, + }, + { } +}; + +static struct platform_driver kabylake_audio = { + .probe = kabylake_audio_probe, + .driver = { + .name = "kbl_da7219_max98927", + .pm = &snd_soc_pm_ops, + }, + .id_table = kbl_board_ids, +}; + +module_platform_driver(kabylake_audio) + +/* Module information */ +MODULE_DESCRIPTION("Audio KabyLake Machine driver for MAX98927 & DA7219"); +MODULE_AUTHOR("Mac Chiang "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:kbl_da7219_max98927"); +MODULE_ALIAS("platform:kbl_max98927"); From 92bdae060d075dc915d0850bd052a28fcbd01445 Mon Sep 17 00:00:00 2001 From: Mac Chiang Date: Tue, 9 Oct 2018 15:37:08 +0800 Subject: [PATCH 0075/1995] ASoC: Intel: common: Add Kabylake Dialog+Maxim machine driver entry This patch adds da7219_max98927 machine driver entry into machine table Signed-off-by: Mac Chiang Signed-off-by: Mark Brown (cherry picked from commit 6530adeaaf5018cd13437dc82adcd9349657a00e) --- sound/soc/intel/common/soc-acpi-intel-kbl-match.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c index 0ee173ca437dd3..a317b7790fcecf 100644 --- a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c @@ -32,6 +32,11 @@ static struct snd_soc_acpi_codecs kbl_7219_98357_codecs = { .codecs = {"MX98357A"} }; +static struct snd_soc_acpi_codecs kbl_7219_98927_codecs = { + .num_codecs = 1, + .codecs = {"MX98927"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { { .id = "INT343A", @@ -83,6 +88,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .quirk_data = &kbl_7219_98357_codecs, .pdata = &skl_dmic_data, }, + { + .id = "DLGS7219", + .drv_name = "kbl_da7219_max98927", + .fw_filename = "intel/dsp_fw_kbl.bin", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &kbl_7219_98927_codecs, + .pdata = &skl_dmic_data + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines); From 1846be98040e37c5970a85362645262ca639335f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 13 Oct 2018 17:17:04 +0200 Subject: [PATCH 0076/1995] ASoC: intel: don't pass GFP_DMA32 to dma_alloc_coherent The DMA API does its own zone decisions based on the coherent_dma_mask. Signed-off-by: Christoph Hellwig Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 3b991038498bc5011b063d6a804503c577a79434) --- sound/soc/intel/common/sst-firmware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c index 11041aedea312c..1e067504b6043b 100644 --- a/sound/soc/intel/common/sst-firmware.c +++ b/sound/soc/intel/common/sst-firmware.c @@ -355,7 +355,7 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp, /* allocate DMA buffer to store FW data */ sst_fw->dma_buf = dma_alloc_coherent(dsp->dma_dev, sst_fw->size, - &sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL); + &sst_fw->dmable_fw_paddr, GFP_KERNEL); if (!sst_fw->dma_buf) { dev_err(dsp->dev, "error: DMA alloc failed\n"); kfree(sst_fw); From c16147435613dbdc01b93f12bee8f86aa0f53213 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 18 Oct 2018 10:34:30 +0300 Subject: [PATCH 0077/1995] ASoC: Intel: kbl_da7219_max98927: minor white space clean up I just added a couple missing tabs. Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown (cherry picked from commit 9ab2a1bd81f7eaef4b496168dd93e0f23e8906fe) --- sound/soc/intel/boards/kbl_da7219_max98927.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 3ab96ee7bd3c55..3fa1c3ca6d376f 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -180,14 +180,14 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); if (ret < 0) { dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret); - return ret; + return ret; } } if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); if (ret < 0) { dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret); - return ret; + return ret; } } } From ec4c1f531b533909666955d88159f1eafe53c4b4 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 11 Oct 2018 17:28:28 +0100 Subject: [PATCH 0078/1995] ASoC: dapm: Add support for hw_free on CODEC to CODEC links Currently, on power down for a CODEC to CODEC DAI link we only call digital_mute and shutdown. Provide a little more flexibility for drivers by adding a call to hw_free as well. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit 3c01b0e129e9486c8004e43eba3a70de7393f645) --- sound/soc/soc-dapm.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8c5b065c888062..a5178845065b35 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3737,25 +3737,30 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, ret = 0; } + substream.stream = SNDRV_PCM_STREAM_CAPTURE; snd_soc_dapm_widget_for_each_source_path(w, path) { source = path->source->priv; + if (source->driver->ops->hw_free) + source->driver->ops->hw_free(&substream, + source); + source->active--; - if (source->driver->ops->shutdown) { - substream.stream = SNDRV_PCM_STREAM_CAPTURE; + if (source->driver->ops->shutdown) source->driver->ops->shutdown(&substream, source); - } } + substream.stream = SNDRV_PCM_STREAM_PLAYBACK; snd_soc_dapm_widget_for_each_sink_path(w, path) { sink = path->sink->priv; + if (sink->driver->ops->hw_free) + sink->driver->ops->hw_free(&substream, sink); + sink->active--; - if (sink->driver->ops->shutdown) { - substream.stream = SNDRV_PCM_STREAM_PLAYBACK; + if (sink->driver->ops->shutdown) sink->driver->ops->shutdown(&substream, sink); - } } break; From f6c174d0d3d191a1e6e6be3df8d7d2acade95398 Mon Sep 17 00:00:00 2001 From: Marcel Ziswiler Date: Thu, 18 Oct 2018 13:18:28 +0200 Subject: [PATCH 0079/1995] ASoC: soc-core: fix trivial checkpatch issues Fix a few trivial aka cosmetic only checkpatch issues like long lines, wrong indentations, spurious blanks and newlines, missing newlines, multi-line comments etc. Signed-off-by: Marcel Ziswiler Signed-off-by: Mark Brown (cherry picked from commit 2c7b696a7589ab14854c132dc732973fbd498d5a) --- sound/soc/soc-core.c | 146 ++++++++++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 58 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 62e8e36062df05..6ddcf12bc030db 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -66,8 +66,9 @@ static int pmdown_time = 5000; module_param(pmdown_time, int, 0); MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); -/* If a DMI filed contain strings in this blacklist (e.g. - * "Type2 - Board Manufacturer" or "Type1 - TBD by OEM"), it will be taken +/* + * If a DMI filed contain strings in this blacklist (e.g. + * "Type2 - Board Manufacturer" or "Type1 - TBD by OEM"), it will be taken * as invalid and dropped when setting the card long name from DMI info. */ static const char * const dmi_blacklist[] = { @@ -222,7 +223,7 @@ static void soc_init_card_debugfs(struct snd_soc_card *card) &card->pop_time); if (!card->debugfs_pop_time) dev_warn(card->dev, - "ASoC: Failed to create pop time debugfs file\n"); + "ASoC: Failed to create pop time debugfs file\n"); } static void soc_cleanup_card_debugfs(struct snd_soc_card *card) @@ -426,7 +427,8 @@ EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); static void codec2codec_close_delayed_work(struct work_struct *work) { - /* Currently nothing to do for c2c links + /* + * Currently nothing to do for c2c links * Since c2c links are internal nodes in the DAPM graph and * don't interface with the outside world or application layer * we don't have to do any special handling on close. @@ -446,8 +448,9 @@ int snd_soc_suspend(struct device *dev) if (!card->instantiated) return 0; - /* Due to the resume being scheduled into a workqueue we could - * suspend before that's finished - wait for it to complete. + /* + * Due to the resume being scheduled into a workqueue we could + * suspend before that's finished - wait for it to complete. */ snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0); @@ -514,10 +517,13 @@ int snd_soc_suspend(struct device *dev) /* suspend all COMPONENTs */ for_each_card_components(card, component) { - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); - /* If there are paths active then the COMPONENT will be held with - * bias _ON and should not be suspended. */ + /* + * If there are paths active then the COMPONENT will be held + * with bias _ON and should not be suspended. + */ if (!component->suspended) { switch (snd_soc_dapm_get_bias_level(dapm)) { case SND_SOC_BIAS_STANDBY: @@ -571,18 +577,21 @@ int snd_soc_suspend(struct device *dev) } EXPORT_SYMBOL_GPL(snd_soc_suspend); -/* deferred resume work, so resume can complete before we finished +/* + * deferred resume work, so resume can complete before we finished * setting our codec back up, which can be very slow on I2C */ static void soc_resume_deferred(struct work_struct *work) { struct snd_soc_card *card = - container_of(work, struct snd_soc_card, deferred_resume_work); + container_of(work, struct snd_soc_card, + deferred_resume_work); struct snd_soc_pcm_runtime *rtd; struct snd_soc_component *component; int i; - /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time, + /* + * our power state is still SNDRV_CTL_POWER_D3hot from suspend time, * so userspace apps are blocked from touching us */ @@ -699,6 +708,7 @@ int snd_soc_resume(struct device *dev) */ for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + bus_control |= cpu_dai->driver->bus_control; } if (bus_control) { @@ -777,7 +787,7 @@ struct snd_soc_dai *snd_soc_find_dai( lockdep_assert_held(&client_mutex); - /* Find CPU DAI from registered DAIs*/ + /* Find CPU DAI from registered DAIs */ for_each_component(component) { if (!snd_soc_is_matching_component(dlc, component)) continue; @@ -795,7 +805,6 @@ struct snd_soc_dai *snd_soc_find_dai( } EXPORT_SYMBOL_GPL(snd_soc_find_dai); - /** * snd_soc_find_dai_link - Find a DAI link * @@ -918,7 +927,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, _err_defer: soc_free_pcm_runtime(rtd); - return -EPROBE_DEFER; + return -EPROBE_DEFER; } static void soc_remove_component(struct snd_soc_component *component) @@ -1074,7 +1083,7 @@ static int snd_soc_init_multicodec(struct snd_soc_card *card, } static int soc_init_dai_link(struct snd_soc_card *card, - struct snd_soc_dai_link *link) + struct snd_soc_dai_link *link) { int i, ret; struct snd_soc_dai_link_component *codec; @@ -1148,7 +1157,8 @@ static int soc_init_dai_link(struct snd_soc_card *card, void snd_soc_disconnect_sync(struct device *dev) { - struct snd_soc_component *component = snd_soc_lookup_component(dev, NULL); + struct snd_soc_component *component = + snd_soc_lookup_component(dev, NULL); if (!component || !component->card) return; @@ -1179,7 +1189,8 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, } lockdep_assert_held(&client_mutex); - /* Notify the machine driver for extra initialization + /* + * Notify the machine driver for extra initialization * on the link created by topology. */ if (dai_link->dobj.type && card->add_dai_link) @@ -1214,7 +1225,8 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card, } lockdep_assert_held(&client_mutex); - /* Notify the machine driver for extra destruction + /* + * Notify the machine driver for extra destruction * on the link created by topology. */ if (dai_link->dobj.type && card->remove_dai_link) @@ -1274,7 +1286,8 @@ static void soc_set_name_prefix(struct snd_soc_card *card, static int soc_probe_component(struct snd_soc_card *card, struct snd_soc_component *component) { - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); struct snd_soc_dai *dai; int ret; @@ -1406,8 +1419,7 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, } static int soc_probe_link_components(struct snd_soc_card *card, - struct snd_soc_pcm_runtime *rtd, - int order) + struct snd_soc_pcm_runtime *rtd, int order) { struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; @@ -1434,6 +1446,7 @@ static int soc_probe_dai(struct snd_soc_dai *dai, int order) if (dai->driver->probe) { int ret = dai->driver->probe(dai); + if (ret < 0) { dev_err(dai->dev, "ASoC: failed to probe DAI %s: %d\n", dai->name, ret); @@ -1541,7 +1554,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, } if (cpu_dai->driver->compress_new) { - /*create compress_device"*/ + /* create compress_device" */ ret = cpu_dai->driver->compress_new(rtd, num); if (ret < 0) { dev_err(card->dev, "ASoC: can't create compress %s\n", @@ -1555,7 +1568,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, ret = soc_new_pcm(rtd, num); if (ret < 0) { dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", - dai_link->stream_name, ret); + dai_link->stream_name, ret); return ret; } ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); @@ -1683,8 +1696,10 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, } } - /* Flip the polarity for the "CPU" end of a CODEC<->CODEC link */ - /* the component which has non_legacy_dai_naming is Codec */ + /* + * Flip the polarity for the "CPU" end of a CODEC<->CODEC link + * the component which has non_legacy_dai_naming is Codec + */ if (cpu_dai->component->driver->non_legacy_dai_naming) { unsigned int inv_dai_fmt; @@ -1718,9 +1733,9 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd, } EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt); - #ifdef CONFIG_DMI -/* Trim special characters, and replace '-' with '_' since '-' is used to +/* + * Trim special characters, and replace '-' with '_' since '-' is used to * separate different DMI fields in the card long name. Only number and * alphabet characters and a few separator characters are kept. */ @@ -1739,7 +1754,8 @@ static void cleanup_dmi_name(char *name) name[j] = '\0'; } -/* Check if a DMI field is valid, i.e. not containing any string +/* + * Check if a DMI field is valid, i.e. not containing any string * in the black list. */ static int is_dmi_valid(const char *field) @@ -1802,7 +1818,6 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) return 0; } - snprintf(card->dmi_longname, sizeof(card->snd_card->longname), "%s", vendor); cleanup_dmi_name(card->dmi_longname); @@ -1818,7 +1833,8 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) if (len < longname_buf_size) cleanup_dmi_name(card->dmi_longname + len); - /* some vendors like Lenovo may only put a self-explanatory + /* + * some vendors like Lenovo may only put a self-explanatory * name in the product version field */ product_version = dmi_get_system_info(DMI_PRODUCT_VERSION); @@ -1914,7 +1930,8 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) dai_link->be_hw_params_fixup = component->driver->be_hw_params_fixup; - /* most BE links don't set stream name, so set it to + /* + * most BE links don't set stream name, so set it to * dai link name if it's NULL to help bind widgets. */ if (!dai_link->stream_name) @@ -1924,7 +1941,7 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) /* Inform userspace we are using alternate topology */ if (component->driver->topology_name_prefix) { - /* topology shortname created ? */ + /* topology shortname created? */ if (!card->topology_shortname_created) { comp_drv = component->driver; @@ -2029,7 +2046,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (ret < 0) goto probe_dai_err; - /* Find new DAI links added during probing components and bind them. + /* + * Find new DAI links added during probing components and bind them. * Components with topology may bring new DAIs and DAI links. */ for_each_card_links(card, dai_link) { @@ -2061,7 +2079,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) snd_soc_dapm_connect_dai_link_widgets(card); if (card->controls) - snd_soc_add_card_controls(card, card->controls, card->num_controls); + snd_soc_add_card_controls(card, card->controls, + card->num_controls); if (card->dapm_routes) snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, @@ -2207,8 +2226,10 @@ int snd_soc_poweroff(struct device *dev) if (!card->instantiated) return 0; - /* Flush out pmdown_time work - we actually do want to run it - * now, we're shutting down so no imminent restart. */ + /* + * Flush out pmdown_time work - we actually do want to run it + * now, we're shutting down so no imminent restart. + */ for_each_card_rtds(card, rtd) flush_delayed_work(&rtd->delayed_work); @@ -2301,6 +2322,7 @@ static int snd_soc_add_controls(struct snd_card *card, struct device *dev, for (i = 0; i < num_controls; i++) { const struct snd_kcontrol_new *control = &controls[i]; + err = snd_ctl_add(card, snd_soc_cnew(control, data, control->name, prefix)); if (err < 0) { @@ -2418,8 +2440,9 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); * * Configures the CODEC master (MCLK) or system (SYSCLK) clocking. */ -int snd_soc_component_set_sysclk(struct snd_soc_component *component, int clk_id, - int source, unsigned int freq, int dir) +int snd_soc_component_set_sysclk(struct snd_soc_component *component, + int clk_id, int source, unsigned int freq, + int dir) { if (component->driver->set_sysclk) return component->driver->set_sysclk(component, clk_id, source, @@ -2487,7 +2510,7 @@ int snd_soc_component_set_pll(struct snd_soc_component *component, int pll_id, { if (component->driver->set_pll) return component->driver->set_pll(component, pll_id, source, - freq_in, freq_out); + freq_in, freq_out); return -EINVAL; } @@ -2533,8 +2556,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); * Generates the TDM tx and rx slot default masks for DAI. */ static int snd_soc_xlate_tdm_slot_mask(unsigned int slots, - unsigned int *tx_mask, - unsigned int *rx_mask) + unsigned int *tx_mask, + unsigned int *rx_mask) { if (*tx_mask || *rx_mask) return 0; @@ -2684,7 +2707,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card) return ret; /* deactivate pins to sleep state */ - for_each_card_rtds(card, rtd) { + for_each_card_rtds(card, rtd) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai; int j; @@ -2799,7 +2822,7 @@ static char *fmt_single_name(struct device *dev, int *id) } } else { - /* I2C component devices are named "bus-addr" */ + /* I2C component devices are named "bus-addr" */ if (sscanf(name, "%x-%x", &id1, &id2) == 2) { char tmp[NAME_SIZE]; @@ -2807,7 +2830,8 @@ static char *fmt_single_name(struct device *dev, int *id) *id = ((id1 & 0xffff) << 16) + id2; /* sanitize component name for DAI link creation */ - snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, name); + snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, + name); strlcpy(name, tmp, NAME_SIZE); } else *id = 0; @@ -2874,7 +2898,7 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, * component-less anymore. */ if (legacy_dai_naming && - (dai_drv->id == 0 || dai_drv->name == NULL)) { + (dai_drv->id == 0 || dai_drv->name == NULL)) { dai->name = fmt_single_name(dev, &dai->id); } else { dai->name = fmt_multiple_name(dev, dai_drv); @@ -2910,7 +2934,8 @@ static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, * @count: Number of DAIs */ static int snd_soc_register_dais(struct snd_soc_component *component, - struct snd_soc_dai_driver *dai_drv, size_t count) + struct snd_soc_dai_driver *dai_drv, + size_t count) { struct device *dev = component->dev; struct snd_soc_dai *dai; @@ -2921,8 +2946,8 @@ static int snd_soc_register_dais(struct snd_soc_component *component, for (i = 0; i < count; i++) { - dai = soc_add_dai(component, dai_drv + i, - count == 1 && !component->driver->non_legacy_dai_naming); + dai = soc_add_dai(component, dai_drv + i, count == 1 && + !component->driver->non_legacy_dai_naming); if (dai == NULL) { ret = -ENOMEM; goto err; @@ -2966,7 +2991,8 @@ int snd_soc_register_dai(struct snd_soc_component *component, if (!dai) return -ENOMEM; - /* Create the DAI widgets here. After adding DAIs, topology may + /* + * Create the DAI widgets here. After adding DAIs, topology may * also add routes that need these widgets as source or sink. */ ret = snd_soc_dapm_new_dai_widgets(dapm, dai); @@ -3048,7 +3074,8 @@ static void snd_soc_component_setup_regmap(struct snd_soc_component *component) #ifdef CONFIG_REGMAP /** - * snd_soc_component_init_regmap() - Initialize regmap instance for the component + * snd_soc_component_init_regmap() - Initialize regmap instance for the + * component * @component: The component for which to initialize the regmap instance * @regmap: The regmap instance that should be used by the component * @@ -3066,7 +3093,8 @@ void snd_soc_component_init_regmap(struct snd_soc_component *component, EXPORT_SYMBOL_GPL(snd_soc_component_init_regmap); /** - * snd_soc_component_exit_regmap() - De-initialize regmap instance for the component + * snd_soc_component_exit_regmap() - De-initialize regmap instance for the + * component * @component: The component for which to de-initialize the regmap instance * * Calls regmap_exit() on the regmap instance associated to the component and @@ -3090,7 +3118,8 @@ static void snd_soc_component_add(struct snd_soc_component *component) if (!component->driver->write && !component->driver->read) { if (!component->regmap) - component->regmap = dev_get_regmap(component->dev, NULL); + component->regmap = dev_get_regmap(component->dev, + NULL); if (component->regmap) snd_soc_component_setup_regmap(component); } @@ -3235,23 +3264,24 @@ static int __snd_soc_unregister_component(struct device *dev) if (dev != component->dev) continue; - snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); + snd_soc_tplg_component_remove(component, + SND_SOC_TPLG_INDEX_ALL); snd_soc_component_del_unlocked(component); found = 1; break; } mutex_unlock(&client_mutex); - if (found) { + if (found) snd_soc_component_cleanup(component); - } return found; } void snd_soc_unregister_component(struct device *dev) { - while (__snd_soc_unregister_component(dev)); + while (__snd_soc_unregister_component(dev)) + ; } EXPORT_SYMBOL_GPL(snd_soc_unregister_component); @@ -3832,7 +3862,7 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev, for_each_link_codecs(dai_link, index, component) { ret = of_parse_phandle_with_args(of_node, name, "#sound-dai-cells", - index, &args); + index, &args); if (ret) goto err; component->of_node = args.np; From eabf5644c0888534af0d80932bffd4a0ba6bd46a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 26 Oct 2018 16:54:43 -0500 Subject: [PATCH 0080/1995] ASoC: fix oops w/ for_each_rtd_codec_dai_rollback() macro A kernel oops happens on an error case (usual missing BE mixer configuration required by Intel SST driver). Git bisect points to this macro and an operator precedence issue. for (; ((i--) >= 0) && ((dai) = rtd->codec_dais[i]);) The initial code replaced by this macro was while (--i >= 0) { codec_dai = rtd->codec_dais[i]; Fix the C operator precedence difference by reverting to pre-decrement Fixes: 0b7990e3897 ('ASoC: add for_each_rtd_codec_dai() macro') Cc: Kuninori Morimoto Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 23cb2d04db54535df65edbbebbca89f2590f08bd) --- include/sound/soc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index f1dab1f4b194d4..70c10a8f3e90a7 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1192,7 +1192,7 @@ struct snd_soc_pcm_runtime { ((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \ (i)++) #define for_each_rtd_codec_dai_rollback(rtd, i, dai) \ - for (; ((i--) >= 0) && ((dai) = rtd->codec_dais[i]);) + for (; ((--i) >= 0) && ((dai) = rtd->codec_dais[i]);) /* mixer control */ From 61302c063a0d6c618f4caaa03ae09ea8b39bc5d3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 22 Jun 2018 15:47:24 -0500 Subject: [PATCH 0081/1995] ASoC: Intel: common: add ACPI matching tables for ICL Signed-off-by: Pierre-Louis Bossart --- include/sound/soc-acpi-intel-match.h | 1 + sound/soc/intel/common/Makefile | 2 +- .../intel/common/soc-acpi-intel-icl-match.c | 32 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/common/soc-acpi-intel-icl-match.c diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index f48f59e5b7b02b..bb5e1e4ce8bf91 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -24,6 +24,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[]; /* * generic table used for HDA codec-based platforms, possibly with diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index c1f50a079d34aa..56c81e20b5bf8d 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -7,7 +7,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-hsw-bdw-match.o \ soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ - soc-acpi-intel-cnl-match.o \ + soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \ soc-acpi-intel-hda-match.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c new file mode 100644 index 00000000000000..33b441dca4d308 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-apci-intel-icl-match.c - tables and support for ICL ACPI enumeration. + * + * Copyright (c) 2018, Intel Corporation. + * + */ + +#include +#include +#include "../skylake/skl.h" + +static struct skl_machine_pdata icl_pdata = { + .use_tplg_pcm = true, +}; + +struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { + { + .id = "INT34C2", + .drv_name = "icl_rt274", + .fw_filename = "intel/dsp_fw_icl.bin", + .pdata = &icl_pdata, + .sof_fw_filename = "intel/sof-icl.ri", + .sof_tplg_filename = "intel/sof-icl-rt274.tplg", + .asoc_plat_name = "0000:00:1f.3", + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_icl_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); From e7b326c20e0f28b6b53d7259921d787a9639c242 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 12 Jun 2018 18:52:58 -0500 Subject: [PATCH 0082/1995] ASoC: Intel: common: add ACPI match for CannonLake MX98373 is used on some CNL boards Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index ec8e28e7b937aa..ae3be064e75e99 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -24,6 +24,15 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .sof_tplg_filename = "intel/sof-cnl-rt274.tplg", .asoc_plat_name = "0000:00:1f.3", }, + { + .id = "MX98373", + .drv_name = "cnl_max98373", + .fw_filename = "intel/dsp_fw_cnl.bin", + .pdata = &cnl_pdata, + .sof_fw_filename = "intel/sof-cnl.ri", + .sof_tplg_filename = "intel/sof-cnl.tplg", + .asoc_plat_name = "0000:00:0e.0", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_machines); From c2754ce91e1729a639397359f4e246fe44a808c0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 31 Jul 2018 19:43:13 -0500 Subject: [PATCH 0083/1995] ASoC: core: support driver alias names for FE topology overrides When the same machine driver is reused between platforms but with a different alias, using the driver name is not enough. Add additional fallback case to use the card device name. Tested on GeminiLake with bxt_da7219_max98357a machine driver Signed-off-by: Pierre-Louis Bossart --- sound/soc/soc-core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6ddcf12bc030db..ec00104e80a8aa 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1900,10 +1900,13 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) continue; /* for this machine ? */ + if (!strcmp(component->driver->ignore_machine, + card->dev->driver->name)) + goto match; if (strcmp(component->driver->ignore_machine, - card->dev->driver->name)) + dev_name(card->dev))) continue; - +match: /* machine matches, so override the rtd data */ for_each_card_prelinks(card, i, dai_link) { From 4185428b8cff672ca293ef7db582925b44d53fc7 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 26 Oct 2018 17:05:09 +0800 Subject: [PATCH 0084/1995] ASoC: Intel: common: add SOF information for APL RVP Add firmware/topology information for APL RVP Signed-off-by: Bard liao --- sound/soc/intel/common/soc-acpi-intel-bxt-match.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c index f39386e540d322..2756fa4ab55201 100644 --- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c @@ -19,6 +19,9 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .id = "INT343A", .drv_name = "bxt_alc298s_i2s", .fw_filename = "intel/dsp_fw_bxtn.bin", + .sof_fw_filename = "intel/sof-apl.ri", + .sof_tplg_filename = "intel/sof-apl-rt298.tplg", + .asoc_plat_name = "0000:00:0e.0", }, { .id = "DLGS7219", From 95eedaa607c071c3a740b36248c5a2ef2c2d8c16 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 31 Aug 2018 15:00:22 +0800 Subject: [PATCH 0085/1995] ALSA: HDA: export process_unsol_events() which can be used without hdac_bus library. In some cases, we want to initialize hda bus without this hdac_bus library(e.g. for non-HDA I2S only usuage on Intel Skylake+ platforms), where we will do hdac bus non-HDA-only implementation in BSD license. When we want to add hda link support(GPL) in this implementation, we need reuse this process_unsol_events(), so export it is better solution comparing to implement it again. Signed-off-by: Keyon Jie --- include/sound/hdaudio.h | 1 + sound/hda/hdac_bus.c | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index cd1773d0e08f07..2ee9eccf8d5405 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -389,6 +389,7 @@ void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex); int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec); void snd_hdac_bus_remove_device(struct hdac_bus *bus, struct hdac_device *codec); +void snd_hdac_bus_process_unsol_events(struct work_struct *work); static inline void snd_hdac_codec_link_up(struct hdac_device *codec) { diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c index 714a51721a313c..012305177f6822 100644 --- a/sound/hda/hdac_bus.c +++ b/sound/hda/hdac_bus.c @@ -9,8 +9,6 @@ #include #include "trace.h" -static void process_unsol_events(struct work_struct *work); - static const struct hdac_bus_ops default_ops = { .command = snd_hdac_bus_send_cmd, .get_response = snd_hdac_bus_get_response, @@ -37,7 +35,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, bus->io_ops = io_ops; INIT_LIST_HEAD(&bus->stream_list); INIT_LIST_HEAD(&bus->codec_list); - INIT_WORK(&bus->unsol_work, process_unsol_events); + INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); spin_lock_init(&bus->reg_lock); mutex_init(&bus->cmd_mutex); bus->irq = -1; @@ -148,7 +146,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_bus_queue_event); /* * process queued unsolicited events */ -static void process_unsol_events(struct work_struct *work) +void snd_hdac_bus_process_unsol_events(struct work_struct *work) { struct hdac_bus *bus = container_of(work, struct hdac_bus, unsol_work); struct hdac_device *codec; @@ -171,6 +169,7 @@ static void process_unsol_events(struct work_struct *work) drv->unsol_event(codec, res); } } +EXPORT_SYMBOL_GPL(snd_hdac_bus_process_unsol_events); /** * snd_hdac_bus_add_device - Add a codec to bus From a2b54ab25a7c4b2b754c68386f3d041a078896b9 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Thu, 6 Sep 2018 20:16:01 +0300 Subject: [PATCH 0086/1995] ASoC: dapm: fix kcontrols for effect widgets This patch adds the handling of snd_soc_dapm_effect that was missing. Signed-off-by: Ranjani Sridharan Signed-off-by: Seppo Ingalsuo --- sound/soc/soc-dapm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index a5178845065b35..8f0b2a35651dc1 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -841,6 +841,7 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w, case snd_soc_dapm_switch: case snd_soc_dapm_mixer: case snd_soc_dapm_pga: + case snd_soc_dapm_effect: case snd_soc_dapm_out_drv: wname_in_long_name = true; kcname_in_long_name = true; @@ -2322,6 +2323,7 @@ static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt, case snd_soc_dapm_dac: case snd_soc_dapm_adc: case snd_soc_dapm_pga: + case snd_soc_dapm_effect: case snd_soc_dapm_out_drv: case snd_soc_dapm_mixer: case snd_soc_dapm_mixer_named_ctl: @@ -3061,6 +3063,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) dapm_new_mux(w); break; case snd_soc_dapm_pga: + case snd_soc_dapm_effect: case snd_soc_dapm_out_drv: dapm_new_pga(w); break; From 4c10c446363c340d865e9ba6358032cf498b1b6a Mon Sep 17 00:00:00 2001 From: Wu Zhigang Date: Tue, 4 Sep 2018 21:32:49 +0800 Subject: [PATCH 0087/1995] ASoC:core:bug fix: oops caused by pointer dereference. oops case: the snd_card{} would be freed ahead of dynamic kcontrol remove process, in this process, the snd_card{} will be used, then the oops will be hit. the solution: the operation of removing the dynamic kcontrol should be ahead of snd_card{} free. Signed-off-by: Wu Zhigang --- sound/soc/soc-core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ec00104e80a8aa..568cd6a90927af 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2187,11 +2187,21 @@ static int soc_probe(struct platform_device *pdev) static int soc_cleanup_card_resources(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; + struct snd_soc_component *component; + int ret; /* make sure any delayed work runs */ for_each_card_rtds(card, rtd) flush_delayed_work(&rtd->delayed_work); + /* remove dynamic controls for all component driver */ + list_for_each_entry(component, &card->component_dev_list, card_list) { + ret = snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); + if (ret < 0) + dev_err(component->dev, + "error: component free failed %d\n", ret); + } + /* free the ALSA card at first; this syncs with pending operations */ snd_card_free(card->snd_card); From d28e9af0a5df63d5a89fc9ad37c99085cfab4eb0 Mon Sep 17 00:00:00 2001 From: Wu Zhigang Date: Mon, 10 Sep 2018 17:26:49 +0800 Subject: [PATCH 0088/1995] ASoC:topology:delete dynamic object during widget remove remove the dynamic object during the topology free stage. to avoid multi remove operation. Signed-off-by: Wu Zhigang --- sound/soc/soc-topology.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 045ef136903d63..0fab1633617be9 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -491,6 +491,7 @@ static void remove_widget(struct snd_soc_component *comp, } free_news: + list_del(&dobj->list); kfree(w->kcontrol_news); /* widget w is freed by soc-dapm.c */ From 5711d8e9d7614ea7727599317d2fbc08f7ef5646 Mon Sep 17 00:00:00 2001 From: Wu Zhigang Date: Tue, 28 Aug 2018 13:43:11 +0800 Subject: [PATCH 0089/1995] ASoC:topology:bug fix:check return value avoid oops. check the return value to free the kcontrols instance to avoid oops caused by the pointer dereference. Signed-off-by: Wu Zhigang [guennadi.liakhovetski@intel.com add handling of .autodisable=1 cases] --- sound/soc/soc-dapm.c | 99 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 90 insertions(+), 9 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8f0b2a35651dc1..51ad4f9d3d8f28 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2396,12 +2396,11 @@ static void dapm_free_path(struct snd_soc_dapm_path *path) kfree(path); } -void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) +static void snd_soc_dapm_free_widget_data(struct snd_soc_dapm_widget *w) { struct snd_soc_dapm_path *p, *next_p; enum snd_soc_dapm_direction dir; - list_del(&w->list); /* * remove source and sink paths associated to this widget. * While removing the path, remove reference to it from both @@ -2414,6 +2413,12 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) kfree(w->kcontrols); kfree_const(w->name); +} + +void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) +{ + list_del(&w->list); + snd_soc_dapm_free_widget_data(w); kfree(w); } @@ -3032,11 +3037,16 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes); */ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) { - struct snd_soc_dapm_widget *w; + struct snd_soc_dapm_widget *w, *last; unsigned int val; + int ret = 0; mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); + /* + * widgets with the snd_soc_dapm_kcontrol ID and .num_controls = 0 can + * be appended to the list while scanning it, this is safe. + */ list_for_each_entry(w, &card->widgets, list) { if (w->new) @@ -3047,8 +3057,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) sizeof(struct snd_kcontrol *), GFP_KERNEL); if (!w->kcontrols) { - mutex_unlock(&card->dapm_mutex); - return -ENOMEM; + ret = -ENOMEM; + goto out_free; } } @@ -3056,24 +3066,30 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) case snd_soc_dapm_switch: case snd_soc_dapm_mixer: case snd_soc_dapm_mixer_named_ctl: - dapm_new_mixer(w); + ret = dapm_new_mixer(w); break; case snd_soc_dapm_mux: case snd_soc_dapm_demux: - dapm_new_mux(w); + ret = dapm_new_mux(w); break; case snd_soc_dapm_pga: case snd_soc_dapm_effect: case snd_soc_dapm_out_drv: - dapm_new_pga(w); + ret = dapm_new_pga(w); break; case snd_soc_dapm_dai_link: - dapm_new_dai_link(w); + ret = dapm_new_dai_link(w); break; default: break; } + if (ret < 0) { + kfree(w->kcontrols); + w->kcontrols = NULL; + goto out_free; + } + /* Read the initial power state from the device */ if (w->reg >= 0) { soc_dapm_read(w->dapm, w->reg, &val); @@ -3082,6 +3098,11 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) if (val == w->on_val) w->power = 1; } + } + + list_for_each_entry(w, &card->widgets, list) { + if (w->new) + continue; w->new = 1; @@ -3092,6 +3113,66 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP); mutex_unlock(&card->dapm_mutex); return 0; + +out_free: + last = w; + + /* + * If any new widgets have been created above for .autodisable = 1 + * controls, they are also on this list, but at its very end. We're + * processing an error case, so the loop above was interrupted before + * reaching dynamically added widgets, since the latter cannot fail - + * their .num_controls = 0, so allocation cannot fail, and their type is + * snd_soc_dapm_kcontrol, those cannot fail either. Therefore "last" + * points to a widget before the first dynamic one. + */ + list_for_each_entry(w, &card->widgets, list) { + unsigned int i; + + if (w->new) + continue; + + if (w == last) + break; + + switch (w->id) { + case snd_soc_dapm_switch: + case snd_soc_dapm_mixer: + case snd_soc_dapm_mixer_named_ctl: + for (i = 0; i < w->num_kcontrols; i++) { + struct snd_kcontrol *kcontrol = w->kcontrols[i]; + struct dapm_kcontrol_data *data = + kcontrol->private_data; + struct soc_mixer_control *mc = + (struct soc_mixer_control *) + kcontrol->private_value; + + if (mc->autodisable) + snd_soc_dapm_free_widget(data->widget); + } + break; + case snd_soc_dapm_demux: + case snd_soc_dapm_mux: + for (i = 0; i < w->num_kcontrols; i++) { + struct snd_kcontrol *kcontrol = w->kcontrols[i]; + struct dapm_kcontrol_data *data = + kcontrol->private_data; + struct soc_enum *e = (struct soc_enum *) + kcontrol->private_value; + + if (e->autodisable) + snd_soc_dapm_free_widget(data->widget); + } + break; + default: + break; + } + + snd_soc_dapm_free_widget_data(w); + } + + mutex_unlock(&card->dapm_mutex); + return ret; } EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); From 057637349447338e7eeb289921380cd7011b84c9 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 20 Sep 2018 15:42:14 +0200 Subject: [PATCH 0090/1995] soc: fix a use after free case Unloading ASoC modules as used by the SOF driver leads to an object being used after it's been freed. Fix this be clearing a reference to it and making sure to check for its presence. This fixes issue #144. Signed-off-by: Guennadi Liakhovetski --- sound/soc/soc-core.c | 2 +- sound/soc/soc-topology.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 568cd6a90927af..abc779fbec8dc0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -951,7 +951,7 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order) { int err; - if (!dai || !dai->probed || + if (!dai || !dai->probed || !dai->driver || dai->driver->remove_order != order) return; diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 0fab1633617be9..bc09fec712c4db 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -503,6 +503,7 @@ static void remove_dai(struct snd_soc_component *comp, { struct snd_soc_dai_driver *dai_drv = container_of(dobj, struct snd_soc_dai_driver, dobj); + struct snd_soc_dai *dai; if (pass != SOC_TPLG_PASS_PCM_DAI) return; @@ -510,6 +511,10 @@ static void remove_dai(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->dai_unload) dobj->ops->dai_unload(comp, dobj); + list_for_each_entry(dai, &comp->dai_list, list) + if (dai->driver == dai_drv) + dai->driver = NULL; + kfree(dai_drv->name); list_del(&dobj->list); kfree(dai_drv); From cd1ab393f0286b4293ffe364d201576d254dbd28 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:30:59 +0000 Subject: [PATCH 0091/1995] ASoC: SOF: Add Sound Open Firmware driver core The Sound Open Firmware driver core is a generic architecture independent layer that allows SOF to be used on many different different architectures and platforms. It abstracts DSP operations and IO methods so that the target DSP can be an internal memory mapped or external SPI or I2C based device. This abstraction also allows SOF to be run on many different VMs on the same physical HW. SOF also requires some data in ASoC PCM runtime data for looking up SOF data during ASoC PCM operations. Signed-off-by: Liam Girdwood --- include/sound/soc.h | 3 + include/sound/sof.h | 105 ++++++++ sound/soc/sof/core.c | 410 +++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 546 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 1064 insertions(+) create mode 100644 include/sound/sof.h create mode 100644 sound/soc/sof/core.c create mode 100644 sound/soc/sof/sof-priv.h diff --git a/include/sound/soc.h b/include/sound/soc.h index 70c10a8f3e90a7..84ff592f9f50e4 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1186,6 +1186,9 @@ struct snd_soc_pcm_runtime { /* bit field */ unsigned int dev_registered:1; unsigned int pop_wait:1; + + /* private data - core does not touch */ + void *private; }; #define for_each_rtd_codec_dai(rtd, i, dai)\ for ((i) = 0; \ diff --git a/include/sound/sof.h b/include/sound/sof.h new file mode 100644 index 00000000000000..e0adeb3fae8501 --- /dev/null +++ b/include/sound/sof.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __INCLUDE_SOUND_SOF_H +#define __INCLUDE_SOUND_SOF_H + +#include +#include +#include +#include +#include +#include +#include +#include + +struct snd_sof_dsp_ops; + +/* SOF probe type */ +enum sof_device_type { + SOF_DEVICE_PCI = 0, + SOF_DEVICE_APCI, + SOF_DEVICE_SPI +}; + +/* + * SOF Platform data. + */ +struct snd_sof_machine { + const u8 id[ACPI_ID_LEN]; + const char *drv_name; + const char *sof_fw_filename; + const char *sof_tplg_filename; + const char *asoc_plat_name; + const struct snd_sof_dsp_ops *ops; +}; + +struct snd_sof_pdata { + u32 id; /* PCI/ACPI ID */ + const struct firmware *fw; + const char *drv_name; + const char *name; + const char *platform; + + /* parent device */ + struct device *dev; + enum sof_device_type type; + + /* descriptor */ + const struct sof_dev_desc *desc; + + /* SPI data */ + unsigned int gpio; + unsigned int active; + + /* hda codec */ + unsigned long codec_mask; + + /* machine */ + struct platform_device *pdev_mach; + union { + const struct snd_soc_acpi_mach *machine; + const struct snd_sof_machine *sof_machine; + }; +}; + +/* + * Descriptor used for setting up SOF platform data. This is used when + * ACPI/PCI data is missing or mapped differently. + */ +struct sof_dev_desc { + /* list of machines using this configuration */ + union { + struct snd_soc_acpi_mach *machines; + struct snd_sof_machine *sof_machines; + }; + + /* Platform resource indexes in BAR / ACPI resources. */ + /* Must set to -1 if not used - add new items to end */ + int resindex_lpe_base; + int resindex_pcicfg_base; + int resindex_imr_base; + int irqindex_host_ipc; + int resindex_dma_base; + + /* DMA only valid when resindex_dma_base != -1*/ + int dma_engine; + int dma_size; + + /* IPC timeouts in ms */ + int ipc_timeout; + int boot_timeout; + + /* defaults for no codec mode */ + const char *nocodec_fw_filename; + const char *nocodec_tplg_filename; +}; + +#endif diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c new file mode 100644 index 00000000000000..edd5ea3e505fa8 --- /dev/null +++ b/sound/soc/sof/core.c @@ -0,0 +1,410 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sof-priv.h" +#include "ops.h" + +/* SOF defaults if not provided by the platform in ms */ +#define TIMEOUT_DEFAULT_IPC 5 +#define TIMEOUT_DEFAULT_BOOT 100 + +/* + * Generic object lookup APIs. + */ + +struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_sof_dev *sdev, + struct snd_soc_pcm_runtime *rtd) +{ + struct snd_sof_pcm *spcm = NULL; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + if (le32_to_cpu(spcm->pcm.dai_id) == rtd->dai_link->id) + return spcm; + } + + return NULL; +} + +struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev, + char *name) +{ + struct snd_sof_pcm *spcm = NULL; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + if (strcmp(spcm->pcm.dai_name, name) == 0) + return spcm; + + if (strcmp(spcm->pcm.caps[0].name, name) == 0) + return spcm; + + if (strcmp(spcm->pcm.caps[1].name, name) == 0) + return spcm; + } + + return NULL; +} + +struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev, + unsigned int comp_id, + int *direction) +{ + struct snd_sof_pcm *spcm = NULL; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id == + comp_id) { + *direction = SNDRV_PCM_STREAM_PLAYBACK; + return spcm; + } + if (spcm->stream[SNDRV_PCM_STREAM_CAPTURE].comp_id == comp_id) { + *direction = SNDRV_PCM_STREAM_CAPTURE; + return spcm; + } + } + + return NULL; +} + +struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev, + unsigned int pcm_id) +{ + struct snd_sof_pcm *spcm = NULL; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + if (le32_to_cpu(spcm->pcm.pcm_id) == pcm_id) + return spcm; + } + + return NULL; +} + +struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev, + char *name) +{ + struct snd_sof_widget *swidget = NULL; + + list_for_each_entry(swidget, &sdev->widget_list, list) { + if (strcmp(name, swidget->widget->name) == 0) + return swidget; + } + + return NULL; +} + +struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev, + char *name) +{ + struct snd_sof_dai *dai = NULL; + + list_for_each_entry(dai, &sdev->dai_list, list) { + if (!dai->name) + continue; + + if (strcmp(name, dai->name) == 0) + return dai; + } + + return NULL; +} + +/* + * FW Panic/fault handling. + */ + +struct sof_panic_msg { + u32 id; + const char *msg; +}; + +/* standard FW panic types */ +static const struct sof_panic_msg panic_msg[] = { + {SOF_IPC_PANIC_MEM, "out of memory"}, + {SOF_IPC_PANIC_WORK, "work subsystem init failed"}, + {SOF_IPC_PANIC_IPC, "IPC subsystem init failed"}, + {SOF_IPC_PANIC_ARCH, "arch init failed"}, + {SOF_IPC_PANIC_PLATFORM, "platform init failed"}, + {SOF_IPC_PANIC_TASK, "scheduler init failed"}, + {SOF_IPC_PANIC_EXCEPTION, "runtime exception"}, + {SOF_IPC_PANIC_DEADLOCK, "deadlock"}, + {SOF_IPC_PANIC_STACK, "stack overflow"}, + {SOF_IPC_PANIC_IDLE, "can't enter idle"}, + {SOF_IPC_PANIC_WFI, "invalid wait state"}, +}; + +int snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, + u32 tracep_code, void *oops, + struct sof_ipc_panic_info *panic_info, + void *stack, size_t stack_words) +{ + u32 code; + int i; + + /* is firmware dead ? */ + if ((panic_code & SOF_IPC_PANIC_MAGIC_MASK) != SOF_IPC_PANIC_MAGIC) { + dev_err(sdev->dev, "error: unexpected fault 0x%8.8x trace 0x%8.8x\n", + panic_code, tracep_code); + return 0; /* no fault ? */ + } + + code = panic_code & + (SOF_IPC_PANIC_MAGIC_MASK | SOF_IPC_PANIC_CODE_MASK); + + for (i = 0; i < ARRAY_SIZE(panic_msg); i++) { + if (panic_msg[i].id == code) { + dev_err(sdev->dev, "error: %s\n", panic_msg[i].msg); + dev_err(sdev->dev, "error: trace point %8.8x\n", + tracep_code); + goto out; + } + } + + /* unknown error */ + dev_err(sdev->dev, "error: unknown reason %8.8x\n", panic_code); + dev_err(sdev->dev, "error: trace point %8.8x\n", tracep_code); + +out: + dev_err(sdev->dev, "error: panic happen at %s:%d\n", + panic_info->filename, panic_info->linenum); + sof_oops(sdev, oops); + sof_stack(sdev, oops, stack, stack_words); + return -EFAULT; +} +EXPORT_SYMBOL(snd_sof_get_status); + +/* + * Generic buffer page table creation. + * Take the each physical page address and drop the least significant unused + * bites from each (based on PAGE_SIZE). Then pack valid page address bits + * into compressed page table. + */ + +int snd_sof_create_page_table(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab, + unsigned char *page_table, size_t size) +{ + int i, pages; + + pages = snd_sgbuf_aligned_pages(size); + + dev_dbg(sdev->dev, "generating page table for %p size 0x%zx pages %d\n", + dmab->area, size, pages); + + for (i = 0; i < pages; i++) { + u32 idx = (((i << 2) + i)) >> 1; + u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT; + u32 *pg_table; + + dev_vdbg(sdev->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); + + pg_table = (u32 *)(page_table + idx); + + if (i & 1) + *pg_table |= (pfn << 4); + else + *pg_table |= pfn; + } + + return pages; +} + +/* + * SOF Driver enumeration. + */ + +static int sof_probe(struct platform_device *pdev) +{ + struct snd_sof_pdata *plat_data = dev_get_platdata(&pdev->dev); + struct snd_sof_dev *sdev; + const char *drv_name; + const void *mach; + int size; + int ret; + + sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL); + if (!sdev) + return -ENOMEM; + + dev_dbg(&pdev->dev, "probing SOF DSP device....\n"); + + /* initialize sof device */ + sdev->dev = &pdev->dev; + sdev->parent = plat_data->dev; + if (plat_data->type == SOF_DEVICE_PCI) + sdev->pci = container_of(plat_data->dev, struct pci_dev, dev); + sdev->ops = plat_data->machine->pdata; + + sdev->pdata = plat_data; + INIT_LIST_HEAD(&sdev->pcm_list); + INIT_LIST_HEAD(&sdev->kcontrol_list); + INIT_LIST_HEAD(&sdev->widget_list); + INIT_LIST_HEAD(&sdev->dai_list); + INIT_LIST_HEAD(&sdev->route_list); + dev_set_drvdata(&pdev->dev, sdev); + spin_lock_init(&sdev->ipc_lock); + spin_lock_init(&sdev->hw_lock); + + /* set up platform component driver */ + snd_sof_new_platform_drv(sdev); + + /* set default timeouts if none provided */ + if (plat_data->desc->ipc_timeout == 0) + sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC; + else + sdev->ipc_timeout = plat_data->desc->ipc_timeout; + if (plat_data->desc->boot_timeout == 0) + sdev->boot_timeout = TIMEOUT_DEFAULT_BOOT; + else + sdev->boot_timeout = plat_data->desc->boot_timeout; + + /* probe the DSP hardware */ + ret = snd_sof_probe(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret); + return ret; + } + + /* register any debug/trace capabilities */ + ret = snd_sof_dbg_init(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to init DSP trace/debug %d\n", + ret); + goto dbg_err; + } + + /* init the IPC */ + sdev->ipc = snd_sof_ipc_init(sdev); + if (!sdev->ipc) { + dev_err(sdev->dev, "error: failed to init DSP IPC %d\n", ret); + goto ipc_err; + } + + /* load the firmware */ + ret = snd_sof_load_firmware(sdev, true); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to load DSP firmware %d\n", + ret); + goto fw_load_err; + } + + /* boot the firmware */ + ret = snd_sof_run_firmware(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to boot DSP firmware %d\n", + ret); + goto fw_run_err; + } + + /* init DMA trace */ + ret = snd_sof_init_trace(sdev); + if (ret < 0) { + /* non fatal */ + dev_warn(sdev->dev, + "warning: failed to initialize trace %d\n", ret); + } + + /* now register audio DSP platform driver and dai */ + ret = snd_soc_register_component(&pdev->dev, &sdev->plat_drv, + sdev->ops->drv, + sdev->ops->num_drv); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to register DSP DAI driver %d\n", ret); + goto comp_err; + } + + /* do we need to generate any machine plat data ? */ + if (plat_data->machine->new_mach_data) { + plat_data->pdev_mach = + plat_data->machine->new_mach_data(plat_data); + } else { + drv_name = plat_data->machine->drv_name; + mach = (const void *)plat_data; + size = sizeof(*plat_data); + + /* register machine driver, pass machine info as pdata */ + plat_data->pdev_mach = + platform_device_register_data(sdev->dev, + drv_name, -1, mach, size); + } + if (IS_ERR(plat_data->pdev_mach)) { + ret = PTR_ERR(plat_data->pdev_mach); + goto comp_err; + } + + dev_dbg(sdev->dev, "created machine %s\n", + dev_name(&plat_data->pdev_mach->dev)); + + /* autosuspend sof device */ + pm_runtime_mark_last_busy(sdev->dev); + pm_runtime_put_autosuspend(sdev->dev); + + /* autosuspend pci/acpi/spi device */ + pm_runtime_mark_last_busy(plat_data->dev); + pm_runtime_put_autosuspend(plat_data->dev); + + return 0; + +comp_err: + snd_soc_unregister_component(&pdev->dev); + snd_sof_free_topology(sdev); +fw_run_err: + snd_sof_fw_unload(sdev); +fw_load_err: + snd_sof_ipc_free(sdev); +ipc_err: + snd_sof_free_debug(sdev); +dbg_err: + snd_sof_remove(sdev); + + return ret; +} + +static int sof_remove(struct platform_device *pdev) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(&pdev->dev); + + snd_soc_unregister_component(&pdev->dev); + snd_sof_fw_unload(sdev); + snd_sof_ipc_free(sdev); + snd_sof_free_debug(sdev); + snd_sof_free_trace(sdev); + snd_sof_remove(sdev); + return 0; +} + +void snd_sof_shutdown(struct device *dev) +{ +} +EXPORT_SYMBOL(snd_sof_shutdown); + +static struct platform_driver sof_driver = { + .driver = { + .name = "sof-audio", + }, + + .probe = sof_probe, + .remove = sof_remove, +}; +module_platform_driver(sof_driver); + +MODULE_AUTHOR("Liam Girdwood"); +MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("platform:sof-audio"); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h new file mode 100644 index 00000000000000..47329893fd25fc --- /dev/null +++ b/sound/soc/sof/sof-priv.h @@ -0,0 +1,546 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __SOUND_SOC_SOF_PRIV_H +#define __SOUND_SOC_SOF_PRIV_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* debug flags */ +#define SOF_DBG_REGS BIT(1) +#define SOF_DBG_MBOX BIT(2) +#define SOF_DBG_TEXT BIT(3) +#define SOF_DBG_PCI BIT(4) + +/* max BARs mmaped devices can use */ +#define SND_SOF_BARS 8 + +/* time in ms for runtime suspend delay */ +#define SND_SOF_SUSPEND_DELAY 2000 + +/* DMA buffer size for trace */ +#define DMA_BUF_SIZE_FOR_TRACE (PAGE_SIZE * 16) + +/* max number of FE PCMs before BEs */ +#define SOF_BE_PCM_BASE 16 + +#define SOF_IPC_DSP_REPLY 0 +#define SOF_IPC_HOST_REPLY 1 + +/* convenience constructor for DAI driver streams */ +#define SOF_DAI_STREAM(sname, scmin, scmax, srates, sfmt) \ + {.stream_name = sname, .channels_min = scmin, .channels_max = scmax, \ + .rates = srates, .formats = sfmt} + +#define SOF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_FLOAT) + +struct snd_sof_dev; +struct snd_sof_ipc_msg; +struct snd_sof_ipc; +struct snd_sof_debugfs_map; +struct snd_soc_tplg_ops; +struct snd_soc_component; +struct sof_intel_hda_dev; +struct snd_sof_pdata; + +/* + * SOF DSP HW abstraction operations. + * Used to abstract DSP HW architecture and any IO busses between host CPU + * and DSP device(s). + */ +struct snd_sof_dsp_ops { + /* probe and remove */ + int (*remove)(struct snd_sof_dev *sof_dev); + int (*probe)(struct snd_sof_dev *sof_dev); + + /* DSP core boot / reset */ + int (*run)(struct snd_sof_dev *sof_dev); + int (*stall)(struct snd_sof_dev *sof_dev); + int (*reset)(struct snd_sof_dev *sof_dev); + + /* DSP PM */ + int (*suspend)(struct snd_sof_dev *sof_dev, int state); + int (*resume)(struct snd_sof_dev *sof_dev); + int (*runtime_suspend)(struct snd_sof_dev *sof_dev, int state); + int (*runtime_resume)(struct snd_sof_dev *sof_dev); + + /* DSP clocking */ + int (*set_clk)(struct snd_sof_dev *sof_dev, u32 freq); + + /* Register IO */ + void (*write)(struct snd_sof_dev *sof_dev, void __iomem *addr, + u32 value); + u32 (*read)(struct snd_sof_dev *sof_dev, void __iomem *addr); + void (*write64)(struct snd_sof_dev *sof_dev, void __iomem *addr, + u64 value); + u64 (*read64)(struct snd_sof_dev *sof_dev, void __iomem *addr); + + /* memcpy IO */ + void (*block_read)(struct snd_sof_dev *sof_dev, + u32 offset, void *dest, size_t size); + void (*block_write)(struct snd_sof_dev *sof_dev, + u32 offset, void *src, size_t size); + + /* doorbell */ + irqreturn_t (*irq_handler)(int irq, void *context); + irqreturn_t (*irq_thread)(int irq, void *context); + + /* mailbox */ + void (*mailbox_read)(struct snd_sof_dev *sof_dev, u32 offset, + void *addr, size_t bytes); + void (*mailbox_write)(struct snd_sof_dev *sof_dev, u32 offset, + void *addr, size_t bytes); + + /* ipc */ + int (*send_msg)(struct snd_sof_dev *sof_dev, + struct snd_sof_ipc_msg *msg); + int (*get_reply)(struct snd_sof_dev *sof_dev, + struct snd_sof_ipc_msg *msg); + int (*is_ready)(struct snd_sof_dev *sof_dev); + int (*cmd_done)(struct snd_sof_dev *sof_dev, int dir); + + /* debug */ + const struct snd_sof_debugfs_map *debug_map; + int debug_map_count; + void (*dbg_dump)(struct snd_sof_dev *sof_dev, u32 flags); + + /* connect pcm substream to a host stream */ + int (*pcm_open)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); + /* disconnect pcm substream to a host stream */ + int (*pcm_close)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); + + /* host stream hw params */ + int (*pcm_hw_params)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct sof_ipc_stream_params *ipc_params); + + /* host stream trigger */ + int (*pcm_trigger)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, int cmd); + + /* host stream pointer */ + snd_pcm_uframes_t (*pcm_pointer)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); + + /* FW loading */ + int (*load_firmware)(struct snd_sof_dev *sof_dev, + bool first_boot); + int (*load_module)(struct snd_sof_dev *sof_dev, + struct snd_sof_mod_hdr *hdr); + int (*fw_ready)(struct snd_sof_dev *sdev, u32 msg_id); + + /* host DMA trace initialization */ + int (*trace_init)(struct snd_sof_dev *sdev, u32 *stream_tag); + int (*trace_release)(struct snd_sof_dev *sdev); + int (*trace_trigger)(struct snd_sof_dev *sdev, int cmd); + + /* DAI ops */ + struct snd_soc_dai_driver *drv; + int num_drv; +}; + +/* DSP architecture specific callbacks for oops and stack dumps */ +struct sof_arch_ops { + void (*dsp_oops)(struct snd_sof_dev *sdev, void *oops); + void (*dsp_stack)(struct snd_sof_dev *sdev, void *oops, + u32 *stack, u32 stack_words); +}; + +/* DSP device HW descriptor mapping between bus ID and ops */ +struct sof_ops_table { + const struct sof_dev_desc *desc; + struct snd_sof_dsp_ops *ops; + struct platform_device *(*new_data)(struct snd_sof_pdata *pdata); +}; + +/* FS entry for debug files that can expose DSP memories, registers */ +struct snd_sof_dfsentry_io { + struct dentry *dfsentry; + size_t size; + void __iomem *buf; + struct snd_sof_dev *sdev; +}; + +struct snd_sof_dfsentry_buf { + struct dentry *dfsentry; + size_t size; + void *buf; + struct snd_sof_dev *sdev; +}; + +/* Debug mapping for any DSP memory or registers that can used for debug */ +struct snd_sof_debugfs_map { + const char *name; + u32 bar; + u32 offset; + u32 size; +}; + +/* mailbox descriptor, used for host <-> DSP IPC */ +struct snd_sof_mailbox { + u32 offset; + size_t size; +}; + +/* IPC message descriptor for host <-> DSP IO */ +struct snd_sof_ipc_msg { + struct list_head list; + + /* message data */ + u32 header; + void *msg_data; + void *reply_data; + size_t msg_size; + size_t reply_size; + + wait_queue_head_t waitq; + bool complete; +}; + +/* PCM stream, mapped to FW component */ +struct snd_sof_pcm_stream { + u32 comp_id; + struct snd_dma_buffer page_table; + struct sof_ipc_stream_posn posn; + struct snd_pcm_substream *substream; +}; + +/* ASLA SOF PCM device */ +struct snd_sof_pcm { + struct snd_sof_dev *sdev; + struct snd_soc_tplg_pcm pcm; + struct snd_sof_pcm_stream stream[2]; + u32 posn_offset[2]; + struct mutex mutex; /* access mutex */ + struct list_head list; /* list in sdev pcm list */ + struct snd_pcm_hw_params params[2]; + int restore_stream[2]; /* restore hw_params for paused stream */ +}; + +/* ALSA SOF Kcontrol device */ +struct snd_sof_control { + struct snd_sof_dev *sdev; + int comp_id; + int num_channels; + u32 readback_offset; /* offset to mmaped data if used */ + struct sof_ipc_ctrl_data *control_data; + u32 size; /* cdata size */ + enum sof_ipc_ctrl_cmd cmd; + + struct mutex mutex; /* access mutex */ + struct list_head list; /* list in sdev control list */ +}; + +/* ASoC SOF DAPM widget */ +struct snd_sof_widget { + struct snd_sof_dev *sdev; + int comp_id; + int pipeline_id; + int complete; + int id; + + struct snd_soc_dapm_widget *widget; + struct mutex mutex; /* access mutex */ + struct list_head list; /* list in sdev widget list */ + + void *private; /* core does not touch this */ +}; + +/* ASoC SOF DAPM route */ +struct snd_sof_route { + struct snd_sof_dev *sdev; + + struct snd_soc_dapm_route route; + struct list_head list; /* list in sdev route list */ + + void *private; +}; + +/* ASoC DAI device */ +struct snd_sof_dai { + struct snd_sof_dev *sdev; + const char *name; + + struct sof_ipc_comp_dai comp_dai; + struct sof_ipc_dai_config dai_config; + struct list_head list; /* list in sdev dai list */ +}; + +/* + * SOF Device Level. + */ +struct snd_sof_dev { + struct device *dev; + struct device *parent; + spinlock_t ipc_lock; /* lock for IPC users */ + spinlock_t hw_lock; /* lock for HW IO access */ + struct pci_dev *pci; + + /* ASoC components */ + struct snd_soc_component_driver plat_drv; + + /* DSP firmware boot */ + wait_queue_head_t boot_wait; + bool boot_complete; + + /* DSP HW differentiation */ + struct snd_sof_pdata *pdata; + const struct snd_sof_dsp_ops *ops; + struct sof_intel_hda_dev *hda; /* for HDA based DSP HW */ + const struct sof_arch_ops *arch_ops; + + /* IPC */ + struct snd_sof_ipc *ipc; + struct snd_sof_mailbox dsp_box; /* DSP initiated IPC */ + struct snd_sof_mailbox host_box; /* Host initiated IPC */ + struct snd_sof_mailbox stream_box; /* Stream position update */ + u64 irq_status; + int ipc_irq; + u32 next_comp_id; /* monotonic - reset during S3 */ + + /* memory bases for mmaped DSPs - set by dsp_init() */ + void __iomem *bar[SND_SOF_BARS]; /* DSP base address */ + int mmio_bar; + int mailbox_bar; + size_t dsp_oops_offset; + + /* debug */ + struct dentry *debugfs_root; + + /* firmware loader */ + int cl_bar; + struct snd_dma_buffer dmab; + struct snd_dma_buffer dmab_bdl; + struct sof_ipc_fw_ready fw_ready; + + /* topology */ + struct snd_soc_tplg_ops *tplg_ops; + struct list_head pcm_list; + struct list_head kcontrol_list; + struct list_head widget_list; + struct list_head dai_list; + struct list_head route_list; + struct snd_soc_component *component; + + /* FW configuration */ + struct sof_ipc_dma_buffer_data *info_buffer; + struct sof_ipc_window *info_window; + + /* IPC timeouts in ms */ + int ipc_timeout; + int boot_timeout; + + /* Wait queue for code loading */ + wait_queue_head_t waitq; + int code_loading; + + /* DMA for Trace */ + struct snd_dma_buffer dmatb; + struct snd_dma_buffer dmatp; + int dma_trace_pages; + wait_queue_head_t trace_sleep; + u32 host_offset; + bool dtrace_is_enabled; + + /* PM */ + bool restore_kcontrols; /* restore kcontrols upon resume */ + bool first_boot; + + void *private; /* core does not touch this */ +}; + +#define sof_to_bus(s) (&(s)->hda->hbus.core) +#define sof_to_hbus(s) (&(s)->hda->hbus) + +/* + * SOF platform private struct used as drvdata of + * platform dev (e.g. pci/acpi/spi...) drvdata. + */ +struct sof_platform_priv { + struct snd_sof_pdata *sof_pdata; + struct platform_device *pdev_pcm; +}; + +/* + * Device Level. + */ +void snd_sof_shutdown(struct device *dev); +int snd_sof_runtime_suspend(struct device *dev); +int snd_sof_runtime_resume(struct device *dev); +int snd_sof_resume(struct device *dev); +int snd_sof_suspend(struct device *dev); +int snd_sof_prepare(struct device *dev); +int snd_sof_suspend_late(struct device *dev); + +void snd_sof_new_platform_drv(struct snd_sof_dev *sdev); + +int snd_sof_create_page_table(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab, + unsigned char *page_table, size_t size); + +/* + * Firmware loading. + */ +int snd_sof_load_firmware(struct snd_sof_dev *sdev, + bool first_boot); +int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev, + bool first_boot); +int snd_sof_run_firmware(struct snd_sof_dev *sdev); +int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, + struct snd_sof_mod_hdr *module); +void snd_sof_fw_unload(struct snd_sof_dev *sdev); +int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset); + +/* + * IPC low level APIs. + */ +struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev); +void snd_sof_ipc_free(struct snd_sof_dev *sdev); +int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id); +void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev); +void snd_sof_ipc_msgs_tx(struct snd_sof_dev *sdev); +int snd_sof_ipc_stream_pcm_params(struct snd_sof_dev *sdev, + struct sof_ipc_pcm_params *params); +int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox, + size_t dspbox_size, u32 hostbox, + size_t hostbox_size); +int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, void *tx_data, + size_t tx_bytes, void *rx_data, size_t rx_bytes); +struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev, + char *name); +struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev, + char *name); +struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_sof_dev *sdev, + struct snd_soc_pcm_runtime *rtd); +struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev, + char *name); +struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev, + unsigned int comp_id, + int *direction); +struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev, + unsigned int pcm_id); +void sof_ipc_drop_all(struct snd_sof_ipc *ipc); + +/* + * Stream IPC + */ +int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev, + struct snd_sof_pcm *spcm, int direction, + struct sof_ipc_stream_posn *posn); + +/* + * Mixer IPC + */ +int snd_sof_ipc_set_comp_data(struct snd_sof_ipc *ipc, + struct snd_sof_control *scontrol, u32 ipc_cmd, + enum sof_ipc_ctrl_type ctrl_type, + enum sof_ipc_ctrl_cmd ctrl_cmd); +int snd_sof_ipc_get_comp_data(struct snd_sof_ipc *ipc, + struct snd_sof_control *scontrol, u32 ipc_cmd, + enum sof_ipc_ctrl_type ctrl_type, + enum sof_ipc_ctrl_cmd ctrl_cmd); + +/* + * Topology. + */ +int snd_sof_init_topology(struct snd_sof_dev *sdev, + struct snd_soc_tplg_ops *ops); +int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file); +void snd_sof_free_topology(struct snd_sof_dev *sdev); +int snd_sof_complete_pipeline(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget); + +/* + * Trace/debug + */ +int snd_sof_init_trace(struct snd_sof_dev *sdev); +void snd_sof_release_trace(struct snd_sof_dev *sdev); +void snd_sof_free_trace(struct snd_sof_dev *sdev); +int snd_sof_dbg_init(struct snd_sof_dev *sdev); +void snd_sof_free_debug(struct snd_sof_dev *sdev); +int snd_sof_debugfs_create_item(struct snd_sof_dev *sdev, + void __iomem *base, size_t size, + const char *name); +int snd_sof_trace_update_pos(struct snd_sof_dev *sdev, + struct sof_ipc_dma_trace_posn *posn); +void snd_sof_trace_notify_for_error(struct snd_sof_dev *sdev); +int snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, + u32 tracep_code, void *oops, + struct sof_ipc_panic_info *panic_info, + void *stack, size_t stack_size); +int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev); + +/* + * Platform specific ops. + */ +extern struct snd_compr_ops sof_compressed_ops; + +/* + * Kcontrols. + */ + +int snd_sof_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, + const unsigned int __user *bytes, + unsigned int size); +int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, + unsigned int __user *bytes, + unsigned int size); + +/* + * DSP Architectures. + */ +static inline void sof_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack, + u32 stack_words) +{ + if (sdev->arch_ops->dsp_stack) + sdev->arch_ops->dsp_stack(sdev, oops, stack, stack_words); +} + +static inline void sof_oops(struct snd_sof_dev *sdev, void *oops) +{ + if (sdev->arch_ops->dsp_oops) + sdev->arch_ops->dsp_oops(sdev, oops); +} + +extern const struct sof_arch_ops sof_xtensa_arch_ops; + +/* + * Utilities + */ +int sof_create_platform_device(struct sof_platform_priv *priv); +#endif From d9e001df59776c7b10b9c192c0ab705319d46d1b Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:31:31 +0000 Subject: [PATCH 0092/1995] ASoC: SOF: Add Sound Open Firmware KControl support SOF exposes regular ALSA Kcontrols that are defined by topology. This patch converts the Kcontrol IO to DSP IPC. Signed-off-by: Liam Girdwood --- sound/soc/sof/control.c | 408 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 408 insertions(+) create mode 100644 sound/soc/sof/control.c diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c new file mode 100644 index 00000000000000..7b72361c3baee1 --- /dev/null +++ b/sound/soc/sof/control.c @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +/* Mixer Controls */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "sof-priv.h" + +static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size) +{ + if (value >= size) + return volume_map[size - 1]; + else + return volume_map[value]; +} + +static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (volume_map[i] >= value) + return i; + } + + return i - 1; +} + +int snd_sof_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *sm = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_sof_control *scontrol = sm->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + unsigned int i, channels = scontrol->num_channels; + int err, ret; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "error: volume get failed to resume %d\n", + ret); + return ret; + } + + /* get all the mixer data from DSP */ + snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_VOLUME); + + /* read back each channel */ + for (i = 0; i < channels; i++) + ucontrol->value.integer.value[i] = + ipc_to_mixer(cdata->chanv[i].value, + scontrol->volume_table, sm->max + 1); + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err(sdev->dev, "error: volume get failed to idle %d\n", + err); + return 0; +} + +int snd_sof_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *sm = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_sof_control *scontrol = sm->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + unsigned int i, channels = scontrol->num_channels; + int ret, err; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "error: volume put failed to resume %d\n", + ret); + return ret; + } + + /* update each channel */ + for (i = 0; i < channels; i++) { + cdata->chanv[i].value = + mixer_to_ipc(ucontrol->value.integer.value[i], + scontrol->volume_table, sm->max + 1); + cdata->chanv[i].channel = i; + } + + /* notify DSP of mixer updates */ + snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_VOLUME); + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err(sdev->dev, "error: volume put failed to idle %d\n", + err); + return 0; +} + +int snd_sof_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *se = + (struct soc_enum *)kcontrol->private_value; + struct snd_sof_control *scontrol = se->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + unsigned int i, channels = scontrol->num_channels; + int err, ret; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "error: enum get failed to resume %d\n", + ret); + return ret; + } + + /* get all the mixer data from DSP */ + snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_ENUM); + + /* read back each channel */ + for (i = 0; i < channels; i++) + ucontrol->value.integer.value[i] = cdata->chanv[i].value; + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err(sdev->dev, "error: enum get failed to idle %d\n", + ret); + return 0; +} + +int snd_sof_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *se = + (struct soc_enum *)kcontrol->private_value; + struct snd_sof_control *scontrol = se->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + unsigned int i, channels = scontrol->num_channels; + int ret, err; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "error: enum put failed to resume %d\n", + ret); + return ret; + } + + /* update each channel */ + for (i = 0; i < channels; i++) + cdata->chanv[i].value = ucontrol->value.integer.value[i]; + + /* notify DSP of mixer updates */ + snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_SET, + SOF_CTRL_CMD_ENUM); + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err(sdev->dev, "error: enum put failed to idle %d\n", + err); + return 0; +} + +int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_bytes_ext *be = + (struct soc_bytes_ext *)kcontrol->private_value; + struct snd_sof_control *scontrol = be->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct sof_abi_hdr *data = cdata->data; + size_t size; + int ret, err; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "error: bytes get failed to resume %d\n", + ret); + return ret; + } + + /* get all the mixer data from DSP */ + snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_DATA, + SOF_CTRL_TYPE_DATA_GET, scontrol->cmd); + size = data->size + sizeof(*data); + if (size > be->max) { + dev_err(sdev->dev, "error: DSP sent %zu bytes max is %d\n", + size, be->max); + ret = -EINVAL; + goto out; + } + + /* copy back to kcontrol */ + memcpy(ucontrol->value.bytes.data, data, size); + +out: + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err(sdev->dev, "error: bytes get failed to idle %d\n", + err); + return ret; +} + +int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_bytes_ext *be = + (struct soc_bytes_ext *)kcontrol->private_value; + struct snd_sof_control *scontrol = be->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct sof_abi_hdr *data = cdata->data; + int ret, err; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "error: bytes put failed to resume %d\n", + ret); + return ret; + } + + if (data->size > be->max) { + dev_err(sdev->dev, "error: size too big %d bytes max is %d\n", + data->size, be->max); + ret = -EINVAL; + goto out; + } + + /* copy from kcontrol */ + memcpy(data, ucontrol->value.bytes.data, data->size); + + /* notify DSP of mixer updates */ + snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_DATA, + SOF_CTRL_TYPE_DATA_SET, scontrol->cmd); + +out: + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err(sdev->dev, "error: volume get failed to idle %d\n", + err); + return ret; +} + +int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, + const unsigned int __user *binary_data, + unsigned int size) +{ + struct soc_bytes_ext *be = + (struct soc_bytes_ext *)kcontrol->private_value; + struct snd_sof_control *scontrol = be->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct snd_ctl_tlv header; + struct snd_ctl_tlv *tlvd = (struct snd_ctl_tlv *)binary_data; + int ret; + int err; + int max_length = SOF_IPC_MSG_MAX_SIZE - + sizeof(const struct sof_ipc_ctrl_data) - + sizeof(const struct sof_abi_hdr); + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "error: bytes put failed to resume %d\n", + ret); + return ret; + } + + /* The beginning of bytes data contains a header from where + * the length (as bytes) is needed to know the correct copy + * length of data from tlvd->tlv. + */ + if (copy_from_user(&header, tlvd, sizeof(const struct snd_ctl_tlv))) + return -EFAULT; + + /* The maximum length that can be copied is limited by IPC max + * length and topology defined length for ext bytes control. + */ + if (max_length > be->max) + max_length = be->max; + + dev_dbg(sdev->dev, "size of bytes put data is %d, max is %d\n", + header.length, max_length); + if (header.length > max_length) { + dev_err(sdev->dev, "error: size is too large\n"); + ret = -EINVAL; + goto out; + } + + /* Check that header id matches the command */ + if (header.numid != scontrol->cmd) { + dev_err(sdev->dev, "error: incorred numid %d\n", header.numid); + ret = -EINVAL; + goto out; + } + + if (copy_from_user(cdata->data->data, tlvd->tlv, header.length)) + return -EFAULT; + + /* set the ABI header values */ + cdata->data->magic = SOF_ABI_MAGIC; + cdata->data->abi = SOF_ABI_VERSION; + cdata->data->comp_abi = SOF_ABI_VERSION; + + /* notify DSP of mixer updates */ + snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_DATA, + SOF_CTRL_TYPE_DATA_SET, scontrol->cmd); + +out: + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err(sdev->dev, "error: failed to idle %d\n", err); + + return ret; +} + +int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, + unsigned int __user *binary_data, + unsigned int size) +{ + struct soc_bytes_ext *be = + (struct soc_bytes_ext *)kcontrol->private_value; + struct snd_sof_control *scontrol = be->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct snd_ctl_tlv header; + struct snd_ctl_tlv *tlvd = (struct snd_ctl_tlv *)binary_data; + int max_length = SOF_IPC_MSG_MAX_SIZE - + sizeof(const struct sof_ipc_ctrl_data) - + sizeof(const struct sof_abi_hdr); + int ret; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "error: bytes get failed to resume %d\n", + ret); + return ret; + } + + /* Decrement size to fit the ext bytes header and get the the + * upper limit from ext bytes control size from topology and + * SOF IPC max. size limit. + */ + size -= sizeof(const struct snd_ctl_tlv); + if (max_length > be->max) + max_length = be->max; + + dev_dbg(sdev->dev, "request size minus header is %d\n", size); + dev_dbg(sdev->dev, "max size is %d\n", max_length); + + /* Prevent read of other kernel data */ + if (size > max_length) { + dev_err(sdev->dev, "error: size is too large\n"); + ret = -EINVAL; + goto out; + } + + /* set the ABI header values */ + cdata->data->magic = SOF_ABI_MAGIC; + cdata->data->abi = SOF_ABI_VERSION; + cdata->data->comp_abi = SOF_ABI_VERSION; + + /* get all the component data from DSP */ + ret = snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_GET_DATA, + SOF_CTRL_TYPE_DATA_GET, scontrol->cmd); + + header.numid = scontrol->cmd; + header.length = size; + if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) + return -EFAULT; + + if (copy_to_user(tlvd->tlv, cdata->data->data, size)) + return -EFAULT; + +out: + pm_runtime_mark_last_busy(sdev->dev); + pm_runtime_put_autosuspend(sdev->dev); + return ret; +} From 1926564de35771ad5969f6e53c02c9773477320e Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:31:44 +0000 Subject: [PATCH 0093/1995] ASoC: SOF: Add driver debug support. Add debugFS files that can be used to expose DSP memories and and peripherals to userspace to assist with firmware debugging. Signed-off-by: Liam Girdwood --- sound/soc/sof/debug.c | 158 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 sound/soc/sof/debug.c diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c new file mode 100644 index 00000000000000..793d6ac3cf0fe5 --- /dev/null +++ b/sound/soc/sof/debug.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// Yan Wang +// +// Generic debug routines used to export DSP MMIO and memories to userspace +// for firmware debugging. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sof-priv.h" +#include "ops.h" + +static int sof_dfsentry_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + + return 0; +} + +static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct snd_sof_dfsentry_io *dfse = file->private_data; + struct snd_sof_dev *sdev = dfse->sdev; + int size, err; + u32 *buf; + loff_t pos = *ppos; + size_t ret; + + size = dfse->size; + + /* validate position & count */ + if (pos < 0) + return -EINVAL; + if (pos >= size || !count) + return 0; + if (count > size - pos) + count = size - pos; + + /* intermediate buffer size must be u32 multiple */ + size = (count + 3) & ~3; + buf = kzalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* copy from DSP MMIO */ + err = pm_runtime_get_sync(sdev->dev); + if (err < 0) { + dev_err(sdev->dev, "error: debugFS failed to resume %d\n", + err); + kfree(buf); + return err; + } + + memcpy_fromio(buf, dfse->buf + pos, size); + + ret = pm_runtime_put(sdev->dev); + if (ret < 0) + dev_err(sdev->dev, "error: debugFS failed to idle %zd\n", + ret); + + /* copy to userspace */ + ret = copy_to_user(buffer, buf, count); + kfree(buf); + + /* update count & position if copy succeeded */ + if (ret == count) + return -EFAULT; + count -= ret; + *ppos = pos + count; + + return count; +} + +static const struct file_operations sof_dfs_fops = { + .open = sof_dfsentry_open, + .read = sof_dfsentry_read, + .llseek = default_llseek, +}; + +int snd_sof_debugfs_create_item(struct snd_sof_dev *sdev, + void __iomem *base, size_t size, + const char *name) +{ + struct snd_sof_dfsentry_io *dfse; + + if (!sdev) + return -EINVAL; + + dfse = kzalloc(sizeof(*dfse), GFP_KERNEL); + if (!dfse) + return -ENOMEM; + + dfse->buf = base; + dfse->size = size; + dfse->sdev = sdev; + + dfse->dfsentry = debugfs_create_file(name, 0444, sdev->debugfs_root, + dfse, &sof_dfs_fops); + if (!dfse->dfsentry) { + dev_err(sdev->dev, "cannot create debugfs entry.\n"); + kfree(dfse); + return -ENODEV; + } + + return 0; +} +EXPORT_SYMBOL(snd_sof_debugfs_create_item); + +int snd_sof_dbg_init(struct snd_sof_dev *sdev) +{ + const struct snd_sof_dsp_ops *ops = sdev->ops; + const struct snd_sof_debugfs_map *map; + int err = 0, i; + + /* use "sof" as top level debugFS dir */ + sdev->debugfs_root = debugfs_create_dir("sof", NULL); + if (IS_ERR_OR_NULL(sdev->debugfs_root)) { + dev_err(sdev->dev, "error: failed to create debugfs directory\n"); + return -EINVAL; + } + + /* create debugFS files for platform specific MMIO/DSP memories */ + for (i = 0; i < ops->debug_map_count; i++) { + map = &ops->debug_map[i]; + + err = snd_sof_debugfs_create_item(sdev, sdev->bar[map->bar] + + map->offset, map->size, + map->name); + if (err < 0) + dev_err(sdev->dev, "cannot create debugfs for %s\n", + map->name); + } + + return err; +} +EXPORT_SYMBOL(snd_sof_dbg_init); + +void snd_sof_free_debug(struct snd_sof_dev *sdev) +{ + debugfs_remove_recursive(sdev->debugfs_root); +} +EXPORT_SYMBOL(snd_sof_free_debug); From 8f3b2f0dac7725748eab644fa12b538846865d30 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:32:12 +0000 Subject: [PATCH 0094/1995] ASoC: SOF: Add support for IPC IO between DSP and Host Define an IPC ABI for all host <--> DSP communication. This ABI should be transport agnostic. i.e. it should work on MMIO and SPI/I2C style interfaces. Signed-off-by: Liam Girdwood --- include/uapi/sound/sof-ipc.h | 991 +++++++++++++++++++++++++++++++++++ sound/soc/sof/ipc.c | 791 ++++++++++++++++++++++++++++ 2 files changed, 1782 insertions(+) create mode 100644 include/uapi/sound/sof-ipc.h create mode 100644 sound/soc/sof/ipc.c diff --git a/include/uapi/sound/sof-ipc.h b/include/uapi/sound/sof-ipc.h new file mode 100644 index 00000000000000..5b042079ea9595 --- /dev/null +++ b/include/uapi/sound/sof-ipc.h @@ -0,0 +1,991 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ + +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + * Keyon Jie + */ + +#ifndef __INCLUDE_UAPI_SOF_IPC_H__ +#define __INCLUDE_UAPI_SOF_IPC_H__ + +#include + +/* + * IPC messages have a prefixed 32 bit identifier made up as follows :- + * + * 0xGCCCNNNN where + * G is global cmd type (4 bits) + * C is command type (12 bits) + * I is the ID number (16 bits) - monotonic and overflows + * + * This is sent at the start of the IPM message in the mailbox. Messages should + * not be sent in the doorbell (special exceptions for firmware . + */ + +/* Global Message - Generic */ +#define SOF_GLB_TYPE_SHIFT 28 +#define SOF_GLB_TYPE_MASK (0xf << SOF_GLB_TYPE_SHIFT) +#define SOF_GLB_TYPE(x) ((x) << SOF_GLB_TYPE_SHIFT) + +/* Command Message - Generic */ +#define SOF_CMD_TYPE_SHIFT 16 +#define SOF_CMD_TYPE_MASK (0xfff << SOF_CMD_TYPE_SHIFT) +#define SOF_CMD_TYPE(x) ((x) << SOF_CMD_TYPE_SHIFT) + +/* Global Message Types */ +#define SOF_IPC_GLB_REPLY SOF_GLB_TYPE(0x1U) +#define SOF_IPC_GLB_COMPOUND SOF_GLB_TYPE(0x2U) +#define SOF_IPC_GLB_TPLG_MSG SOF_GLB_TYPE(0x3U) +#define SOF_IPC_GLB_PM_MSG SOF_GLB_TYPE(0x4U) +#define SOF_IPC_GLB_COMP_MSG SOF_GLB_TYPE(0x5U) +#define SOF_IPC_GLB_STREAM_MSG SOF_GLB_TYPE(0x6U) +#define SOF_IPC_FW_READY SOF_GLB_TYPE(0x7U) +#define SOF_IPC_GLB_DAI_MSG SOF_GLB_TYPE(0x8U) +#define SOF_IPC_GLB_TRACE_MSG SOF_GLB_TYPE(0x9U) + +/* + * DSP Command Message Types + */ + +/* topology */ +#define SOF_IPC_TPLG_COMP_NEW SOF_CMD_TYPE(0x001) +#define SOF_IPC_TPLG_COMP_FREE SOF_CMD_TYPE(0x002) +#define SOF_IPC_TPLG_COMP_CONNECT SOF_CMD_TYPE(0x003) +#define SOF_IPC_TPLG_PIPE_NEW SOF_CMD_TYPE(0x010) +#define SOF_IPC_TPLG_PIPE_FREE SOF_CMD_TYPE(0x011) +#define SOF_IPC_TPLG_PIPE_CONNECT SOF_CMD_TYPE(0x012) +#define SOF_IPC_TPLG_PIPE_COMPLETE SOF_CMD_TYPE(0x013) +#define SOF_IPC_TPLG_BUFFER_NEW SOF_CMD_TYPE(0x020) +#define SOF_IPC_TPLG_BUFFER_FREE SOF_CMD_TYPE(0x021) + +/* PM */ +#define SOF_IPC_PM_CTX_SAVE SOF_CMD_TYPE(0x001) +#define SOF_IPC_PM_CTX_RESTORE SOF_CMD_TYPE(0x002) +#define SOF_IPC_PM_CTX_SIZE SOF_CMD_TYPE(0x003) +#define SOF_IPC_PM_CLK_SET SOF_CMD_TYPE(0x004) +#define SOF_IPC_PM_CLK_GET SOF_CMD_TYPE(0x005) +#define SOF_IPC_PM_CLK_REQ SOF_CMD_TYPE(0x006) +#define SOF_IPC_PM_CORE_ENABLE SOF_CMD_TYPE(0x007) + +/* component runtime config - multiple different types */ +#define SOF_IPC_COMP_SET_VALUE SOF_CMD_TYPE(0x001) +#define SOF_IPC_COMP_GET_VALUE SOF_CMD_TYPE(0x002) +#define SOF_IPC_COMP_SET_DATA SOF_CMD_TYPE(0x003) +#define SOF_IPC_COMP_GET_DATA SOF_CMD_TYPE(0x004) + +/* DAI messages */ +#define SOF_IPC_DAI_CONFIG SOF_CMD_TYPE(0x001) +#define SOF_IPC_DAI_LOOPBACK SOF_CMD_TYPE(0x002) + +/* stream */ +#define SOF_IPC_STREAM_PCM_PARAMS SOF_CMD_TYPE(0x001) +#define SOF_IPC_STREAM_PCM_PARAMS_REPLY SOF_CMD_TYPE(0x002) +#define SOF_IPC_STREAM_PCM_FREE SOF_CMD_TYPE(0x003) +#define SOF_IPC_STREAM_TRIG_START SOF_CMD_TYPE(0x004) +#define SOF_IPC_STREAM_TRIG_STOP SOF_CMD_TYPE(0x005) +#define SOF_IPC_STREAM_TRIG_PAUSE SOF_CMD_TYPE(0x006) +#define SOF_IPC_STREAM_TRIG_RELEASE SOF_CMD_TYPE(0x007) +#define SOF_IPC_STREAM_TRIG_DRAIN SOF_CMD_TYPE(0x008) +#define SOF_IPC_STREAM_TRIG_XRUN SOF_CMD_TYPE(0x009) +#define SOF_IPC_STREAM_POSITION SOF_CMD_TYPE(0x00a) +#define SOF_IPC_STREAM_VORBIS_PARAMS SOF_CMD_TYPE(0x010) +#define SOF_IPC_STREAM_VORBIS_FREE SOF_CMD_TYPE(0x011) + +/* trace and debug */ +#define SOF_IPC_TRACE_DMA_PARAMS SOF_CMD_TYPE(0x001) +#define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002) + +/* Get message component id */ +#define SOF_IPC_MESSAGE_ID(x) ((x) & 0xffff) + +/* maximum message size for mailbox Tx/Rx */ +#define SOF_IPC_MSG_MAX_SIZE 384 + +/* + * SOF panic codes + */ +#define SOF_IPC_PANIC_MAGIC 0x0dead000 +#define SOF_IPC_PANIC_MAGIC_MASK 0x0ffff000 +#define SOF_IPC_PANIC_CODE_MASK 0x00000fff +#define SOF_IPC_PANIC_MEM (SOF_IPC_PANIC_MAGIC | 0x0) +#define SOF_IPC_PANIC_WORK (SOF_IPC_PANIC_MAGIC | 0x1) +#define SOF_IPC_PANIC_IPC (SOF_IPC_PANIC_MAGIC | 0x2) +#define SOF_IPC_PANIC_ARCH (SOF_IPC_PANIC_MAGIC | 0x3) +#define SOF_IPC_PANIC_PLATFORM (SOF_IPC_PANIC_MAGIC | 0x4) +#define SOF_IPC_PANIC_TASK (SOF_IPC_PANIC_MAGIC | 0x5) +#define SOF_IPC_PANIC_EXCEPTION (SOF_IPC_PANIC_MAGIC | 0x6) +#define SOF_IPC_PANIC_DEADLOCK (SOF_IPC_PANIC_MAGIC | 0x7) +#define SOF_IPC_PANIC_STACK (SOF_IPC_PANIC_MAGIC | 0x8) +#define SOF_IPC_PANIC_IDLE (SOF_IPC_PANIC_MAGIC | 0x9) +#define SOF_IPC_PANIC_WFI (SOF_IPC_PANIC_MAGIC | 0xa) + +/* + * SOF memory capabilities, add new ones at the end + */ +#define SOF_MEM_CAPS_RAM (1 << 0) +#define SOF_MEM_CAPS_ROM (1 << 1) +#define SOF_MEM_CAPS_EXT (1 << 2) /* external */ +#define SOF_MEM_CAPS_LP (1 << 3) /* low power */ +#define SOF_MEM_CAPS_HP (1 << 4) /* high performance */ +#define SOF_MEM_CAPS_DMA (1 << 5) /* DMA'able */ +#define SOF_MEM_CAPS_CACHE (1 << 6) /* cacheable */ +#define SOF_MEM_CAPS_EXEC (1 << 7) /* executable */ + +/* + * Command Header - Header for all IPC. Identifies IPC message. + * The size can be greater than the structure size and that means there is + * extended bespoke data beyond the end of the structure including variable + * arrays. + */ + +struct sof_ipc_hdr { + uint32_t cmd; /* SOF_IPC_GLB_ + cmd */ + uint32_t size; /* size of structure */ +} __attribute__((packed)); + +/* + * Generic reply message. Some commands override this with their own reply + * types that must include this at start. + */ +struct sof_ipc_reply { + struct sof_ipc_hdr hdr; + int32_t error; /* negative error numbers */ +} __attribute__((packed)); + +/* + * Compound commands - SOF_IPC_GLB_COMPOUND. + * + * Compound commands are sent to the DSP as a single IPC operation. The + * commands are split into blocks and each block has a header. This header + * identifies the command type and the number of commands before the next + * header. + */ + +struct sof_ipc_compound_hdr { + struct sof_ipc_hdr hdr; + uint32_t count; /* count of 0 means end of compound sequence */ +} __attribute__((packed)); + +/* + * DAI Configuration. + * + * Each different DAI type will have it's own structure and IPC cmd. + */ + +#define SOF_DAI_FMT_I2S 1 /* I2S mode */ +#define SOF_DAI_FMT_RIGHT_J 2 /* Right Justified mode */ +#define SOF_DAI_FMT_LEFT_J 3 /* Left Justified mode */ +#define SOF_DAI_FMT_DSP_A 4 /* L data MSB after FRM LRC */ +#define SOF_DAI_FMT_DSP_B 5 /* L data MSB during FRM LRC */ +#define SOF_DAI_FMT_PDM 6 /* Pulse density modulation */ + +#define SOF_DAI_FMT_CONT (1 << 4) /* continuous clock */ +#define SOF_DAI_FMT_GATED (0 << 4) /* clock is gated */ + +#define SOF_DAI_FMT_NB_NF (0 << 8) /* normal bit clock + frame */ +#define SOF_DAI_FMT_NB_IF (2 << 8) /* normal BCLK + inv FRM */ +#define SOF_DAI_FMT_IB_NF (3 << 8) /* invert BCLK + nor FRM */ +#define SOF_DAI_FMT_IB_IF (4 << 8) /* invert BCLK + FRM */ + +#define SOF_DAI_FMT_CBM_CFM (0 << 12) /* codec clk & FRM master */ +#define SOF_DAI_FMT_CBS_CFM (2 << 12) /* codec clk slave & FRM master */ +#define SOF_DAI_FMT_CBM_CFS (3 << 12) /* codec clk master & frame slave */ +#define SOF_DAI_FMT_CBS_CFS (4 << 12) /* codec clk & FRM slave */ + +#define SOF_DAI_FMT_FORMAT_MASK 0x000f +#define SOF_DAI_FMT_CLOCK_MASK 0x00f0 +#define SOF_DAI_FMT_INV_MASK 0x0f00 +#define SOF_DAI_FMT_MASTER_MASK 0xf000 + + /* ssc1: TINTE */ +#define SOF_DAI_INTEL_SSP_QUIRK_TINTE (1 << 0) + /* ssc1: PINTE */ +#define SOF_DAI_INTEL_SSP_QUIRK_PINTE (1 << 1) + /* ssc2: SMTATF */ +#define SOF_DAI_INTEL_SSP_QUIRK_SMTATF (1 << 2) + /* ssc2: MMRATF */ +#define SOF_DAI_INTEL_SSP_QUIRK_MMRATF (1 << 3) + /* ssc2: PSPSTWFDFD */ +#define SOF_DAI_INTEL_SSP_QUIRK_PSPSTWFDFD (1 << 4) + /* ssc2: PSPSRWFDFD */ +#define SOF_DAI_INTEL_SSP_QUIRK_PSPSRWFDFD (1 << 5) + /* here is the possibility to define others aux macros */ + +#define SOF_DAI_INTEL_SSP_FRAME_PULSE_WIDTH_MAX 38 +#define SOF_DAI_INTEL_SSP_SLOT_PADDING_MAX 31 + +/* SSP clocks control settings + * + * Macros for clks_control field in sof_ipc_dai_ssp_params struct. + */ + +/* mclk 0 disable */ +#define SOF_DAI_INTEL_SSP_MCLK_0_DISABLE BIT(0) +/* mclk 1 disable */ +#define SOF_DAI_INTEL_SSP_MCLK_1_DISABLE BIT(1) +/* mclk keep active */ +#define SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_KA BIT(2) +/* bclk keep active */ +#define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_KA BIT(3) +/* fs keep active */ +#define SOF_DAI_INTEL_SSP_CLKCTRL_FS_KA BIT(4) +/* bclk idle */ +#define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_IDLE_HIGH BIT(5) + +/** \brief Types of DAI */ +enum sof_ipc_dai_type { + SOF_DAI_INTEL_NONE = 0, /**< None */ + SOF_DAI_INTEL_SSP, /**< Intel SSP */ + SOF_DAI_INTEL_DMIC, /**< Intel DMIC */ + SOF_DAI_INTEL_HDA, /**< Intel HD/A */ +}; + +/* SSP Configuration Request - SOF_IPC_DAI_SSP_CONFIG */ +struct sof_ipc_dai_ssp_params { + uint16_t mode; // FIXME: do we need this? + uint16_t mclk_id; + + uint32_t mclk_rate; /* mclk frequency in Hz */ + uint32_t fsync_rate; /* fsync frequency in Hz */ + uint32_t bclk_rate; /* bclk frequency in Hz */ + + /* TDM */ + uint32_t tdm_slots; + uint32_t rx_slots; + uint32_t tx_slots; + + /* data */ + uint32_t sample_valid_bits; + uint16_t tdm_slot_width; + uint16_t reserved2; /* alignment */ + + /* MCLK */ + uint32_t mclk_direction; + + uint16_t frame_pulse_width; + uint16_t tdm_per_slot_padding_flag; + uint32_t clks_control; + uint32_t quirks; // FIXME: is 32 bits enough ? + /* private data, e.g. for quirks */ + //uint32_t pdata[10]; // FIXME: would really need ~16 u32 +} __attribute__((packed)); + +/* HDA Configuration Request - SOF_IPC_DAI_HDA_CONFIG */ +struct sof_ipc_dai_hda_params { + struct sof_ipc_hdr hdr; + /* TODO */ +} __attribute__((packed)); + +/* DMIC Configuration Request - SOF_IPC_DAI_DMIC_CONFIG */ + +/* This struct is defined per 2ch PDM controller available in the platform. + * Normally it is sufficient to set the used microphone specific enables to 1 + * and keep other parameters as zero. The customizations are: + * + * 1. If a device mixes different microphones types with different polarity + * and/or the absolute polarity matters the PCM signal from a microphone + * can be inverted with the controls. + * + * 2. If the microphones in a stereo pair do not appear in captured stream + * in desired order due to board schematics choises they can be swapped with + * the clk_edge parameter. + * + * 3. If PDM bit errors are seen in capture (poor quality) the skew parameter + * that delays the sampling time of data by half cycles of DMIC source clock + * can be tried for improvement. However there is no guarantee for this to fix + * data integrity problems. + */ +struct sof_ipc_dai_dmic_pdm_ctrl { + uint16_t id; /* PDM controller ID */ + uint16_t enable_mic_a; /* Use A (left) channel mic (0 or 1)*/ + uint16_t enable_mic_b; /* Use B (right) channel mic (0 or 1)*/ + uint16_t polarity_mic_a; /* Optionally invert mic A signal (0 or 1) */ + uint16_t polarity_mic_b; /* Optionally invert mic B signal (0 or 1) */ + uint16_t clk_edge; /* Optionally swap data clock edge (0 or 1) */ + uint16_t skew; /* Adjust PDM data sampling vs. clock (0..15) */ + uint16_t pad; /* Make sure the total size is 4 bytes aligned */ +} __attribute__((packed)); + +/* This struct contains the global settings for all 2ch PDM controllers. The + * version number used in configuration data is checked vs. version used by + * device driver src/drivers/dmic.c need to match. It is incremented from + * initial value 1 if updates done for the to driver would alter the operation + * of the microhone. + * + * Note: The microphone clock (pdmclk_min, pdmclk_max, duty_min, duty_max) + * parameters need to be set as defined in microphone data sheet. E.g. clock + * range 1.0 - 3.2 MHz is usually supported microphones. Some microphones are + * multi-mode capable and there may be denied mic clock frequencies between + * the modes. In such case set the clock range limits of the desired mode to + * avoid the driver to set clock to an illegal rate. + * + * The duty cycle could be set to 48-52% if not known. Generally these + * parameters can be altered within data sheet specified limits to match + * required audio application performance power. + * + * The microphone clock needs to be usually about 50-80 times the used audio + * sample rate. With highest sample rates above 48 kHz this can relaxed + * somewhat. + */ +struct sof_ipc_dai_dmic_params { + uint32_t driver_ipc_version; /* Version (1..N) */ + uint32_t pdmclk_min; /* Minimum microphone clock in Hz (100000..N) */ + uint32_t pdmclk_max; /* Maximum microphone clock in Hz (min...N) */ + uint32_t fifo_fs_a; /* FIFO A sample rate in Hz (8000..96000) */ + uint32_t fifo_fs_b; /* FIFO B sample rate in Hz (8000..96000) */ + uint16_t fifo_bits_a; /* FIFO A word length (16 or 32) */ + uint16_t fifo_bits_b; /* FIFO B word length (16 or 32) */ + uint16_t duty_min; /* Min. mic clock duty cycle in % (20..80) */ + uint16_t duty_max; /* Max. mic clock duty cycle in % (min..80) */ + uint32_t num_pdm_active; /* Number of active pdm controllers */ + /* variable number of pdm controller config */ + struct sof_ipc_dai_dmic_pdm_ctrl pdm[0]; +} __attribute__((packed)); + +/* general purpose DAI configuration */ +struct sof_ipc_dai_config { + struct sof_ipc_hdr hdr; + enum sof_ipc_dai_type type; + uint32_t dai_index; /* index of this type dai */ + + /* physical protocol and clocking */ + uint16_t format; /* SOF_DAI_FMT_ */ + uint16_t reserved; /* alignment */ + + /* HW specific data */ + union { + struct sof_ipc_dai_ssp_params ssp; + struct sof_ipc_dai_hda_params hda; + struct sof_ipc_dai_dmic_params dmic; + }; +}; + +/* + * Stream configuration. + */ + +#define SOF_IPC_MAX_CHANNELS 8 + +/* channel positions - uses same values as ALSA */ +enum sof_ipc_chmap { + SOF_CHMAP_UNKNOWN = 0, + SOF_CHMAP_NA, /* N/A, silent */ + SOF_CHMAP_MONO, /* mono stream */ + SOF_CHMAP_FL, /* front left */ + SOF_CHMAP_FR, /* front right */ + SOF_CHMAP_RL, /* rear left */ + SOF_CHMAP_RR, /* rear right */ + SOF_CHMAP_FC, /* front centre */ + SOF_CHMAP_LFE, /* LFE */ + SOF_CHMAP_SL, /* side left */ + SOF_CHMAP_SR, /* side right */ + SOF_CHMAP_RC, /* rear centre */ + SOF_CHMAP_FLC, /* front left centre */ + SOF_CHMAP_FRC, /* front right centre */ + SOF_CHMAP_RLC, /* rear left centre */ + SOF_CHMAP_RRC, /* rear right centre */ + SOF_CHMAP_FLW, /* front left wide */ + SOF_CHMAP_FRW, /* front right wide */ + SOF_CHMAP_FLH, /* front left high */ + SOF_CHMAP_FCH, /* front centre high */ + SOF_CHMAP_FRH, /* front right high */ + SOF_CHMAP_TC, /* top centre */ + SOF_CHMAP_TFL, /* top front left */ + SOF_CHMAP_TFR, /* top front right */ + SOF_CHMAP_TFC, /* top front centre */ + SOF_CHMAP_TRL, /* top rear left */ + SOF_CHMAP_TRR, /* top rear right */ + SOF_CHMAP_TRC, /* top rear centre */ + SOF_CHMAP_TFLC, /* top front left centre */ + SOF_CHMAP_TFRC, /* top front right centre */ + SOF_CHMAP_TSL, /* top side left */ + SOF_CHMAP_TSR, /* top side right */ + SOF_CHMAP_LLFE, /* left LFE */ + SOF_CHMAP_RLFE, /* right LFE */ + SOF_CHMAP_BC, /* bottom centre */ + SOF_CHMAP_BLC, /* bottom left centre */ + SOF_CHMAP_BRC, /* bottom right centre */ + SOF_CHMAP_LAST = SOF_CHMAP_BRC, +}; + +/* common sample rates for use in masks */ +#define SOF_RATE_8000 (1 << 0) /* 8000Hz */ +#define SOF_RATE_11025 (1 << 1) /* 11025Hz */ +#define SOF_RATE_12000 (1 << 2) /* 12000Hz */ +#define SOF_RATE_16000 (1 << 3) /* 16000Hz */ +#define SOF_RATE_22050 (1 << 4) /* 22050Hz */ +#define SOF_RATE_24000 (1 << 5) /* 24000Hz */ +#define SOF_RATE_32000 (1 << 6) /* 32000Hz */ +#define SOF_RATE_44100 (1 << 7) /* 44100Hz */ +#define SOF_RATE_48000 (1 << 8) /* 48000Hz */ +#define SOF_RATE_64000 (1 << 9) /* 64000Hz */ +#define SOF_RATE_88200 (1 << 10) /* 88200Hz */ +#define SOF_RATE_96000 (1 << 11) /* 96000Hz */ +#define SOF_RATE_176400 (1 << 12) /* 176400Hz */ +#define SOF_RATE_192000 (1 << 13) /* 192000Hz */ + +/* continuous and non-standard rates for flexibility */ +#define SOF_RATE_CONTINUOUS (1 << 30) /* range */ +#define SOF_RATE_KNOT (1 << 31) /* non-continuous */ + +/* stream PCM frame format */ +enum sof_ipc_frame { + SOF_IPC_FRAME_S16_LE = 0, + SOF_IPC_FRAME_S24_4LE, + SOF_IPC_FRAME_S32_LE, + SOF_IPC_FRAME_FLOAT, + /* other formats here */ +}; + +/* stream buffer format */ +enum sof_ipc_buffer_format { + SOF_IPC_BUFFER_INTERLEAVED, + SOF_IPC_BUFFER_NONINTERLEAVED, + /* other formats here */ +}; + +/* stream direction */ +enum sof_ipc_stream_direction { + SOF_IPC_STREAM_PLAYBACK = 0, + SOF_IPC_STREAM_CAPTURE, +}; + +/* stream ring info */ +struct sof_ipc_host_buffer { + uint32_t phy_addr; + uint32_t pages; + uint32_t size; + uint32_t offset; +} __attribute__((packed)); + +struct sof_ipc_stream_params { + struct sof_ipc_host_buffer buffer; + enum sof_ipc_stream_direction direction; + enum sof_ipc_frame frame_fmt; + enum sof_ipc_buffer_format buffer_fmt; + uint32_t stream_tag; + uint32_t rate; + uint32_t channels; + uint32_t sample_valid_bytes; + uint32_t sample_container_bytes; + /* for notifying host period has completed - 0 means no period IRQ */ + uint32_t host_period_bytes; + enum sof_ipc_chmap chmap[SOF_IPC_MAX_CHANNELS]; /* channel map */ +} __attribute__((packed)); + +/* PCM params info - SOF_IPC_STREAM_PCM_PARAMS */ +struct sof_ipc_pcm_params { + struct sof_ipc_hdr hdr; + uint32_t comp_id; + struct sof_ipc_stream_params params; +} __attribute__((packed)); + +/* PCM params info reply - SOF_IPC_STREAM_PCM_PARAMS_REPLY */ +struct sof_ipc_pcm_params_reply { + struct sof_ipc_reply rhdr; + uint32_t comp_id; + uint32_t posn_offset; +} __attribute__((packed)); + +/* compressed vorbis params - SOF_IPC_STREAM_VORBIS_PARAMS */ +struct sof_ipc_vorbis_params { + struct sof_ipc_hdr hdr; + uint32_t comp_id; + struct sof_ipc_stream_params params; + /* TODO */ +} __attribute__((packed)); + +/* free stream - SOF_IPC_STREAM_PCM_PARAMS */ +struct sof_ipc_stream { + struct sof_ipc_hdr hdr; + uint32_t comp_id; +} __attribute__((packed)); + +/* flags indicating which time stamps are in sync with each other */ +#define SOF_TIME_HOST_SYNC (1 << 0) +#define SOF_TIME_DAI_SYNC (1 << 1) +#define SOF_TIME_WALL_SYNC (1 << 2) +#define SOF_TIME_STAMP_SYNC (1 << 3) + +/* flags indicating which time stamps are valid */ +#define SOF_TIME_HOST_VALID (1 << 8) +#define SOF_TIME_DAI_VALID (1 << 9) +#define SOF_TIME_WALL_VALID (1 << 10) +#define SOF_TIME_STAMP_VALID (1 << 11) + +/* flags indicating time stamps are 64bit else 3use low 32bit */ +#define SOF_TIME_HOST_64 (1 << 16) +#define SOF_TIME_DAI_64 (1 << 17) +#define SOF_TIME_WALL_64 (1 << 18) +#define SOF_TIME_STAMP_64 (1 << 19) + +struct sof_ipc_stream_posn { + struct sof_ipc_reply rhdr; + uint32_t comp_id; /* host component ID */ + uint32_t flags; /* SOF_TIME_ */ + uint32_t wallclock_hz; /* frequency of wallclock in Hz */ + uint32_t timestamp_ns; /* resolution of timestamp in ns */ + uint64_t host_posn; /* host DMA position in bytes */ + uint64_t dai_posn; /* DAI DMA position in bytes */ + uint64_t comp_posn; /* comp position in bytes */ + uint64_t wallclock; /* audio wall clock */ + uint64_t timestamp; /* system time stamp */ + uint32_t xrun_comp_id; /* comp ID of XRUN component */ + int32_t xrun_size; /* XRUN size in bytes */ +} __attribute__((packed)); + +/* + * Component Mixers and Controls + */ + +/* control data type and direction */ +enum sof_ipc_ctrl_type { + /* per channel data - uses struct sof_ipc_ctrl_value_chan */ + SOF_CTRL_TYPE_VALUE_CHAN_GET = 0, + SOF_CTRL_TYPE_VALUE_CHAN_SET, + /* component data - uses struct sof_ipc_ctrl_value_comp */ + SOF_CTRL_TYPE_VALUE_COMP_GET, + SOF_CTRL_TYPE_VALUE_COMP_SET, + /* bespoke data - struct struct sof_abi_hdr */ + SOF_CTRL_TYPE_DATA_GET, + SOF_CTRL_TYPE_DATA_SET, +}; + +/* control command type */ +enum sof_ipc_ctrl_cmd { + SOF_CTRL_CMD_VOLUME = 0, /* maps to ALSA volume style controls */ + SOF_CTRL_CMD_ENUM, /* maps to ALSA enum style controls */ + SOF_CTRL_CMD_SWITCH, /* maps to ALSA switch style controls */ + SOF_CTRL_CMD_BINARY, /* maps to ALSA binary style controls */ +}; + +/* generic channel mapped value data */ +struct sof_ipc_ctrl_value_chan { + enum sof_ipc_chmap channel; + uint32_t value; +} __attribute__((packed)); + +/* generic component mapped value data */ +struct sof_ipc_ctrl_value_comp { + uint32_t index; /* component source/sink/control index in control */ + union { + uint32_t uvalue; + int32_t svalue; + }; +} __attribute__((packed)); + +/* generic control data */ +struct sof_ipc_ctrl_data { + struct sof_ipc_reply rhdr; + uint32_t comp_id; + + /* control access and data type */ + enum sof_ipc_ctrl_type type; + enum sof_ipc_ctrl_cmd cmd; + uint32_t index; /* control index for comps > 1 control */ + + /* control data - can either be appended or DMAed from host */ + struct sof_ipc_host_buffer buffer; + uint32_t num_elems; /* in array elems or bytes */ + + /* control data - add new types if needed */ + union { + /* channel values can be used by volume type controls */ + struct sof_ipc_ctrl_value_chan chanv[0]; + /* component values used by routing controls like mux, mixer */ + struct sof_ipc_ctrl_value_comp compv[0]; + /* data can be used by binary controls */ + struct sof_abi_hdr data[0]; + }; +} __attribute__((packed)); + +/* + * Component + */ + +/* types of component */ +enum sof_comp_type { + SOF_COMP_NONE = 0, + SOF_COMP_HOST, + SOF_COMP_DAI, + SOF_COMP_SG_HOST, /* scatter gather variant */ + SOF_COMP_SG_DAI, /* scatter gather variant */ + SOF_COMP_VOLUME, + SOF_COMP_MIXER, + SOF_COMP_MUX, + SOF_COMP_SRC, + SOF_COMP_SPLITTER, + SOF_COMP_TONE, + SOF_COMP_SWITCH, + SOF_COMP_BUFFER, + SOF_COMP_EQ_IIR, + SOF_COMP_EQ_FIR, + SOF_COMP_FILEREAD, /* host test based file IO */ + SOF_COMP_FILEWRITE, /* host test based file IO */ +}; + +/* XRUN action for component */ +#define SOF_XRUN_STOP 1 /* stop stream */ +#define SOF_XRUN_UNDER_ZERO 2 /* send 0s to sink */ +#define SOF_XRUN_OVER_NULL 4 /* send data to NULL */ + +/* create new generic component - SOF_IPC_TPLG_COMP_NEW */ +struct sof_ipc_comp { + struct sof_ipc_hdr hdr; + uint32_t id; + enum sof_comp_type type; + uint32_t pipeline_id; +} __attribute__((packed)); + +/* + * Component Buffers + */ + +/* create new component buffer - SOF_IPC_TPLG_BUFFER_NEW */ +struct sof_ipc_buffer { + struct sof_ipc_comp comp; + uint32_t size; /* buffer size in bytes */ + uint32_t caps; /* SOF_MEM_CAPS_ */ +} __attribute__((packed)); + +/* generic component config data - must always be after struct sof_ipc_comp */ +struct sof_ipc_comp_config { + uint32_t periods_sink; /* 0 means variable */ + uint32_t periods_source; /* 0 means variable */ + uint32_t preload_count; /* how many periods to preload */ + enum sof_ipc_frame frame_fmt; + uint32_t xrun_action; +} __attribute__((packed)); + +/* generic host component */ +struct sof_ipc_comp_host { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + enum sof_ipc_stream_direction direction; + uint32_t no_irq; /* don't send periodic IRQ to host/DSP */ + uint32_t dmac_config; /* DMA engine specific */ +} __attribute__((packed)); + +/* generic DAI component */ +struct sof_ipc_comp_dai { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + enum sof_ipc_stream_direction direction; + uint32_t dai_index; /* index of this type dai */ + enum sof_ipc_dai_type type; + uint32_t dmac_config; /* DMA engine specific */ +} __attribute__((packed)); + +/* generic mixer component */ +struct sof_ipc_comp_mixer { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; +} __attribute__((packed)); + +/* volume ramping types */ +enum sof_volume_ramp { + SOF_VOLUME_LINEAR = 0, + SOF_VOLUME_LOG, + SOF_VOLUME_LINEAR_ZC, + SOF_VOLUME_LOG_ZC, +}; + +/* generic volume component */ +struct sof_ipc_comp_volume { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + uint32_t channels; + uint32_t min_value; + uint32_t max_value; + enum sof_volume_ramp ramp; + uint32_t initial_ramp; /* ramp space in ms */ +} __attribute__((packed)); + +/* generic SRC component */ +struct sof_ipc_comp_src { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + /* either source or sink rate must be non zero */ + uint32_t source_rate; /* source rate or 0 for variable */ + uint32_t sink_rate; /* sink rate or 0 for variable */ + uint32_t rate_mask; /* SOF_RATE_ supported rates */ +} __attribute__((packed)); + +/* generic MUX component */ +struct sof_ipc_comp_mux { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; +} __attribute__((packed)); + +/* generic tone generator component */ +struct sof_ipc_comp_tone { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + int32_t sample_rate; + int32_t frequency; + int32_t amplitude; + int32_t freq_mult; + int32_t ampl_mult; + int32_t length; + int32_t period; + int32_t repeats; + int32_t ramp_step; +} __attribute__((packed)); + +/* FIR equalizer component */ +struct sof_ipc_comp_eq_fir { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + uint32_t size; + unsigned char data[0]; +} __attribute__((packed)); + +/* IIR equalizer component */ +struct sof_ipc_comp_eq_iir { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + uint32_t size; + unsigned char data[0]; +} __attribute__((packed)); + +/** \brief Types of EFFECT */ +enum sof_ipc_effect_type { + SOF_EFFECT_NONE = 0, /**< None */ + SOF_EFFECT_INTEL_EQFIR, /**< Intel FIR */ + SOF_EFFECT_INTEL_EQIIR, /**< Intel IIR */ +}; + +/* general purpose EFFECT configuration */ +struct sof_ipc_comp_effect { + enum sof_ipc_effect_type type; +} __attribute__((packed)); + +/* frees components, buffers and pipelines + * SOF_IPC_TPLG_COMP_FREE, SOF_IPC_TPLG_PIPE_FREE, SOF_IPC_TPLG_BUFFER_FREE + */ +struct sof_ipc_free { + struct sof_ipc_hdr hdr; + uint32_t id; +} __attribute__((packed)); + +struct sof_ipc_comp_reply { + struct sof_ipc_reply rhdr; + uint32_t id; + uint32_t offset; +} __attribute__((packed)); + +/* + * Pipeline + */ + +/* new pipeline - SOF_IPC_TPLG_PIPE_NEW */ +struct sof_ipc_pipe_new { + struct sof_ipc_hdr hdr; + uint32_t comp_id; /* component id for pipeline */ + uint32_t pipeline_id; /* pipeline id */ + uint32_t sched_id; /* sheduling component id */ + uint32_t core; /* core we run on */ + uint32_t deadline; /* execution completion deadline in us*/ + uint32_t priority; /* priority level 0 (low) to 10 (max) */ + uint32_t mips; /* worst case instruction count per period */ + uint32_t frames_per_sched;/* output frames of pipeline, 0 is variable */ + uint32_t xrun_limit_usecs; /* report xruns greater than limit */ + + /* non zero if timer scheduled, otherwise DAI DMA irq scheduled */ + uint32_t timer_delay; +} __attribute__((packed)); + +/* pipeline construction complete - SOF_IPC_TPLG_PIPE_COMPLETE */ +struct sof_ipc_pipe_ready { + struct sof_ipc_hdr hdr; + uint32_t comp_id; +} __attribute__((packed)); + +struct sof_ipc_pipe_free { + struct sof_ipc_hdr hdr; + uint32_t comp_id; +} __attribute__((packed)); + +/* connect two components in pipeline - SOF_IPC_TPLG_COMP_CONNECT */ +struct sof_ipc_pipe_comp_connect { + struct sof_ipc_hdr hdr; + uint32_t source_id; + uint32_t sink_id; +} __attribute__((packed)); + +/* + * PM + */ + +/* PM context element */ +struct sof_ipc_pm_ctx_elem { + uint32_t type; + uint32_t size; + uint64_t addr; +} __attribute__((packed)); + +/* + * PM context - SOF_IPC_PM_CTX_SAVE, SOF_IPC_PM_CTX_RESTORE, + * SOF_IPC_PM_CTX_SIZE + */ +struct sof_ipc_pm_ctx { + struct sof_ipc_hdr hdr; + struct sof_ipc_host_buffer buffer; + uint32_t num_elems; + uint32_t size; + struct sof_ipc_pm_ctx_elem elems[]; +}; + +/* enable or disable cores - SOF_IPC_PM_CORE_ENABLE */ +struct sof_ipc_pm_core_config { + struct sof_ipc_hdr hdr; + uint32_t enable_mask; +}; + +/* + * Firmware boot and version + */ + +#define SOF_IPC_MAX_ELEMS 16 + +/* extended data types that can be appended onto end of sof_ipc_fw_ready */ +enum sof_ipc_ext_data { + SOF_IPC_EXT_DMA_BUFFER = 0, + SOF_IPC_EXT_WINDOW, +}; + +/* FW version - SOF_IPC_GLB_VERSION */ +struct sof_ipc_fw_version { + uint16_t major; + uint16_t minor; + uint16_t build; + uint8_t date[12]; + uint8_t time[10]; + uint8_t tag[6]; + uint16_t abi_version; + /* Make sure the total size is 4 bytes aligned */ +} __attribute__((packed)); + +/* FW ready Message - sent by firmware when boot has completed */ +struct sof_ipc_fw_ready { + struct sof_ipc_hdr hdr; + uint32_t dspbox_offset; /* dsp initiated IPC mailbox */ + uint32_t hostbox_offset; /* host initiated IPC mailbox */ + uint32_t dspbox_size; + uint32_t hostbox_size; + struct sof_ipc_fw_version version; +} __attribute__((packed)); + +/* + * Extended Firmware data. All optional, depends on platform/arch. + */ + +enum sof_ipc_region { + SOF_IPC_REGION_DOWNBOX = 0, + SOF_IPC_REGION_UPBOX, + SOF_IPC_REGION_TRACE, + SOF_IPC_REGION_DEBUG, + SOF_IPC_REGION_STREAM, + SOF_IPC_REGION_REGS, + SOF_IPC_REGION_EXCEPTION, +}; + +struct sof_ipc_ext_data_hdr { + struct sof_ipc_hdr hdr; + enum sof_ipc_ext_data type; /* SOF_IPC_EXT_ */ +}; + +struct sof_ipc_dma_buffer_elem { + enum sof_ipc_region type; + uint32_t id; /* platform specific - used to map to host memory */ + struct sof_ipc_host_buffer buffer; +}; + +/* extended data DMA buffers for IPC, trace and debug */ +struct sof_ipc_dma_buffer_data { + struct sof_ipc_ext_data_hdr ext_hdr; + uint32_t num_buffers; + /* host files in buffer[n].buffer */ + struct sof_ipc_dma_buffer_elem buffer[]; +} __attribute__((packed)); + +struct sof_ipc_window_elem { + enum sof_ipc_region type; + uint32_t id; /* platform specific - used to map to host memory */ + uint32_t flags; /* R, W, RW, etc - to define */ + uint32_t size; /* size of region in bytes */ + /* offset in window region as windows can be partitioned */ + uint32_t offset; +}; + +/* extended data memory windows for IPC, trace and debug */ +struct sof_ipc_window { + struct sof_ipc_ext_data_hdr ext_hdr; + uint32_t num_windows; + struct sof_ipc_window_elem window[]; +} __attribute__((packed)); + +/* + * DMA for Trace + */ + +/* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS */ +struct sof_ipc_dma_trace_params { + struct sof_ipc_hdr hdr; + struct sof_ipc_host_buffer buffer; + uint32_t stream_tag; +} __attribute__((packed)); + +/* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS */ +struct sof_ipc_dma_trace_posn { + struct sof_ipc_reply rhdr; + uint32_t host_offset; /* Offset of DMA host buffer */ + uint32_t overflow; /* overflow bytes if any */ + uint32_t messages; /* total trace messages */ +} __attribute__((packed)); + +/* + * Architecture specific debug + */ + +/* Xtensa Firmware Oops data */ +struct sof_ipc_dsp_oops_xtensa { + uint32_t exccause; + uint32_t excvaddr; + uint32_t ps; + uint32_t epc1; + uint32_t epc2; + uint32_t epc3; + uint32_t epc4; + uint32_t epc5; + uint32_t epc6; + uint32_t epc7; + uint32_t eps2; + uint32_t eps3; + uint32_t eps4; + uint32_t eps5; + uint32_t eps6; + uint32_t eps7; + uint32_t depc; + uint32_t intenable; + uint32_t interrupt; + uint32_t sar; + uint32_t stack; +} __attribute__((packed)); + +/* + * Commom debug + */ + +/* panic info include filename and line number */ +struct sof_ipc_panic_info { + char filename[32]; + uint32_t linenum; +} __attribute__((packed)); + +#endif diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c new file mode 100644 index 00000000000000..4ee63ce4dd2b11 --- /dev/null +++ b/sound/soc/sof/ipc.c @@ -0,0 +1,791 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// +// Generic IPC layer that can work over MMIO and SPI/I2C. PHY layer provided +// by platform driver code. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sof-priv.h" +#include "ops.h" + +/* + * IPC message default size and timeout (msecs). + * TODO: allow platforms to set size and timeout. + */ +#define IPC_TIMEOUT_MSECS 300 +#define IPC_EMPTY_LIST_SIZE 8 + +static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id); +static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd); + +/* + * IPC message Tx/Rx message handling. + */ + +/* SOF generic IPC data */ +struct snd_sof_ipc { + struct snd_sof_dev *sdev; + + /* TX message work and status */ + wait_queue_head_t wait_txq; + struct work_struct tx_kwork; + bool msg_pending; + + /* Rx Message work and status */ + struct work_struct rx_kwork; + + /* lists */ + struct list_head tx_list; + struct list_head reply_list; + struct list_head empty_list; +}; + +/* locks held by caller */ +static struct snd_sof_ipc_msg *msg_get_empty(struct snd_sof_ipc *ipc) +{ + struct snd_sof_ipc_msg *msg = NULL; + + /* get first empty message in the list */ + if (!list_empty(&ipc->empty_list)) { + msg = list_first_entry(&ipc->empty_list, struct snd_sof_ipc_msg, + list); + list_del(&msg->list); + } + + return msg; +} + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC) +static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) +{ + u8 *str; + u32 glb; + u32 type; + + glb = cmd & SOF_GLB_TYPE_MASK; + type = cmd & SOF_CMD_TYPE_MASK; + + switch (glb) { + case SOF_IPC_GLB_REPLY: + str = "GLB_REPLY"; break; + case SOF_IPC_GLB_COMPOUND: + str = "GLB_COMPOUND"; break; + case SOF_IPC_GLB_TPLG_MSG: + switch (type) { + case SOF_IPC_TPLG_COMP_NEW: + str = "GLB_TPLG_MSG: COMP_NEW"; break; + case SOF_IPC_TPLG_COMP_FREE: + str = "GLB_TPLG_MSG: COMP_FREE"; break; + case SOF_IPC_TPLG_COMP_CONNECT: + str = "GLB_TPLG_MSG: COMP_CONNECT"; break; + case SOF_IPC_TPLG_PIPE_NEW: + str = "GLB_TPLG_MSG: PIPE_NEW"; break; + case SOF_IPC_TPLG_PIPE_FREE: + str = "GLB_TPLG_MSG: PIPE_FREE"; break; + case SOF_IPC_TPLG_PIPE_CONNECT: + str = "GLB_TPLG_MSG: PIPE_CONNECT"; break; + case SOF_IPC_TPLG_PIPE_COMPLETE: + str = "GLB_TPLG_MSG: PIPE_COMPLETE"; break; + case SOF_IPC_TPLG_BUFFER_NEW: + str = "GLB_TPLG_MSG: BUFFER_NEW"; break; + case SOF_IPC_TPLG_BUFFER_FREE: + str = "GLB_TPLG_MSG: BUFFER_FREE"; break; + default: + str = "GLB_TPLG_MSG: unknown type"; break; + } + break; + case SOF_IPC_GLB_PM_MSG: + switch (type) { + case SOF_IPC_PM_CTX_SAVE: + str = "GLB_PM_MSG: CTX_SAVE"; break; + case SOF_IPC_PM_CTX_RESTORE: + str = "GLB_PM_MSG: CTX_RESTORE"; break; + case SOF_IPC_PM_CTX_SIZE: + str = "GLB_PM_MSG: CTX_SIZE"; break; + case SOF_IPC_PM_CLK_SET: + str = "GLB_PM_MSG: CLK_SET"; break; + case SOF_IPC_PM_CLK_GET: + str = "GLB_PM_MSG: CLK_GET"; break; + case SOF_IPC_PM_CLK_REQ: + str = "GLB_PM_MSG: CLK_REQ"; break; + default: + str = "GLB_PM_MSG: unknown type"; break; + } + break; + case SOF_IPC_GLB_COMP_MSG: + switch (type) { + case SOF_IPC_COMP_SET_VALUE: + str = "GLB_COMP_MSG: SET_VALUE"; break; + case SOF_IPC_COMP_GET_VALUE: + str = "GLB_COMP_MSG: GET_VALUE"; break; + case SOF_IPC_COMP_SET_DATA: + str = "GLB_COMP_MSG: SET_DATA"; break; + case SOF_IPC_COMP_GET_DATA: + str = "GLB_COMP_MSG: GET_DATA"; break; + default: + str = "GLB_COMP_MSG: unknown type"; break; + } + break; + case SOF_IPC_GLB_STREAM_MSG: + switch (type) { + case SOF_IPC_STREAM_PCM_PARAMS: + str = "GLB_STREAM_MSG: PCM_PARAMS"; break; + case SOF_IPC_STREAM_PCM_PARAMS_REPLY: + str = "GLB_STREAM_MSG: PCM_REPLY"; break; + case SOF_IPC_STREAM_PCM_FREE: + str = "GLB_STREAM_MSG: PCM_FREE"; break; + case SOF_IPC_STREAM_TRIG_START: + str = "GLB_STREAM_MSG: TRIG_START"; break; + case SOF_IPC_STREAM_TRIG_STOP: + str = "GLB_STREAM_MSG: TRIG_STOP"; break; + case SOF_IPC_STREAM_TRIG_PAUSE: + str = "GLB_STREAM_MSG: TRIG_PAUSE"; break; + case SOF_IPC_STREAM_TRIG_RELEASE: + str = "GLB_STREAM_MSG: TRIG_RELEASE"; break; + case SOF_IPC_STREAM_TRIG_DRAIN: + str = "GLB_STREAM_MSG: TRIG_DRAIN"; break; + case SOF_IPC_STREAM_TRIG_XRUN: + str = "GLB_STREAM_MSG: TRIG_XRUN"; break; + case SOF_IPC_STREAM_POSITION: + str = "GLB_STREAM_MSG: POSITION"; break; + case SOF_IPC_STREAM_VORBIS_PARAMS: + str = "GLB_STREAM_MSG: VORBIS_PARAMS"; break; + case SOF_IPC_STREAM_VORBIS_FREE: + str = "GLB_STREAM_MSG: VORBIS_FREE"; break; + default: + str = "GLB_STREAM_MSG: unknown type"; break; + } + break; + case SOF_IPC_FW_READY: + str = "FW_READY"; break; + case SOF_IPC_GLB_DAI_MSG: + switch (type) { + case SOF_IPC_DAI_CONFIG: + str = "GLB_DAI_MSG: CONFIG"; break; + case SOF_IPC_DAI_LOOPBACK: + str = "GLB_DAI_MSG: LOOPBACK"; break; + default: + str = "GLB_DAI_MSG: unknown type"; break; + } + break; + case SOF_IPC_GLB_TRACE_MSG: + str = "GLB_TRACE_MSG"; break; + default: + str = "unknown GLB command"; break; + } + + dev_dbg(dev, "%s: 0x%x: %s\n", text, cmd, str); +} +#else +static inline void ipc_log_header(struct device *dev, u8 *text, u32 cmd) +{ + dev_dbg(dev, "%s: 0x%x\n", text, cmd); +} +#endif + +/* wait for IPC message reply */ +static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, + void *reply_data) +{ + struct snd_sof_dev *sdev = ipc->sdev; + struct sof_ipc_hdr *hdr = (struct sof_ipc_hdr *)msg->msg_data; + unsigned long flags; + int ret; + + /* wait for DSP IPC completion */ + ret = wait_event_timeout(msg->waitq, msg->complete, + msecs_to_jiffies(IPC_TIMEOUT_MSECS)); + + spin_lock_irqsave(&sdev->ipc_lock, flags); + + if (ret == 0) { + dev_err(sdev->dev, "error: ipc timed out for 0x%x size 0x%x\n", + hdr->cmd, hdr->size); + snd_sof_dsp_dbg_dump(ipc->sdev, SOF_DBG_REGS | SOF_DBG_MBOX); + snd_sof_trace_notify_for_error(ipc->sdev); + ret = -ETIMEDOUT; + } else { + /* copy the data returned from DSP */ + ret = snd_sof_dsp_get_reply(sdev, msg); + if (msg->reply_size) + memcpy(reply_data, msg->reply_data, msg->reply_size); + if (ret < 0) + dev_err(sdev->dev, "error: ipc error for 0x%x size 0x%zx\n", + hdr->cmd, msg->reply_size); + else + ipc_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd); + } + + /* return message body to empty list */ + list_move(&msg->list, &ipc->empty_list); + + spin_unlock_irqrestore(&sdev->ipc_lock, flags); + + snd_sof_dsp_cmd_done(sdev, SOF_IPC_DSP_REPLY); + + /* continue to schedule any remaining messages... */ + snd_sof_ipc_msgs_tx(sdev); + + return ret; +} + +/* send IPC message from host to DSP */ +int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, + void *msg_data, size_t msg_bytes, void *reply_data, + size_t reply_bytes) +{ + struct snd_sof_dev *sdev = ipc->sdev; + struct snd_sof_ipc_msg *msg; + unsigned long flags; + + spin_lock_irqsave(&sdev->ipc_lock, flags); + + /* get an empty message */ + msg = msg_get_empty(ipc); + if (!msg) { + spin_unlock_irqrestore(&sdev->ipc_lock, flags); + return -EBUSY; + } + + msg->header = header; + msg->msg_size = msg_bytes; + msg->reply_size = reply_bytes; + msg->complete = false; + + /* attach any data */ + if (msg_bytes) + memcpy(msg->msg_data, msg_data, msg_bytes); + + /* add message to transmit list */ + list_add_tail(&msg->list, &ipc->tx_list); + + /* schedule the message if not busy */ + if (snd_sof_dsp_is_ready(sdev)) + schedule_work(&ipc->tx_kwork); + + spin_unlock_irqrestore(&sdev->ipc_lock, flags); + + /* now wait for completion */ + return tx_wait_done(ipc, msg, reply_data); +} +EXPORT_SYMBOL(sof_ipc_tx_message); + +/* send next IPC message in list */ +static void ipc_tx_next_msg(struct work_struct *work) +{ + struct snd_sof_ipc *ipc = + container_of(work, struct snd_sof_ipc, tx_kwork); + struct snd_sof_dev *sdev = ipc->sdev; + struct snd_sof_ipc_msg *msg; + unsigned long flags; + + spin_lock_irqsave(&sdev->ipc_lock, flags); + + /* send message if HW read and message in TX list */ + if (list_empty(&ipc->tx_list) || !snd_sof_dsp_is_ready(sdev)) + goto out; + + /* send first message in TX list */ + msg = list_first_entry(&ipc->tx_list, struct snd_sof_ipc_msg, list); + list_move(&msg->list, &ipc->reply_list); + snd_sof_dsp_send_msg(sdev, msg); + + ipc_log_header(sdev->dev, "ipc tx", msg->header); +out: + spin_unlock_irqrestore(&sdev->ipc_lock, flags); +} + +/* find original TX message from DSP reply */ +static struct snd_sof_ipc_msg *sof_ipc_reply_find_msg(struct snd_sof_ipc *ipc, + u32 header) +{ + struct snd_sof_dev *sdev = ipc->sdev; + struct snd_sof_ipc_msg *msg; + + header = SOF_IPC_MESSAGE_ID(header); + + if (list_empty(&ipc->reply_list)) + goto err; + + list_for_each_entry(msg, &ipc->reply_list, list) { + if (SOF_IPC_MESSAGE_ID(msg->header) == header) + return msg; + } + +err: + dev_err(sdev->dev, "error: rx list empty but received 0x%x\n", + header); + return NULL; +} + +/* mark IPC message as complete - locks held by caller */ +static void sof_ipc_tx_msg_reply_complete(struct snd_sof_ipc *ipc, + struct snd_sof_ipc_msg *msg) +{ + msg->complete = true; + wake_up(&msg->waitq); +} + +/* drop all IPC messages in preparation for DSP stall/reset */ +void sof_ipc_drop_all(struct snd_sof_ipc *ipc) +{ + struct snd_sof_dev *sdev = ipc->sdev; + struct snd_sof_ipc_msg *msg, *tmp; + unsigned long flags; + + /* drop all TX and Rx messages before we stall + reset DSP */ + spin_lock_irqsave(&sdev->ipc_lock, flags); + + list_for_each_entry_safe(msg, tmp, &ipc->tx_list, list) { + list_move(&msg->list, &ipc->empty_list); + dev_err(sdev->dev, "error: dropped msg %d\n", msg->header); + } + + list_for_each_entry_safe(msg, tmp, &ipc->reply_list, list) { + list_move(&msg->list, &ipc->empty_list); + dev_err(sdev->dev, "error: dropped reply %d\n", msg->header); + } + + spin_unlock_irqrestore(&sdev->ipc_lock, flags); +} +EXPORT_SYMBOL(sof_ipc_drop_all); + +/* handle reply message from DSP */ +int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct snd_sof_ipc_msg *msg; + + msg = sof_ipc_reply_find_msg(sdev->ipc, msg_id); + if (!msg) { + dev_err(sdev->dev, "error: can't find message header 0x%x", + msg_id); + return -EINVAL; + } + + /* wake up and return the error if we have waiters on this message ? */ + sof_ipc_tx_msg_reply_complete(sdev->ipc, msg); + return 0; +} +EXPORT_SYMBOL(snd_sof_ipc_reply); + +/* DSP firmware has sent host a message */ +static void ipc_msgs_rx(struct work_struct *work) +{ + struct snd_sof_ipc *ipc = + container_of(work, struct snd_sof_ipc, rx_kwork); + struct snd_sof_dev *sdev = ipc->sdev; + struct sof_ipc_hdr hdr; + u32 cmd, type; + int err = -EINVAL; + + /* read back header */ + snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &hdr, sizeof(hdr)); + ipc_log_header(sdev->dev, "ipc rx", hdr.cmd); + + cmd = hdr.cmd & SOF_GLB_TYPE_MASK; + type = hdr.cmd & SOF_CMD_TYPE_MASK; + + /* check message type */ + switch (cmd) { + case SOF_IPC_GLB_REPLY: + dev_err(sdev->dev, "error: ipc reply unknown\n"); + break; + case SOF_IPC_FW_READY: + /* check for FW boot completion */ + if (!sdev->boot_complete) { + if (sdev->ops->fw_ready) + err = sdev->ops->fw_ready(sdev, cmd); + if (err < 0) { + dev_err(sdev->dev, "DSP firmware boot timeout %d\n", + err); + } else { + /* firmware boot completed OK */ + sdev->boot_complete = true; + dev_dbg(sdev->dev, "booting DSP firmware completed\n"); + wake_up(&sdev->boot_wait); + } + } + break; + case SOF_IPC_GLB_COMPOUND: + case SOF_IPC_GLB_TPLG_MSG: + case SOF_IPC_GLB_PM_MSG: + case SOF_IPC_GLB_COMP_MSG: + break; + case SOF_IPC_GLB_STREAM_MSG: + /* need to pass msg id into the function */ + ipc_stream_message(sdev, hdr.cmd); + break; + case SOF_IPC_GLB_TRACE_MSG: + ipc_trace_message(sdev, type); + break; + default: + dev_err(sdev->dev, "unknown DSP message 0x%x\n", cmd); + break; + } + + ipc_log_header(sdev->dev, "ipc rx done", hdr.cmd); + + /* tell DSP we are done */ + snd_sof_dsp_cmd_done(sdev, SOF_IPC_HOST_REPLY); +} + +/* schedule work to transmit any IPC in queue */ +void snd_sof_ipc_msgs_tx(struct snd_sof_dev *sdev) +{ + schedule_work(&sdev->ipc->tx_kwork); +} +EXPORT_SYMBOL(snd_sof_ipc_msgs_tx); + +/* schedule work to handle IPC from DSP */ +void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) +{ + schedule_work(&sdev->ipc->rx_kwork); +} +EXPORT_SYMBOL(snd_sof_ipc_msgs_rx); + +/* + * IPC trace mechanism. + */ + +static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct sof_ipc_dma_trace_posn posn; + + switch (msg_id) { + case SOF_IPC_TRACE_DMA_POSITION: + /* read back full message */ + snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn, + sizeof(posn)); + snd_sof_trace_update_pos(sdev, &posn); + break; + default: + dev_err(sdev->dev, "error: unhandled trace message %x\n", + msg_id); + break; + } +} + +/* + * IPC stream position. + */ + +static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct sof_ipc_stream_posn posn; + struct snd_sof_pcm *spcm; + u32 posn_offset; + int direction; + + /* check if we have stream box */ + if (sdev->stream_box.size == 0) { + /* read back full message */ + snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn, + sizeof(posn)); + + spcm = snd_sof_find_spcm_comp(sdev, posn.comp_id, &direction); + } else { + spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction); + } + + if (!spcm) { + dev_err(sdev->dev, + "period elapsed for unknown stream, msg_id %d\n", + msg_id); + return; + } + + /* have stream box read from stream box */ + if (sdev->stream_box.size != 0) { + posn_offset = spcm->posn_offset[direction]; + snd_sof_dsp_mailbox_read(sdev, posn_offset, &posn, + sizeof(posn)); + + dev_dbg(sdev->dev, "posn mailbox: posn offset is 0x%x", + posn_offset); + } + + dev_dbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n", + posn.host_posn, posn.dai_posn, posn.wallclock); + + memcpy(&spcm->stream[direction].posn, &posn, sizeof(posn)); + + /* only inform ALSA for period_wakeup mode */ + if (!spcm->stream[direction].substream->runtime->no_period_wakeup) + snd_pcm_period_elapsed(spcm->stream[direction].substream); +} + +/* DSP notifies host of an XRUN within FW */ +static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct sof_ipc_stream_posn posn; + struct snd_sof_pcm *spcm; + u32 posn_offset; + int direction; + + /* check if we have stream MMIO on this platform */ + if (sdev->stream_box.size == 0) { + /* read back full message */ + snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn, + sizeof(posn)); + + spcm = snd_sof_find_spcm_comp(sdev, posn.comp_id, &direction); + } else { + spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction); + } + + if (!spcm) { + dev_err(sdev->dev, "XRUN for unknown stream, msg_id %d\n", + msg_id); + return; + } + + /* have stream box read from stream box */ + if (sdev->stream_box.size != 0) { + posn_offset = spcm->posn_offset[direction]; + snd_sof_dsp_mailbox_read(sdev, posn_offset, &posn, + sizeof(posn)); + + dev_dbg(sdev->dev, "posn mailbox: posn offset is 0x%x", + posn_offset); + } + + dev_dbg(sdev->dev, "posn XRUN: host %llx comp %d size %d\n", + posn.host_posn, posn.xrun_comp_id, posn.xrun_size); + +#if defined(CONFIG_SOC_SOF_DEBUG_XRUN_STOP) + /* stop PCM on XRUN - used for pipeline debug */ + memcpy(&spcm->stream[direction].posn, &posn, sizeof(posn)); + snd_pcm_stop_xrun(spcm->stream[direction].substream); +#endif +} + +/* stream notifications from DSP FW */ +static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd) +{ + /* get msg cmd type and msd id */ + u32 msg_type = msg_cmd & SOF_CMD_TYPE_MASK; + u32 msg_id = SOF_IPC_MESSAGE_ID(msg_cmd); + + switch (msg_type) { + case SOF_IPC_STREAM_POSITION: + ipc_period_elapsed(sdev, msg_id); + break; + case SOF_IPC_STREAM_TRIG_XRUN: + ipc_xrun(sdev, msg_id); + break; + default: + dev_err(sdev->dev, "error: unhandled stream message %x\n", + msg_id); + break; + } +} + +/* get stream position IPC - use faster MMIO method if available on platform */ +int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev, + struct snd_sof_pcm *spcm, int direction, + struct sof_ipc_stream_posn *posn) +{ + struct sof_ipc_stream stream; + int err; + + /* read position via slower IPC */ + stream.hdr.size = sizeof(stream); + stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_POSITION; + stream.comp_id = spcm->stream[direction].comp_id; + + /* send IPC to the DSP */ + err = sof_ipc_tx_message(sdev->ipc, + stream.hdr.cmd, &stream, sizeof(stream), &posn, + sizeof(*posn)); + if (err < 0) { + dev_err(sdev->dev, "error: failed to get stream %d position\n", + stream.comp_id); + return err; + } + + return 0; +} +EXPORT_SYMBOL(snd_sof_ipc_stream_posn); + +/* + * IPC get()/set() for kcontrols. + */ + +int snd_sof_ipc_set_comp_data(struct snd_sof_ipc *ipc, + struct snd_sof_control *scontrol, u32 ipc_cmd, + enum sof_ipc_ctrl_type ctrl_type, + enum sof_ipc_ctrl_cmd ctrl_cmd) +{ + struct snd_sof_dev *sdev = ipc->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + int err; + + /* read firmware volume */ + if (scontrol->readback_offset != 0) { + /* we can read value header via mmaped region */ + snd_sof_dsp_block_write(sdev, scontrol->readback_offset, + cdata->chanv, + sizeof(struct sof_ipc_ctrl_value_chan) * + cdata->num_elems); + + } else { + /* write value via slower IPC */ + cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd; + cdata->cmd = ctrl_cmd; + cdata->type = ctrl_type; + cdata->rhdr.hdr.size = scontrol->size; + cdata->comp_id = scontrol->comp_id; + cdata->num_elems = scontrol->num_channels; + + /* send IPC to the DSP */ + err = sof_ipc_tx_message(sdev->ipc, + cdata->rhdr.hdr.cmd, cdata, + cdata->rhdr.hdr.size, + cdata, cdata->rhdr.hdr.size); + if (err < 0) { + dev_err(sdev->dev, "error: failed to set control %d values\n", + cdata->comp_id); + return err; + } + } + + return 0; +} +EXPORT_SYMBOL(snd_sof_ipc_set_comp_data); + +int snd_sof_ipc_get_comp_data(struct snd_sof_ipc *ipc, + struct snd_sof_control *scontrol, u32 ipc_cmd, + enum sof_ipc_ctrl_type ctrl_type, + enum sof_ipc_ctrl_cmd ctrl_cmd) +{ + struct snd_sof_dev *sdev = ipc->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + int err; + + /* read firmware byte counters */ + if (scontrol->readback_offset != 0) { + /* we can read values via mmaped region */ + snd_sof_dsp_block_read(sdev, scontrol->readback_offset, + cdata->chanv, + sizeof(struct sof_ipc_ctrl_value_chan) * + cdata->num_elems); + + } else { + /* read position via slower IPC */ + cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd; + cdata->cmd = ctrl_cmd; + cdata->type = ctrl_type; + cdata->rhdr.hdr.size = scontrol->size; + cdata->comp_id = scontrol->comp_id; + cdata->num_elems = scontrol->num_channels; + + /* send IPC to the DSP */ + err = sof_ipc_tx_message(sdev->ipc, + cdata->rhdr.hdr.cmd, cdata, + cdata->rhdr.hdr.size, + cdata, cdata->rhdr.hdr.size); + if (err < 0) { + dev_err(sdev->dev, "error: failed to get control %d values\n", + cdata->comp_id); + return err; + } + } + + return 0; +} +EXPORT_SYMBOL(snd_sof_ipc_get_comp_data); + +/* + * IPC layer enumeration. + */ + +int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox, + size_t dspbox_size, u32 hostbox, + size_t hostbox_size) +{ + sdev->dsp_box.offset = dspbox; + sdev->dsp_box.size = dspbox_size; + sdev->host_box.offset = hostbox; + sdev->host_box.size = hostbox_size; + return 0; +} +EXPORT_SYMBOL(snd_sof_dsp_mailbox_init); + +struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) +{ + struct snd_sof_ipc *ipc; + struct snd_sof_ipc_msg *msg; + int i; + + ipc = devm_kzalloc(sdev->dev, sizeof(*ipc), GFP_KERNEL); + if (!ipc) + return NULL; + + INIT_LIST_HEAD(&ipc->tx_list); + INIT_LIST_HEAD(&ipc->reply_list); + INIT_LIST_HEAD(&ipc->empty_list); + init_waitqueue_head(&ipc->wait_txq); + INIT_WORK(&ipc->tx_kwork, ipc_tx_next_msg); + INIT_WORK(&ipc->rx_kwork, ipc_msgs_rx); + ipc->sdev = sdev; + + /* pre-allocate messages */ + dev_dbg(sdev->dev, "pre-allocate %d IPC messages\n", + IPC_EMPTY_LIST_SIZE); + msg = devm_kzalloc(sdev->dev, sizeof(struct snd_sof_ipc_msg) * + IPC_EMPTY_LIST_SIZE, GFP_KERNEL); + if (!msg) + return NULL; + + /* pre-allocate message data */ + for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { + msg->msg_data = devm_kzalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL); + if (!msg->msg_data) + return NULL; + + msg->reply_data = devm_kzalloc(sdev->dev, PAGE_SIZE, + GFP_KERNEL); + if (!msg->reply_data) + return NULL; + + init_waitqueue_head(&msg->waitq); + list_add(&msg->list, &ipc->empty_list); + msg++; + } + + return ipc; +} +EXPORT_SYMBOL(snd_sof_ipc_init); + +void snd_sof_ipc_free(struct snd_sof_dev *sdev) +{ + cancel_work_sync(&sdev->ipc->tx_kwork); + cancel_work_sync(&sdev->ipc->rx_kwork); +} +EXPORT_SYMBOL(snd_sof_ipc_free); From 3f3a20f425d031fbbbd64f4e68dbd38a33e409fd Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:32:38 +0000 Subject: [PATCH 0095/1995] ASoC: SOF: Add PCM operations support Add support for exposing PCMs to userspace. PCMs are defined by topology and the operations in this patch map to SOF IPC calls. Signed-off-by: Liam Girdwood --- sound/soc/sof/pcm.c | 759 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 759 insertions(+) create mode 100644 sound/soc/sof/pcm.c diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c new file mode 100644 index 00000000000000..f2e256d129bf50 --- /dev/null +++ b/sound/soc/sof/pcm.c @@ -0,0 +1,759 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// +// PCM Layer, interface between ALSA and IPC. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sof-priv.h" +#include "ops.h" + +#define DRV_NAME "sof-audio" + +/* Create DMA buffer page table for DSP */ +static int create_page_table(struct snd_pcm_substream *substream, + unsigned char *dma_area, size_t size) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm = rtd->private; + struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream); + int stream = substream->stream; + + return snd_sof_create_page_table(sdev, dmab, + spcm->stream[stream].page_table.area, size); +} + +/* this may get called several times by oss emulation */ +static int sof_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm = rtd->private; + struct sof_ipc_pcm_params pcm; + struct sof_ipc_pcm_params_reply ipc_params_reply; + int posn_offset; + int ret; + + /* nothing todo for BE */ + if (rtd->dai_link->no_pcm) + return 0; + + dev_dbg(sdev->dev, "pcm: hw params stream %d dir %d\n", + spcm->pcm.pcm_id, substream->stream); + + memset(&pcm, 0, sizeof(pcm)); + + /* allocate audio buffer pages */ + ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); + if (ret < 0) { + dev_err(sdev->dev, "error: could not allocate %d bytes for PCM %d\n", + params_buffer_bytes(params), ret); + return ret; + } + + /* craete compressed page table for audio firmware */ + ret = create_page_table(substream, runtime->dma_area, + runtime->dma_bytes); + if (ret < 0) + return ret; + + /* number of pages should be rounded up */ + if (runtime->dma_bytes % PAGE_SIZE) + pcm.params.buffer.pages = (runtime->dma_bytes / PAGE_SIZE) + 1; + else + pcm.params.buffer.pages = runtime->dma_bytes / PAGE_SIZE; + + /* set IPC PCM parameters */ + pcm.hdr.size = sizeof(pcm); + pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS; + pcm.comp_id = spcm->stream[substream->stream].comp_id; + pcm.params.buffer.phy_addr = + spcm->stream[substream->stream].page_table.addr; + pcm.params.buffer.size = runtime->dma_bytes; + pcm.params.buffer.offset = 0; + pcm.params.direction = substream->stream; + pcm.params.sample_valid_bytes = params_width(params) >> 3; + pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED; + pcm.params.rate = params_rate(params); + pcm.params.channels = params_channels(params); + pcm.params.host_period_bytes = params_period_bytes(params); + + /* container size */ + switch (params_width(params)) { + case 16: + pcm.params.sample_container_bytes = 2; + break; + case 24: + pcm.params.sample_container_bytes = 4; + break; + case 32: + pcm.params.sample_container_bytes = 4; + break; + default: + return -EINVAL; + } + + /* format */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16: + pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE; + break; + case SNDRV_PCM_FORMAT_S24: + pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE; + break; + case SNDRV_PCM_FORMAT_S32: + pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE; + break; + case SNDRV_PCM_FORMAT_FLOAT: + pcm.params.frame_fmt = SOF_IPC_FRAME_FLOAT; + break; + default: + return -EINVAL; + } + + /* firmware already configured host stream */ + ret = snd_sof_pcm_platform_hw_params(sdev, + substream, + params, + &pcm.params); + dev_dbg(sdev->dev, "stream_tag %d", pcm.params.stream_tag); + + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm), + &ipc_params_reply, sizeof(ipc_params_reply)); + + /* validate offset */ + posn_offset = ipc_params_reply.posn_offset; + + /* check if offset is overflow or it is not aligned */ + if (posn_offset > sdev->stream_box.size || + posn_offset % sizeof(struct sof_ipc_stream_posn) != 0) { + dev_err(sdev->dev, "error: got wrong posn offset 0x%x for PCM %d\n", + posn_offset, ret); + return ret; + } + spcm->posn_offset[substream->stream] = + sdev->stream_box.offset + posn_offset; + + /* save pcm hw_params */ + memcpy(&spcm->params[substream->stream], params, sizeof(*params)); + + return ret; +} + +static int sof_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm = rtd->private; + struct sof_ipc_stream stream; + struct sof_ipc_reply reply; + int ret; + + /* nothing todo for BE */ + if (rtd->dai_link->no_pcm) + return 0; + + dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id, + substream->stream); + + stream.hdr.size = sizeof(stream); + stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE; + stream.comp_id = spcm->stream[substream->stream].comp_id; + + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, + sizeof(stream), &reply, sizeof(reply)); + + snd_pcm_lib_free_pages(substream); + return ret; +} + +static int sof_restore_hw_params(struct snd_pcm_substream *substream, + struct snd_sof_pcm *spcm, + struct snd_sof_dev *sdev) +{ + snd_pcm_uframes_t host = 0; + u64 host_posn; + int ret = 0; + + /* resume stream */ + host_posn = spcm->stream[substream->stream].posn.host_posn; + host = bytes_to_frames(substream->runtime, host_posn); + dev_dbg(sdev->dev, + "PCM: resume stream %d dir %d DMA position %lu\n", + spcm->pcm.pcm_id, substream->stream, host); + + /* set hw_params */ + ret = sof_pcm_hw_params(substream, + &spcm->params[substream->stream]); + if (ret < 0) { + dev_err(sdev->dev, + "error: set pcm hw_params after resume\n"); + return ret; + } + + return 0; +} + +static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm = rtd->private; + struct sof_ipc_stream stream; + struct sof_ipc_reply reply; + int ret = 0; + + /* nothing todo for BE */ + if (rtd->dai_link->no_pcm) + return 0; + + dev_dbg(sdev->dev, "pcm: trigger stream %d dir %d cmd %d\n", + spcm->pcm.pcm_id, substream->stream, cmd); + + stream.hdr.size = sizeof(stream); + stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG; + stream.comp_id = spcm->stream[substream->stream].comp_id; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_STOP: + + /* + * Check if stream was marked for restore before suspend + */ + if (spcm->restore_stream[substream->stream]) { + + /* unset restore_stream */ + spcm->restore_stream[substream->stream] = 0; + + /* do not send ipc as the stream hasn't been set up */ + return 0; + } + + stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_PAUSE; + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + + /* check if the stream hw_params needs to be restored */ + if (spcm->restore_stream[substream->stream]) { + + /* restore hw_params */ + ret = sof_restore_hw_params(substream, spcm, sdev); + if (ret < 0) + return ret; + + /* unset restore_stream */ + spcm->restore_stream[substream->stream] = 0; + + /* trigger start */ + stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_START; + } else { + + /* trigger pause release */ + stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE; + } + break; + case SNDRV_PCM_TRIGGER_START: + /* fall through */ + case SNDRV_PCM_TRIGGER_RESUME: + + /* check if the stream hw_params needs to be restored */ + if (spcm->restore_stream[substream->stream]) { + + /* restore hw_params */ + ret = sof_restore_hw_params(substream, spcm, sdev); + if (ret < 0) + return ret; + + /* unset restore_stream */ + spcm->restore_stream[substream->stream] = 0; + } + + /* trigger stream */ + stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_START; + + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + break; + default: + dev_err(sdev->dev, "error: unhandled trigger cmd %d\n", cmd); + return -EINVAL; + } + + snd_sof_pcm_platform_trigger(sdev, substream, cmd); + + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, + sizeof(stream), &reply, sizeof(reply)); + + return ret; +} + +static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm = rtd->private; + snd_pcm_uframes_t host = 0, dai = 0; + + /* nothing todo for BE */ + if (rtd->dai_link->no_pcm) + return 0; + + /* if have dsp ops pointer callback, use that directly */ + if (sdev->hda && sdev->ops->pcm_pointer) + return sdev->ops->pcm_pointer(sdev, substream); + + /* read position from DSP */ + host = bytes_to_frames(substream->runtime, + spcm->stream[substream->stream].posn.host_posn); + dai = bytes_to_frames(substream->runtime, + spcm->stream[substream->stream].posn.dai_posn); + + dev_dbg(sdev->dev, "PCM: stream %d dir %d DMA position %lu DAI position %lu\n", + spcm->pcm.pcm_id, substream->stream, host, dai); + + return host; +} + +static int sof_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm = rtd->private; + struct snd_soc_tplg_stream_caps *caps = + &spcm->pcm.caps[substream->stream]; + int ret; + + /* nothing todo for BE */ + if (rtd->dai_link->no_pcm) + return 0; + + dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id, + substream->stream); + + mutex_lock(&spcm->mutex); + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "error: pcm open failed to resume %d\n", + ret); + mutex_unlock(&spcm->mutex); + return ret; + } + + /* set any runtime constraints based on topology */ + snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + le32_to_cpu(caps->period_size_min)); + snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + le32_to_cpu(caps->period_size_min)); + + /* set runtime config */ + runtime->hw.info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP; + runtime->hw.formats = le64_to_cpu(caps->formats); + runtime->hw.period_bytes_min = le32_to_cpu(caps->period_size_min); + runtime->hw.period_bytes_max = le32_to_cpu(caps->period_size_max); + runtime->hw.periods_min = le32_to_cpu(caps->periods_min); + runtime->hw.periods_max = le32_to_cpu(caps->periods_max); + runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max); + + dev_dbg(sdev->dev, "period min %zd max %zd bytes\n", + runtime->hw.period_bytes_min, + runtime->hw.period_bytes_max); + dev_dbg(sdev->dev, "period count %d max %d\n", + runtime->hw.periods_min, + runtime->hw.periods_max); + dev_dbg(sdev->dev, "buffer max %zd bytes\n", + runtime->hw.buffer_bytes_max); + + /* set wait time - TODO: come from topology */ + substream->wait_time = 500; + + spcm->stream[substream->stream].posn.host_posn = 0; + spcm->stream[substream->stream].posn.dai_posn = 0; + spcm->stream[substream->stream].substream = substream; + + snd_sof_pcm_platform_open(sdev, substream); + + mutex_unlock(&spcm->mutex); + return 0; +} + +static int sof_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm = rtd->private; + int err; + + /* nothing todo for BE */ + if (rtd->dai_link->no_pcm) + return 0; + + dev_dbg(sdev->dev, "pcm: close stream %d dir %d\n", spcm->pcm.pcm_id, + substream->stream); + + snd_sof_pcm_platform_close(sdev, substream); + + mutex_lock(&spcm->mutex); + pm_runtime_mark_last_busy(sdev->dev); + + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err(sdev->dev, "error: pcm close failed to idle %d\n", + err); + + mutex_unlock(&spcm->mutex); + return 0; +} + +static struct snd_pcm_ops sof_pcm_ops = { + .open = sof_pcm_open, + .close = sof_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = sof_pcm_hw_params, + .hw_free = sof_pcm_hw_free, + .trigger = sof_pcm_trigger, + .pointer = sof_pcm_pointer, + .page = snd_pcm_sgbuf_ops_page, +}; + +static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm; + struct snd_pcm *pcm = rtd->pcm; + struct snd_soc_tplg_stream_caps *caps; + int ret = 0, stream = SNDRV_PCM_STREAM_PLAYBACK; + + /* find SOF PCM for this RTD */ + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) { + dev_warn(sdev->dev, "warn: can't find PCM with DAI ID %d\n", + rtd->dai_link->id); + return 0; + } + rtd->private = spcm; + + dev_dbg(sdev->dev, "creating new PCM %s\n", spcm->pcm.pcm_name); + + /* do we need to allocate playback PCM DMA pages */ + if (!spcm->pcm.playback) + goto capture; + + caps = &spcm->pcm.caps[stream]; + + /* pre-allocate playback audio buffer pages */ + dev_dbg(sdev->dev, "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n", + caps->name, caps->buffer_size_min, caps->buffer_size_max); + + ret = snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream, + SNDRV_DMA_TYPE_DEV_SG, sdev->parent, + le32_to_cpu(caps->buffer_size_min), + le32_to_cpu(caps->buffer_size_max)); + if (ret) { + dev_err(sdev->dev, "error: can't alloc DMA buffer size 0x%x/0x%x for %s %d\n", + caps->buffer_size_min, caps->buffer_size_max, + caps->name, ret); + return ret; + } + + /* allocate playback page table buffer */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->parent, + PAGE_SIZE, &spcm->stream[stream].page_table); + if (ret < 0) { + dev_err(sdev->dev, "error: can't alloc page table for %s %d\n", + caps->name, ret); + return ret; + } + +capture: + stream = SNDRV_PCM_STREAM_CAPTURE; + + /* do we need to allocate capture PCM DMA pages */ + if (!spcm->pcm.capture) + return ret; + + caps = &spcm->pcm.caps[stream]; + + /* pre-allocate capture audio buffer pages */ + dev_dbg(sdev->dev, "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n", + caps->name, caps->buffer_size_min, caps->buffer_size_max); + + ret = snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream, + SNDRV_DMA_TYPE_DEV_SG, sdev->parent, + le32_to_cpu(caps->buffer_size_min), + le32_to_cpu(caps->buffer_size_max)); + if (ret) { + dev_err(sdev->dev, "error: can't alloc DMA buffer size 0x%x/0x%x for %s %d\n", + caps->buffer_size_min, caps->buffer_size_max, + caps->name, ret); + snd_dma_free_pages(&spcm->stream[stream].page_table); + return ret; + } + + /* allocate capture page table buffer */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->parent, + PAGE_SIZE, &spcm->stream[stream].page_table); + if (ret < 0) { + dev_err(sdev->dev, "error: can't alloc page table for %s %d\n", + caps->name, ret); + snd_dma_free_pages(&spcm->stream[stream].page_table); + return ret; + } + + /* TODO: assign channel maps from topology */ + + return ret; +} + +static void sof_pcm_free(struct snd_pcm *pcm) +{ + struct snd_sof_pcm *spcm; + struct snd_soc_pcm_runtime *rtd = pcm->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(component); + + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) { + dev_warn(sdev->dev, "warn: can't find PCM with DAI ID %d\n", + rtd->dai_link->id); + return; + } + + if (spcm->pcm.playback) + snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].page_table); + + if (spcm->pcm.capture) + snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_CAPTURE].page_table); + + snd_sof_free_topology(sdev); +} + +/* fixup the BE DAI link to match any values from topology */ +static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(component); + struct snd_sof_dai *dai = + snd_sof_find_dai(sdev, (char *)rtd->dai_link->name); + + /* no topology exists for this BE, try a common configuration */ + if (!dai) { + dev_warn(sdev->dev, "warning: no topology found for BE DAI %s config\n", + rtd->dai_link->name); + + /* set 48k, stereo, 16bits by default */ + rate->min = 48000; + rate->max = 48000; + + channels->min = 2; + channels->max = 2; + + snd_mask_none(fmt); + snd_mask_set(fmt, (__force int)SNDRV_PCM_FORMAT_S16_LE); + + return 0; + } + + /* read format from topology */ + snd_mask_none(fmt); + + switch (dai->comp_dai.config.frame_fmt) { + case SOF_IPC_FRAME_S16_LE: + snd_mask_set(fmt, (__force int)SNDRV_PCM_FORMAT_S16_LE); + break; + case SOF_IPC_FRAME_S24_4LE: + snd_mask_set(fmt, (__force int)SNDRV_PCM_FORMAT_S24_LE); + break; + case SOF_IPC_FRAME_S32_LE: + snd_mask_set(fmt, (__force int)SNDRV_PCM_FORMAT_S32_LE); + break; + default: + dev_err(sdev->dev, "No available DAI format!\n"); + return -EINVAL; + } + + /* read rate and channels from topology */ + switch (dai->dai_config.type) { + case SOF_DAI_INTEL_SSP: + rate->min = dai->dai_config.ssp.fsync_rate; + rate->max = dai->dai_config.ssp.fsync_rate; + channels->min = dai->dai_config.ssp.tdm_slots; + channels->max = dai->dai_config.ssp.tdm_slots; + + dev_dbg(sdev->dev, + "rate_min: %d rate_max: %d\n", rate->min, rate->max); + dev_dbg(sdev->dev, + "channels_min: %d channels_max: %d\n", + channels->min, channels->max); + + break; + case SOF_DAI_INTEL_DMIC: + /* DMIC only supports 16 or 32 bit formats */ + if (dai->comp_dai.config.frame_fmt == SOF_IPC_FRAME_S24_4LE) { + dev_err(sdev->dev, + "error: invalid fmt %d for DAI type %d\n", + dai->comp_dai.config.frame_fmt, + dai->dai_config.type); + } + /* TODO: add any other DMIC specific fixups */ + break; + case SOF_DAI_INTEL_HDA: + /* do nothing for HDA dai_link */ + break; + default: + dev_err(sdev->dev, "error: invalid DAI type %d\n", + dai->dai_config.type); + break; + } + + return 0; +} + +static int sof_pcm_probe(struct snd_soc_component *component) +{ + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(component); + struct snd_sof_pdata *plat_data = dev_get_platdata(component->dev); + const char *tplg_filename; + int ret, err; + + /* load the default topology */ + sdev->component = component; + + switch (plat_data->type) { + case SOF_DEVICE_SPI: + tplg_filename = plat_data->sof_machine->sof_tplg_filename; + break; + default: + tplg_filename = plat_data->machine->sof_tplg_filename; + } + + ret = snd_sof_load_topology(sdev, tplg_filename); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to load DSP topology %d\n", + ret); + goto err; + } + + /* enable runtime PM with auto suspend */ + pm_runtime_set_autosuspend_delay(component->dev, + SND_SOF_SUSPEND_DELAY); + pm_runtime_use_autosuspend(component->dev); + pm_runtime_enable(component->dev); + err = pm_runtime_idle(component->dev); + if (err < 0) + dev_err(sdev->dev, "error: failed to enter PM idle %d\n", err); + +err: + return ret; +} + +static void sof_pcm_remove(struct snd_soc_component *component) +{ + pm_runtime_disable(component->dev); +} + +void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) +{ + struct snd_soc_component_driver *pd = &sdev->plat_drv; + struct snd_sof_pdata *plat_data = sdev->pdata; + const char *plat_name, *drv_name; + + switch (plat_data->type) { + case SOF_DEVICE_SPI: + plat_name = plat_data->sof_machine->asoc_plat_name; + drv_name = plat_data->sof_machine->drv_name; + break; + default: + plat_name = plat_data->machine->asoc_plat_name; + drv_name = plat_data->machine->drv_name; + } + + dev_dbg(sdev->dev, "using platform alias %s\n", plat_name); + + pd->name = "sof-audio"; + pd->probe = sof_pcm_probe; + pd->remove = sof_pcm_remove; + pd->ops = &sof_pcm_ops; + pd->compr_ops = &sof_compressed_ops; + pd->pcm_new = sof_pcm_new; + pd->pcm_free = sof_pcm_free; + pd->ignore_machine = drv_name; + pd->be_hw_params_fixup = sof_pcm_dai_link_fixup; + pd->be_pcm_base = SOF_BE_PCM_BASE; + pd->use_dai_pcm_id = true; + pd->topology_name_prefix = "sof"; +} + From 734a80fbb3a030809f4691bd712b1e20cdccaedf Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:33:05 +0000 Subject: [PATCH 0096/1995] ASoC: SOF: Add support for loading topologies SOF uses topology to define the DAPM graphs and widgets, DAIs, PCMs and set parameters for init and run time usage. This patch loads topology and maps it to IPC commands that are build the topology on the DSP. Signed-off-by: Liam Girdwood --- include/uapi/sound/sof-topology.h | 95 ++ sound/soc/sof/sof-priv.h | 1 + sound/soc/sof/topology.c | 2511 +++++++++++++++++++++++++++++ 3 files changed, 2607 insertions(+) create mode 100644 include/uapi/sound/sof-topology.h create mode 100644 sound/soc/sof/topology.c diff --git a/include/uapi/sound/sof-topology.h b/include/uapi/sound/sof-topology.h new file mode 100644 index 00000000000000..0db5253a37bf35 --- /dev/null +++ b/include/uapi/sound/sof-topology.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * Author: Liam Girdwood + * Keyon Jie + */ + +/* + * Topology IDs and tokens. + * + * ** MUST BE ALIGNED WITH TOPOLOGY CONFIGURATION TOKEN VALUES ** + */ + +#ifndef __INCLUDE_UAPI_SOF_TOPOLOGY_H__ +#define __INCLUDE_UAPI_SOF_TOPOLOGY_H__ + +/* + * Kcontrol IDs + */ +#define SOF_TPLG_KCTL_VOL_ID 256 +#define SOF_TPLG_KCTL_ENUM_ID 257 +#define SOF_TPLG_KCTL_BYTES_ID 258 + +/* + * Tokens - must match values in topology configurations + */ + +/* buffers */ +#define SOF_TKN_BUF_SIZE 100 +#define SOF_TKN_BUF_CAPS 101 + +/* DAI */ +#define SOF_TKN_DAI_DMAC_CONFIG 153 +#define SOF_TKN_DAI_TYPE 154 +#define SOF_TKN_DAI_INDEX 155 +#define SOF_TKN_DAI_DIRECTION 156 + +/* scheduling */ +#define SOF_TKN_SCHED_DEADLINE 200 +#define SOF_TKN_SCHED_PRIORITY 201 +#define SOF_TKN_SCHED_MIPS 202 +#define SOF_TKN_SCHED_CORE 203 +#define SOF_TKN_SCHED_FRAMES 204 +#define SOF_TKN_SCHED_TIMER 205 + +/* volume */ +#define SOF_TKN_VOLUME_RAMP_STEP_TYPE 250 +#define SOF_TKN_VOLUME_RAMP_STEP_MS 251 + +/* SRC */ +#define SOF_TKN_SRC_RATE_IN 300 +#define SOF_TKN_SRC_RATE_OUT 301 + +/* PCM */ +#define SOF_TKN_PCM_DMAC_CONFIG 353 + +/* Generic components */ +#define SOF_TKN_COMP_PERIOD_SINK_COUNT 400 +#define SOF_TKN_COMP_PERIOD_SOURCE_COUNT 401 +#define SOF_TKN_COMP_FORMAT 402 +#define SOF_TKN_COMP_PRELOAD_COUNT 403 + +/* SSP */ +#define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500 +#define SOF_TKN_INTEL_SSP_MCLK_ID 501 +#define SOF_TKN_INTEL_SSP_SAMPLE_BITS 502 +#define SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH 503 +#define SOF_TKN_INTEL_SSP_QUIRKS 504 +#define SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT 505 + +/* DMIC */ +#define SOF_TKN_INTEL_DMIC_DRIVER_VERSION 600 +#define SOF_TKN_INTEL_DMIC_CLK_MIN 601 +#define SOF_TKN_INTEL_DMIC_CLK_MAX 602 +#define SOF_TKN_INTEL_DMIC_DUTY_MIN 603 +#define SOF_TKN_INTEL_DMIC_DUTY_MAX 604 +#define SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE 605 +#define SOF_TKN_INTEL_DMIC_SAMPLE_RATE 608 +#define SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH 609 + +/* DMIC PDM */ +#define SOF_TKN_INTEL_DMIC_PDM_CTRL_ID 700 +#define SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable 701 +#define SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable 702 +#define SOF_TKN_INTEL_DMIC_PDM_POLARITY_A 703 +#define SOF_TKN_INTEL_DMIC_PDM_POLARITY_B 704 +#define SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE 705 +#define SOF_TKN_INTEL_DMIC_PDM_SKEW 706 + +#define SOF_TKN_EFFECT_TYPE 900 + +#endif diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 47329893fd25fc..ade7b2068fcb03 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -249,6 +249,7 @@ struct snd_sof_control { struct sof_ipc_ctrl_data *control_data; u32 size; /* cdata size */ enum sof_ipc_ctrl_cmd cmd; + u32 *volume_table; /* volume table computed from tlv data*/ struct mutex mutex; /* access mutex */ struct list_head list; /* list in sdev control list */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c new file mode 100644 index 00000000000000..c71ad4ab962367 --- /dev/null +++ b/sound/soc/sof/topology.c @@ -0,0 +1,2511 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sof-priv.h" + +#define COMP_ID_UNASSIGNED 0xffffffff +/* Constants used in the computation of linear volume gain from dB gain */ +/* 20th root of 10 in Q1.16 fixed-point notation*/ +#define VOL_TWENTIETH_ROOT_OF_TEN 73533 +/* 40th root of 10 in Q1.16 fixed-point notation*/ +#define VOL_FORTIETH_ROOT_OF_TEN 69419 +/* Volume fractional word length */ +#define VOLUME_FWL 16 +/* 0.5 dB step value in topology TLV */ +#define VOL_HALF_DB_STEP 50 + +/* TLV data items */ +#define TLV_ITEMS 3 +#define TLV_MIN 0 +#define TLV_STEP 1 +#define TLV_MUTE 2 + +static inline int get_tlv_data(const int *p, int tlv[TLV_ITEMS]) +{ + /* we only support dB scale TLV type at the moment */ + if ((int)p[SNDRV_CTL_TLVO_TYPE] != SNDRV_CTL_TLVT_DB_SCALE) + return -EINVAL; + + /* min value in topology tlv data is multiplied by 100 */ + tlv[TLV_MIN] = (int)p[SNDRV_CTL_TLVO_DB_SCALE_MIN] / 100; + + /* volume steps */ + tlv[TLV_STEP] = (int)(p[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] & + TLV_DB_SCALE_MASK); + + /* mute ON/OFF */ + if ((p[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] & + TLV_DB_SCALE_MUTE) == 0) + tlv[TLV_MUTE] = 0; + else + tlv[TLV_MUTE] = 1; + + return 0; +} + +/* Function to truncate an unsigned 64-bit number + * by x bits and return 32-bit unsigned number + * This function also takes care of rounding while truncating + */ +static inline u32 vol_shift_64(u64 i, u32 x) +{ + /* do not truncate more than 32 bits */ + if (x > 32) + x = 32; + + if (x == 0) + return (u32)i; + + return (u32)(((i >> (x - 1)) + 1) >> 1); +} + +/* Function to compute a ^ exp where, + * a is a fractional number represented by a fixed-point integer + * with a fractional world length of "fwl" + * exp is an integer + * fwl is the fractional word length + * Return value is a fractional number represented by a fixed-point + * integer with a fractional word length of "fwl" + */ +static u32 vol_pow32(u32 a, int exp, u32 fwl) +{ + int i, iter; + u32 power = 1 << fwl; + u64 numerator; + + /* if exponent is 0, return 1 */ + if (exp == 0) + return power; + + /* determine the number of iterations based on the exponent */ + if (exp < 0) + iter = exp * -1; + else + iter = exp; + + /* mutiply a "iter" times to compute power */ + for (i = 0; i < iter; i++) { + /* Product of 2 Qx.fwl fixed-point numbers yields a Q2*x.2*fwl + * Truncate product back to fwl fractional bits with rounding + */ + power = vol_shift_64((u64)power * a, fwl); + } + + if (exp > 0) { + /* if exp is positive, return the result */ + return power; + } + + /* if exp is negative, return the multiplicative inverse */ + numerator = (u64)1 << (fwl << 1); + do_div(numerator, power); + + return (u32)numerator; +} + +/* Function to calculate volume gain from TLV data + * This function can only handle gain steps that are multiples of 0.5 dB + */ +static u32 vol_compute_gain(u32 value, int *tlv) +{ + int dB_gain; + u32 linear_gain; + int f_step; + + /* mute volume */ + if (value == 0 && tlv[TLV_MUTE]) + return 0; + + /* compute dB gain from tlv + * tlv_step in topology is multiplied by 100 + */ + dB_gain = tlv[TLV_MIN] + (value * tlv[TLV_STEP]) / 100; + + /* compute linear gain + * represented by fixed-point int with VOLUME_FWL fractional bits + */ + linear_gain = vol_pow32(VOL_TWENTIETH_ROOT_OF_TEN, dB_gain, VOLUME_FWL); + + /* extract the fractional part of volume step */ + f_step = tlv[TLV_STEP] - (tlv[TLV_STEP] / 100); + + /* if volume step is an odd multiple of 0.5 dB */ + if (f_step == VOL_HALF_DB_STEP && (value & 1)) + linear_gain = vol_shift_64((u64)linear_gain * + VOL_FORTIETH_ROOT_OF_TEN, + VOLUME_FWL); + + return linear_gain; +} + +/* Set up volume table for kcontrols from tlv data + * "size" specifies the number of entries in the table + */ +static int set_up_volume_table(struct snd_sof_control *scontrol, + int tlv[TLV_ITEMS], int size) +{ + int j; + + /* init the volume table */ + scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL); + if (!scontrol->volume_table) + return -ENOMEM; + + /* populate the volume table */ + for (j = 0; j < size ; j++) + scontrol->volume_table[j] = vol_compute_gain(j, tlv); + + return 0; +} + +struct sof_dai_types { + const char *name; + enum sof_ipc_dai_type type; +}; + +static const struct sof_dai_types sof_dais[] = { + {"SSP", SOF_DAI_INTEL_SSP}, + {"HDA", SOF_DAI_INTEL_HDA}, + {"DMIC", SOF_DAI_INTEL_DMIC}, +}; + +static enum sof_ipc_dai_type find_dai(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sof_dais); i++) { + if (strcmp(name, sof_dais[i].name) == 0) + return sof_dais[i].type; + } + + return SOF_DAI_INTEL_NONE; +} + +/* + * Supported Frame format types and lookup, add new ones to end of list. + */ + +struct sof_frame_types { + const char *name; + enum sof_ipc_frame frame; +}; + +static const struct sof_frame_types sof_frames[] = { + {"s16le", SOF_IPC_FRAME_S16_LE}, + {"s24le", SOF_IPC_FRAME_S24_4LE}, + {"s32le", SOF_IPC_FRAME_S32_LE}, + {"float", SOF_IPC_FRAME_FLOAT}, +}; + +static enum sof_ipc_frame find_format(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sof_frames); i++) { + if (strcmp(name, sof_frames[i].name) == 0) + return sof_frames[i].frame; + } + + /* use s32le if nothing is specified */ + return SOF_IPC_FRAME_S32_LE; +} + +struct sof_effect_types { + const char *name; + enum sof_ipc_effect_type type; +}; + +static const struct sof_effect_types sof_effects[] = { + {"EQFIR", SOF_EFFECT_INTEL_EQFIR}, + {"EQIIR", SOF_EFFECT_INTEL_EQIIR}, +}; + +static enum sof_ipc_effect_type find_effect(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sof_effects); i++) { + if (strcmp(name, sof_effects[i].name) == 0) + return sof_effects[i].type; + } + + return SOF_EFFECT_NONE; +} + +/* + * Standard Kcontrols. + */ + +static int sof_control_load_volume(struct snd_soc_component *scomp, + struct snd_sof_control *scontrol, + struct snd_kcontrol_new *kc, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_mixer_control *mc = + (struct snd_soc_tplg_mixer_control *)hdr; + struct sof_ipc_ctrl_data *cdata; + + /* validate topology data */ + if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN) + return -EINVAL; + + /* init the volume get/put data */ + scontrol->size = sizeof(struct sof_ipc_ctrl_data) + + sizeof(struct sof_ipc_ctrl_value_chan) * + le32_to_cpu(mc->num_channels); + scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); + cdata = scontrol->control_data; + if (!scontrol->control_data) + return -ENOMEM; + + scontrol->comp_id = sdev->next_comp_id; + scontrol->num_channels = le32_to_cpu(mc->num_channels); + + dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", + scontrol->comp_id, scontrol->num_channels); + + return 0; +} + +static int sof_control_load_bytes(struct snd_soc_component *scomp, + struct snd_sof_control *scontrol, + struct snd_kcontrol_new *kc, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc_ctrl_data *cdata; + struct snd_soc_tplg_bytes_control *control = + (struct snd_soc_tplg_bytes_control *)hdr; + + /* init the get/put bytes data */ + scontrol->size = SOF_IPC_MSG_MAX_SIZE; + scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); + cdata = scontrol->control_data; + if (!scontrol->control_data) + return -ENOMEM; + + scontrol->comp_id = sdev->next_comp_id; + scontrol->cmd = SOF_CTRL_CMD_BINARY; + + dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", + scontrol->comp_id, scontrol->num_channels); + + if (le32_to_cpu(control->priv.size) > SOF_IPC_MSG_MAX_SIZE) { + dev_warn(sdev->dev, "bytes priv data size %d too big\n", + control->priv.size); + return -EINVAL; + } + + if (le32_to_cpu(control->priv.size) > 0) { + memcpy(cdata->data->data, control->priv.data, + le32_to_cpu(control->priv.size)); + cdata->data->size = control->priv.size; + cdata->data->magic = SOF_ABI_MAGIC; + cdata->data->abi = SOF_ABI_VERSION; + cdata->data->comp_abi = SOF_ABI_VERSION; + } + + return 0; +} + +/* + * Topology Token Parsing. + * New tokens should be added to headers and parsing tables below. + */ + +struct sof_topology_token { + u32 token; + u32 type; + int (*get_token)(void *elem, void *object, u32 offset, u32 size); + u32 offset; + u32 size; +}; + +static int get_token_u32(void *elem, void *object, u32 offset, u32 size) +{ + struct snd_soc_tplg_vendor_value_elem *velem = elem; + u32 *val = object + offset; + + *val = le32_to_cpu(velem->value); + return 0; +} + +static int get_token_u16(void *elem, void *object, u32 offset, u32 size) +{ + struct snd_soc_tplg_vendor_value_elem *velem = elem; + u16 *val = object + offset; + + *val = (u16)le32_to_cpu(velem->value); + return 0; +} + +static int get_token_comp_format(void *elem, void *object, u32 offset, u32 size) +{ + struct snd_soc_tplg_vendor_string_elem *velem = elem; + u32 *val = object + offset; + + *val = find_format(velem->string); + return 0; +} + +static int get_token_dai_type(void *elem, void *object, u32 offset, u32 size) +{ + struct snd_soc_tplg_vendor_string_elem *velem = elem; + u32 *val = object + offset; + + *val = find_dai(velem->string); + return 0; +} + +static int get_token_effect_type(void *elem, void *object, u32 offset, u32 size) +{ + struct snd_soc_tplg_vendor_string_elem *velem = elem; + u32 *val = object + offset; + + *val = find_effect(velem->string); + return 0; +} + +/* Buffers */ +static const struct sof_topology_token buffer_tokens[] = { + {SOF_TKN_BUF_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_buffer, size), 0}, + {SOF_TKN_BUF_CAPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_buffer, caps), 0}, +}; + +/* DAI */ +static const struct sof_topology_token dai_tokens[] = { + {SOF_TKN_DAI_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_dai, dmac_config), 0}, + {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, + offsetof(struct sof_ipc_comp_dai, type), 0}, + {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_dai, dai_index), 0}, + {SOF_TKN_DAI_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_dai, direction), 0}, +}; + +/* BE DAI link */ +static const struct sof_topology_token dai_link_tokens[] = { + {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, + offsetof(struct sof_ipc_dai_config, type), 0}, + {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_config, dai_index), 0}, +}; + +/* scheduling */ +static const struct sof_topology_token sched_tokens[] = { + {SOF_TKN_SCHED_DEADLINE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, deadline), 0}, + {SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, priority), 0}, + {SOF_TKN_SCHED_MIPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, mips), 0}, + {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, core), 0}, + {SOF_TKN_SCHED_FRAMES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, frames_per_sched), 0}, + {SOF_TKN_SCHED_TIMER, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, timer_delay), 0}, +}; + +/* volume */ +static const struct sof_topology_token volume_tokens[] = { + {SOF_TKN_VOLUME_RAMP_STEP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, offsetof(struct sof_ipc_comp_volume, ramp), 0}, + {SOF_TKN_VOLUME_RAMP_STEP_MS, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_volume, initial_ramp), 0}, +}; + +/* SRC */ +static const struct sof_topology_token src_tokens[] = { + {SOF_TKN_SRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_src, source_rate), 0}, + {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_src, sink_rate), 0}, +}; + +/* Tone */ +static const struct sof_topology_token tone_tokens[] = { +}; + +/* EFFECT */ +static const struct sof_topology_token effect_tokens[] = { + {SOF_TKN_EFFECT_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, + get_token_effect_type, + offsetof(struct sof_ipc_comp_effect, type), 0}, +}; + +/* PCM */ +static const struct sof_topology_token pcm_tokens[] = { + {SOF_TKN_PCM_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_host, dmac_config), 0}, +}; + +/* Generic components */ +static const struct sof_topology_token comp_tokens[] = { + {SOF_TKN_COMP_PERIOD_SINK_COUNT, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_config, periods_sink), 0}, + {SOF_TKN_COMP_PERIOD_SOURCE_COUNT, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_config, periods_source), 0}, + {SOF_TKN_COMP_FORMAT, + SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format, + offsetof(struct sof_ipc_comp_config, frame_fmt), 0}, + {SOF_TKN_COMP_PRELOAD_COUNT, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_config, preload_count), 0}, +}; + +/* SSP */ +static const struct sof_topology_token ssp_tokens[] = { + {SOF_TKN_INTEL_SSP_CLKS_CONTROL, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_ssp_params, clks_control), 0}, + {SOF_TKN_INTEL_SSP_MCLK_ID, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_ssp_params, mclk_id), 0}, + {SOF_TKN_INTEL_SSP_SAMPLE_BITS, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, + offsetof(struct sof_ipc_dai_ssp_params, sample_valid_bits), 0}, + {SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT, + get_token_u16, + offsetof(struct sof_ipc_dai_ssp_params, frame_pulse_width), 0}, + {SOF_TKN_INTEL_SSP_QUIRKS, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, + offsetof(struct sof_ipc_dai_ssp_params, quirks), 0}, + {SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT, SND_SOC_TPLG_TUPLE_TYPE_BOOL, + get_token_u16, + offsetof(struct sof_ipc_dai_ssp_params, + tdm_per_slot_padding_flag), 0}, + +}; + +/* DMIC */ +static const struct sof_topology_token dmic_tokens[] = { + {SOF_TKN_INTEL_DMIC_DRIVER_VERSION, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, driver_ipc_version), + 0}, + {SOF_TKN_INTEL_DMIC_CLK_MIN, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, pdmclk_min), 0}, + {SOF_TKN_INTEL_DMIC_CLK_MAX, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, pdmclk_max), 0}, + {SOF_TKN_INTEL_DMIC_SAMPLE_RATE, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, fifo_fs_a), 0}, + {SOF_TKN_INTEL_DMIC_DUTY_MIN, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_params, duty_min), 0}, + {SOF_TKN_INTEL_DMIC_DUTY_MAX, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_params, duty_max), 0}, + {SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, + num_pdm_active), 0}, + {SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_params, fifo_bits_a), 0}, +}; + +/* + * DMIC PDM Tokens + * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token + * as it increments the index while parsing the array of pdm tokens + * and determines the correct offset + */ +static const struct sof_topology_token dmic_pdm_tokens[] = { + {SOF_TKN_INTEL_DMIC_PDM_CTRL_ID, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, id), + 0}, + {SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_a), + 0}, + {SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_b), + 0}, + {SOF_TKN_INTEL_DMIC_PDM_POLARITY_A, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_a), + 0}, + {SOF_TKN_INTEL_DMIC_PDM_POLARITY_B, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_b), + 0}, + {SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, clk_edge), + 0}, + {SOF_TKN_INTEL_DMIC_PDM_SKEW, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, skew), + 0}, +}; + +/* HDA */ +static const struct sof_topology_token hda_tokens[] = { +}; + +static void sof_parse_uuid_tokens(struct snd_soc_component *scomp, + void *object, + const struct sof_topology_token *tokens, + int count, + struct snd_soc_tplg_vendor_array *array) +{ + struct snd_soc_tplg_vendor_uuid_elem *elem; + int i, j; + + /* parse element by element */ + for (i = 0; i < le32_to_cpu(array->num_elems); i++) { + elem = &array->uuid[i]; + + /* search for token */ + for (j = 0; j < count; j++) { + /* match token type */ + if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_UUID) + continue; + + /* match token id */ + if (tokens[j].token != le32_to_cpu(elem->token)) + continue; + + /* matched - now load token */ + tokens[j].get_token(elem, object, tokens[j].offset, + tokens[j].size); + } + } +} + +static void sof_parse_string_tokens(struct snd_soc_component *scomp, + void *object, + const struct sof_topology_token *tokens, + int count, + struct snd_soc_tplg_vendor_array *array) +{ + struct snd_soc_tplg_vendor_string_elem *elem; + int i, j; + + /* parse element by element */ + for (i = 0; i < le32_to_cpu(array->num_elems); i++) { + elem = &array->string[i]; + + /* search for token */ + for (j = 0; j < count; j++) { + /* match token type */ + if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_STRING) + continue; + + /* match token id */ + if (tokens[j].token != le32_to_cpu(elem->token)) + continue; + + /* matched - now load token */ + tokens[j].get_token(elem, object, tokens[j].offset, + tokens[j].size); + } + } +} + +static void sof_parse_word_tokens(struct snd_soc_component *scomp, + void *object, + const struct sof_topology_token *tokens, + int count, + struct snd_soc_tplg_vendor_array *array) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_vendor_value_elem *elem; + size_t size = sizeof(struct sof_ipc_dai_dmic_pdm_ctrl); + int i, j; + u32 offset; + u32 *index = NULL; + + /* parse element by element */ + for (i = 0; i < le32_to_cpu(array->num_elems); i++) { + elem = &array->value[i]; + + /* search for token */ + for (j = 0; j < count; j++) { + /* match token type */ + if (!(tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_WORD || + tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_SHORT)) + continue; + + /* match token id */ + if (tokens[j].token != le32_to_cpu(elem->token)) + continue; + + /* pdm config array index */ + if (sdev->private) + index = (u32 *)sdev->private; + + /* matched - determine offset */ + switch (tokens[j].token) { + case SOF_TKN_INTEL_DMIC_PDM_CTRL_ID: + + /* inc number of pdm array index */ + if (index) + (*index)++; + /* fallthrough */ + case SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable: + case SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable: + case SOF_TKN_INTEL_DMIC_PDM_POLARITY_A: + case SOF_TKN_INTEL_DMIC_PDM_POLARITY_B: + case SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE: + case SOF_TKN_INTEL_DMIC_PDM_SKEW: + + /* check if array index is valid */ + if (!index || *index == 0) { + dev_err(sdev->dev, + "error: invalid array offset\n"); + continue; + } else { + /* offset within the pdm config array */ + offset = size * (*index - 1); + } + break; + default: + offset = 0; + break; + } + + /* load token */ + tokens[j].get_token(elem, object, + offset + tokens[j].offset, + tokens[j].size); + } + } +} + +static int sof_parse_tokens(struct snd_soc_component *scomp, + void *object, + const struct sof_topology_token *tokens, + int count, + struct snd_soc_tplg_vendor_array *array, + int priv_size) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + int asize; + + while (priv_size > 0) { + asize = le32_to_cpu(array->size); + + /* validate asize */ + if (asize < 0) { /* FIXME: A zero-size array makes no sense */ + dev_err(sdev->dev, "error: invalid array size 0x%x\n", + asize); + return -EINVAL; + } + + /* make sure there is enough data before parsing */ + priv_size -= asize; + if (priv_size < 0) { + dev_err(sdev->dev, "error: invalid array size 0x%x\n", + asize); + return -EINVAL; + } + + /* call correct parser depending on type */ + switch (le32_to_cpu(array->type)) { + case SND_SOC_TPLG_TUPLE_TYPE_UUID: + sof_parse_uuid_tokens(scomp, object, tokens, count, + array); + break; + case SND_SOC_TPLG_TUPLE_TYPE_STRING: + sof_parse_string_tokens(scomp, object, tokens, count, + array); + break; + case SND_SOC_TPLG_TUPLE_TYPE_BOOL: + case SND_SOC_TPLG_TUPLE_TYPE_BYTE: + case SND_SOC_TPLG_TUPLE_TYPE_WORD: + case SND_SOC_TPLG_TUPLE_TYPE_SHORT: + sof_parse_word_tokens(scomp, object, tokens, count, + array); + break; + default: + dev_err(sdev->dev, "error: unknown token type %d\n", + array->type); + return -EINVAL; + } + + /* next array */ + array = (void *)array + asize; + } + return 0; +} + +static void sof_dbg_comp_config(struct snd_soc_component *scomp, + struct sof_ipc_comp_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + + dev_dbg(sdev->dev, " config: periods snk %d src %d fmt %d\n", + config->periods_sink, config->periods_source, + config->frame_fmt); +} + +/* external kcontrol init - used for any driver specific init */ +static int sof_control_load(struct snd_soc_component *scomp, int index, + struct snd_kcontrol_new *kc, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct soc_mixer_control *sm; + struct soc_bytes_ext *sbe; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_dobj *dobj = NULL; + struct snd_sof_control *scontrol; + int ret = -EINVAL; + + dev_dbg(sdev->dev, "tplg: load control type %d name : %s\n", + hdr->type, hdr->name); + + scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL); + if (!scontrol) + return -ENOMEM; + + scontrol->sdev = sdev; + mutex_init(&scontrol->mutex); + + switch (le32_to_cpu(hdr->ops.info)) { + case SND_SOC_TPLG_CTL_VOLSW: + case SND_SOC_TPLG_CTL_VOLSW_SX: + case SND_SOC_TPLG_CTL_VOLSW_XR_SX: + sm = (struct soc_mixer_control *)kc->private_value; + dobj = &sm->dobj; + ret = sof_control_load_volume(scomp, scontrol, kc, hdr); + break; + case SND_SOC_TPLG_CTL_BYTES: + sbe = (struct soc_bytes_ext *)kc->private_value; + dobj = &sbe->dobj; + ret = sof_control_load_bytes(scomp, scontrol, kc, hdr); + break; + case SND_SOC_TPLG_CTL_ENUM: + case SND_SOC_TPLG_CTL_ENUM_VALUE: + case SND_SOC_TPLG_CTL_RANGE: + case SND_SOC_TPLG_CTL_STROBE: + case SND_SOC_TPLG_DAPM_CTL_VOLSW: + case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: + case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: + case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: + case SND_SOC_TPLG_DAPM_CTL_PIN: + default: + dev_warn(sdev->dev, "control type not supported %d:%d:%d\n", + hdr->ops.get, hdr->ops.put, hdr->ops.info); + kfree(scontrol); + return 0; + } + + dobj->private = scontrol; + list_add(&scontrol->list, &sdev->kcontrol_list); + return ret; +} + +static int sof_control_unload(struct snd_soc_component *scomp, + struct snd_soc_dobj *dobj) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc_free fcomp; + struct snd_sof_control *scontrol = dobj->private; + + dev_dbg(sdev->dev, "tplg: unload control name : %s\n", scomp->name); + + fcomp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_FREE; + fcomp.hdr.size = sizeof(fcomp); + fcomp.id = scontrol->comp_id; + + /* send IPC to the DSP */ + return sof_ipc_tx_message(sdev->ipc, + fcomp.hdr.cmd, &fcomp, sizeof(fcomp), + NULL, 0); +} + +/* + * DAI Topology + */ + +static int sof_connect_dai_widget(struct snd_soc_component *scomp, + struct snd_soc_dapm_widget *w, + struct snd_soc_tplg_dapm_widget *tw, + struct snd_sof_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_card *card = scomp->card; + struct snd_soc_pcm_runtime *rtd; + + list_for_each_entry(rtd, &card->rtd_list, list) { + dev_vdbg(sdev->dev, "tplg: check widget: %s stream: %s dai stream: %s\n", + w->name, w->sname, rtd->dai_link->stream_name); + + if (!w->sname || !rtd->dai_link->stream_name) + continue; + + /* does stream match DAI link ? */ + if (strcmp(w->sname, rtd->dai_link->stream_name)) + continue; + + switch (w->id) { + case snd_soc_dapm_dai_out: + rtd->cpu_dai->capture_widget = w; + if (dai) + dai->name = rtd->dai_link->name; + dev_dbg(sdev->dev, "tplg: connected widget %s -> DAI link %s\n", + w->name, rtd->dai_link->name); + break; + case snd_soc_dapm_dai_in: + rtd->cpu_dai->playback_widget = w; + if (dai) + dai->name = rtd->dai_link->name; + dev_dbg(sdev->dev, "tplg: connected widget %s -> DAI link %s\n", + w->name, rtd->dai_link->name); + break; + default: + break; + } + } + + /* check we have a connection */ + if (!dai->name) { + dev_err(sdev->dev, "error: can't connect DAI %s stream %s\n", + w->name, w->sname); + return -EINVAL; + } + + return 0; +} + +static int sof_widget_load_dai(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r, + struct snd_sof_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_dai comp_dai; + int ret; + + /* configure dai IPC message */ + memset(&comp_dai, 0, sizeof(comp_dai)); + comp_dai.comp.hdr.size = sizeof(comp_dai); + comp_dai.comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + comp_dai.comp.id = swidget->comp_id; + comp_dai.comp.type = SOF_COMP_DAI; + comp_dai.comp.pipeline_id = index; + + ret = sof_parse_tokens(scomp, &comp_dai, dai_tokens, + ARRAY_SIZE(dai_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse dai tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + + ret = sof_parse_tokens(scomp, &comp_dai.config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse dai.cfg tokens failed %d\n", + private->size); + return ret; + } + + dev_dbg(sdev->dev, "dai %s: type %d index %d\n", + swidget->widget->name, comp_dai.type, comp_dai.dai_index); + sof_dbg_comp_config(scomp, &comp_dai.config); + + ret = sof_ipc_tx_message(sdev->ipc, comp_dai.comp.hdr.cmd, + &comp_dai, sizeof(comp_dai), r, sizeof(*r)); + + if (ret == 0 && dai) { + dai->sdev = sdev; + memcpy(&dai->comp_dai, &comp_dai, sizeof(comp_dai)); + } + + return ret; +} + +/* + * Buffer topology + */ + +static int sof_widget_load_buffer(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_buffer *buffer; + int ret; + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + /* configure dai IPC message */ + buffer->comp.hdr.size = sizeof(*buffer); + buffer->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_BUFFER_NEW; + buffer->comp.id = swidget->comp_id; + buffer->comp.type = SOF_COMP_BUFFER; + buffer->comp.pipeline_id = index; + + ret = sof_parse_tokens(scomp, buffer, buffer_tokens, + ARRAY_SIZE(buffer_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse buffer tokens failed %d\n", + private->size); + kfree(buffer); + return ret; + } + + dev_dbg(sdev->dev, "buffer %s: size %d caps 0x%x\n", + swidget->widget->name, buffer->size, buffer->caps); + + swidget->private = (void *)buffer; + + ret = sof_ipc_tx_message(sdev->ipc, buffer->comp.hdr.cmd, buffer, + sizeof(*buffer), r, sizeof(*r)); + if (ret < 0) { + dev_err(sdev->dev, "buffer %s load failed\n", + swidget->widget->name); + kfree(buffer); + } + + return ret; +} + +/* + * PCM Topology + */ + +static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + enum sof_ipc_stream_direction dir, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_host *host; + int ret; + + host = kzalloc(sizeof(*host), GFP_KERNEL); + if (!host) + return -ENOMEM; + + /* configure mixer IPC message */ + host->comp.hdr.size = sizeof(*host); + host->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + host->comp.id = swidget->comp_id; + host->comp.type = SOF_COMP_HOST; + host->comp.pipeline_id = index; + host->direction = dir; + + ret = sof_parse_tokens(scomp, host, pcm_tokens, + ARRAY_SIZE(pcm_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse host tokens failed %d\n", + private->size); + goto err; + } + + ret = sof_parse_tokens(scomp, &host->config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse host.cfg tokens failed %d\n", + le32_to_cpu(private->size)); + goto err; + } + + dev_dbg(sdev->dev, "loaded host %s\n", swidget->widget->name); + sof_dbg_comp_config(scomp, &host->config); + + swidget->private = (void *)host; + + ret = sof_ipc_tx_message(sdev->ipc, host->comp.hdr.cmd, host, + sizeof(*host), r, sizeof(*r)); + if (ret >= 0) + return ret; +err: + kfree(host); + return ret; +} + +/* + * Pipeline Topology + */ + +static int sof_widget_load_pipeline(struct snd_soc_component *scomp, + int index, struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_pipe_new *pipeline; + struct snd_sof_widget *comp_swidget; + int ret; + + pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL); + if (!pipeline) + return -ENOMEM; + + /* configure dai IPC message */ + pipeline->hdr.size = sizeof(*pipeline); + pipeline->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_NEW; + pipeline->pipeline_id = index; + pipeline->comp_id = swidget->comp_id; + + /* component at start of pipeline is our stream id */ + comp_swidget = snd_sof_find_swidget(sdev, tw->sname); + if (!comp_swidget) { + dev_err(sdev->dev, "error: widget %s refers to non existent widget %s\n", + tw->name, tw->sname); + ret = -EINVAL; + goto err; + } + + pipeline->sched_id = comp_swidget->comp_id; + + dev_dbg(sdev->dev, "tplg: pipeline id %d comp %d scheduling comp id %d\n", + pipeline->pipeline_id, pipeline->comp_id, pipeline->sched_id); + + ret = sof_parse_tokens(scomp, pipeline, sched_tokens, + ARRAY_SIZE(sched_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse pipeline tokens failed %d\n", + private->size); + goto err; + } + + dev_dbg(sdev->dev, "pipeline %s: deadline %d pri %d mips %d core %d frames %d\n", + swidget->widget->name, pipeline->deadline, pipeline->priority, + pipeline->mips, pipeline->core, pipeline->frames_per_sched); + + swidget->private = (void *)pipeline; + + ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline, + sizeof(*pipeline), r, sizeof(*r)); + if (ret >= 0) + return ret; +err: + kfree(pipeline); + return ret; +} + +/* + * Mixer topology + */ + +static int sof_widget_load_mixer(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_mixer *mixer; + int ret; + + mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); + if (!mixer) + return -ENOMEM; + + /* configure mixer IPC message */ + mixer->comp.hdr.size = sizeof(*mixer); + mixer->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + mixer->comp.id = swidget->comp_id; + mixer->comp.type = SOF_COMP_MIXER; + mixer->comp.pipeline_id = index; + + ret = sof_parse_tokens(scomp, &mixer->config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse mixer.cfg tokens failed %d\n", + private->size); + kfree(mixer); + return ret; + } + + sof_dbg_comp_config(scomp, &mixer->config); + + swidget->private = (void *)mixer; + + ret = sof_ipc_tx_message(sdev->ipc, mixer->comp.hdr.cmd, mixer, + sizeof(*mixer), r, sizeof(*r)); + if (ret < 0) + kfree(mixer); + + return ret; +} + +/* + * PGA Topology + */ + +static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_volume *volume; + struct snd_soc_dapm_widget *widget = swidget->widget; + const struct snd_kcontrol_new *kc = NULL; + struct soc_mixer_control *sm; + struct snd_sof_control *scontrol; + const unsigned int *p; + int ret, tlv[TLV_ITEMS]; + + volume = kzalloc(sizeof(*volume), GFP_KERNEL); + if (!volume) + return -ENOMEM; + + if (le32_to_cpu(tw->num_kcontrols) != 1) { + dev_err(sdev->dev, "error: invalid kcontrol count %d for volume\n", + tw->num_kcontrols); + ret = -EINVAL; + goto err; + } + + /* set up volume gain tables for kcontrol */ + kc = &widget->kcontrol_news[0]; + sm = (struct soc_mixer_control *)kc->private_value; + + /* get volume control */ + scontrol = sm->dobj.private; + + /* set cmd for pga kcontrol */ + scontrol->cmd = SOF_CTRL_CMD_VOLUME; + + /* get topology tlv data */ + p = kc->tlv.p; + + /* extract tlv data */ + if (get_tlv_data(p, tlv) < 0) { + dev_err(sdev->dev, "error: invalid TLV data\n"); + ret = -EINVAL; + goto err; + } + + /* set up volume table */ + ret = set_up_volume_table(scontrol, tlv, sm->max + 1); + if (ret < 0) { + dev_err(sdev->dev, "error: setting up volume table\n"); + goto err; + } + + /* configure dai IPC message */ + volume->comp.hdr.size = sizeof(*volume); + volume->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + volume->comp.id = swidget->comp_id; + volume->comp.type = SOF_COMP_VOLUME; + volume->comp.pipeline_id = index; + + ret = sof_parse_tokens(scomp, volume, volume_tokens, + ARRAY_SIZE(volume_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse volume tokens failed %d\n", + private->size); + goto err; + } + ret = sof_parse_tokens(scomp, &volume->config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse volume.cfg tokens failed %d\n", + le32_to_cpu(private->size)); + goto err; + } + + sof_dbg_comp_config(scomp, &volume->config); + + swidget->private = (void *)volume; + + ret = sof_ipc_tx_message(sdev->ipc, volume->comp.hdr.cmd, volume, + sizeof(*volume), r, sizeof(*r)); + if (ret >= 0) + return ret; +err: + kfree(volume); + return ret; +} + +/* + * SRC Topology + */ + +static int sof_widget_load_src(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_src *src; + int ret; + + src = kzalloc(sizeof(*src), GFP_KERNEL); + if (!src) + return -ENOMEM; + + /* configure mixer IPC message */ + src->comp.hdr.size = sizeof(*src); + src->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + src->comp.id = swidget->comp_id; + src->comp.type = SOF_COMP_SRC; + src->comp.pipeline_id = index; + + ret = sof_parse_tokens(scomp, src, src_tokens, + ARRAY_SIZE(src_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse src tokens failed %d\n", + private->size); + goto err; + } + + ret = sof_parse_tokens(scomp, &src->config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse src.cfg tokens failed %d\n", + le32_to_cpu(private->size)); + goto err; + } + + dev_dbg(sdev->dev, "src %s: source rate %d sink rate %d\n", + swidget->widget->name, src->source_rate, src->sink_rate); + sof_dbg_comp_config(scomp, &src->config); + + swidget->private = (void *)src; + + ret = sof_ipc_tx_message(sdev->ipc, src->comp.hdr.cmd, src, + sizeof(*src), r, sizeof(*r)); + if (ret >= 0) + return ret; +err: + kfree(src); + return ret; +} + +/* + * Signal Generator Topology + */ + +static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_tone *tone; + int ret; + + tone = kzalloc(sizeof(*tone), GFP_KERNEL); + if (!tone) + return -ENOMEM; + + /* configure mixer IPC message */ + tone->comp.hdr.size = sizeof(*tone); + tone->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + tone->comp.id = swidget->comp_id; + tone->comp.type = SOF_COMP_TONE; + tone->comp.pipeline_id = index; + + ret = sof_parse_tokens(scomp, tone, tone_tokens, + ARRAY_SIZE(tone_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse tone tokens failed %d\n", + le32_to_cpu(private->size)); + goto err; + } + + ret = sof_parse_tokens(scomp, &tone->config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse tone.cfg tokens failed %d\n", + le32_to_cpu(private->size)); + goto err; + } + + dev_dbg(sdev->dev, "tone %s: frequency %d amplitude %d\n", + swidget->widget->name, tone->frequency, tone->amplitude); + sof_dbg_comp_config(scomp, &tone->config); + + swidget->private = (void *)tone; + + ret = sof_ipc_tx_message(sdev->ipc, tone->comp.hdr.cmd, tone, + sizeof(*tone), r, sizeof(*r)); + if (ret >= 0) + return ret; +err: + kfree(tone); + return ret; +} + +static int sof_effect_fir_load(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) + +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct snd_sof_control *scontrol = NULL; + struct snd_soc_dapm_widget *widget = swidget->widget; + const struct snd_kcontrol_new *kc = NULL; + struct soc_bytes_ext *sbe; + struct sof_abi_hdr *pdata = NULL; + struct sof_ipc_comp_eq_fir *fir; + size_t ipc_size = 0, fir_data_size = 0; + int ret; + + /* get possible eq controls */ + kc = &widget->kcontrol_news[0]; + if (kc) { + sbe = (struct soc_bytes_ext *)kc->private_value; + scontrol = sbe->dobj.private; + } + + /* + * Check if there's eq parameters in control's private member and set + * data size accordingly. If there's no parameters eq will use defaults + * in firmware (which in this case is passthrough). + */ + if (scontrol && scontrol->cmd == SOF_CTRL_CMD_BINARY) { + pdata = scontrol->control_data->data; + if (pdata->size > 0 && pdata->magic == SOF_ABI_MAGIC) + fir_data_size = pdata->size; + } + + ipc_size = sizeof(struct sof_ipc_comp_eq_fir) + + le32_to_cpu(private->size) + + fir_data_size; + + fir = kzalloc(ipc_size, GFP_KERNEL); + if (!fir) + return -ENOMEM; + + /* configure fir IPC message */ + fir->comp.hdr.size = ipc_size; + fir->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + fir->comp.id = swidget->comp_id; + fir->comp.type = SOF_COMP_EQ_FIR; + fir->comp.pipeline_id = index; + + ret = sof_parse_tokens(scomp, &fir->config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse fir.cfg tokens failed %d\n", + le32_to_cpu(private->size)); + goto err; + } + + sof_dbg_comp_config(scomp, &fir->config); + + /* we have a private data found in control, so copy it */ + if (fir_data_size > 0) { + memcpy(&fir->data, pdata->data, pdata->size); + fir->size = fir_data_size; + } + + swidget->private = (void *)fir; + + ret = sof_ipc_tx_message(sdev->ipc, fir->comp.hdr.cmd, fir, + ipc_size, r, sizeof(*r)); + if (ret >= 0) + return ret; +err: + kfree(fir); + return ret; +} + +static int sof_effect_iir_load(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct snd_soc_dapm_widget *widget = swidget->widget; + const struct snd_kcontrol_new *kc = NULL; + struct soc_bytes_ext *sbe; + struct snd_sof_control *scontrol = NULL; + struct sof_abi_hdr *pdata = NULL; + struct sof_ipc_comp_eq_iir *iir; + size_t ipc_size = 0, iir_data_size = 0; + int ret; + + /* get possible eq controls */ + kc = &widget->kcontrol_news[0]; + if (kc) { + sbe = (struct soc_bytes_ext *)kc->private_value; + scontrol = sbe->dobj.private; + } + + /* + * Check if there's eq parameters in control's private member and set + * data size accordingly. If there's no parameters eq will use defaults + * in firmware (which in this case is passthrough). + */ + if (scontrol && scontrol->cmd == SOF_CTRL_CMD_BINARY) { + pdata = scontrol->control_data->data; + if (pdata->size > 0 && pdata->magic == SOF_ABI_MAGIC) + iir_data_size = pdata->size; + } + + ipc_size = sizeof(struct sof_ipc_comp_eq_iir) + + le32_to_cpu(private->size) + + iir_data_size; + + iir = kzalloc(ipc_size, GFP_KERNEL); + if (!iir) + return -ENOMEM; + + /* configure iir IPC message */ + iir->comp.hdr.size = ipc_size; + iir->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + iir->comp.id = swidget->comp_id; + iir->comp.type = SOF_COMP_EQ_IIR; + iir->comp.pipeline_id = index; + + ret = sof_parse_tokens(scomp, &iir->config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse iir.cfg tokens failed %d\n", + le32_to_cpu(private->size)); + goto err; + } + + sof_dbg_comp_config(scomp, &iir->config); + + /* we have a private data found in control, so copy it */ + if (iir_data_size > 0) { + memcpy(&iir->data, pdata->data, pdata->size); + iir->size = iir_data_size; + } + + swidget->private = (void *)iir; + + ret = sof_ipc_tx_message(sdev->ipc, iir->comp.hdr.cmd, iir, + ipc_size, r, sizeof(*r)); + if (ret >= 0) + return ret; +err: + kfree(iir); + return ret; +} + +/* + * Effect Topology + */ + +static int sof_widget_load_effect(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_effect config; + int ret; + + /* check we have some tokens - we need at least effect type */ + if (le32_to_cpu(private->size) == 0) { + dev_err(sdev->dev, "error: effect tokens not found\n"); + return -EINVAL; + } + + memset(&config, 0, sizeof(config)); + + /* get the effect token */ + ret = sof_parse_tokens(scomp, &config, effect_tokens, + ARRAY_SIZE(effect_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse effect tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + + /* now load effect specific data and send IPC */ + switch (config.type) { + case SOF_EFFECT_INTEL_EQFIR: + ret = sof_effect_fir_load(scomp, index, swidget, tw, r); + break; + case SOF_EFFECT_INTEL_EQIIR: + ret = sof_effect_iir_load(scomp, index, swidget, tw, r); + break; + default: + dev_err(sdev->dev, "error: invalid effect type %d\n", + config.type); + ret = -EINVAL; + break; + } + + if (ret < 0) { + dev_err(sdev->dev, "error: effect loading failed\n"); + return ret; + } + + return 0; +} + +/* + * Generic widget loader. + */ + +static int sof_widget_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dapm_widget *w, + struct snd_soc_tplg_dapm_widget *tw) +{ + /* nothing todo atm */ + return 0; +} + +/* external widget init - used for any driver specific init */ +static int sof_widget_ready(struct snd_soc_component *scomp, int index, + struct snd_soc_dapm_widget *w, + struct snd_soc_tplg_dapm_widget *tw) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_widget *swidget; + struct snd_sof_dai *dai; + struct sof_ipc_comp_reply reply; + struct snd_sof_control *scontrol = NULL; + int ret = 0; + + swidget = kzalloc(sizeof(*swidget), GFP_KERNEL); + if (!swidget) + return -ENOMEM; + + swidget->sdev = sdev; + swidget->widget = w; + swidget->comp_id = sdev->next_comp_id++; + swidget->complete = 0; + swidget->id = w->id; + swidget->pipeline_id = index; + swidget->private = NULL; + memset(&reply, 0, sizeof(reply)); + + dev_dbg(sdev->dev, "tplg: ready widget id %d pipe %d type %d name : %s stream %s\n", + swidget->comp_id, index, swidget->id, tw->name, + strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 + ? tw->sname : "none"); + + /* handle any special case widgets */ + switch (w->id) { + case snd_soc_dapm_dai_in: + case snd_soc_dapm_dai_out: + dai = kzalloc(sizeof(*dai), GFP_KERNEL); + if (!dai) { + kfree(swidget); + return -ENOMEM; + } + + ret = sof_widget_load_dai(scomp, index, swidget, tw, &reply, + dai); + if (ret == 0) { + sof_connect_dai_widget(scomp, w, tw, dai); + list_add(&dai->list, &sdev->dai_list); + swidget->private = dai; + } else { + kfree(dai); + } + break; + case snd_soc_dapm_mixer: + ret = sof_widget_load_mixer(scomp, index, swidget, tw, &reply); + break; + case snd_soc_dapm_pga: + ret = sof_widget_load_pga(scomp, index, swidget, tw, &reply); + /* Find scontrol for this pga and set readback offset*/ + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + if (scontrol->comp_id == swidget->comp_id) { + scontrol->readback_offset = reply.offset; + break; + } + } + break; + case snd_soc_dapm_buffer: + ret = sof_widget_load_buffer(scomp, index, swidget, tw, &reply); + break; + case snd_soc_dapm_scheduler: + ret = sof_widget_load_pipeline(scomp, index, swidget, tw, + &reply); + break; + case snd_soc_dapm_aif_out: + ret = sof_widget_load_pcm(scomp, index, swidget, + SOF_IPC_STREAM_CAPTURE, tw, &reply); + break; + case snd_soc_dapm_aif_in: + ret = sof_widget_load_pcm(scomp, index, swidget, + SOF_IPC_STREAM_PLAYBACK, tw, &reply); + break; + case snd_soc_dapm_src: + ret = sof_widget_load_src(scomp, index, swidget, tw, &reply); + break; + case snd_soc_dapm_siggen: + ret = sof_widget_load_siggen(scomp, index, swidget, tw, &reply); + break; + case snd_soc_dapm_effect: + ret = sof_widget_load_effect(scomp, index, swidget, tw, &reply); + break; + case snd_soc_dapm_mux: + case snd_soc_dapm_demux: + case snd_soc_dapm_switch: + case snd_soc_dapm_dai_link: + case snd_soc_dapm_kcontrol: + default: + dev_warn(sdev->dev, "warning: widget type %d name %s not handled\n", + swidget->id, tw->name); + break; + } + + /* check IPC reply */ + if (ret < 0 || reply.rhdr.error < 0) { + dev_err(sdev->dev, + "error: DSP failed to add widget id %d type %d name : %s stream %s reply %d\n", + tw->shift, swidget->id, tw->name, + strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 + ? tw->sname : "none", reply.rhdr.error); + kfree(swidget); + return ret; + } + + w->dobj.private = swidget; + mutex_init(&swidget->mutex); + list_add(&swidget->list, &sdev->widget_list); + return ret; +} + +static int sof_widget_unload(struct snd_soc_component *scomp, + struct snd_soc_dobj *dobj) +{ + const struct snd_kcontrol_new *kc = NULL; + struct snd_soc_dapm_widget *widget; + struct snd_sof_control *scontrol; + struct snd_sof_widget *swidget; + struct soc_mixer_control *sm; + struct snd_sof_dai *dai; + + swidget = dobj->private; + if (!swidget) + return 0; + + widget = swidget->widget; + + switch (swidget->id) { + case snd_soc_dapm_dai_in: + case snd_soc_dapm_dai_out: + dai = swidget->private; + + /* remove and free dai object */ + if (dai) { + list_del(&dai->list); + kfree(dai); + } + break; + case snd_soc_dapm_pga: + + /* get volume kcontrol */ + kc = &widget->kcontrol_news[0]; + sm = (struct soc_mixer_control *)kc->private_value; + scontrol = sm->dobj.private; + + /* free volume table */ + kfree(scontrol->volume_table); + + /* fallthrough */ + default: + /* free private value */ + kfree(swidget->private); + break; + } + + /* remove and free swidget object */ + list_del(&swidget->list); + kfree(swidget); + + return 0; +} + +/* + * DAI HW configuration. + */ + +/* FE DAI - used for any driver specific init */ +static int sof_dai_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_driver *dai_drv, + struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_pcm *spcm; + + /* don't need to do anything for BEs atm */ + if (!pcm) + return 0; + + spcm = kzalloc(sizeof(*spcm), GFP_KERNEL); + if (!spcm) + return -ENOMEM; + + spcm->sdev = sdev; + spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id = COMP_ID_UNASSIGNED; + spcm->stream[SNDRV_PCM_STREAM_CAPTURE].comp_id = COMP_ID_UNASSIGNED; + if (pcm) { + spcm->pcm = *pcm; + dev_dbg(sdev->dev, "tplg: load pcm %s\n", pcm->dai_name); + } + dai_drv->dobj.private = spcm; + mutex_init(&spcm->mutex); + list_add(&spcm->list, &sdev->pcm_list); + + return 0; +} + +static int sof_dai_unload(struct snd_soc_component *scomp, + struct snd_soc_dobj *dobj) +{ + struct snd_sof_pcm *spcm = dobj->private; + + list_del(&spcm->list); + kfree(spcm); + + return 0; +} + +static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + /* clock directions wrt codec */ + if (hw_config->bclk_master == SND_SOC_TPLG_BCLK_CM) { + /* codec is bclk master */ + if (hw_config->fsync_master == SND_SOC_TPLG_FSYNC_CM) + config->format |= SOF_DAI_FMT_CBM_CFM; + else + config->format |= SOF_DAI_FMT_CBM_CFS; + } else { + /* codec is bclk slave */ + if (hw_config->fsync_master == SND_SOC_TPLG_FSYNC_CM) + config->format |= SOF_DAI_FMT_CBS_CFM; + else + config->format |= SOF_DAI_FMT_CBS_CFS; + } + + /* inverted clocks ? */ + if (hw_config->invert_bclk) { + if (hw_config->invert_fsync) + config->format |= SOF_DAI_FMT_IB_IF; + else + config->format |= SOF_DAI_FMT_IB_NF; + } else { + if (hw_config->invert_fsync) + config->format |= SOF_DAI_FMT_NB_IF; + else + config->format |= SOF_DAI_FMT_NB_NF; + } +} + +static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &cfg->priv; + struct sof_ipc_reply reply; + u32 size = sizeof(*config); + int ret; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->ssp, 0, sizeof(struct sof_ipc_dai_ssp_params)); + config->hdr.size = size; + + ret = sof_parse_tokens(scomp, &config->ssp, ssp_tokens, + ARRAY_SIZE(ssp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse ssp tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + + config->ssp.mclk_rate = le32_to_cpu(hw_config->mclk_rate); + config->ssp.bclk_rate = le32_to_cpu(hw_config->bclk_rate); + config->ssp.fsync_rate = le32_to_cpu(hw_config->fsync_rate); + config->ssp.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + config->ssp.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width); + config->ssp.mclk_direction = hw_config->mclk_direction; + config->ssp.rx_slots = le32_to_cpu(hw_config->rx_slots); + config->ssp.tx_slots = le32_to_cpu(hw_config->tx_slots); + + dev_dbg(sdev->dev, "tplg: config SSP%d fmt 0x%x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d\n", + config->dai_index, config->format, + config->ssp.mclk_rate, config->ssp.bclk_rate, + config->ssp.fsync_rate, config->ssp.sample_valid_bits, + config->ssp.tdm_slot_width, config->ssp.tdm_slots, + config->ssp.mclk_id); + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + config->hdr.cmd, config, size, &reply, + sizeof(reply)); + + if (ret < 0) + dev_err(sdev->dev, "error: failed to set DAI config for SSP%d\n", + config->dai_index); + + return ret; +} + +static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &cfg->priv; + struct sof_ipc_dai_config *ipc_config; + struct sof_ipc_reply reply; + u32 size; + int ret, j; + + memset(&config->dmic, 0, sizeof(struct sof_ipc_dai_dmic_params)); + + /* get DMIC tokens */ + ret = sof_parse_tokens(scomp, &config->dmic, dmic_tokens, + ARRAY_SIZE(dmic_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse dmic tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + + /* + * allocate memory for common dai params, dmic params + * and dmic pdm controller params + */ + ipc_config = kzalloc(sizeof(*config) + + sizeof(struct sof_ipc_dai_dmic_pdm_ctrl) * + config->dmic.num_pdm_active, + GFP_KERNEL); + if (!ipc_config) { + dev_err(sdev->dev, "error: allocating memory for config\n"); + return -ENOMEM; + } + + /* copy the common dai config and dmic params */ + memcpy(ipc_config, config, sizeof(*config)); + + /* + * alloc memory for private member + * Used to track the pdm config array index currently being parsed + */ + sdev->private = kzalloc(sizeof(u32), GFP_KERNEL); + + /* get DMIC PDM tokens */ + ret = sof_parse_tokens(scomp, &ipc_config->dmic.pdm[0], dmic_pdm_tokens, + ARRAY_SIZE(dmic_pdm_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse dmic pdm tokens failed %d\n", + le32_to_cpu(private->size)); + kfree(ipc_config); + return ret; + } + + /* set IPC header size */ + size = sizeof(*ipc_config); + ipc_config->hdr.size = size; + + /* debug messages */ + dev_dbg(sdev->dev, "tplg: config DMIC%d driver version %d\n", + ipc_config->dai_index, ipc_config->dmic.driver_ipc_version); + dev_dbg(sdev->dev, "pdmclk_min %d pdm_clkmax %d duty_min %hd\n", + ipc_config->dmic.pdmclk_min, ipc_config->dmic.pdmclk_max, + ipc_config->dmic.duty_min); + dev_dbg(sdev->dev, "duty_max %hd fifo_fs %d num_pdms active %d\n", + ipc_config->dmic.duty_max, ipc_config->dmic.fifo_fs_a, + ipc_config->dmic.num_pdm_active); + dev_dbg(sdev->dev, "fifo word length %hd\n", + ipc_config->dmic.fifo_bits_a); + + for (j = 0; j < ipc_config->dmic.num_pdm_active; j++) { + dev_dbg(sdev->dev, "pdm %hd mic a %hd mic b %hd\n", + ipc_config->dmic.pdm[j].id, + ipc_config->dmic.pdm[j].enable_mic_a, + ipc_config->dmic.pdm[j].enable_mic_b); + dev_dbg(sdev->dev, "pdm %hd polarity a %hd polarity b %hd\n", + ipc_config->dmic.pdm[j].id, + ipc_config->dmic.pdm[j].polarity_mic_a, + ipc_config->dmic.pdm[j].polarity_mic_b); + dev_dbg(sdev->dev, "pdm %hd clk_edge %hd skew %hd\n", + ipc_config->dmic.pdm[j].id, + ipc_config->dmic.pdm[j].clk_edge, + ipc_config->dmic.pdm[j].skew); + } + + /* TODO: check if fifo_b word length is needed */ + ipc_config->dmic.fifo_bits_b = ipc_config->dmic.fifo_bits_a; + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + ipc_config->hdr.cmd, ipc_config, size, &reply, + sizeof(reply)); + + if (ret < 0) + dev_err(sdev->dev, "error: failed to set DAI config for DMIC%d\n", + config->dai_index); + + /* update config with pdm config */ + memcpy(config, ipc_config, sizeof(*ipc_config)); + + kfree(sdev->private); + kfree(ipc_config); + + return ret; +} + +static int sof_link_hda_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &cfg->priv; + struct sof_ipc_reply reply; + u32 size = sizeof(*config); + int ret; + + /* init IPC */ + memset(&config->hda, 0, sizeof(struct sof_ipc_dai_hda_params)); + config->hdr.size = size; + + /* get any bespoke DAI tokens */ + ret = sof_parse_tokens(scomp, config, hda_tokens, + ARRAY_SIZE(hda_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse hda tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + + dev_dbg(sdev->dev, "tplg: config HDA%d fmt 0x%x\n", + config->dai_index, config->format); + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + config->hdr.cmd, config, size, &reply, + sizeof(reply)); + + if (ret < 0) + dev_err(sdev->dev, "error: failed to set DAI config for HDA%d\n", + config->dai_index); + + return ret; +} + +/* DAI link - used for any driver specific init */ +static int sof_link_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &cfg->priv; + struct sof_ipc_dai_config config; + struct snd_soc_tplg_hw_config *hw_config; + struct snd_sof_dai *dai; + int ret = 0; + + link->platform_name = "sof-audio"; + link->nonatomic = true; + + /* send BE configurations to DSP */ + if (!link->no_pcm) + return 0; + + /* only support 1 config atm */ + if (le32_to_cpu(cfg->num_hw_configs) != 1) { + dev_err(sdev->dev, "error: unexpected DAI config count %d\n", + le32_to_cpu(cfg->num_hw_configs)); + return -EINVAL; + } + + /* check we have some tokens - we need at least DAI type */ + if (le32_to_cpu(private->size) == 0) { + dev_err(sdev->dev, "error: expected tokens for DAI, none found\n"); + return -EINVAL; + } + + memset(&config, 0, sizeof(config)); + + /* get any common DAI tokens */ + ret = sof_parse_tokens(scomp, &config, dai_link_tokens, + ARRAY_SIZE(dai_link_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse link tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + + /* configure dai IPC message */ + hw_config = &cfg->hw_config[0]; + + config.hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG; + config.format = le32_to_cpu(hw_config->fmt); + + /* now load DAI specific data and send IPC - type comes from token */ + switch (config.type) { + case SOF_DAI_INTEL_SSP: + ret = sof_link_ssp_load(scomp, index, link, cfg, hw_config, + &config); + break; + case SOF_DAI_INTEL_DMIC: + ret = sof_link_dmic_load(scomp, index, link, cfg, hw_config, + &config); + break; + case SOF_DAI_INTEL_HDA: + ret = sof_link_hda_load(scomp, index, link, cfg, hw_config, + &config); + break; + default: + dev_err(sdev->dev, "error: invalid DAI type %d\n", config.type); + ret = -EINVAL; + break; + } + if (ret < 0) + return ret; + + /* set config for all DAI's with name matching the link name */ + list_for_each_entry(dai, &sdev->dai_list, list) { + if (!dai->name) + continue; + + if (strcmp(link->name, dai->name) == 0) + memcpy(&dai->dai_config, &config, + sizeof(struct sof_ipc_dai_config)); + } + + return 0; +} + +static int sof_link_unload(struct snd_soc_component *scomp, + struct snd_soc_dobj *dobj) +{ + return 0; +} + +/* bind PCM ID to host component ID */ +static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm, + const char *host) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_widget *host_widget; + + host_widget = snd_sof_find_swidget(sdev, (char *)host); + if (!host_widget) { + dev_err(sdev->dev, "error: can't find host component %s\n", + host); + return -ENODEV; + } + + switch (host_widget->id) { + case snd_soc_dapm_aif_in: + spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id = + host_widget->comp_id; + break; + case snd_soc_dapm_aif_out: + spcm->stream[SNDRV_PCM_STREAM_CAPTURE].comp_id = + host_widget->comp_id; + break; + default: + dev_err(sdev->dev, "error: host is wrong type %d\n", + host_widget->id); + return -EINVAL; + } + + return 0; +} + +/* Used for free route in topology free stage */ +static void sof_route_remove(struct snd_soc_dapm_route *route) +{ + if (!route) + return; + + kfree(route->source); + kfree(route->sink); + kfree(route->control); +} + +/* DAI link - used for any driver specific init */ +static int sof_route_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dapm_route *route) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc_pipe_comp_connect *connect; + struct snd_sof_widget *source_swidget, *sink_swidget; + struct snd_sof_pcm *spcm; + struct snd_sof_route *sroute; + struct sof_ipc_reply reply; + int ret = 0; + + /* allocate memory for sroute and connect */ + sroute = kzalloc(sizeof(*sroute), GFP_KERNEL); + if (!sroute) + return -ENOMEM; + + sroute->sdev = sdev; + + connect = kzalloc(sizeof(*connect), GFP_KERNEL); + if (!connect) { + kfree(sroute); + return -ENOMEM; + } + + connect->hdr.size = sizeof(*connect); + connect->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_CONNECT; + + dev_dbg(sdev->dev, "sink %s control %s source %s\n", + route->sink, route->control ? route->control : "none", + route->source); + + /* source component */ + source_swidget = snd_sof_find_swidget(sdev, (char *)route->source); + if (!source_swidget) { + /* don't send any routes to DSP that include a driver PCM */ + spcm = snd_sof_find_spcm_name(sdev, (char *)route->source); + if (spcm) { + ret = spcm_bind(scomp, spcm, route->sink); + goto err; + } + + dev_err(sdev->dev, "error: source %s not found\n", + route->source); + ret = -EINVAL; + goto err; + } + + connect->source_id = source_swidget->comp_id; + + /* sink component */ + sink_swidget = snd_sof_find_swidget(sdev, (char *)route->sink); + if (!sink_swidget) { + /* don't send any routes to DSP that include a driver PCM */ + spcm = snd_sof_find_spcm_name(sdev, (char *)route->sink); + if (spcm) { + ret = spcm_bind(scomp, spcm, route->source); + goto err; + } + + dev_err(sdev->dev, "error: sink %s not found\n", + route->sink); + ret = -EINVAL; + goto err; + } + + connect->sink_id = sink_swidget->comp_id; + + /* Some virtual routes and widgets may been added in topology for + * compatibility. For virtual routes, both sink and source are not + * buffer. Since only buffer linked to component is supported by + * FW, others are reported as error, add check in route function, + * do not send it to FW when both source and sink are not buffer + */ + if (source_swidget->id != snd_soc_dapm_buffer && + sink_swidget->id != snd_soc_dapm_buffer) { + dev_dbg(sdev->dev, "warning: neither Linked source component %s nor sink component %s is of buffer type, ignoring link\n", + route->source, route->sink); + ret = 0; + goto err; + } else { + ret = sof_ipc_tx_message(sdev->ipc, + connect->hdr.cmd, + connect, sizeof(*connect), + &reply, sizeof(reply)); + + /* check IPC return value */ + if (ret < 0) { + dev_err(sdev->dev, "error: failed to add route sink %s control %s source %s\n", + route->sink, + route->control ? route->control : "none", + route->source); + goto err; + } + + /* check IPC reply */ + if (reply.error < 0) { + dev_err(sdev->dev, "error: DSP failed to add route sink %s control %s source %s result %d\n", + route->sink, + route->control ? route->control : "none", + route->source, reply.error); + ret = reply.error; + goto err; + } + + sroute->route.source = kstrdup(route->source, GFP_KERNEL); + if (!sroute->route.source) + goto err; + + sroute->route.sink = kstrdup(route->sink, GFP_KERNEL); + if (!sroute->route.sink) { + kfree(sroute->route.source); + goto err; + } + + if (route->control) { + sroute->route.control = kstrdup(route->control, + GFP_KERNEL); + if (!sroute->route.control) { + kfree(sroute->route.source); + kfree(sroute->route.sink); + goto err; + } + } + + sroute->private = connect; + + /* add route to route list */ + list_add(&sroute->list, &sdev->route_list); + + return ret; + } + +err: + kfree(connect); + kfree(sroute); + return ret; +} + +static int sof_route_unload(struct snd_soc_component *scomp, + struct snd_soc_dobj *dobj) +{ + /* TODO: unload routes when topology is changed */ + return 0; +} + +int snd_sof_complete_pipeline(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget) +{ + struct sof_ipc_pipe_ready ready; + struct sof_ipc_reply reply; + int ret; + + dev_dbg(sdev->dev, "tplg: complete pipeline %s id %d\n", + swidget->widget->name, swidget->comp_id); + + memset(&ready, 0, sizeof(ready)); + ready.hdr.size = sizeof(ready); + ready.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_COMPLETE; + ready.comp_id = swidget->comp_id; + + ret = sof_ipc_tx_message(sdev->ipc, + ready.hdr.cmd, &ready, sizeof(ready), &reply, + sizeof(reply)); + if (ret < 0) + return ret; + return 1; +} + +/* completion - called at completion of firmware loading */ +static void sof_complete(struct snd_soc_component *scomp) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_widget *swidget; + + /* some widget types require completion notificattion */ + list_for_each_entry(swidget, &sdev->widget_list, list) { + if (swidget->complete) + continue; + + switch (swidget->id) { + case snd_soc_dapm_scheduler: + swidget->complete = + snd_sof_complete_pipeline(sdev, swidget); + break; + default: + break; + } + } +} + +/* manifest - optional to inform component of manifest */ +static int sof_manifest(struct snd_soc_component *scomp, int index, + struct snd_soc_tplg_manifest *man) +{ + /* not currently parsed */ + return 0; +} + +/* vendor specific kcontrol handlers available for binding */ +static const struct snd_soc_tplg_kcontrol_ops sof_io_ops[] = { + {SOF_TPLG_KCTL_VOL_ID, snd_sof_volume_get, snd_sof_volume_put}, + {SOF_TPLG_KCTL_ENUM_ID, snd_sof_enum_get, snd_sof_enum_put}, + {SOF_TPLG_KCTL_BYTES_ID, snd_sof_bytes_get, snd_sof_bytes_put}, +}; + +/* vendor specific bytes ext handlers available for binding */ +static const struct snd_soc_tplg_bytes_ext_ops sof_bytes_ext_ops[] = { + {SOF_TPLG_KCTL_BYTES_ID, snd_sof_bytes_ext_get, snd_sof_bytes_ext_put}, +}; + +static struct snd_soc_tplg_ops sof_tplg_ops = { + /* external kcontrol init - used for any driver specific init */ + .control_load = sof_control_load, + .control_unload = sof_control_unload, + + /* external kcontrol init - used for any driver specific init */ + .dapm_route_load = sof_route_load, + .dapm_route_unload = sof_route_unload, + + /* external widget init - used for any driver specific init */ + .widget_load = sof_widget_load, + .widget_ready = sof_widget_ready, + .widget_unload = sof_widget_unload, + + /* FE DAI - used for any driver specific init */ + .dai_load = sof_dai_load, + .dai_unload = sof_dai_unload, + + /* DAI link - used for any driver specific init */ + .link_load = sof_link_load, + .link_unload = sof_link_unload, + + /* completion - called at completion of firmware loading */ + .complete = sof_complete, + + /* manifest - optional to inform component of manifest */ + .manifest = sof_manifest, + + /* vendor specific kcontrol handlers available for binding */ + .io_ops = sof_io_ops, + .io_ops_count = ARRAY_SIZE(sof_io_ops), + + /* vendor specific bytes ext handlers available for binding */ + .bytes_ext_ops = sof_bytes_ext_ops, + .bytes_ext_ops_count = ARRAY_SIZE(sof_bytes_ext_ops), +}; + +int snd_sof_init_topology(struct snd_sof_dev *sdev, + struct snd_soc_tplg_ops *ops) +{ + /* TODO: support linked list of topologies */ + sdev->tplg_ops = ops; + return 0; +} +EXPORT_SYMBOL(snd_sof_init_topology); + +int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file) +{ + const struct firmware *fw; + struct snd_soc_tplg_hdr *hdr; + int ret; + + dev_dbg(sdev->dev, "loading topology:%s\n", file); + + ret = request_firmware(&fw, file, sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "error: tplg %s load failed with %d\n", + file, ret); + return ret; + } + + hdr = (struct snd_soc_tplg_hdr *)fw->data; + ret = snd_soc_tplg_component_load(sdev->component, + &sof_tplg_ops, fw, + SND_SOC_TPLG_INDEX_ALL); + if (ret < 0) { + dev_err(sdev->dev, "error: tplg component load failed %d\n", + ret); + ret = -EINVAL; + } + + release_firmware(fw); + return ret; +} +EXPORT_SYMBOL(snd_sof_load_topology); + +void snd_sof_free_topology(struct snd_sof_dev *sdev) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(sdev->component); + struct snd_sof_route *sroute, *temp; + int ret; + + dev_dbg(sdev->dev, "free topology...\n"); + + /* remove routes */ + list_for_each_entry_safe(sroute, temp, &sdev->route_list, list) { + + /* delete dapm route */ + snd_soc_dapm_del_routes(dapm, &sroute->route, 1); + + sof_route_remove(&sroute->route); + + /* free sroute and its private data */ + kfree(sroute->private); + kfree(sroute); + } + + ret = snd_soc_tplg_component_remove(sdev->component, + SND_SOC_TPLG_INDEX_ALL); + if (ret < 0) + dev_err(sdev->dev, + "error: tplg component free failed %d\n", ret); +} +EXPORT_SYMBOL(snd_sof_free_topology); From d587d747267a3f112e6e0c944b9cd92384b71251 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:33:15 +0000 Subject: [PATCH 0097/1995] ASoC: SOF: Add DSP firmware trace event support Add a trace event buffer that can be used by userspace to read DSP runtime trace events alongside bespoke trace data in realtime for firmware debug. Signed-off-by: Liam Girdwood --- sound/soc/sof/sof-priv.h | 1 + sound/soc/sof/trace.c | 306 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 307 insertions(+) create mode 100644 sound/soc/sof/trace.c diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index ade7b2068fcb03..0f7ddf19bf8a15 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -365,6 +365,7 @@ struct snd_sof_dev { wait_queue_head_t trace_sleep; u32 host_offset; bool dtrace_is_enabled; + bool dtrace_error; /* PM */ bool restore_kcontrols; /* restore kcontrols upon resume */ diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c new file mode 100644 index 00000000000000..5aeb6ea3c58b2b --- /dev/null +++ b/sound/soc/sof/trace.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// Yan Wang +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sof-priv.h" +#include "ops.h" + +static size_t sof_wait_trace_avail(struct snd_sof_dev *sdev, + loff_t pos, size_t buffer_size) +{ + wait_queue_entry_t wait; + + /* + * If host offset is less than local pos, it means write pointer of + * host DMA buffer has been wrapped. We should output the trace data + * at the end of host DMA buffer at first. + */ + if (sdev->host_offset < pos) + return buffer_size - pos; + + /* If there is available trace data now, it is unnecessary to wait. */ + if (sdev->host_offset > pos) + return sdev->host_offset - pos; + + /* wait for available trace data from FW */ + init_waitqueue_entry(&wait, current); + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&sdev->trace_sleep, &wait); + + if (signal_pending(current)) { + remove_wait_queue(&sdev->trace_sleep, &wait); + goto out; + } + + /* set timeout to max value, no error code */ + schedule_timeout(MAX_SCHEDULE_TIMEOUT); + remove_wait_queue(&sdev->trace_sleep, &wait); + +out: + /* return bytes available for copy */ + if (sdev->host_offset < pos) + return buffer_size - pos; + else + return sdev->host_offset - pos; +} + +static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct snd_sof_dfsentry_buf *dfse = file->private_data; + struct snd_sof_dev *sdev = dfse->sdev; + unsigned long rem; + loff_t lpos = *ppos; + size_t avail, buffer_size = dfse->size; + u64 lpos_64; + + /* make sure we know about any failures on the DSP side */ + sdev->dtrace_error = false; + + /* check pos and count */ + if (lpos < 0) + return -EINVAL; + if (!count) + return 0; + + /* check for buffer wrap and count overflow */ + lpos_64 = lpos; + lpos = do_div(lpos_64, buffer_size); + + if (count > buffer_size - lpos) + count = buffer_size - lpos; + + /* get available count based on current host offset */ + avail = sof_wait_trace_avail(sdev, lpos, buffer_size); + if (sdev->dtrace_error) { + dev_err(sdev->dev, "error: trace IO error\n"); + return -EIO; + } + + /* make sure count is <= avail */ + count = avail > count ? count : avail; + + /* copy available trace data to debugfs */ + rem = copy_to_user(buffer, dfse->buf + lpos, count); + if (rem == count) + return -EFAULT; + + *ppos += count; + + /* move debugfs reading position */ + return count; +} + +static const struct file_operations sof_dfs_trace_fops = { + .open = simple_open, + .read = sof_dfsentry_trace_read, + .llseek = default_llseek, +}; + +static int trace_debugfs_create(struct snd_sof_dev *sdev) +{ + struct snd_sof_dfsentry_buf *dfse; + + if (!sdev) + return -EINVAL; + + dfse = kzalloc(sizeof(*dfse), GFP_KERNEL); + if (!dfse) + return -ENOMEM; + + dfse->buf = sdev->dmatb.area; + dfse->size = sdev->dmatb.bytes; + dfse->sdev = sdev; + + dfse->dfsentry = debugfs_create_file("trace", 0444, sdev->debugfs_root, + dfse, &sof_dfs_trace_fops); + if (!dfse->dfsentry) { + dev_err(sdev->dev, + "error: cannot create debugfs entry for trace\n"); + kfree(dfse); + return -ENODEV; + } + + return 0; +} + +int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) +{ + struct sof_ipc_dma_trace_params params; + struct sof_ipc_reply ipc_reply; + int ret; + + if (sdev->dtrace_is_enabled) + return -EINVAL; + + /* set IPC parameters */ + params.hdr.size = sizeof(params); + params.hdr.cmd = SOF_IPC_GLB_TRACE_MSG | SOF_IPC_TRACE_DMA_PARAMS; + params.buffer.phy_addr = sdev->dmatp.addr; + params.buffer.size = sdev->dmatb.bytes; + params.buffer.offset = 0; + params.buffer.pages = sdev->dma_trace_pages; + + init_waitqueue_head(&sdev->trace_sleep); + sdev->host_offset = 0; + + ret = snd_sof_dma_trace_init(sdev, ¶ms.stream_tag); + if (ret < 0) { + dev_err(sdev->dev, + "error: fail in snd_sof_dma_trace_init %d\n", ret); + return ret; + } + dev_dbg(sdev->dev, "stream_tag: %d\n", params.stream_tag); + + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + params.hdr.cmd, ¶ms, sizeof(params), + &ipc_reply, sizeof(ipc_reply)); + if (ret < 0) { + dev_err(sdev->dev, + "error: can't set params for DMA for trace %d\n", ret); + return ret; + } + + ret = snd_sof_dma_trace_trigger(sdev, SNDRV_PCM_TRIGGER_START); + if (ret < 0) { + dev_err(sdev->dev, + "error: snd_sof_dma_trace_trigger: start: %d\n", ret); + return ret; + } + + sdev->dtrace_is_enabled = true; + + return 0; +} + +int snd_sof_init_trace(struct snd_sof_dev *sdev) +{ + int ret; + + /* set false before start initialization */ + sdev->dtrace_is_enabled = false; + + /* allocate trace page table buffer */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->parent, + PAGE_SIZE, &sdev->dmatp); + if (ret < 0) { + dev_err(sdev->dev, + "error: can't alloc page table for trace %d\n", ret); + return ret; + } + + /* allocate trace data buffer */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, sdev->parent, + DMA_BUF_SIZE_FOR_TRACE, &sdev->dmatb); + if (ret < 0) { + dev_err(sdev->dev, + "error: can't alloc buffer for trace %d\n", ret); + goto page_err; + } + + /* craete compressed page table for audio firmware */ + ret = snd_sof_create_page_table(sdev, &sdev->dmatb, sdev->dmatp.area, + sdev->dmatb.bytes); + if (ret < 0) + goto table_err; + + sdev->dma_trace_pages = ret; + dev_dbg(sdev->dev, "dma_trace_pages: %d\n", sdev->dma_trace_pages); + + if (sdev->first_boot) { + ret = trace_debugfs_create(sdev); + if (ret < 0) + goto table_err; + } + + ret = snd_sof_init_trace_ipc(sdev); + if (ret < 0) + goto table_err; + + return 0; +table_err: + snd_dma_free_pages(&sdev->dmatb); +page_err: + snd_dma_free_pages(&sdev->dmatp); + return ret; +} +EXPORT_SYMBOL(snd_sof_init_trace); + +int snd_sof_trace_update_pos(struct snd_sof_dev *sdev, + struct sof_ipc_dma_trace_posn *posn) +{ + if (sdev->dtrace_is_enabled && sdev->host_offset != posn->host_offset) { + sdev->host_offset = posn->host_offset; + wake_up(&sdev->trace_sleep); + } + + if (posn->overflow != 0) + dev_err(sdev->dev, + "error: DSP trace buffer overflow %u bytes. Total messages %d\n", + posn->overflow, posn->messages); + + return 0; +} + +/* an error has occurred within the DSP that prevents further trace */ +void snd_sof_trace_notify_for_error(struct snd_sof_dev *sdev) +{ + if (sdev->dtrace_is_enabled) { + dev_err(sdev->dev, "error: waking up any trace sleepers\n"); + sdev->dtrace_error = true; + wake_up(&sdev->trace_sleep); + } +} +EXPORT_SYMBOL(snd_sof_trace_notify_for_error); + +void snd_sof_release_trace(struct snd_sof_dev *sdev) +{ + int ret; + + if (!sdev->dtrace_is_enabled) + return; + + ret = snd_sof_dma_trace_trigger(sdev, SNDRV_PCM_TRIGGER_STOP); + if (ret < 0) + dev_err(sdev->dev, + "error: snd_sof_dma_trace_trigger: stop: %d\n", ret); + + ret = snd_sof_dma_trace_release(sdev); + if (ret < 0) + dev_err(sdev->dev, + "error: fail in snd_sof_dma_trace_release %d\n", ret); + + sdev->dtrace_is_enabled = false; +} +EXPORT_SYMBOL(snd_sof_release_trace); + +void snd_sof_free_trace(struct snd_sof_dev *sdev) +{ + snd_sof_release_trace(sdev); + + snd_dma_free_pages(&sdev->dmatb); + snd_dma_free_pages(&sdev->dmatp); +} +EXPORT_SYMBOL(snd_sof_free_trace); From 1d7c0b37959772881c254844aeb4047a17ddd825 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:33:43 +0000 Subject: [PATCH 0098/1995] ASoC: SOF: Add DSP HW abstraction operations Add operation pointers that can be called by core to control a wide variety of DSP targets. The DSP HW drivers will fill in these operations. Signed-off-by: Liam Girdwood --- sound/soc/sof/ops.c | 210 ++++++++++++++++++++++++++++ sound/soc/sof/ops.h | 329 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 539 insertions(+) create mode 100644 sound/soc/sof/ops.c create mode 100644 sound/soc/sof/ops.h diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c new file mode 100644 index 00000000000000..48ea9ac32620b5 --- /dev/null +++ b/sound/soc/sof/ops.c @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +#include +#include +#include +#include +#include +#include +#include +#include "ops.h" +#include "sof-priv.h" + +int snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset, + u32 mask, u32 value) +{ + bool change; + unsigned int old, new; + u32 ret = ~0; /* explicit init to remove uninitialized use warnings */ + + pci_read_config_dword(sdev->pci, offset, &ret); + dev_dbg(sdev->dev, "Debug PCIR: %8.8x at %8.8x\n", + pci_read_config_dword(sdev->pci, offset, &ret), offset); + + old = ret; + new = (old & (~mask)) | (value & mask); + + change = (old != new); + if (change) { + pci_write_config_dword(sdev->pci, offset, new); + dev_dbg(sdev->dev, "Debug PCIW: %8.8x at %8.8x\n", value, + offset); + } + + return change; +} +EXPORT_SYMBOL(snd_sof_pci_update_bits_unlocked); + +int snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset, + u32 mask, u32 value) +{ + unsigned long flags; + bool change; + + spin_lock_irqsave(&sdev->hw_lock, flags); + change = snd_sof_pci_update_bits_unlocked(sdev, offset, mask, value); + spin_unlock_irqrestore(&sdev->hw_lock, flags); + return change; +} +EXPORT_SYMBOL(snd_sof_pci_update_bits); + +int snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u32 mask, u32 value) +{ + bool change; + unsigned int old, new; + u32 ret; + + ret = snd_sof_dsp_read(sdev, bar, offset); + + old = ret; + new = (old & (~mask)) | (value & mask); + + change = (old != new); + if (change) + snd_sof_dsp_write(sdev, bar, offset, new); + + return change; +} +EXPORT_SYMBOL(snd_sof_dsp_update_bits_unlocked); + +int snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u64 mask, u64 value) +{ + bool change; + u64 old, new; + + old = snd_sof_dsp_read64(sdev, bar, offset); + + new = (old & (~mask)) | (value & mask); + + change = (old != new); + if (change) + snd_sof_dsp_write64(sdev, bar, offset, new); + + return change; +} +EXPORT_SYMBOL(snd_sof_dsp_update_bits64_unlocked); + +/* This is for registers bits with attribute RWC */ +void snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u32 mask, u32 value) +{ + unsigned int old, new; + u32 ret; + + ret = snd_sof_dsp_read(sdev, bar, offset); + + old = ret; + new = (old & (~mask)) | (value & mask); + + snd_sof_dsp_write(sdev, bar, offset, new); +} +EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced_unlocked); + +int snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset, + u32 mask, u32 value) +{ + unsigned long flags; + bool change; + + spin_lock_irqsave(&sdev->hw_lock, flags); + change = snd_sof_dsp_update_bits_unlocked(sdev, bar, offset, mask, + value); + spin_unlock_irqrestore(&sdev->hw_lock, flags); + return change; +} +EXPORT_SYMBOL(snd_sof_dsp_update_bits); + +int snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, u32 offset, + u64 mask, u64 value) +{ + unsigned long flags; + bool change; + + spin_lock_irqsave(&sdev->hw_lock, flags); + change = snd_sof_dsp_update_bits64_unlocked(sdev, bar, offset, mask, + value); + spin_unlock_irqrestore(&sdev->hw_lock, flags); + return change; +} +EXPORT_SYMBOL(snd_sof_dsp_update_bits64); + +/* This is for registers bits with attribute RWC */ +void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u32 mask, u32 value) +{ + unsigned long flags; + + spin_lock_irqsave(&sdev->hw_lock, flags); + snd_sof_dsp_update_bits_forced_unlocked(sdev, bar, offset, mask, value); + spin_unlock_irqrestore(&sdev->hw_lock, flags); +} +EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced); + +int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset, + u32 mask, u32 target, u32 timeout) +{ + int time, ret; + bool done = false; + + /* + * we will poll for couple of ms using mdelay, if not successful + * then go to longer sleep using usleep_range + */ + + /* check if set state successful */ + for (time = 0; time < 5; time++) { + if ((snd_sof_dsp_read(sdev, bar, offset) & mask) == target) { + done = true; + break; + } + msleep(20); + } + + if (!done) { + /* sleeping in 10ms steps so adjust timeout value */ + timeout /= 10; + + for (time = 0; time < timeout; time++) { + if ((snd_sof_dsp_read(sdev, bar, offset) & mask) == + target) + break; + + usleep_range(5000, 10000); + } + } + + ret = time < timeout ? 0 : -ETIME; + + return ret; +} +EXPORT_SYMBOL(snd_sof_dsp_register_poll); + +void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset) +{ + dev_err(sdev->dev, "error : DSP panic!\n"); + + /* check if DSP is not ready and did not set the dsp_oops_offset. + * if the dsp_oops_offset is not set, set it from the panic message. + * Also add a check to memory window setting with panic message. + */ + if (!sdev->dsp_oops_offset) + sdev->dsp_oops_offset = offset; + else + dev_dbg(sdev->dev, "panic: dsp_oops_offset %zu offset %d\n", + sdev->dsp_oops_offset, offset); + + snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX); + snd_sof_trace_notify_for_error(sdev); + snd_sof_dsp_cmd_done(sdev, SOF_IPC_HOST_REPLY); +} +EXPORT_SYMBOL(snd_sof_dsp_panic); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h new file mode 100644 index 00000000000000..5bd6e3921b5510 --- /dev/null +++ b/sound/soc/sof/ops.h @@ -0,0 +1,329 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __SOUND_SOC_SOF_IO_H +#define __SOUND_SOC_SOF_IO_H + +#include +#include +#include +#include +#include +#include +#include "sof-priv.h" + +/* init */ +static inline int snd_sof_probe(struct snd_sof_dev *sdev) +{ + if (sdev->ops->probe) + return sdev->ops->probe(sdev); + else + return 0; +} + +static inline int snd_sof_remove(struct snd_sof_dev *sdev) +{ + if (sdev->ops->remove) + return sdev->ops->remove(sdev); + else + return 0; +} + +/* control */ +static inline int snd_sof_dsp_run(struct snd_sof_dev *sdev) +{ + if (sdev->ops->run) + return sdev->ops->run(sdev); + else + return 0; +} + +static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev) +{ + if (sdev->ops->stall) + return sdev->ops->stall(sdev); + else + return 0; +} + +static inline int snd_sof_dsp_reset(struct snd_sof_dev *sdev) +{ + if (sdev->ops->reset) + return sdev->ops->reset(sdev); + else + return 0; +} + +/* power management */ +static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev) +{ + if (sdev->ops->resume) + return sdev->ops->resume(sdev); + else + return 0; +} + +static inline int snd_sof_dsp_suspend(struct snd_sof_dev *sdev, int state) +{ + if (sdev->ops->suspend) + return sdev->ops->suspend(sdev, state); + else + return 0; +} + +static inline int snd_sof_dsp_runtime_resume(struct snd_sof_dev *sdev) +{ + if (sdev->ops->runtime_resume) + return sdev->ops->runtime_resume(sdev); + else + return 0; +} + +static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev, + int state) +{ + if (sdev->ops->runtime_suspend) + return sdev->ops->runtime_suspend(sdev, state); + else + return 0; +} + +static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq) +{ + if (sdev->ops->set_clk) + return sdev->ops->set_clk(sdev, freq); + else + return 0; +} + +/* debug */ +static inline void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, u32 flags) +{ + if (sdev->ops->dbg_dump) + return sdev->ops->dbg_dump(sdev, flags); +} + +/* register IO */ +static inline void snd_sof_dsp_write(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u32 value) +{ + if (sdev->ops->write) + sdev->ops->write(sdev, sdev->bar[bar] + offset, value); +} + +static inline void snd_sof_dsp_write64(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u64 value) +{ + if (sdev->ops->write64) + sdev->ops->write64(sdev, + sdev->bar[bar] + offset, value); +} + +static inline u32 snd_sof_dsp_read(struct snd_sof_dev *sdev, u32 bar, + u32 offset) +{ + if (sdev->ops->read) + return sdev->ops->read(sdev, sdev->bar[bar] + offset); + else + return 0; +} + +static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar, + u32 offset) +{ + if (sdev->ops->read64) + return sdev->ops->read64(sdev, sdev->bar[bar] + offset); + else + return 0; +} + +/* block IO */ +static inline void snd_sof_dsp_block_read(struct snd_sof_dev *sdev, + u32 offset, void *dest, size_t bytes) +{ + if (sdev->ops->block_read) + sdev->ops->block_read(sdev, offset, dest, bytes); +} + +static inline void snd_sof_dsp_block_write(struct snd_sof_dev *sdev, + u32 offset, void *src, size_t bytes) +{ + if (sdev->ops->block_write) + sdev->ops->block_write(sdev, offset, src, bytes); +} + +/* mailbox */ +static inline void snd_sof_dsp_mailbox_read(struct snd_sof_dev *sdev, + u32 offset, void *message, + size_t bytes) +{ + if (sdev->ops->mailbox_read) + sdev->ops->mailbox_read(sdev, offset, message, bytes); +} + +static inline void snd_sof_dsp_mailbox_write(struct snd_sof_dev *sdev, + u32 offset, void *message, + size_t bytes) +{ + if (sdev->ops->mailbox_write) + sdev->ops->mailbox_write(sdev, offset, message, bytes); +} + +/* ipc */ +static inline int snd_sof_dsp_send_msg(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg) +{ + if (sdev->ops->send_msg) + return sdev->ops->send_msg(sdev, msg); + else + return 0; +} + +static inline int snd_sof_dsp_get_reply(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg) +{ + if (sdev->ops->get_reply) + return sdev->ops->get_reply(sdev, msg); + else + return 0; +} + +static inline int snd_sof_dsp_is_ready(struct snd_sof_dev *sdev) +{ + if (sdev->ops->is_ready) + return sdev->ops->is_ready(sdev); + else + return 0; +} + +static inline int snd_sof_dsp_cmd_done(struct snd_sof_dev *sdev, + int dir) +{ + if (sdev->ops->cmd_done) + return sdev->ops->cmd_done(sdev, dir); + else + return 0; +} + +/* host DMA trace */ +static inline int snd_sof_dma_trace_init(struct snd_sof_dev *sdev, + u32 *stream_tag) +{ + if (sdev->ops->trace_init) + return sdev->ops->trace_init(sdev, stream_tag); + else + return 0; +} + +static inline int snd_sof_dma_trace_release(struct snd_sof_dev *sdev) +{ + if (sdev->ops->trace_release) + return sdev->ops->trace_release(sdev); + else + return 0; +} + +static inline int snd_sof_dma_trace_trigger(struct snd_sof_dev *sdev, int cmd) +{ + if (sdev->ops->trace_trigger) + return sdev->ops->trace_trigger(sdev, cmd); + else + return 0; +} + +/* host PCM ops */ +static inline int +snd_sof_pcm_platform_open(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + if (sdev->ops && sdev->ops->pcm_open) + return sdev->ops->pcm_open(sdev, substream); + else + return 0; +} + +/* disconnect pcm substream to a host stream */ +static inline int +snd_sof_pcm_platform_close(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + if (sdev->ops && sdev->ops->pcm_close) + return sdev->ops->pcm_close(sdev, substream); + else + return 0; +} + +/* host stream hw params */ +static inline int +snd_sof_pcm_platform_hw_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct sof_ipc_stream_params *ipc_params) +{ + if (sdev->ops && sdev->ops->pcm_hw_params) + return sdev->ops->pcm_hw_params(sdev, substream, + params, ipc_params); + else + return 0; +} + +/* host stream trigger */ +static inline int +snd_sof_pcm_platform_trigger(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, int cmd) +{ + if (sdev->ops && sdev->ops->pcm_trigger) + return sdev->ops->pcm_trigger(sdev, substream, cmd); + else + return 0; +} + +/* host stream pointer */ +static inline snd_pcm_uframes_t +snd_sof_pcm_platform_pointer(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + if (sdev->ops && sdev->ops->pcm_pointer) + return sdev->ops->pcm_pointer(sdev, substream); + else + return 0; +} + +int snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u32 mask, u32 value); + +int snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u64 mask, u64 value); + +/* This is for registers bits with attribute RWC */ +void snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u32 mask, u32 value); + +int snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset, + u32 mask, u32 value); + +int snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u64 mask, u64 value); + +/* This is for registers bits with attribute RWC */ +void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u32 mask, u32 value); + +int snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset, + u32 mask, u32 value); + +int snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset, + u32 mask, u32 value); + +int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset, + u32 mask, u32 target, u32 timeout); + +void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset); +#endif From 9a02526442a498e92f79ef1287e73210e6ea29c1 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:34:01 +0000 Subject: [PATCH 0099/1995] ASoC: SOF: Add firmware loader support The firmware loader exports APIs that can be called by core to load and process multiple different file formats. Signed-off-by: Liam Girdwood --- sound/soc/sof/loader.c | 316 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 sound/soc/sof/loader.c diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c new file mode 100644 index 00000000000000..e30531026209e9 --- /dev/null +++ b/sound/soc/sof/loader.c @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// +// Generic firmware loader. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sof-priv.h" +#include "ops.h" + +static int get_ext_windows(struct snd_sof_dev *sdev, + struct sof_ipc_ext_data_hdr *ext_hdr) +{ + struct sof_ipc_window *w = (struct sof_ipc_window *)ext_hdr; + + int ret = 0; + size_t size; + + if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS) + return -EINVAL; + + size = sizeof(*w) + sizeof(struct sof_ipc_window_elem) * w->num_windows; + + /* keep a local copy of the data */ + sdev->info_window = kmemdup(w, size, GFP_KERNEL); + if (!sdev->info_window) + return -ENOMEM; + + return ret; +} + +/* parse the extended FW boot data structures from FW boot message */ +int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) +{ + struct sof_ipc_ext_data_hdr *ext_hdr; + void *ext_data; + int ret = 0; + + ext_data = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!ext_data) + return -ENOMEM; + + /* get first header */ + snd_sof_dsp_block_read(sdev, offset, ext_data, sizeof(*ext_hdr)); + ext_hdr = (struct sof_ipc_ext_data_hdr *)ext_data; + + while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) { + /* read in ext structure */ + offset += sizeof(*ext_hdr); + snd_sof_dsp_block_read(sdev, offset, + ext_data + sizeof(*ext_hdr), + ext_hdr->hdr.size - sizeof(*ext_hdr)); + + dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n", + ext_hdr->type, ext_hdr->hdr.size); + + /* process structure data */ + switch (ext_hdr->type) { + case SOF_IPC_EXT_DMA_BUFFER: + break; + case SOF_IPC_EXT_WINDOW: + ret = get_ext_windows(sdev, ext_hdr); + break; + default: + break; + } + + if (ret < 0) { + dev_err(sdev->dev, "error: failed to parse ext data type %d\n", + ext_hdr->type); + } + + /* move to next header */ + offset += ext_hdr->hdr.size; + snd_sof_dsp_block_read(sdev, offset, ext_data, + sizeof(*ext_hdr)); + ext_hdr = (struct sof_ipc_ext_data_hdr *)ext_data; + } + + kfree(ext_data); + return ret; +} +EXPORT_SYMBOL(snd_sof_fw_parse_ext_data); + +/* generic module parser for mmaped DSPs */ +int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, + struct snd_sof_mod_hdr *module) +{ + struct snd_sof_blk_hdr *block; + int count; + u32 offset; + + dev_dbg(sdev->dev, "new module size 0x%x blocks 0x%x type 0x%x\n", + module->size, module->num_blocks, module->type); + + block = (void *)module + sizeof(*module); + + for (count = 0; count < module->num_blocks; count++) { + if (block->size == 0) { + dev_warn(sdev->dev, + "warning: block %d size zero\n", count); + dev_warn(sdev->dev, " type 0x%x offset 0x%x\n", + block->type, block->offset); + continue; + } + + switch (block->type) { + case SOF_BLK_IMAGE: + case SOF_BLK_CACHE: + case SOF_BLK_REGS: + case SOF_BLK_SIG: + case SOF_BLK_ROM: + continue; /* not handled atm */ + case SOF_BLK_TEXT: + case SOF_BLK_DATA: + offset = block->offset; + break; + default: + dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n", + block->type, count); + return -EINVAL; + } + + dev_dbg(sdev->dev, + "block %d type 0x%x size 0x%x ==> offset 0x%x\n", + count, block->type, block->size, offset); + + snd_sof_dsp_block_write(sdev, offset, + (void *)block + sizeof(*block), + block->size); + + /* next block */ + block = (void *)block + sizeof(*block) + block->size; + } + + return 0; +} +EXPORT_SYMBOL(snd_sof_parse_module_memcpy); + +static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw) +{ + struct snd_sof_fw_header *header; + + /* Read the header information from the data pointer */ + header = (struct snd_sof_fw_header *)fw->data; + + /* verify FW sig */ + if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) { + dev_err(sdev->dev, "error: invalid firmware signature\n"); + return -EINVAL; + } + + /* check size is valid */ + if (fw->size != header->file_size + sizeof(*header)) { + dev_err(sdev->dev, "error: invalid filesize mismatch got 0x%zx expected 0x%zx\n", + fw->size, header->file_size + sizeof(*header)); + return -EINVAL; + } + + dev_dbg(sdev->dev, "header size=0x%x modules=0x%x abi=0x%x size=%zu\n", + header->file_size, header->num_modules, + header->abi, sizeof(*header)); + + return 0; +} + +static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw) +{ + struct snd_sof_fw_header *header; + struct snd_sof_mod_hdr *module; + int (*load_module)(struct snd_sof_dev *sof_dev, + struct snd_sof_mod_hdr *hdr); + int ret, count; + + header = (struct snd_sof_fw_header *)fw->data; + load_module = sdev->ops->load_module; + if (!load_module) + return -EINVAL; + + /* parse each module */ + module = (void *)fw->data + sizeof(*header); + for (count = 0; count < header->num_modules; count++) { + /* module */ + ret = load_module(sdev, module); + if (ret < 0) { + dev_err(sdev->dev, "error: invalid module %d\n", count); + return ret; + } + module = (void *)module + sizeof(*module) + module->size; + } + + return 0; +} + +int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev, + bool first_boot) +{ + struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev); + const char *fw_filename; + int ret; + + /* set code loading condition to true */ + sdev->code_loading = 1; + + switch (plat_data->type) { + case SOF_DEVICE_SPI: + fw_filename = plat_data->sof_machine->sof_fw_filename; + break; + default: + fw_filename = plat_data->machine->sof_fw_filename; + } + + ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev); + + if (ret < 0) { + dev_err(sdev->dev, "error: request firmware failed err: %d\n", + ret); + return ret; + } + + /* make sure the FW header and file is valid */ + ret = check_header(sdev, plat_data->fw); + if (ret < 0) { + dev_err(sdev->dev, "error: invalid FW header\n"); + goto error; + } + + /* prepare the DSP for FW loading */ + ret = snd_sof_dsp_reset(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to reset DSP\n"); + goto error; + } + + /* parse and load firmware modules to DSP */ + ret = load_modules(sdev, plat_data->fw); + if (ret < 0) { + dev_err(sdev->dev, "error: invalid FW modules\n"); + goto error; + } + + return 0; + +error: + release_firmware(plat_data->fw); + return ret; + +} +EXPORT_SYMBOL(snd_sof_load_firmware_memcpy); + +int snd_sof_load_firmware(struct snd_sof_dev *sdev, + bool first_boot) +{ + dev_dbg(sdev->dev, "loading firmware\n"); + + sdev->first_boot = first_boot; + + if (sdev->ops->load_firmware) + return sdev->ops->load_firmware(sdev, first_boot); + return 0; +} +EXPORT_SYMBOL(snd_sof_load_firmware); + +int snd_sof_run_firmware(struct snd_sof_dev *sdev) +{ + int ret; + + init_waitqueue_head(&sdev->boot_wait); + sdev->boot_complete = false; + + dev_dbg(sdev->dev, "booting DSP firmware\n"); + + /* boot the firmware on the DSP */ + ret = snd_sof_dsp_run(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to reset DSP\n"); + return ret; + } + + /* now wait for the DSP to boot */ + ret = wait_event_timeout(sdev->boot_wait, sdev->boot_complete, + msecs_to_jiffies(sdev->boot_timeout)); + if (ret == 0) { + dev_err(sdev->dev, "error: firmware boot timeout\n"); + snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX | + SOF_DBG_TEXT | SOF_DBG_PCI); + return -EIO; + } + + dev_info(sdev->dev, "firmware boot complete\n"); + + return 0; +} +EXPORT_SYMBOL(snd_sof_run_firmware); + +void snd_sof_fw_unload(struct snd_sof_dev *sdev) +{ + /* TODO: support module unloading at runtime */ +} +EXPORT_SYMBOL(snd_sof_fw_unload); From 589be0fd53654a949c5e8e523daf6358c5d5fe49 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:39:03 +0000 Subject: [PATCH 0100/1995] ASoC: SOF: Add userspace ABI support Add userspace ABI for audio userspace application IO outside of regular ALSA PCM and kcontrols. This is intended to be used to format coefficients and data for custom processing components. Signed-off-by: Liam Girdwood --- include/uapi/sound/sof-abi.h | 50 +++++++++++ include/uapi/sound/sof-eq.h | 158 ++++++++++++++++++++++++++++++++++ include/uapi/sound/sof-fw.h | 67 ++++++++++++++ include/uapi/sound/sof-tone.h | 27 ++++++ 4 files changed, 302 insertions(+) create mode 100644 include/uapi/sound/sof-abi.h create mode 100644 include/uapi/sound/sof-eq.h create mode 100644 include/uapi/sound/sof-fw.h create mode 100644 include/uapi/sound/sof-tone.h diff --git a/include/uapi/sound/sof-abi.h b/include/uapi/sound/sof-abi.h new file mode 100644 index 00000000000000..88c61f8c2a4a7a --- /dev/null +++ b/include/uapi/sound/sof-abi.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_UAPI_ABI_H__ +#define __INCLUDE_UAPI_ABI_H__ + +#define SOF_ABI_VER(major, minor, micro) \ + (((major) << 8) | ((minor) << 4) | (micro)) +#define SOF_ABI_VERSION_MAJOR(version) (((version) >> 8) & 0xff) +#define SOF_ABI_VERSION_MINOR(version) (((version) >> 4) & 0xf) +#define SOF_ABI_VERSION_MICRO(version) ((version) & 0xf) +#define SOF_ABI_VERSION_INCOMPATIBLE(sof_ver, client_ver) \ + (SOF_ABI_VERSION_MAJOR((sof_ver)) != \ + SOF_ABI_VERSION_MAJOR((client_ver)) || \ + ( \ + SOF_ABI_VERSION_MAJOR((sof_ver)) == \ + SOF_ABI_VERSION_MAJOR((client_ver)) && \ + SOF_ABI_VERSION_MINOR((sof_ver)) != \ + SOF_ABI_VERSION_MINOR((client_ver)) \ + ) \ + ) + +#define SOF_ABI_MAJOR 1 +#define SOF_ABI_MINOR 0 +#define SOF_ABI_MICRO 0 + +#define SOF_ABI_VERSION SOF_ABI_VER(SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_MICRO) + +#define SOF_ABI_MAGIC 0x00464F53 /* "SOF\0" */ + +/* + * Header for all non IPC ABI data. Identifies data type, size and ABI. + * Used by any bespoke component data structures or binary blobs. + */ + +struct sof_abi_hdr { + uint32_t magic; /* 'S', 'O', 'F', '\0' */ + uint32_t type; /* component specific type */ + uint32_t size; /* size in bytes of data excluding this struct */ + uint32_t abi; /* SOF ABI version */ + uint32_t comp_abi; /* component specific ABI version */ + char data[0]; +} __attribute__((packed)); + +#endif diff --git a/include/uapi/sound/sof-eq.h b/include/uapi/sound/sof-eq.h new file mode 100644 index 00000000000000..bd82fea5206ed0 --- /dev/null +++ b/include/uapi/sound/sof-eq.h @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Seppo Ingalsuo + */ + +#ifndef EQ_H +#define EQ_H + +/* FIR EQ type */ + +/* Component will reject non-matching configuration. The version number need + * to be incremented with any ABI changes in function fir_cmd(). + */ +#define SOF_EQ_FIR_ABI_VERSION 1 + +#define SOF_EQ_FIR_IDX_SWITCH 0 + +#define SOF_EQ_FIR_MAX_SIZE 4096 /* Max size allowed for coef data in bytes */ + +#define SOF_EQ_FIR_MAX_LENGTH 192 /* Max length for individual filter */ + +/* + * eq_fir_configuration data structure contains this information + * uint32_t size + * This is the number of bytes need to store the received EQ + * configuration. + * uint16_t channels_in_config + * This describes the number of channels in this EQ config data. It + * can be different from PLATFORM_MAX_CHANNELS. + * uint16_t number_of_responses + * 0=no responses, 1=one response defined, 2=two responses defined, etc. + * int16_t data[] + * assign_response[channels_in_config] + * 0 = use first response, 1 = use 2nd response, etc. + * E.g. {0, 0, 0, 0, 1, 1, 1, 1} would apply to channels 0-3 the + * same first defined response and for to channels 4-7 the second. + * coef_data[] + * Repeated data + * { filter_length, output_shift, h[] } + * for every EQ response defined where vector h has filter_length + * number of coefficients. Coefficients in h[] are in Q1.15 format. + * E.g. 16384 (Q1.15) = 0.5. The shifts are number of right shifts. + * + * NOTE: The channels_in_config must be even to have coef_data aligned to + * 32 bit word in RAM. Therefore a mono EQ assign must be duplicated to 2ch + * even if it would never used. Similarly a 5ch EQ assign must be increased + * to 6ch. EQ init will return an error if this is not met. + * + * NOTE: The filter_length must be multiple of four. Therefore the filter must + * be padded from the end with zeros have this condition met. + */ + +struct sof_eq_fir_config { + uint32_t size; + uint16_t channels_in_config; + uint16_t number_of_responses; + int16_t data[]; +}; + +struct sof_eq_fir_coef_data { + int16_t length; /* Number of FIR taps */ + int16_t out_shift; /* Amount of right shifts at output */ + int16_t coef[]; /* FIR coefficients */ +}; + +/* In the struct above there's two words (length, shift) before the actual + * FIR coefficients. This information is used in parsing of the config blob. + */ +#define SOF_EQ_FIR_COEF_NHEADER 2 + +/* IIR EQ type */ + +/* Component will reject non-matching configuration. The version number need + * to be incremented with any ABI changes in function fir_cmd(). + */ +#define SOF_EQ_IIR_ABI_VERSION 1 + +#define SOF_EQ_IIR_IDX_SWITCH 0 + +#define SOF_EQ_IIR_MAX_SIZE 1024 /* Max size allowed for coef data in bytes */ + +#define SOF_EQ_IIR_MAX_RESPONSES 8 /* A blob can define max 8 IIR EQs */ + +/* eq_iir_configuration + * uint32_t channels_in_config + * This describes the number of channels in this EQ config data. It + * can be different from PLATFORM_MAX_CHANNELS. + * uint32_t number_of_responses_defined + * 0=no responses, 1=one response defined, 2=two responses defined, etc. + * int32_t data[] + * Data consist of two parts. First is the response assign vector that + * has length of channels_in_config. The latter part is coefficient + * data. + * uint32_t assign_response[channels_in_config] + * -1 = not defined, 0 = use first response, 1 = use 2nd, etc. + * E.g. {0, 0, 0, 0, -1, -1, -1, -1} would apply to channels 0-3 the + * same first defined response and leave channels 4-7 unequalized. + * coefficient_data[] + * <1st EQ> + * uint32_t num_biquads + * uint32_t num_biquads_in_series + * <1st biquad> + * int32_t coef_a2 Q2.30 format + * int32_t coef_a1 Q2.30 format + * int32_t coef_b2 Q2.30 format + * int32_t coef_b1 Q2.30 format + * int32_t coef_b0 Q2.30 format + * int32_t output_shift number of shifts right, shift left is negative + * int32_t output_gain Q2.14 format + * <2nd biquad> + * ... + * <2nd EQ> + * + * Note: A flat response biquad can be made with a section set to + * b0 = 1.0, gain = 1.0, and other parameters set to 0 + * {0, 0, 0, 0, 1073741824, 0, 16484} + */ + +struct sof_eq_iir_config { + uint32_t size; + uint32_t channels_in_config; + uint32_t number_of_responses; + int32_t data[]; /* eq_assign[channels], eq 0, eq 1, ... */ +}; + +struct sof_eq_iir_header_df2t { + uint32_t num_sections; + uint32_t num_sections_in_series; + int32_t biquads[]; /* Repeated biquad coefficients */ +}; + +struct sof_eq_iir_biquad_df2t { + int32_t a2; /* Q2.30 */ + int32_t a1; /* Q2.30 */ + int32_t b2; /* Q2.30 */ + int32_t b1; /* Q2.30 */ + int32_t b0; /* Q2.30 */ + int32_t output_shift; /* Number of right shifts */ + int32_t output_gain; /* Q2.14 */ +}; + +/* A full 22th order equalizer with 11 biquads cover octave bands 1-11 in + * in the 0 - 20 kHz bandwidth. + */ +#define SOF_EQ_IIR_DF2T_BIQUADS_MAX 11 + +/* The number of int32_t words in sof_eq_iir_header_df2t */ +#define SOF_EQ_IIR_NHEADER_DF2T 2 + +/* The number of int32_t words in sof_eq_iir_biquad_df2t */ +#define SOF_EQ_IIR_NBIQUAD_DF2T 7 + +#endif /* EQ_H */ diff --git a/include/uapi/sound/sof-fw.h b/include/uapi/sound/sof-fw.h new file mode 100644 index 00000000000000..e55ea88ee69607 --- /dev/null +++ b/include/uapi/sound/sof-fw.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +/* + * Firmware file format . + */ + +#ifndef __INCLUDE_UAPI_SOF_FW_H__ +#define __INCLUDE_UAPI_SOF_FW_H__ + +#define SND_SOF_FW_SIG_SIZE 4 +#define SND_SOF_FW_ABI 1 +#define SND_SOF_FW_SIG "Reef" + +/* + * Firmware module is made up of 1 . N blocks of different types. The + * Block header is used to determine where and how block is to be copied in the + * DSP/host memory space. + */ +enum snd_sof_fw_blk_type { + SOF_BLK_IMAGE = 0, /* whole image - parsed by ROMs */ + SOF_BLK_TEXT = 1, + SOF_BLK_DATA = 2, + SOF_BLK_CACHE = 3, + SOF_BLK_REGS = 4, + SOF_BLK_SIG = 5, + SOF_BLK_ROM = 6, + /* add new block types here */ +}; + +struct snd_sof_blk_hdr { + enum snd_sof_fw_blk_type type; + uint32_t size; /* bytes minus this header */ + uint32_t offset; /* offset from base */ +} __attribute__((packed)); + +/* + * Firmware file is made up of 1 .. N different modules types. The module + * type is used to determine how to load and parse the module. + */ +enum snd_sof_fw_mod_type { + SOF_FW_BASE = 0, /* base firmware image */ + SOF_FW_MODULE = 1, /* firmware module */ +}; + +struct snd_sof_mod_hdr { + enum snd_sof_fw_mod_type type; + uint32_t size; /* bytes minus this header */ + uint32_t num_blocks; /* number of blocks */ +} __attribute__((packed)); + +/* + * Firmware file header. + */ +struct snd_sof_fw_header { + unsigned char sig[SND_SOF_FW_SIG_SIZE]; /* "Reef" */ + uint32_t file_size; /* size of file minus this header */ + uint32_t num_modules; /* number of modules */ + uint32_t abi; /* version of header format */ +} __attribute__((packed)); + +#endif diff --git a/include/uapi/sound/sof-tone.h b/include/uapi/sound/sof-tone.h new file mode 100644 index 00000000000000..ce258cd7ef70ec --- /dev/null +++ b/include/uapi/sound/sof-tone.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * Author: Seppo Ingalsuo + */ + +#ifndef TONE_H +#define TONE_H + +/* Component will reject non-matching configuration. The version number need + * to be incremented with any ABI changes in function fir_cmd(). + */ +#define SOF_TONE_ABI_VERSION 1 + +#define SOF_TONE_IDX_FREQUENCY 0 +#define SOF_TONE_IDX_AMPLITUDE 1 +#define SOF_TONE_IDX_FREQ_MULT 2 +#define SOF_TONE_IDX_AMPL_MULT 3 +#define SOF_TONE_IDX_LENGTH 4 +#define SOF_TONE_IDX_PERIOD 5 +#define SOF_TONE_IDX_REPEATS 6 +#define SOF_TONE_IDX_LIN_RAMP_STEP 7 + +#endif /* TONE_ABI_H */ From eb424f5cec31b9a0b8b25223402c1ab23c1bed8b Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:34:16 +0000 Subject: [PATCH 0101/1995] ASoC: SOF: Add compressed PCM support Add support for compressed audio playback/capture in SOF. TODO: to be completed. Signed-off-by: Liam Girdwood --- sound/soc/sof/compressed.c | 188 +++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 sound/soc/sof/compressed.c diff --git a/sound/soc/sof/compressed.c b/sound/soc/sof/compressed.c new file mode 100644 index 00000000000000..e747293fe4fac2 --- /dev/null +++ b/sound/soc/sof/compressed.c @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sof-priv.h" + +#define DRV_NAME "sof-audio" + +static int sof_compressed_open(struct snd_compr_stream *cstream) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm = rtd->private; + int ret; + + mutex_lock(&spcm->mutex); + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) + dev_err(sdev->dev, "error: comp open failed to resume %d\n", + ret); + mutex_unlock(&spcm->mutex); + return ret; +} + +static int sof_compressed_free(struct snd_compr_stream *cstream) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm = rtd->private; + int err; + + mutex_lock(&spcm->mutex); + err = pm_runtime_put(sdev->dev); + if (err < 0) + dev_err(sdev->dev, "error: comp close failed to idle %d\n", + err); + mutex_unlock(&spcm->mutex); + return err; +} + +static int sof_vorbis_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params) +{ + return 0; +} + +static int sof_mp3_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params) +{ + return 0; +} + +static int sof_compressed_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(component); + + switch (params->codec.id) { + case SND_AUDIOCODEC_VORBIS: + return sof_vorbis_set_params(cstream, params); + case SND_AUDIOCODEC_MP3: + return sof_mp3_set_params(cstream, params); + default: + dev_err(sdev->dev, "error: codec id %d not supported\n", + params->codec.id); + return -EINVAL; + } +} + +static int sof_compressed_trigger(struct snd_compr_stream *cstream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm = rtd->private; + struct sof_ipc_stream stream; + struct sof_ipc_reply reply; + + stream.hdr.size = sizeof(stream); + stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG; + stream.comp_id = spcm->stream[cstream->direction].comp_id; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_START; + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE; + break; + case SNDRV_PCM_TRIGGER_STOP: + stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_PAUSE; + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_RESUME: + default: + break; + } + + /* send IPC to the DSP */ + return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, + sizeof(stream), &reply, sizeof(reply)); +} + +static int sof_compressed_pointer(struct snd_compr_stream *cstream, + struct snd_compr_tstamp *tstamp) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(component); + struct sof_ipc_stream_posn posn; + struct snd_sof_pcm *spcm = rtd->private; + + snd_sof_ipc_stream_posn(sdev, spcm, cstream->direction, &posn); + + dev_vdbg(sdev->dev, "CPCM: DMA position %llu DAI position %llu\n", + posn.host_posn, posn.dai_posn); + + return 0; +} + +static int sof_compressed_ack(struct snd_compr_stream *cstream, + size_t bytes) +{ + return 0; +} + +static int sof_compressed_get_caps(struct snd_compr_stream *cstream, + struct snd_compr_caps *caps) +{ + return 0; +} + +static int sof_compressed_get_codec_caps(struct snd_compr_stream *cstream, + struct snd_compr_codec_caps *codec) +{ + return 0; +} + +static int sof_compressed_set_metadata(struct snd_compr_stream *cstream, + struct snd_compr_metadata *metadata) +{ + return 0; +} + +struct snd_compr_ops sof_compressed_ops = { + .open = sof_compressed_open, + .free = sof_compressed_free, + .set_params = sof_compressed_set_params, + .set_metadata = sof_compressed_set_metadata, + .trigger = sof_compressed_trigger, + .pointer = sof_compressed_pointer, + .ack = sof_compressed_ack, + .get_caps = sof_compressed_get_caps, + .get_codec_caps = sof_compressed_get_codec_caps, +}; From e25bc7a982deb409324120efea080d492a1c53cd Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Tue, 16 Jan 2018 15:36:57 +0000 Subject: [PATCH 0102/1995] ASoC: SOF: Add PM support Add support for saving and restoring DSP context in D3 to host DDR. The suspend callback includes: suspend all pcm's stream that are running, send CTX_SAVE ipc, drop all ipc's, release trace dma and then power off the DSP. And the resume callback performs the following steps: load FW, run FW, re-initialize trace, restore pipeline, restore the kcontrol values and finally send the ctx restore ipc to the dsp. The streams that are suspended are resumed by the ALSA resume trigger. If the streams are paused during system suspend, they are marked explicitly so they can be restored during PAUSE_RELEASE. Signed-off-by: Liam Girdwood --- sound/soc/sof/pm.c | 408 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 408 insertions(+) create mode 100644 sound/soc/sof/pm.c diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c new file mode 100644 index 00000000000000..a235b6ccf48436 --- /dev/null +++ b/sound/soc/sof/pm.c @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ops.h" +#include "sof-priv.h" + +#define RUNTIME_PM 1 + +static int sof_restore_kcontrols(struct snd_sof_dev *sdev) +{ + struct snd_sof_control *scontrol = NULL; + int ipc_cmd, ctrl_type, sof_abi; + int ret = 0; + + /* restore kcontrol values */ + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + /* reset readback offset for scontrol after resuming */ + scontrol->readback_offset = 0; + + /* notify DSP of kcontrol values */ + switch (scontrol->cmd) { + case SOF_CTRL_CMD_VOLUME: + ipc_cmd = SOF_IPC_COMP_SET_VALUE; + ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET; + ret = snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, + ipc_cmd, ctrl_type, + scontrol->cmd); + break; + case SOF_CTRL_CMD_BINARY: + + /* Check if control data contains valid data. + * SOF_ABI_MAGIC will not match if there is no data. + */ + ipc_cmd = SOF_IPC_COMP_SET_DATA; + ctrl_type = SOF_CTRL_TYPE_DATA_SET; + sof_abi = scontrol->control_data->data->magic; + if (sof_abi == SOF_ABI_MAGIC) + ret = snd_sof_ipc_set_comp_data(sdev->ipc, + scontrol, + ipc_cmd, + ctrl_type, + scontrol->cmd); + break; + + default: + break; + } + if (ret < 0) { + dev_err(sdev->dev, + "error: failed kcontrol value set for widget: %d\n", + scontrol->comp_id); + + return ret; + } + } + + return 0; +} + +static int sof_restore_pipelines(struct snd_sof_dev *sdev) +{ + struct snd_sof_widget *swidget = NULL; + struct snd_sof_route *sroute = NULL; + struct snd_sof_dai *dai; + struct sof_ipc_comp_dai *comp_dai; + struct sof_ipc_hdr *hdr; + int ret = 0; + + /* restore pipeline components */ + list_for_each_entry_reverse(swidget, &sdev->widget_list, list) { + struct sof_ipc_comp_reply r; + + /* skip if there is no private data */ + if (!swidget->private) + continue; + + switch (swidget->id) { + case snd_soc_dapm_dai_in: + /* fallthrough */ + case snd_soc_dapm_dai_out: + dai = (struct snd_sof_dai *)swidget->private; + comp_dai = &dai->comp_dai; + ret = sof_ipc_tx_message(sdev->ipc, + comp_dai->comp.hdr.cmd, + comp_dai, sizeof(*comp_dai), + &r, sizeof(r)); + break; + default: + hdr = (struct sof_ipc_hdr *)swidget->private; + ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, + swidget->private, hdr->size, + &r, sizeof(r)); + break; + } + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to load widget type %d with ID: %d\n", + swidget->widget->id, swidget->comp_id); + + return ret; + } + } + + /* restore pipeline connections */ + list_for_each_entry_reverse(sroute, &sdev->route_list, list) { + struct sof_ipc_pipe_comp_connect *connect; + struct sof_ipc_reply reply; + + /* skip if there's no private data */ + if (!sroute->private) + continue; + + connect = sroute->private; + + /* send ipc */ + ret = sof_ipc_tx_message(sdev->ipc, + connect->hdr.cmd, + connect, sizeof(*connect), + &reply, sizeof(reply)); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to load route sink %s control %s source %s\n", + sroute->route.sink, + sroute->route.control ? sroute->route.control + : "none", + sroute->route.source); + + return ret; + } + } + + /* restore dai links */ + list_for_each_entry_reverse(dai, &sdev->dai_list, list) { + struct sof_ipc_reply reply; + struct sof_ipc_dai_config *config = &dai->dai_config; + + ret = sof_ipc_tx_message(sdev->ipc, + config->hdr.cmd, config, + sizeof(*config), + &reply, sizeof(reply)); + + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to set dai config for %s\n", + dai->name); + + return ret; + } + } + + /* complete pipeline */ + list_for_each_entry(swidget, &sdev->widget_list, list) { + switch (swidget->id) { + case snd_soc_dapm_scheduler: + swidget->complete = + snd_sof_complete_pipeline(sdev, swidget); + break; + default: + break; + } + } + + /* restore pipeline kcontrols */ + if (sdev->restore_kcontrols) + return sof_restore_kcontrols(sdev); + + return 0; +} + +static int sof_send_pm_ipc(struct snd_sof_dev *sdev, int cmd) +{ + struct sof_ipc_pm_ctx pm_ctx; + + memset(&pm_ctx, 0, sizeof(pm_ctx)); + + /* configure ctx save ipc message */ + pm_ctx.hdr.size = sizeof(pm_ctx); + pm_ctx.hdr.cmd = SOF_IPC_GLB_PM_MSG | cmd; + + /* send ctx save ipc to dsp */ + return sof_ipc_tx_message(sdev->ipc, pm_ctx.hdr.cmd, &pm_ctx, + sizeof(pm_ctx), &pm_ctx, sizeof(pm_ctx)); +} + +static void sof_suspend_streams(struct snd_sof_dev *sdev) +{ + struct snd_sof_pcm *spcm; + struct snd_pcm_substream *substream; + int dir; + + /* suspend all running streams */ + list_for_each_entry(spcm, &sdev->pcm_list, list) { + + mutex_lock(&spcm->mutex); + + /* suspend running playback stream */ + dir = SNDRV_PCM_STREAM_PLAYBACK; + substream = spcm->stream[dir].substream; + + if (substream && substream->runtime) { + + snd_pcm_suspend(substream); + + /* + * set restore_stream so that hw_params can be + * restored during resume + */ + spcm->restore_stream[dir] = 1; + } + + /* suspend running capture stream */ + dir = SNDRV_PCM_STREAM_CAPTURE; + substream = spcm->stream[dir].substream; + + if (substream && substream->runtime) { + + snd_pcm_suspend(substream); + + /* + * set restore_stream so that hw_params can be + * restored during resume + */ + spcm->restore_stream[dir] = 1; + } + + mutex_unlock(&spcm->mutex); + } +} + +static int sof_resume(struct device *dev, int runtime_resume) +{ + struct sof_platform_priv *priv = dev_get_drvdata(dev); + struct snd_sof_dev *sdev = dev_get_drvdata(&priv->pdev_pcm->dev); + int ret = 0; + + /* do nothing if dsp resume callbacks are not set */ + if (!sdev->ops->resume || !sdev->ops->runtime_resume) + return 0; + + /* + * if the runtime_resume flag is set, call the runtime_resume routine + * or else call the system resume routine + */ + if (runtime_resume) + ret = snd_sof_dsp_runtime_resume(sdev); + else + ret = snd_sof_dsp_resume(sdev); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to power up DSP after resume\n"); + return ret; + } + + /* load the firmware */ + ret = snd_sof_load_firmware(sdev, false); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to load DSP firmware after resume %d\n", + ret); + return ret; + } + + /* boot the firmware */ + ret = snd_sof_run_firmware(sdev); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to boot DSP firmware after resume %d\n", + ret); + return ret; + } + + /* resume DMA trace, only need send ipc */ + ret = snd_sof_init_trace_ipc(sdev); + if (ret < 0) { + /* non fatal */ + dev_warn(sdev->dev, + "warning: failed to init trace after resume %d\n", + ret); + } + + /* restore pipelines */ + ret = sof_restore_pipelines(sdev); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to restore pipeline after resume %d\n", + ret); + return ret; + } + + /* notify DSP of system resume */ + ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_RESTORE); + if (ret < 0) + dev_err(sdev->dev, + "error: ctx_restore ipc error during resume %d\n", + ret); + + return ret; +} + +static int sof_suspend(struct device *dev, int runtime_suspend) +{ + struct sof_platform_priv *priv = dev_get_drvdata(dev); + struct snd_sof_dev *sdev = dev_get_drvdata(&priv->pdev_pcm->dev); + int ret = 0; + + /* do nothing if dsp suspend callback is not set */ + if (!sdev->ops->suspend) + return 0; + + /* release trace */ + snd_sof_release_trace(sdev); + + /* + * Suspend running pcm streams. + * They will be restarted by ALSA resume trigger call. + */ + sof_suspend_streams(sdev); + + /* notify DSP of upcoming power down */ + ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_SAVE); + if (ret < 0) { + dev_err(sdev->dev, + "error: ctx_save ipc error during suspend %d\n", + ret); + return ret; + } + + /* drop all ipc */ + sof_ipc_drop_all(sdev->ipc); + + /* power down DSP */ + if (runtime_suspend) + ret = snd_sof_dsp_runtime_suspend(sdev, 0); + else + ret = snd_sof_dsp_suspend(sdev, 0); + if (ret < 0) + dev_err(sdev->dev, + "error: failed to power down DSP during suspend %d\n", + ret); + + /* set flag for restoring kcontrols upon resuming */ + sdev->restore_kcontrols = true; + + return ret; +} + +int snd_sof_runtime_suspend(struct device *dev) +{ + return sof_suspend(dev, RUNTIME_PM); +} +EXPORT_SYMBOL(snd_sof_runtime_suspend); + +int snd_sof_runtime_resume(struct device *dev) +{ + return sof_resume(dev, RUNTIME_PM); +} +EXPORT_SYMBOL(snd_sof_runtime_resume); + +int snd_sof_resume(struct device *dev) +{ + return sof_resume(dev, !RUNTIME_PM); +} +EXPORT_SYMBOL(snd_sof_resume); + +int snd_sof_suspend(struct device *dev) +{ + return 0; +} +EXPORT_SYMBOL(snd_sof_suspend); + +int snd_sof_suspend_late(struct device *dev) +{ + return sof_suspend(dev, !RUNTIME_PM); +} +EXPORT_SYMBOL(snd_sof_suspend_late); + +int snd_sof_prepare(struct device *dev) +{ + struct sof_platform_priv *priv = dev_get_drvdata(dev); + struct snd_sof_dev *sdev = dev_get_drvdata(&priv->pdev_pcm->dev); + + /* + * PCI devices are brought back to full power before system suspend. + * Setting this flag will prevent restoring kcontrols + * when resuming before system suspend + */ + sdev->restore_kcontrols = false; + + return 0; +} +EXPORT_SYMBOL(snd_sof_prepare); From efefbc60f7ec77fc7257b35e23bee6cbb688ba13 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:37:08 +0000 Subject: [PATCH 0103/1995] ASoC: SOF: Add Nocodec machine driver support Add a simple "fallback" machine driver that can be used to enable SOF on boards with no codec device. This machine driver can also be forced for debug/development. Signed-off-by: Liam Girdwood --- include/sound/sof.h | 10 +++++ sound/soc/sof/nocodec.c | 91 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 sound/soc/sof/nocodec.c diff --git a/include/sound/sof.h b/include/sound/sof.h index e0adeb3fae8501..06f5d9d015b046 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -102,4 +103,13 @@ struct sof_dev_desc { const char *nocodec_tplg_filename; }; +int sof_nocodec_setup(struct device *dev, + struct snd_sof_pdata *sof_pdata, + struct snd_soc_acpi_mach *mach, + const struct sof_dev_desc *desc, + struct snd_sof_dsp_ops *ops); + +int sof_bes_setup(struct device *dev, struct snd_sof_dsp_ops *ops, + struct snd_soc_dai_link *links, int link_num, + struct snd_soc_card *card); #endif diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c new file mode 100644 index 00000000000000..3ec658f96b3d08 --- /dev/null +++ b/sound/soc/sof/nocodec.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sof-priv.h" + +static struct snd_soc_card sof_nocodec_card = { + .name = "sof-nocodec", +}; + +int sof_nocodec_setup(struct device *dev, + struct snd_sof_pdata *sof_pdata, + struct snd_soc_acpi_mach *mach, + const struct sof_dev_desc *desc, + struct snd_sof_dsp_ops *ops) +{ + struct snd_soc_dai_link *links; + int ret; + + if (!mach) + return -EINVAL; + + sof_pdata->drv_name = "sof-nocodec"; + + mach->drv_name = "sof-nocodec"; + mach->sof_fw_filename = desc->nocodec_fw_filename; + mach->sof_tplg_filename = desc->nocodec_tplg_filename; + + /* create dummy BE dai_links */ + links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * + ops->num_drv, GFP_KERNEL); + if (!links) + return -ENOMEM; + + ret = sof_bes_setup(dev, ops, links, ops->num_drv, + &sof_nocodec_card); + if (ret) { + kfree(links); + return ret; + } + + return 0; +} +EXPORT_SYMBOL(sof_nocodec_setup); + +static int sof_nocodec_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &sof_nocodec_card; + + card->dev = &pdev->dev; + + return devm_snd_soc_register_card(&pdev->dev, card); +} + +static int sof_nocodec_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver sof_nocodec_audio = { + .probe = sof_nocodec_probe, + .remove = sof_nocodec_remove, + .driver = { + .name = "sof-nocodec", + .pm = &snd_soc_pm_ops, + }, +}; +module_platform_driver(sof_nocodec_audio) + +MODULE_DESCRIPTION("ASoC sof nocodec"); +MODULE_AUTHOR("Liam Girdwood"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("platform:sof-nocodec"); From eafed357c9c0ef439a40d6e0ef68192dd3f7dffb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 20 Jul 2018 11:31:11 -0500 Subject: [PATCH 0104/1995] ASoC: SOF: Add xtensa support Add common directory for xtensa architecture Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/xtensa/Kconfig | 3 + sound/soc/sof/xtensa/Makefile | 5 ++ sound/soc/sof/xtensa/core.c | 159 ++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 sound/soc/sof/xtensa/Kconfig create mode 100644 sound/soc/sof/xtensa/Makefile create mode 100644 sound/soc/sof/xtensa/core.c diff --git a/sound/soc/sof/xtensa/Kconfig b/sound/soc/sof/xtensa/Kconfig new file mode 100644 index 00000000000000..f66f17bb03357f --- /dev/null +++ b/sound/soc/sof/xtensa/Kconfig @@ -0,0 +1,3 @@ +config SND_SOC_SOF_XTENSA + tristate + diff --git a/sound/soc/sof/xtensa/Makefile b/sound/soc/sof/xtensa/Makefile new file mode 100644 index 00000000000000..cc89c7472a3802 --- /dev/null +++ b/sound/soc/sof/xtensa/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) + +snd-sof-xtensa-dsp-objs := core.o + +obj-$(CONFIG_SND_SOC_SOF_XTENSA) += snd-sof-xtensa-dsp.o diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c new file mode 100644 index 00000000000000..5ca9185f5afdf5 --- /dev/null +++ b/sound/soc/sof/xtensa/core.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Pan Xiuli + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../sof-priv.h" +#include "../ops.h" + +struct xtensa_exception_cause { + u32 id; + const char *msg; + const char *description; +}; + +/* From 4.4.1.5 table 4-64 Exception Causes of + * Xtensa Instruction Set Architecture (ISA) Reference Manual + */ +static const struct xtensa_exception_cause xtensa_exception_causes[] = { + {0, "IllegalInstructionCause", "Illegal instruction"}, + {1, "SyscallCause", "SYSCALL instruction"}, + {2, "InstructionFetchErrorCause", + "Processor internal physical address or data error during instruction fetch"}, + {3, "LoadStoreErrorCause", + "Processor internal physical address or data error during load or store"}, + {4, "Level1InterruptCause", + "Level-1 interrupt as indicated by set level-1 bits in the INTERRUPT register"}, + {5, "AllocaCause", + "MOVSP instruction, if caller’s registers are not in the register file"}, + {6, "IntegerDivideByZeroCause", + "QUOS, QUOU, REMS, or REMU divisor operand is zero"}, + {8, "PrivilegedCause", + "Attempt to execute a privileged operation when CRING ? 0"}, + {9, "LoadStoreAlignmentCause", "Load or store to an unaligned address"}, + {12, "InstrPIFDataErrorCause", + "PIF data error during instruction fetch"}, + {13, "LoadStorePIFDataErrorCause", + "Synchronous PIF data error during LoadStore access"}, + {14, "InstrPIFAddrErrorCause", + "PIF address error during instruction fetch"}, + {15, "LoadStorePIFAddrErrorCause", + "Synchronous PIF address error during LoadStore access"}, + {16, "InstTLBMissCause", "Error during Instruction TLB refill"}, + {17, "InstTLBMultiHitCause", + "Multiple instruction TLB entries matched"}, + {18, "InstFetchPrivilegeCause", + "An instruction fetch referenced a virtual address at a ring level less than CRING"}, + {20, "InstFetchProhibitedCause", + "An instruction fetch referenced a page mapped with an attribute that does not permit instruction fetch"}, + {24, "LoadStoreTLBMissCause", + "Error during TLB refill for a load or store"}, + {25, "LoadStoreTLBMultiHitCause", + "Multiple TLB entries matched for a load or store"}, + {26, "LoadStorePrivilegeCause", + "A load or store referenced a virtual address at a ring level less than CRING"}, + {28, "LoadProhibitedCause", + "A load referenced a page mapped with an attribute that does not permit loads"}, + {32, "Coprocessor0Disabled", + "Coprocessor 0 instruction when cp0 disabled"}, + {33, "Coprocessor1Disabled", + "Coprocessor 1 instruction when cp1 disabled"}, + {34, "Coprocessor2Disabled", + "Coprocessor 2 instruction when cp2 disabled"}, + {35, "Coprocessor3Disabled", + "Coprocessor 3 instruction when cp3 disabled"}, + {36, "Coprocessor4Disabled", + "Coprocessor 4 instruction when cp4 disabled"}, + {37, "Coprocessor5Disabled", + "Coprocessor 5 instruction when cp5 disabled"}, + {38, "Coprocessor6Disabled", + "Coprocessor 6 instruction when cp6 disabled"}, + {39, "Coprocessor7Disabled", + "Coprocessor 7 instruction when cp7 disabled"}, +}; + +/* only need xtensa atm */ +static void xtensa_dsp_oops(struct snd_sof_dev *sdev, void *oops) +{ + struct sof_ipc_dsp_oops_xtensa *xoops = oops; + int i; + + dev_err(sdev->dev, "error: DSP Firmware Oops\n"); + for (i = 0; i < ARRAY_SIZE(xtensa_exception_causes); i++) { + if (xtensa_exception_causes[i].id == xoops->exccause) { + dev_err(sdev->dev, "error: Exception Cause: %s, %s\n", + xtensa_exception_causes[i].msg, + xtensa_exception_causes[i].description); + } + } + dev_err(sdev->dev, "EXCCAUSE 0x%8.8x EXCVADDR 0x%8.8x PS 0x%8.8x SAR 0x%8.8x\n", + xoops->exccause, xoops->excvaddr, xoops->ps, xoops->sar); + dev_err(sdev->dev, "EPC1 0x%8.8x EPC2 0x%8.8x EPC3 0x%8.8x EPC4 0x%8.8x", + xoops->epc1, xoops->epc2, xoops->epc3, xoops->epc4); + dev_err(sdev->dev, "EPC5 0x%8.8x EPC6 0x%8.8x EPC7 0x%8.8x DEPC 0x%8.8x", + xoops->epc5, xoops->epc6, xoops->epc7, xoops->depc); + dev_err(sdev->dev, "EPS2 0x%8.8x EPS3 0x%8.8x EPS4 0x%8.8x EPS5 0x%8.8x", + xoops->eps2, xoops->eps3, xoops->eps4, xoops->eps5); + dev_err(sdev->dev, "EPS6 0x%8.8x EPS7 0x%8.8x INTENABL 0x%8.8x INTERRU 0x%8.8x", + xoops->eps6, xoops->eps7, xoops->intenable, xoops->interrupt); +} + +static void xtensa_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack, + u32 stack_words) +{ + struct sof_ipc_dsp_oops_xtensa *xoops = oops; + u32 stack_ptr = xoops->stack; + int i; + + dev_err(sdev->dev, "stack dump from 0x%8.8x\n", stack_ptr); + + for (i = 0; i <= stack_words - 4; i += 4) { + dev_err(sdev->dev, "0x%8.8x: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n", + stack_ptr + i, stack[i], stack[i + 1], stack[i + 2], + stack[i + 3]); + } + + /* deal with any remaining words */ + switch (stack_words - i) { + case 0: + break; + case 1: + dev_err(sdev->dev, "0x%8.8x: 0x%8.8x\n", + stack_ptr + stack_words - 1, stack[stack_words - 1]); + break; + case 2: + dev_err(sdev->dev, "0x%8.8x: 0x%8.8x 0x%8.8x\n", + stack_ptr + stack_words - 2, stack[stack_words - 2], + stack[stack_words - 1]); + break; + case 3: + dev_err(sdev->dev, "0x%8.8x: 0x%8.8x 0x%8.8x 0x%8.8x\n", + stack_ptr + stack_words - 3, stack[stack_words - 3], + stack[stack_words - 2], stack[stack_words - 1]); + break; + default: + break; + } +} + +const struct sof_arch_ops sof_xtensa_arch_ops = { + .dsp_oops = xtensa_dsp_oops, + .dsp_stack = xtensa_stack, +}; +EXPORT_SYMBOL(sof_xtensa_arch_ops); + +MODULE_DESCRIPTION("SOF Xtensa DSP support"); +MODULE_LICENSE("Dual BSD/GPL"); From 6d0111f64da857c28e4c056747d677eaee080fb9 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:37:40 +0000 Subject: [PATCH 0105/1995] ASoC: SOF: Intel: Add BYT, CHT and BSW DSP HW support. Add support for the audio DSP hardware found on Intel Baytrail, Cherrytrail and Braswell based devices. Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/byt.c | 926 +++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/shim.h | 157 +++++++ 2 files changed, 1083 insertions(+) create mode 100644 sound/soc/sof/intel/byt.c create mode 100644 sound/soc/sof/intel/shim.h diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c new file mode 100644 index 00000000000000..25d5bf0ed6f31c --- /dev/null +++ b/sound/soc/sof/intel/byt.c @@ -0,0 +1,926 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +/* + * Hardware interface for audio DSP on Baytrail, Braswell and Cherrytrail. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sof-priv.h" +#include "../ops.h" +#include "shim.h" + +/* DSP memories */ +#define IRAM_OFFSET 0x0C0000 +#define IRAM_SIZE (80 * 1024) +#define DRAM_OFFSET 0x100000 +#define DRAM_SIZE (160 * 1024) +#define SHIM_OFFSET 0x140000 +#define SHIM_SIZE 0x100 +#define MBOX_OFFSET 0x144000 +#define MBOX_SIZE 0x1000 +#define EXCEPT_OFFSET 0x800 + +/* DSP peripherals */ +#define DMAC0_OFFSET 0x098000 +#define DMAC1_OFFSET 0x09c000 +#define DMAC2_OFFSET 0x094000 +#define DMAC_SIZE 0x420 +#define SSP0_OFFSET 0x0a0000 +#define SSP1_OFFSET 0x0a1000 +#define SSP2_OFFSET 0x0a2000 +#define SSP3_OFFSET 0x0a4000 +#define SSP4_OFFSET 0x0a5000 +#define SSP5_OFFSET 0x0a6000 +#define SSP_SIZE 0x100 + +#define BYT_STACK_DUMP_SIZE 32 + +#define BYT_PCI_BAR_SIZE 0x200000 + +#define BYT_PANIC_OFFSET(x) (((x) & (0xFFFFll << 32)) >> 32) + +/* + * Debug + */ + +#define MBOX_DUMP_SIZE 0x30 + +/* BARs */ +#define BYT_DSP_BAR 0 +#define BYT_PCI_BAR 1 +#define BYT_IMR_BAR 2 + +static const struct snd_sof_debugfs_map byt_debugfs[] = { + {"dmac0", BYT_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE}, + {"dmac1", BYT_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE}, + {"ssp0", BYT_DSP_BAR, SSP0_OFFSET, SSP_SIZE}, + {"ssp1", BYT_DSP_BAR, SSP1_OFFSET, SSP_SIZE}, + {"ssp2", BYT_DSP_BAR, SSP2_OFFSET, SSP_SIZE}, + {"iram", BYT_DSP_BAR, IRAM_OFFSET, IRAM_SIZE}, + {"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE}, + {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE}, +}; + +static const struct snd_sof_debugfs_map cht_debugfs[] = { + {"dmac0", BYT_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE}, + {"dmac1", BYT_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE}, + {"dmac2", BYT_DSP_BAR, DMAC2_OFFSET, DMAC_SIZE}, + {"ssp0", BYT_DSP_BAR, SSP0_OFFSET, SSP_SIZE}, + {"ssp1", BYT_DSP_BAR, SSP1_OFFSET, SSP_SIZE}, + {"ssp2", BYT_DSP_BAR, SSP2_OFFSET, SSP_SIZE}, + {"ssp3", BYT_DSP_BAR, SSP3_OFFSET, SSP_SIZE}, + {"ssp4", BYT_DSP_BAR, SSP4_OFFSET, SSP_SIZE}, + {"ssp5", BYT_DSP_BAR, SSP5_OFFSET, SSP_SIZE}, + {"iram", BYT_DSP_BAR, IRAM_OFFSET, IRAM_SIZE}, + {"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE}, + {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE}, +}; + +static int byt_cmd_done(struct snd_sof_dev *sdev, int dir); + +/* + * Register IO + */ + +static void byt_write(struct snd_sof_dev *sdev, void __iomem *addr, + u32 value) +{ + writel(value, addr); +} + +static u32 byt_read(struct snd_sof_dev *sdev, void __iomem *addr) +{ + return readl(addr); +} + +static void byt_write64(struct snd_sof_dev *sdev, void __iomem *addr, + u64 value) +{ + memcpy_toio(addr, &value, sizeof(value)); +} + +static u64 byt_read64(struct snd_sof_dev *sdev, void __iomem *addr) +{ + u64 val; + + memcpy_fromio(&val, addr, sizeof(val)); + return val; +} + +/* + * Memory copy. + */ + +static void byt_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, + size_t size) +{ + void __iomem *dest = sdev->bar[sdev->mmio_bar] + offset; + u32 tmp = 0; + int i, m, n; + const u8 *src_byte = src; + + m = size / 4; + n = size % 4; + + /* __iowrite32_copy use 32bit size values so divide by 4 */ + __iowrite32_copy(dest, src, m); + + if (n) { + for (i = 0; i < n; i++) + tmp |= (u32)*(src_byte + m * 4 + i) << (i * 8); + __iowrite32_copy(dest + m * 4, &tmp, 1); + } +} + +static void byt_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, + size_t size) +{ + void __iomem *src = sdev->bar[sdev->mmio_bar] + offset; + + memcpy_fromio(dest, src, size); +} + +/* + * IPC Firmware ready. + */ +static void byt_get_windows(struct snd_sof_dev *sdev) +{ + struct sof_ipc_window_elem *elem; + u32 outbox_offset = 0; + u32 stream_offset = 0; + u32 inbox_offset = 0; + u32 outbox_size = 0; + u32 stream_size = 0; + u32 inbox_size = 0; + int i; + + if (!sdev->info_window) { + dev_err(sdev->dev, "error: have no window info\n"); + return; + } + + for (i = 0; i < sdev->info_window->num_windows; i++) { + elem = &sdev->info_window->window[i]; + + switch (elem->type) { + case SOF_IPC_REGION_UPBOX: + inbox_offset = elem->offset + MBOX_OFFSET; + inbox_size = elem->size; + snd_sof_debugfs_create_item(sdev, + sdev->bar[BYT_DSP_BAR] + + inbox_offset, + elem->size, "inbox"); + break; + case SOF_IPC_REGION_DOWNBOX: + outbox_offset = elem->offset + MBOX_OFFSET; + outbox_size = elem->size; + snd_sof_debugfs_create_item(sdev, + sdev->bar[BYT_DSP_BAR] + + outbox_offset, + elem->size, "outbox"); + break; + case SOF_IPC_REGION_TRACE: + snd_sof_debugfs_create_item(sdev, + sdev->bar[BYT_DSP_BAR] + + elem->offset + MBOX_OFFSET, + elem->size, "etrace"); + break; + case SOF_IPC_REGION_DEBUG: + snd_sof_debugfs_create_item(sdev, + sdev->bar[BYT_DSP_BAR] + + elem->offset + MBOX_OFFSET, + elem->size, "debug"); + break; + case SOF_IPC_REGION_STREAM: + stream_offset = elem->offset + MBOX_OFFSET; + stream_size = elem->size; + snd_sof_debugfs_create_item(sdev, + sdev->bar[BYT_DSP_BAR] + + stream_offset, + elem->size, "stream"); + break; + case SOF_IPC_REGION_REGS: + snd_sof_debugfs_create_item(sdev, + sdev->bar[BYT_DSP_BAR] + + elem->offset + MBOX_OFFSET, + elem->size, "regs"); + break; + case SOF_IPC_REGION_EXCEPTION: + sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; + snd_sof_debugfs_create_item(sdev, + sdev->bar[BYT_DSP_BAR] + + elem->offset + MBOX_OFFSET, + elem->size, "exception"); + break; + default: + dev_err(sdev->dev, "error: get illegal window info\n"); + return; + } + } + + if (outbox_size == 0 || inbox_size == 0) { + dev_err(sdev->dev, "error: get illegal mailbox window\n"); + return; + } + + snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, + outbox_offset, outbox_size); + sdev->stream_box.offset = stream_offset; + sdev->stream_box.size = stream_size; + + dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", + inbox_offset, inbox_size); + dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", + outbox_offset, outbox_size); + dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", + stream_offset, stream_size); +} + +static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; + struct sof_ipc_fw_version *v = &fw_ready->version; + u32 offset; + + /* mailbox must be on 4k boundary */ + offset = MBOX_OFFSET; + + dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n", + msg_id, offset); + + /* copy data from the DSP FW ready offset */ + byt_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); + + snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, + fw_ready->dspbox_size, + fw_ready->hostbox_offset, + fw_ready->hostbox_size); + + dev_info(sdev->dev, + " Firmware info: version %d:%d-%s build %d on %s:%s\n", + v->major, v->minor, v->tag, v->build, v->date, v->time); + + /* now check for extended data */ + snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + + sizeof(struct sof_ipc_fw_ready)); + + byt_get_windows(sdev); + + return 0; +} + +/* + * IPC Mailbox IO + */ + +static void byt_mailbox_write(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes) +{ + void __iomem *dest = sdev->bar[sdev->mailbox_bar] + offset; + + memcpy_toio(dest, message, bytes); +} + +static void byt_mailbox_read(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes) +{ + void __iomem *src = sdev->bar[sdev->mailbox_bar] + offset; + + memcpy_fromio(message, src, bytes); +} + +/* + * Debug + */ + +static void byt_get_registers(struct snd_sof_dev *sdev, + struct sof_ipc_dsp_oops_xtensa *xoops, + struct sof_ipc_panic_info *panic_info, + u32 *stack, size_t stack_words) +{ + /* first read regsisters */ + byt_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); + + /* then get panic info */ + byt_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), + panic_info, sizeof(*panic_info)); + + /* then get the stack */ + byt_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + + sizeof(*panic_info), stack, + stack_words * sizeof(u32)); +} + +static void byt_dump(struct snd_sof_dev *sdev, u32 flags) +{ + struct sof_ipc_dsp_oops_xtensa xoops; + struct sof_ipc_panic_info panic_info; + u32 stack[BYT_STACK_DUMP_SIZE]; + u32 status, panic; + + /* now try generic SOF status messages */ + status = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IPCD); + panic = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IPCX); + byt_get_registers(sdev, &xoops, &panic_info, stack, + BYT_STACK_DUMP_SIZE); + snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, + BYT_STACK_DUMP_SIZE); +} + +/* + * IPC Doorbell IRQ handler and thread. + */ + +static irqreturn_t byt_irq_handler(int irq, void *context) +{ + struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + u64 isr; + int ret = IRQ_NONE; + + /* Interrupt arrived, check src */ + isr = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_ISRX); + if (isr & SHIM_ISRX_DONE) { + /* Mask Done interrupt before return */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_DONE, + SHIM_IMRX_DONE); + ret = IRQ_WAKE_THREAD; + } + + if (isr & SHIM_ISRX_BUSY) { + /* Mask Busy interrupt before return */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_BUSY, + SHIM_IMRX_BUSY); + ret = IRQ_WAKE_THREAD; + } + + return ret; +} + +static irqreturn_t byt_irq_thread(int irq, void *context) +{ + struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + u64 ipcx, ipcd; + + ipcx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCX); + + /* reply message from DSP */ + if (ipcx & SHIM_BYT_IPCX_DONE) { + /* + * handle immediate reply from DSP core. If the msg is + * found, set done bit in cmd_done which is called at the + * end of message processing function, else set it here + * because the done bit can't be set in cmd_done function + * which is triggered by msg + */ + if (snd_sof_ipc_reply(sdev, ipcx)) + byt_cmd_done(sdev, SOF_IPC_DSP_REPLY); + } + + /* new message from DSP */ + ipcd = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCD); + if (ipcd & SHIM_BYT_IPCD_BUSY) { + /* Handle messages from DSP Core */ + if ((ipcd & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { + snd_sof_dsp_panic(sdev, BYT_PANIC_OFFSET(ipcd) + + MBOX_OFFSET); + } else { + snd_sof_ipc_msgs_rx(sdev); + } + } + + return IRQ_HANDLED; +} + +static int byt_is_ready(struct snd_sof_dev *sdev) +{ + u64 ipcx; + + ipcx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCX); + if ((ipcx & SHIM_BYT_IPCX_BUSY) || (ipcx & SHIM_BYT_IPCX_DONE)) + return 0; + + return 1; +} + +static int byt_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + u64 cmd = msg->header; + + /* send the message */ + byt_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + snd_sof_dsp_write64(sdev, BYT_DSP_BAR, SHIM_IPCX, + cmd | SHIM_BYT_IPCX_BUSY); + + return 0; +} + +static int byt_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + struct sof_ipc_reply reply; + int ret = 0; + u32 size; + + /* get reply */ + byt_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); + if (reply.error < 0) { + size = sizeof(reply); + ret = reply.error; + } else { + /* reply correct size ? */ + if (reply.hdr.size != msg->reply_size) { + dev_err(sdev->dev, "error: reply expected 0x%zx got 0x%x bytes\n", + msg->reply_size, reply.hdr.size); + size = msg->reply_size; + ret = -EINVAL; + } else { + size = reply.hdr.size; + } + } + + /* read the message */ + if (msg->msg_data && size > 0) + byt_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, + size); + + return ret; +} + +static int byt_cmd_done(struct snd_sof_dev *sdev, int dir) +{ + if (dir == SOF_IPC_HOST_REPLY) { + /* clear BUSY bit and set DONE bit - accept new messages */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCD, + SHIM_BYT_IPCD_BUSY | + SHIM_BYT_IPCD_DONE, + SHIM_BYT_IPCD_DONE); + + /* unmask busy interrupt */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_BUSY, 0); + } else { + /* clear DONE bit - tell DSP we have completed */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCX, + SHIM_BYT_IPCX_DONE, 0); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_DONE, 0); + } + + return 0; +} + +/* + * DSP control. + */ + +static int byt_run(struct snd_sof_dev *sdev) +{ + int tries = 10; + + /* release stall and wait to unstall */ + snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_CSR, + SHIM_BYT_CSR_STALL, 0x0); + while (tries--) { + if (!(snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_CSR) & + SHIM_BYT_CSR_PWAITMODE)) + break; + msleep(100); + } + if (tries < 0) { + dev_err(sdev->dev, "error: unable to run DSP firmware\n"); + byt_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX); + return -ENODEV; + } + + return 0; +} + +static int byt_reset(struct snd_sof_dev *sdev) +{ + /* put DSP into reset, set reset vector and stall */ + snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_CSR, + SHIM_BYT_CSR_RST | SHIM_BYT_CSR_VECTOR_SEL | + SHIM_BYT_CSR_STALL, + SHIM_BYT_CSR_RST | SHIM_BYT_CSR_VECTOR_SEL | + SHIM_BYT_CSR_STALL); + + usleep_range(10, 15); + + /* take DSP out of reset and keep stalled for FW loading */ + snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_CSR, + SHIM_BYT_CSR_RST, 0); + + return 0; +} + +/* + * Probe and remove. + */ + +static int byt_acpi_probe(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *pdata = sdev->pdata; + const struct sof_dev_desc *desc = pdata->desc; + struct platform_device *pdev = + container_of(sdev->parent, struct platform_device, dev); + struct resource *mmio; + u32 base, size; + int ret = 0; + + /* set DSP arch ops */ + sdev->arch_ops = &sof_xtensa_arch_ops; + + /* DSP DMA can only access low 31 bits of host memory */ + ret = dma_coerce_mask_and_coherent(sdev->dev, DMA_BIT_MASK(31)); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DMA mask %d\n", ret); + return ret; + } + + /* LPE base */ + mmio = platform_get_resource(pdev, IORESOURCE_MEM, + desc->resindex_lpe_base); + if (mmio) { + base = mmio->start; + size = resource_size(mmio); + } else { + dev_err(sdev->dev, "error: failed to get LPE base at idx %d\n", + desc->resindex_lpe_base); + return -EINVAL; + } + + dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); + sdev->bar[BYT_DSP_BAR] = ioremap(base, size); + if (!sdev->bar[BYT_DSP_BAR]) { + dev_err(sdev->dev, "error: failed to ioremap LPE base 0x%x size 0x%x\n", + base, size); + return -ENODEV; + } + dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[BYT_DSP_BAR]); + + /* TODO: add offsets */ + sdev->mmio_bar = BYT_DSP_BAR; + sdev->mailbox_bar = BYT_DSP_BAR; + + /* IMR base - optional */ + if (desc->resindex_imr_base == -1) + goto irq; + + mmio = platform_get_resource(pdev, IORESOURCE_MEM, + desc->resindex_imr_base); + if (mmio) { + base = mmio->start; + size = resource_size(mmio); + } else { + dev_err(sdev->dev, "error: failed to get IMR base at idx %d\n", + desc->resindex_imr_base); + ret = -ENODEV; + goto imr_err; + } + + /* some BIOSes don't map IMR */ + if (base == 0x55aa55aa || base == 0x0) { + dev_info(sdev->dev, "IMR not set by BIOS. Ignoring\n"); + goto irq; + } + + dev_dbg(sdev->dev, "IMR base at 0x%x size 0x%x", base, size); + sdev->bar[BYT_IMR_BAR] = ioremap(base, size); + if (!sdev->bar[BYT_IMR_BAR]) { + dev_err(sdev->dev, "error: failed to ioremap IMR base 0x%x size 0x%x\n", + base, size); + ret = -ENODEV; + goto imr_err; + } + dev_dbg(sdev->dev, "IMR VADDR %p\n", sdev->bar[BYT_IMR_BAR]); + +irq: + /* register our IRQ */ + sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc); + if (sdev->ipc_irq < 0) { + dev_err(sdev->dev, "error: failed to get IRQ at index %d\n", + desc->irqindex_host_ipc); + ret = sdev->ipc_irq; + goto irq_err; + } + + dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); + ret = request_threaded_irq(sdev->ipc_irq, byt_irq_handler, + byt_irq_thread, IRQF_SHARED, "AudioDSP", + sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to register IRQ %d\n", + sdev->ipc_irq); + goto irq_err; + } + + /* enable Interrupt from both sides */ + snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRX, 0x3, 0x0); + snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRD, 0x3, 0x0); + + /* set BARS */ + sdev->cl_bar = BYT_DSP_BAR; + + /* set default mailbox offset for FW ready message */ + sdev->dsp_box.offset = MBOX_OFFSET; + + return ret; + +irq_err: + iounmap(sdev->bar[BYT_IMR_BAR]); +imr_err: + iounmap(sdev->bar[BYT_DSP_BAR]); + return ret; +} + +static int byt_pci_probe(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *pdata = sdev->pdata; + const struct sof_dev_desc *desc = pdata->desc; + struct pci_dev *pci = sdev->pci; + u32 base, size; + int ret = 0; + + /* DSP DMA can only access low 31 bits of host memory */ + ret = dma_coerce_mask_and_coherent(&pci->dev, DMA_BIT_MASK(31)); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DMA mask %d\n", ret); + return ret; + } + + /* LPE base */ + base = pci_resource_start(pci, desc->resindex_lpe_base) - IRAM_OFFSET; + size = BYT_PCI_BAR_SIZE; + + dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); + sdev->bar[BYT_DSP_BAR] = ioremap(base, size); + if (!sdev->bar[BYT_DSP_BAR]) { + dev_err(sdev->dev, "error: failed to ioremap LPE base 0x%x size 0x%x\n", + base, size); + return -ENODEV; + } + dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[BYT_DSP_BAR]); + + /* IMR base - optional */ + if (desc->resindex_imr_base == -1) + goto irq; + + base = pci_resource_start(pci, desc->resindex_imr_base); + size = pci_resource_len(pci, desc->resindex_imr_base); + + /* some BIOSes don't map IMR */ + if (base == 0x55aa55aa || base == 0x0) { + dev_info(sdev->dev, "IMR not set by BIOS. Ignoring\n"); + goto irq; + } + + dev_dbg(sdev->dev, "IMR base at 0x%x size 0x%x", base, size); + sdev->bar[BYT_IMR_BAR] = ioremap(base, size); + if (!sdev->bar[BYT_IMR_BAR]) { + dev_err(sdev->dev, "error: failed to ioremap IMR base 0x%x size 0x%x\n", + base, size); + ret = -ENODEV; + goto imr_err; + } + dev_dbg(sdev->dev, "IMR VADDR %p\n", sdev->bar[BYT_IMR_BAR]); + +irq: + /* register our IRQ */ + sdev->ipc_irq = pci->irq; + dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); + ret = request_threaded_irq(sdev->ipc_irq, byt_irq_handler, + byt_irq_thread, 0, "AudioDSP", sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to register IRQ %d\n", + sdev->ipc_irq); + goto irq_err; + } + + /* enable Interrupt from both sides */ + snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRX, 0x3, 0x0); + snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRD, 0x3, 0x0); + + /* set BARS */ + sdev->cl_bar = BYT_DSP_BAR; + + /* set default mailbox offset for FW ready message */ + sdev->dsp_box.offset = MBOX_OFFSET; + + return ret; + +irq_err: + iounmap(sdev->bar[BYT_IMR_BAR]); +imr_err: + iounmap(sdev->bar[BYT_DSP_BAR]); + return ret; +} + +static int byt_probe(struct snd_sof_dev *sdev) +{ + if (sdev->pci) + return byt_pci_probe(sdev); + else + return byt_acpi_probe(sdev); +} + +static int byt_acpi_remove(struct snd_sof_dev *sdev) +{ + iounmap(sdev->bar[BYT_DSP_BAR]); + iounmap(sdev->bar[BYT_PCI_BAR]); + iounmap(sdev->bar[BYT_IMR_BAR]); + free_irq(sdev->ipc_irq, sdev); + return 0; +} + +static int byt_pci_remove(struct snd_sof_dev *sdev) +{ + free_irq(sdev->ipc_irq, sdev); + return 0; +} + +static int byt_remove(struct snd_sof_dev *sdev) +{ + if (sdev->pci) + return byt_pci_remove(sdev); + else + return byt_acpi_remove(sdev); +} + +#define BYT_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +/* Baytrail DAIs */ +static struct snd_soc_dai_driver byt_dai[] = { +{ + .name = "ssp0-port", + .playback = SOF_DAI_STREAM("ssp0 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), + .capture = SOF_DAI_STREAM("ssp0 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), +}, +{ + .name = "ssp1-port", + .playback = SOF_DAI_STREAM("ssp1 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), + .capture = SOF_DAI_STREAM("ssp1 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), +}, +{ + .name = "ssp2-port", + .playback = SOF_DAI_STREAM("ssp2 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), + .capture = SOF_DAI_STREAM("ssp2 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), +}, +{ + .name = "ssp3-port", + .playback = SOF_DAI_STREAM("ssp3 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), + .capture = SOF_DAI_STREAM("ssp3 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), +}, +{ + .name = "ssp4-port", + .playback = SOF_DAI_STREAM("ssp4 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), + .capture = SOF_DAI_STREAM("ssp4 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), +}, +{ + .name = "ssp5-port", + .playback = SOF_DAI_STREAM("ssp5 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), + .capture = SOF_DAI_STREAM("ssp5 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), +}, +}; + +/* baytrail ops */ +struct snd_sof_dsp_ops sof_byt_ops = { + /* device init */ + .probe = byt_probe, + .remove = byt_remove, + + /* DSP core boot / reset */ + .run = byt_run, + .reset = byt_reset, + + /* Register IO */ + .write = byt_write, + .read = byt_read, + .write64 = byt_write64, + .read64 = byt_read64, + + /* Block IO */ + .block_read = byt_block_read, + .block_write = byt_block_write, + + /* doorbell */ + .irq_handler = byt_irq_handler, + .irq_thread = byt_irq_thread, + + /* mailbox */ + .mailbox_read = byt_mailbox_read, + .mailbox_write = byt_mailbox_write, + + /* ipc */ + .send_msg = byt_send_msg, + .get_reply = byt_get_reply, + .fw_ready = byt_fw_ready, + .is_ready = byt_is_ready, + .cmd_done = byt_cmd_done, + + /* debug */ + .debug_map = byt_debugfs, + .debug_map_count = ARRAY_SIZE(byt_debugfs), + .dbg_dump = byt_dump, + + /* module loading */ + .load_module = snd_sof_parse_module_memcpy, + + /*Firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + + /* DAI drivers */ + .drv = byt_dai, + .num_drv = 3, /* we have only 3 SSPs on byt*/ +}; +EXPORT_SYMBOL(sof_byt_ops); + +/* cherrytrail and braswell ops */ +struct snd_sof_dsp_ops sof_cht_ops = { + /* device init */ + .probe = byt_probe, + .remove = byt_remove, + + /* DSP core boot / reset */ + .run = byt_run, + .reset = byt_reset, + + /* Register IO */ + .write = byt_write, + .read = byt_read, + .write64 = byt_write64, + .read64 = byt_read64, + + /* Block IO */ + .block_read = byt_block_read, + .block_write = byt_block_write, + + /* doorbell */ + .irq_handler = byt_irq_handler, + .irq_thread = byt_irq_thread, + + /* mailbox */ + .mailbox_read = byt_mailbox_read, + .mailbox_write = byt_mailbox_write, + + /* ipc */ + .send_msg = byt_send_msg, + .get_reply = byt_get_reply, + .fw_ready = byt_fw_ready, + .is_ready = byt_is_ready, + .cmd_done = byt_cmd_done, + + /* debug */ + .debug_map = cht_debugfs, + .debug_map_count = ARRAY_SIZE(cht_debugfs), + .dbg_dump = byt_dump, + + /* module loading */ + .load_module = snd_sof_parse_module_memcpy, + + /*Firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + + /* DAI drivers */ + .drv = byt_dai, + /* all 6 SSPs may be available for cherrytrail */ + .num_drv = ARRAY_SIZE(byt_dai), +}; +EXPORT_SYMBOL(sof_cht_ops); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h new file mode 100644 index 00000000000000..b6481fc65b2de7 --- /dev/null +++ b/sound/soc/sof/intel/shim.h @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __SOF_INTEL_SHIM_H +#define __SOF_INTEL_SHIM_H + +/* + * SHIM registers for BYT, BSW, CHT, HSW, BDW + */ + +#define SHIM_CSR (SHIM_OFFSET + 0x00) +#define SHIM_PISR (SHIM_OFFSET + 0x08) +#define SHIM_PIMR (SHIM_OFFSET + 0x10) +#define SHIM_ISRX (SHIM_OFFSET + 0x18) +#define SHIM_ISRD (SHIM_OFFSET + 0x20) +#define SHIM_IMRX (SHIM_OFFSET + 0x28) +#define SHIM_IMRD (SHIM_OFFSET + 0x30) +#define SHIM_IPCX (SHIM_OFFSET + 0x38) +#define SHIM_IPCD (SHIM_OFFSET + 0x40) +#define SHIM_ISRSC (SHIM_OFFSET + 0x48) +#define SHIM_ISRLPESC (SHIM_OFFSET + 0x50) +#define SHIM_IMRSC (SHIM_OFFSET + 0x58) +#define SHIM_IMRLPESC (SHIM_OFFSET + 0x60) +#define SHIM_IPCSC (SHIM_OFFSET + 0x68) +#define SHIM_IPCLPESC (SHIM_OFFSET + 0x70) +#define SHIM_CLKCTL (SHIM_OFFSET + 0x78) +#define SHIM_CSR2 (SHIM_OFFSET + 0x80) +#define SHIM_LTRC (SHIM_OFFSET + 0xE0) +#define SHIM_HMDC (SHIM_OFFSET + 0xE8) + +#define SHIM_PWMCTRL 0x1000 + +/* + * SST SHIM register bits for BYT, BSW, CHT HSW, BDW + * Register bit naming and functionaility can differ between devices. + */ + +/* CSR / CS */ +#define SHIM_CSR_RST (0x1 << 1) +#define SHIM_CSR_SBCS0 (0x1 << 2) +#define SHIM_CSR_SBCS1 (0x1 << 3) +#define SHIM_CSR_DCS(x) ((x) << 4) +#define SHIM_CSR_DCS_MASK (0x7 << 4) +#define SHIM_CSR_STALL (0x1 << 10) +#define SHIM_CSR_S0IOCS (0x1 << 21) +#define SHIM_CSR_S1IOCS (0x1 << 23) +#define SHIM_CSR_LPCS (0x1 << 31) +#define SHIM_CSR_24MHZ_LPCS \ + (SHIM_CSR_SBCS0 | SHIM_CSR_SBCS1 | SHIM_CSR_LPCS) +#define SHIM_CSR_24MHZ_NO_LPCS (SHIM_CSR_SBCS0 | SHIM_CSR_SBCS1) +#define SHIM_BYT_CSR_RST (0x1 << 0) +#define SHIM_BYT_CSR_VECTOR_SEL (0x1 << 1) +#define SHIM_BYT_CSR_STALL (0x1 << 2) +#define SHIM_BYT_CSR_PWAITMODE (0x1 << 3) + +/* ISRX / ISC */ +#define SHIM_ISRX_BUSY (0x1 << 1) +#define SHIM_ISRX_DONE (0x1 << 0) +#define SHIM_BYT_ISRX_REQUEST (0x1 << 1) + +/* ISRD / ISD */ +#define SHIM_ISRD_BUSY (0x1 << 1) +#define SHIM_ISRD_DONE (0x1 << 0) + +/* IMRX / IMC */ +#define SHIM_IMRX_BUSY (0x1 << 1) +#define SHIM_IMRX_DONE (0x1 << 0) +#define SHIM_BYT_IMRX_REQUEST (0x1 << 1) + +/* IMRD / IMD */ +#define SHIM_IMRD_DONE (0x1 << 0) +#define SHIM_IMRD_BUSY (0x1 << 1) +#define SHIM_IMRD_SSP0 (0x1 << 16) +#define SHIM_IMRD_DMAC0 (0x1 << 21) +#define SHIM_IMRD_DMAC1 (0x1 << 22) +#define SHIM_IMRD_DMAC (SHIM_IMRD_DMAC0 | SHIM_IMRD_DMAC1) + +/* IPCX / IPCC */ +#define SHIM_IPCX_DONE (0x1 << 30) +#define SHIM_IPCX_BUSY (0x1 << 31) +#define SHIM_BYT_IPCX_DONE ((u64)0x1 << 62) +#define SHIM_BYT_IPCX_BUSY ((u64)0x1 << 63) + +/* IPCD */ +#define SHIM_IPCD_DONE (0x1 << 30) +#define SHIM_IPCD_BUSY (0x1 << 31) +#define SHIM_BYT_IPCD_DONE ((u64)0x1 << 62) +#define SHIM_BYT_IPCD_BUSY ((u64)0x1 << 63) + +/* CLKCTL */ +#define SHIM_CLKCTL_SMOS(x) ((x) << 24) +#define SHIM_CLKCTL_MASK (3 << 24) +#define SHIM_CLKCTL_DCPLCG BIT(18) +#define SHIM_CLKCTL_SCOE1 BIT(17) +#define SHIM_CLKCTL_SCOE0 BIT(16) + +/* CSR2 / CS2 */ +#define SHIM_CSR2_SDFD_SSP0 BIT(1) +#define SHIM_CSR2_SDFD_SSP1 BIT(2) + +/* LTRC */ +#define SHIM_LTRC_VAL(x) ((x) << 0) + +/* HMDC */ +#define SHIM_HMDC_HDDA0(x) ((x) << 0) +#define SHIM_HMDC_HDDA1(x) ((x) << 7) +#define SHIM_HMDC_HDDA_E0_CH0 1 +#define SHIM_HMDC_HDDA_E0_CH1 2 +#define SHIM_HMDC_HDDA_E0_CH2 4 +#define SHIM_HMDC_HDDA_E0_CH3 8 +#define SHIM_HMDC_HDDA_E1_CH0 SHIM_HMDC_HDDA1(SHIM_HMDC_HDDA_E0_CH0) +#define SHIM_HMDC_HDDA_E1_CH1 SHIM_HMDC_HDDA1(SHIM_HMDC_HDDA_E0_CH1) +#define SHIM_HMDC_HDDA_E1_CH2 SHIM_HMDC_HDDA1(SHIM_HMDC_HDDA_E0_CH2) +#define SHIM_HMDC_HDDA_E1_CH3 SHIM_HMDC_HDDA1(SHIM_HMDC_HDDA_E0_CH3) +#define SHIM_HMDC_HDDA_E0_ALLCH \ + (SHIM_HMDC_HDDA_E0_CH0 | SHIM_HMDC_HDDA_E0_CH1 | \ + SHIM_HMDC_HDDA_E0_CH2 | SHIM_HMDC_HDDA_E0_CH3) +#define SHIM_HMDC_HDDA_E1_ALLCH \ + (SHIM_HMDC_HDDA_E1_CH0 | SHIM_HMDC_HDDA_E1_CH1 | \ + SHIM_HMDC_HDDA_E1_CH2 | SHIM_HMDC_HDDA_E1_CH3) + +/* Audio DSP PCI registers */ +#define PCI_VDRTCTL0 0xa0 +#define PCI_VDRTCTL1 0xa4 +#define PCI_VDRTCTL2 0xa8 +#define PCI_VDRTCTL3 0xaC + +/* VDRTCTL0 */ +#define PCI_VDRTCL0_D3PGD BIT(0) +#define PCI_VDRTCL0_D3SRAMPGD BIT(1) +#define PCI_VDRTCL0_DSRAMPGE_SHIFT 12 +#define PCI_VDRTCL0_DSRAMPGE_MASK (0xfffff << PCI_VDRTCL0_DSRAMPGE_SHIFT) +#define PCI_VDRTCL0_ISRAMPGE_SHIFT 2 +#define PCI_VDRTCL0_ISRAMPGE_MASK (0x3ff << PCI_VDRTCL0_ISRAMPGE_SHIFT) + +/* VDRTCTL2 */ +#define PCI_VDRTCL2_DCLCGE BIT(1) +#define PCI_VDRTCL2_DTCGE BIT(10) +#define PCI_VDRTCL2_APLLSE_MASK BIT(31) + +/* PMCS */ +#define PCI_PMCS 0x84 +#define PCI_PMCS_PS_MASK 0x3 + +extern struct snd_sof_dsp_ops sof_byt_ops; +extern struct snd_sof_dsp_ops sof_cht_ops; +extern struct snd_sof_dsp_ops sof_hsw_ops; +extern struct snd_sof_dsp_ops sof_bdw_ops; + +#endif From aa3262e28ca3f3baef8312c545ed8e61f107b0d7 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:37:51 +0000 Subject: [PATCH 0106/1995] ASoC: SOF: Intel: Add HSW HW DSP support Add DSP hardware support for Intel Haswell based devices. Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/hsw.c | 803 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 803 insertions(+) create mode 100644 sound/soc/sof/intel/hsw.c diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c new file mode 100644 index 00000000000000..fef9aa0c8ec249 --- /dev/null +++ b/sound/soc/sof/intel/hsw.c @@ -0,0 +1,803 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +/* + * Hardwre interface for audio DSP on Haswell + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../sof-priv.h" +#include "../ops.h" +#include "shim.h" + +/* BARs */ +#define HSW_DSP_BAR 0 +#define HSW_PCI_BAR 1 + +/* + * Debug + */ + +/* DSP memories for HSW */ +#define IRAM_OFFSET 0x80000 +#define HSW_IRAM_SIZE (10 * 32 * 1024) +#define DRAM_OFFSET 0x00000 +#define HSW_DRAM_SIZE (16 * 32 * 1024) +#define SHIM_OFFSET 0xE7000 +#define SHIM_SIZE 0x100 +#define MBOX_OFFSET 0x7E000 +#define MBOX_SIZE 0x1000 +#define MBOX_DUMP_SIZE 0x30 +#define EXCEPT_OFFSET 0x800 + +/* DSP peripherals */ +#define DMAC0_OFFSET 0xFE000 +#define DMAC1_OFFSET 0xFF000 +#define DMAC_SIZE 0x420 +#define SSP0_OFFSET 0xFC000 +#define SSP1_OFFSET 0xFD000 +#define SSP_SIZE 0x100 + +#define HSW_STACK_DUMP_SIZE 32 + +#define HSW_PANIC_OFFSET(x) ((x) & 0xFFFF) + +static const struct snd_sof_debugfs_map hsw_debugfs[] = { + {"dmac0", HSW_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE}, + {"dmac1", HSW_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE}, + {"ssp0", HSW_DSP_BAR, SSP0_OFFSET, SSP_SIZE}, + {"ssp1", HSW_DSP_BAR, SSP1_OFFSET, SSP_SIZE}, + {"iram", HSW_DSP_BAR, IRAM_OFFSET, HSW_IRAM_SIZE}, + {"dram", HSW_DSP_BAR, DRAM_OFFSET, HSW_DRAM_SIZE}, + {"shim", HSW_DSP_BAR, SHIM_OFFSET, SHIM_SIZE}, +}; + +static int hsw_cmd_done(struct snd_sof_dev *sdev, int dir); + +/* + * Memory copy. + */ + +/* write has to deal with copying non 32 bit sized data */ +static void hsw_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, + size_t size) +{ + void __iomem *dest = sdev->bar[sdev->mmio_bar] + offset; + u32 tmp = 0; + int i, m, n; + const u8 *src_byte = src; + + m = size / 4; + n = size % 4; + + /* __iowrite32_copy use 32bit size values so divide by 4 */ + __iowrite32_copy(dest, src, m); + + if (n) { + for (i = 0; i < n; i++) + tmp |= (u32)*(src_byte + m * 4 + i) << (i * 8); + __iowrite32_copy(dest + m * 4, &tmp, 1); + } +} + +static void hsw_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, + size_t size) +{ + void __iomem *src = sdev->bar[sdev->mmio_bar] + offset; + + memcpy_fromio(dest, src, size); +} + +static void hsw_mailbox_write(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes) +{ + void __iomem *dest = sdev->bar[sdev->mailbox_bar] + offset; + + memcpy_toio(dest, message, bytes); +} + +static void hsw_mailbox_read(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes) +{ + void __iomem *src = sdev->bar[sdev->mailbox_bar] + offset; + + memcpy_fromio(message, src, bytes); +} + +/* + * Register IO + */ + +static void hsw_write(struct snd_sof_dev *sdev, void __iomem *addr, + u32 value) +{ + writel(value, addr); +} + +static u32 hsw_read(struct snd_sof_dev *sdev, void __iomem *addr) +{ + return readl(addr); +} + +static void hsw_write64(struct snd_sof_dev *sdev, void __iomem *addr, + u64 value) +{ + memcpy_toio(addr, &value, sizeof(value)); +} + +static u64 hsw_read64(struct snd_sof_dev *sdev, void __iomem *addr) +{ + u64 val; + + memcpy_fromio(&val, addr, sizeof(val)); + return val; +} + +/* + * DSP Control. + */ + +static int hsw_run(struct snd_sof_dev *sdev) +{ + /* set oportunistic mode on engine 0,1 for all channels */ + snd_sof_dsp_update_bits(sdev, HSW_DSP_BAR, SHIM_HMDC, + SHIM_HMDC_HDDA_E0_ALLCH | + SHIM_HMDC_HDDA_E1_ALLCH, 0); + + /* set DSP to RUN */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_CSR, + SHIM_CSR_STALL, 0x0); + + return 0; //TODO: Fix return value +} + +static int hsw_reset(struct snd_sof_dev *sdev) +{ + /* put DSP into reset and stall */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_CSR, + SHIM_CSR_RST | SHIM_CSR_STALL, + SHIM_CSR_RST | SHIM_CSR_STALL); + + /* keep in reset for 10ms */ + mdelay(10); + + /* take DSP out of reset and keep stalled for FW loading */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_CSR, + SHIM_CSR_RST | SHIM_CSR_STALL, + SHIM_CSR_STALL); + + return 0; //TODO: Fix return value +} + +static int hsw_set_dsp_D0(struct snd_sof_dev *sdev) +{ + int tries = 10; + u32 reg; + + /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_PCI_BAR, PCI_VDRTCTL2, + PCI_VDRTCL2_DCLCGE | PCI_VDRTCL2_DTCGE, + 0); + + /* Disable D3PG (VDRTCTL0.D3PGD = 1) */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_PCI_BAR, PCI_VDRTCTL0, + PCI_VDRTCL0_D3PGD, PCI_VDRTCL0_D3PGD); + + /* Set D0 state */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_PCI_BAR, PCI_PMCS, + PCI_PMCS_PS_MASK, 0); + + /* check that ADSP shim is enabled */ + while (tries--) { + reg = readl(sdev->bar[HSW_PCI_BAR] + PCI_PMCS) + & PCI_PMCS_PS_MASK; + if (reg == 0) + goto finish; + + msleep(20); + } + + return -ENODEV; + +finish: + /* + * select SSP1 19.2MHz base clock, SSP clock 0, + * turn off Low Power Clock + */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_CSR, + SHIM_CSR_S1IOCS | SHIM_CSR_SBCS1 | + SHIM_CSR_LPCS, 0x0); + + /* stall DSP core, set clk to 192/96Mhz */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, + SHIM_CSR, SHIM_CSR_STALL | + SHIM_CSR_DCS_MASK, + SHIM_CSR_STALL | SHIM_CSR_DCS(4)); + + /* Set 24MHz MCLK, prevent local clock gating, enable SSP0 clock */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_CLKCTL, + SHIM_CLKCTL_MASK | SHIM_CLKCTL_DCPLCG | + SHIM_CLKCTL_SCOE0, + SHIM_CLKCTL_MASK | SHIM_CLKCTL_DCPLCG | + SHIM_CLKCTL_SCOE0); + + /* Stall and reset core, set CSR */ + hsw_reset(sdev); + + /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_PCI_BAR, PCI_VDRTCTL2, + PCI_VDRTCL2_DCLCGE | + PCI_VDRTCL2_DTCGE, + PCI_VDRTCL2_DCLCGE | + PCI_VDRTCL2_DTCGE); + + usleep_range(50, 55); + + /* switch on audio PLL */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_PCI_BAR, PCI_VDRTCTL2, + PCI_VDRTCL2_APLLSE_MASK, 0); + + /* + * set default power gating control, enable power gating control for + * all blocks. that is, can't be accessed, please enable each block + * before accessing. + */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_PCI_BAR, PCI_VDRTCTL0, + PCI_VDRTCL0_DSRAMPGE_MASK | + PCI_VDRTCL0_ISRAMPGE_MASK, 0); + + /* disable DMA finish function for SSP0 & SSP1 */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_CSR2, + SHIM_CSR2_SDFD_SSP1, + SHIM_CSR2_SDFD_SSP1); + + /* set on-demond mode on engine 0,1 for all channels */ + snd_sof_dsp_update_bits(sdev, HSW_DSP_BAR, SHIM_HMDC, + SHIM_HMDC_HDDA_E0_ALLCH | + SHIM_HMDC_HDDA_E1_ALLCH, + SHIM_HMDC_HDDA_E0_ALLCH | + SHIM_HMDC_HDDA_E1_ALLCH); + + /* Enable Interrupt from both sides */ + snd_sof_dsp_update_bits(sdev, HSW_DSP_BAR, SHIM_IMRX, + (SHIM_IMRX_BUSY | SHIM_IMRX_DONE), 0x0); + snd_sof_dsp_update_bits(sdev, HSW_DSP_BAR, SHIM_IMRD, + (SHIM_IMRD_DONE | SHIM_IMRD_BUSY | + SHIM_IMRD_SSP0 | SHIM_IMRD_DMAC), 0x0); + + /* clear IPC registers */ + snd_sof_dsp_write(sdev, HSW_DSP_BAR, SHIM_IPCX, 0x0); + snd_sof_dsp_write(sdev, HSW_DSP_BAR, SHIM_IPCD, 0x0); + snd_sof_dsp_write(sdev, HSW_DSP_BAR, 0x80, 0x6); + snd_sof_dsp_write(sdev, HSW_DSP_BAR, 0xe0, 0x300a); + + return 0; +} + +static void hsw_get_registers(struct snd_sof_dev *sdev, + struct sof_ipc_dsp_oops_xtensa *xoops, + struct sof_ipc_panic_info *panic_info, + u32 *stack, size_t stack_words) +{ + /* first read regsisters */ + hsw_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); + + /* then get panic info */ + hsw_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), + panic_info, sizeof(*panic_info)); + + /* then get the stack */ + hsw_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + + sizeof(*panic_info), stack, + stack_words * sizeof(u32)); +} + +static void hsw_dump(struct snd_sof_dev *sdev, u32 flags) +{ + struct sof_ipc_dsp_oops_xtensa xoops; + struct sof_ipc_panic_info panic_info; + u32 stack[HSW_STACK_DUMP_SIZE]; + u32 status, panic; + + /* now try generic SOF status messages */ + status = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_IPCD); + panic = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_IPCX); + hsw_get_registers(sdev, &xoops, &panic_info, stack, + HSW_STACK_DUMP_SIZE); + snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, + HSW_STACK_DUMP_SIZE); +} + +/* + * IPC Doorbell IRQ handler and thread. + */ + +static irqreturn_t hsw_irq_handler(int irq, void *context) +{ + struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + u32 isr; + int ret = IRQ_NONE; + + spin_lock(&sdev->hw_lock); + + /* Interrupt arrived, check src */ + isr = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_ISRX); + if (isr & SHIM_ISRX_DONE) { + /* Mask Done interrupt before return */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_DONE, + SHIM_IMRX_DONE); + ret = IRQ_WAKE_THREAD; + } + + if (isr & SHIM_ISRX_BUSY) { + /* Mask Busy interrupt before return */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_BUSY, + SHIM_IMRX_BUSY); + ret = IRQ_WAKE_THREAD; + } + + spin_unlock(&sdev->hw_lock); + return ret; +} + +static irqreturn_t hsw_irq_thread(int irq, void *context) +{ + struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + u32 ipcx, ipcd, hdr; + + ipcx = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_IPCX); + + /* reply message from DSP */ + if (ipcx & SHIM_IPCX_DONE) { + /* Handle Immediate reply from DSP Core */ + hsw_mailbox_read(sdev, sdev->host_box.offset, &hdr, + sizeof(hdr)); + + /* + * handle immediate reply from DSP core. If the msg is + * found, set done bit in cmd_done which is called at the + * end of message processing function, else set it here + * because the done bit can't be set in cmd_done function + * which is triggered by msg + */ + if (snd_sof_ipc_reply(sdev, hdr)) + hsw_cmd_done(sdev, SOF_IPC_DSP_REPLY); + } + + ipcd = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_IPCD); + + /* new message from DSP */ + if (ipcd & SHIM_IPCD_BUSY) { + /* Handle messages from DSP Core */ + if ((ipcd & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { + snd_sof_dsp_panic(sdev, HSW_PANIC_OFFSET(ipcx) + + MBOX_OFFSET); + } else { + snd_sof_ipc_msgs_rx(sdev); + } + } + + return IRQ_HANDLED; +} + +/* + * IPC Firmware ready. + */ +static void hsw_get_windows(struct snd_sof_dev *sdev) +{ + struct sof_ipc_window_elem *elem; + u32 outbox_offset = 0; + u32 stream_offset = 0; + u32 inbox_offset = 0; + u32 outbox_size = 0; + u32 stream_size = 0; + u32 inbox_size = 0; + int i; + + if (!sdev->info_window) { + dev_err(sdev->dev, "error: have no window info\n"); + return; + } + + for (i = 0; i < sdev->info_window->num_windows; i++) { + elem = &sdev->info_window->window[i]; + + switch (elem->type) { + case SOF_IPC_REGION_UPBOX: + inbox_offset = elem->offset + MBOX_OFFSET; + inbox_size = elem->size; + snd_sof_debugfs_create_item(sdev, + sdev->bar[HSW_DSP_BAR] + + inbox_offset, + elem->size, "inbox"); + break; + case SOF_IPC_REGION_DOWNBOX: + outbox_offset = elem->offset + MBOX_OFFSET; + outbox_size = elem->size; + snd_sof_debugfs_create_item(sdev, + sdev->bar[HSW_DSP_BAR] + + outbox_offset, + elem->size, "outbox"); + break; + case SOF_IPC_REGION_TRACE: + snd_sof_debugfs_create_item(sdev, + sdev->bar[HSW_DSP_BAR] + + elem->offset + MBOX_OFFSET, + elem->size, "etrace"); + break; + case SOF_IPC_REGION_DEBUG: + snd_sof_debugfs_create_item(sdev, + sdev->bar[HSW_DSP_BAR] + + elem->offset + MBOX_OFFSET, + elem->size, "debug"); + break; + case SOF_IPC_REGION_STREAM: + stream_offset = elem->offset + MBOX_OFFSET; + stream_size = elem->size; + snd_sof_debugfs_create_item(sdev, + sdev->bar[HSW_DSP_BAR] + + stream_offset, + elem->size, "stream"); + break; + case SOF_IPC_REGION_REGS: + snd_sof_debugfs_create_item(sdev, + sdev->bar[HSW_DSP_BAR] + + elem->offset + MBOX_OFFSET, + elem->size, "regs"); + break; + case SOF_IPC_REGION_EXCEPTION: + sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; + snd_sof_debugfs_create_item(sdev, + sdev->bar[HSW_DSP_BAR] + + elem->offset + MBOX_OFFSET, + elem->size, "exception"); + break; + default: + dev_err(sdev->dev, "error: get illegal window info\n"); + return; + } + } + + if (outbox_size == 0 || inbox_size == 0) { + dev_err(sdev->dev, "error: get illegal mailbox window\n"); + return; + } + + snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, + outbox_offset, outbox_size); + sdev->stream_box.offset = stream_offset; + sdev->stream_box.size = stream_size; + + dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", + inbox_offset, inbox_size); + dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", + outbox_offset, outbox_size); + dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", + stream_offset, stream_size); +} + +static int hsw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; + struct sof_ipc_fw_version *v = &fw_ready->version; + u32 offset; + + /* mailbox must be on 4k boundary */ + offset = MBOX_OFFSET; + + dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset %d\n", + msg_id, offset); + + /* copy data from the DSP FW ready offset */ + hsw_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); + + snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, + fw_ready->dspbox_size, + fw_ready->hostbox_offset, + fw_ready->hostbox_size); + + dev_info(sdev->dev, + " Firmware info: version %d:%d-%s build %d on %s:%s\n", + v->major, v->minor, v->tag, v->build, v->date, v->time); + + /* now check for extended data */ + snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + + sizeof(struct sof_ipc_fw_ready)); + + hsw_get_windows(sdev); + + return 0; +} + +/* + * IPC Mailbox IO + */ + +static int hsw_is_ready(struct snd_sof_dev *sdev) +{ + u32 val; + + val = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_IPCX); + if ((val & SHIM_IPCX_BUSY) || (val & SHIM_IPCX_DONE)) + return 0; + + return 1; +} + +static int hsw_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + /* send the message */ + hsw_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + snd_sof_dsp_write(sdev, HSW_DSP_BAR, SHIM_IPCX, SHIM_IPCX_BUSY); + + return 0; +} + +static int hsw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + struct sof_ipc_reply reply; + int ret = 0; + u32 size; + + /* get reply */ + hsw_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); + if (reply.error < 0) { + size = sizeof(reply); + ret = reply.error; + } else { + /* reply correct size ? */ + if (reply.hdr.size != msg->reply_size) { + dev_err(sdev->dev, "error: reply expected 0x%zx got 0x%x bytes\n", + msg->reply_size, reply.hdr.size); + size = msg->reply_size; + ret = -EINVAL; + } else { + size = reply.hdr.size; + } + } + + /* read the message */ + if (msg->msg_data && size > 0) + hsw_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, + size); + return ret; +} + +static int hsw_cmd_done(struct snd_sof_dev *sdev, int dir) +{ + if (dir == SOF_IPC_HOST_REPLY) { + /* clear BUSY bit and set DONE bit - accept new messages */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IPCD, + SHIM_IPCD_BUSY | SHIM_IPCD_DONE, + SHIM_IPCD_DONE); + + /* unmask busy interrupt */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_BUSY, 0); + } else { + /* clear DONE bit - tell DSP we have completed */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IPCX, + SHIM_IPCX_DONE, 0); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_DONE, 0); + } + + return 0; +} + +/* + * Probe and remove. + */ +static int hsw_probe(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *pdata = sdev->pdata; + const struct sof_dev_desc *desc = pdata->desc; + struct platform_device *pdev = + container_of(sdev->parent, struct platform_device, dev); + struct resource *mmio; + u32 base, size; + int ret = 0; + + /* set DSP arch ops */ + sdev->arch_ops = &sof_xtensa_arch_ops; + + /* LPE base */ + mmio = platform_get_resource(pdev, IORESOURCE_MEM, + desc->resindex_lpe_base); + if (mmio) { + base = mmio->start; + size = resource_size(mmio); + } else { + dev_err(sdev->dev, "error: failed to get LPE base at idx %d\n", + desc->resindex_lpe_base); + return -EINVAL; + } + + dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); + sdev->bar[HSW_DSP_BAR] = ioremap(base, size); + if (!sdev->bar[HSW_DSP_BAR]) { + dev_err(sdev->dev, + "error: failed to ioremap LPE base 0x%x size 0x%x\n", + base, size); + return -ENODEV; + } + dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[HSW_DSP_BAR]); + + /* TODO: add offsets */ + sdev->mmio_bar = HSW_DSP_BAR; + sdev->mailbox_bar = HSW_DSP_BAR; + + /* PCI base */ + mmio = platform_get_resource(pdev, IORESOURCE_MEM, + desc->resindex_pcicfg_base); + if (mmio) { + base = mmio->start; + size = resource_size(mmio); + } else { + dev_err(sdev->dev, "error: failed to get PCI base at idx %d\n", + desc->resindex_pcicfg_base); + ret = -ENODEV; + goto pci_err; + } + + dev_dbg(sdev->dev, "PCI base at 0x%x size 0x%x", base, size); + sdev->bar[HSW_PCI_BAR] = ioremap(base, size); + if (!sdev->bar[HSW_PCI_BAR]) { + dev_err(sdev->dev, + "error: failed to ioremap PCI base 0x%x size 0x%x\n", + base, size); + ret = -ENODEV; + goto pci_err; + } + dev_dbg(sdev->dev, "PCI VADDR %p\n", sdev->bar[HSW_PCI_BAR]); + + /* register our IRQ */ + sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc); + if (sdev->ipc_irq < 0) { + dev_err(sdev->dev, "error: failed to get IRQ at index %d\n", + desc->irqindex_host_ipc); + ret = sdev->ipc_irq; + goto irq_err; + } + + dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); + ret = request_threaded_irq(sdev->ipc_irq, hsw_irq_handler, + hsw_irq_thread, 0, "AudioDSP", sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to register IRQ %d\n", + sdev->ipc_irq); + goto irq_err; + } + + /* enable the DSP SHIM */ + ret = hsw_set_dsp_D0(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DSP D0\n"); + return ret; + } + + /* DSP DMA can only access low 31 bits of host memory */ + ret = dma_coerce_mask_and_coherent(sdev->dev, DMA_BIT_MASK(31)); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DMA mask %d\n", ret); + return ret; + } + + /* set BARS */ + sdev->cl_bar = HSW_DSP_BAR; + + /* set default mailbox */ + snd_sof_dsp_mailbox_init(sdev, MBOX_OFFSET, MBOX_SIZE, 0, 0); + + return ret; + +irq_err: + iounmap(sdev->bar[HSW_DSP_BAR]); +pci_err: + iounmap(sdev->bar[HSW_PCI_BAR]); + return ret; +} + +static int hsw_remove(struct snd_sof_dev *sdev) +{ + iounmap(sdev->bar[HSW_DSP_BAR]); + iounmap(sdev->bar[HSW_PCI_BAR]); + free_irq(sdev->ipc_irq, sdev); + return 0; +} + +#define HSW_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +/* Haswell DAIs */ +static struct snd_soc_dai_driver hsw_dai[] = { +{ + .name = "ssp0-port", + .playback = SOF_DAI_STREAM("ssp0 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, HSW_FORMATS), + .capture = SOF_DAI_STREAM("ssp0 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, HSW_FORMATS), +}, +{ + .name = "ssp1-port", + .playback = SOF_DAI_STREAM("ssp1 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, HSW_FORMATS), + .capture = SOF_DAI_STREAM("ssp1 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, HSW_FORMATS), +}, +}; + +/* haswell ops */ +struct snd_sof_dsp_ops sof_hsw_ops = { + /*Device init */ + .probe = hsw_probe, + .remove = hsw_remove, + + /* DSP Core Control */ + .run = hsw_run, + .reset = hsw_reset, + + /* Register IO */ + .read = hsw_read, + .write = hsw_write, + .read64 = hsw_read64, + .write64 = hsw_write64, + + /* Block IO */ + .block_read = hsw_block_read, + .block_write = hsw_block_write, + + /* mailbox */ + .mailbox_read = hsw_mailbox_read, + .mailbox_write = hsw_mailbox_write, + + /* ipc */ + .send_msg = hsw_send_msg, + .get_reply = hsw_get_reply, + .fw_ready = hsw_fw_ready, + .is_ready = hsw_is_ready, + .cmd_done = hsw_cmd_done, + + /* debug */ + .debug_map = hsw_debugfs, + .debug_map_count = ARRAY_SIZE(hsw_debugfs), + .dbg_dump = hsw_dump, + + /* Module loading */ + .load_module = snd_sof_parse_module_memcpy, + + /*Firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + + /* DAI drivers */ + .drv = hsw_dai, + .num_drv = ARRAY_SIZE(hsw_dai) + +}; +EXPORT_SYMBOL(sof_hsw_ops); + +MODULE_LICENSE("Dual BSD/GPL"); From 5358fd29b3ebcea5ff1796f84df02b8563ae682a Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:38:14 +0000 Subject: [PATCH 0107/1995] ASoC: SOF: Intel: Add support for BDW HW DSP support Add SOF support for Intel Broadwell based devices. Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/bdw.c | 802 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 802 insertions(+) create mode 100644 sound/soc/sof/intel/bdw.c diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c new file mode 100644 index 00000000000000..8068a48c90cc9b --- /dev/null +++ b/sound/soc/sof/intel/bdw.c @@ -0,0 +1,802 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +/* + * Hardwre interface for audio DSP on Haswell and Broadwell + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "../sof-priv.h" +#include "../ops.h" +#include "shim.h" + +/* BARs */ +#define BDW_DSP_BAR 0 +#define BDW_PCI_BAR 1 + +/* + * Debug + */ + +/* DSP memories for BDW */ +#define IRAM_OFFSET 0xA0000 +#define BDW_IRAM_SIZE (10 * 32 * 1024) +#define DRAM_OFFSET 0x00000 +#define BDW_DRAM_SIZE (20 * 32 * 1024) +#define SHIM_OFFSET 0xFB000 +#define SHIM_SIZE 0x100 +#define MBOX_OFFSET 0x9E000 +#define MBOX_SIZE 0x1000 +#define MBOX_DUMP_SIZE 0x30 +#define EXCEPT_OFFSET 0x800 + +/* DSP peripherals */ +#define DMAC0_OFFSET 0xFE000 +#define DMAC1_OFFSET 0xFF000 +#define DMAC_SIZE 0x420 +#define SSP0_OFFSET 0xFC000 +#define SSP1_OFFSET 0xFD000 +#define SSP_SIZE 0x100 + +#define BDW_STACK_DUMP_SIZE 32 + +#define BDW_PANIC_OFFSET(x) ((x) & 0xFFFF) + +static const struct snd_sof_debugfs_map bdw_debugfs[] = { + {"dmac0", BDW_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE}, + {"dmac1", BDW_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE}, + {"ssp0", BDW_DSP_BAR, SSP0_OFFSET, SSP_SIZE}, + {"ssp1", BDW_DSP_BAR, SSP1_OFFSET, SSP_SIZE}, + {"iram", BDW_DSP_BAR, IRAM_OFFSET, BDW_IRAM_SIZE}, + {"dram", BDW_DSP_BAR, DRAM_OFFSET, BDW_DRAM_SIZE}, + {"shim", BDW_DSP_BAR, SHIM_OFFSET, SHIM_SIZE}, +}; + +static int bdw_cmd_done(struct snd_sof_dev *sdev, int dir); + +/* + * Memory copy. + */ + +/* write has to deal with copying non 32 bit sized data */ +static void bdw_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, + size_t size) +{ + void __iomem *dest = sdev->bar[sdev->mmio_bar] + offset; + u32 tmp = 0; + int i, m, n; + const u8 *src_byte = src; + + m = size / 4; + n = size % 4; + + /* __iowrite32_copy use 32bit size values so divide by 4 */ + __iowrite32_copy(dest, src, m); + + if (n) { + for (i = 0; i < n; i++) + tmp |= (u32)*(src_byte + m * 4 + i) << (i * 8); + __iowrite32_copy(dest + m * 4, &tmp, 1); + } +} + +static void bdw_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, + size_t size) +{ + void __iomem *src = sdev->bar[sdev->mmio_bar] + offset; + + memcpy_fromio(dest, src, size); +} + +static void bdw_mailbox_write(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes) +{ + void __iomem *dest = sdev->bar[sdev->mailbox_bar] + offset; + + memcpy_toio(dest, message, bytes); +} + +static void bdw_mailbox_read(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes) +{ + void __iomem *src = sdev->bar[sdev->mailbox_bar] + offset; + + memcpy_fromio(message, src, bytes); +} + +/* + * Register IO + */ + +static void bdw_write(struct snd_sof_dev *sdev, void __iomem *addr, + u32 value) +{ + writel(value, addr); +} + +static u32 bdw_read(struct snd_sof_dev *sdev, void __iomem *addr) +{ + return readl(addr); +} + +static void bdw_write64(struct snd_sof_dev *sdev, void __iomem *addr, + u64 value) +{ + memcpy_toio(addr, &value, sizeof(value)); +} + +static u64 bdw_read64(struct snd_sof_dev *sdev, void __iomem *addr) +{ + u64 val; + + memcpy_fromio(&val, addr, sizeof(val)); + return val; +} + +/* + * DSP Control. + */ + +static int bdw_run(struct snd_sof_dev *sdev) +{ + /* set oportunistic mode on engine 0,1 for all channels */ + snd_sof_dsp_update_bits(sdev, BDW_DSP_BAR, SHIM_HMDC, + SHIM_HMDC_HDDA_E0_ALLCH | + SHIM_HMDC_HDDA_E1_ALLCH, 0); + + /* set DSP to RUN */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CSR, + SHIM_CSR_STALL, 0x0); + + return 0; +} + +static int bdw_reset(struct snd_sof_dev *sdev) +{ + /* put DSP into reset and stall */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CSR, + SHIM_CSR_RST | SHIM_CSR_STALL, + SHIM_CSR_RST | SHIM_CSR_STALL); + + /* keep in reset for 10ms */ + mdelay(10); + + /* take DSP out of reset and keep stalled for FW loading */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CSR, + SHIM_CSR_RST | SHIM_CSR_STALL, + SHIM_CSR_STALL); + + return 0; +} + +static int bdw_set_dsp_D0(struct snd_sof_dev *sdev) +{ + int tries = 10; + u32 reg; + + /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_VDRTCTL2, + PCI_VDRTCL2_DCLCGE | + PCI_VDRTCL2_DTCGE, 0); + + /* Disable D3PG (VDRTCTL0.D3PGD = 1) */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_VDRTCTL0, + PCI_VDRTCL0_D3PGD, PCI_VDRTCL0_D3PGD); + + /* Set D0 state */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_PMCS, + PCI_PMCS_PS_MASK, 0); + + /* check that ADSP shim is enabled */ + while (tries--) { + reg = readl(sdev->bar[BDW_PCI_BAR] + PCI_PMCS) + & PCI_PMCS_PS_MASK; + if (reg == 0) + goto finish; + + msleep(20); + } + + return -ENODEV; + +finish: + /* + * select SSP1 19.2MHz base clock, SSP clock 0, + * turn off Low Power Clock + */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CSR, + SHIM_CSR_S1IOCS | SHIM_CSR_SBCS1 | + SHIM_CSR_LPCS, 0x0); + + /* stall DSP core, set clk to 192/96Mhz */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, + SHIM_CSR, SHIM_CSR_STALL | + SHIM_CSR_DCS_MASK, + SHIM_CSR_STALL | + SHIM_CSR_DCS(4)); + + /* Set 24MHz MCLK, prevent local clock gating, enable SSP0 clock */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CLKCTL, + SHIM_CLKCTL_MASK | + SHIM_CLKCTL_DCPLCG | + SHIM_CLKCTL_SCOE0, + SHIM_CLKCTL_MASK | + SHIM_CLKCTL_DCPLCG | + SHIM_CLKCTL_SCOE0); + + /* Stall and reset core, set CSR */ + bdw_reset(sdev); + + /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_VDRTCTL2, + PCI_VDRTCL2_DCLCGE | + PCI_VDRTCL2_DTCGE, + PCI_VDRTCL2_DCLCGE | + PCI_VDRTCL2_DTCGE); + + usleep_range(50, 55); + + /* switch on audio PLL */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_VDRTCTL2, + PCI_VDRTCL2_APLLSE_MASK, 0); + + /* + * set default power gating control, enable power gating control for + * all blocks. that is, can't be accessed, please enable each block + * before accessing. + */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_VDRTCTL0, + 0xfffffffC, 0x0); + + /* disable DMA finish function for SSP0 & SSP1 */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CSR2, + SHIM_CSR2_SDFD_SSP1, + SHIM_CSR2_SDFD_SSP1); + + /* set on-demond mode on engine 0,1 for all channels */ + snd_sof_dsp_update_bits(sdev, BDW_DSP_BAR, SHIM_HMDC, + SHIM_HMDC_HDDA_E0_ALLCH | + SHIM_HMDC_HDDA_E1_ALLCH, + SHIM_HMDC_HDDA_E0_ALLCH | + SHIM_HMDC_HDDA_E1_ALLCH); + + /* Enable Interrupt from both sides */ + snd_sof_dsp_update_bits(sdev, BDW_DSP_BAR, SHIM_IMRX, + (SHIM_IMRX_BUSY | SHIM_IMRX_DONE), 0x0); + snd_sof_dsp_update_bits(sdev, BDW_DSP_BAR, SHIM_IMRD, + (SHIM_IMRD_DONE | SHIM_IMRD_BUSY | + SHIM_IMRD_SSP0 | SHIM_IMRD_DMAC), 0x0); + + /* clear IPC registers */ + snd_sof_dsp_write(sdev, BDW_DSP_BAR, SHIM_IPCX, 0x0); + snd_sof_dsp_write(sdev, BDW_DSP_BAR, SHIM_IPCD, 0x0); + snd_sof_dsp_write(sdev, BDW_DSP_BAR, 0x80, 0x6); + snd_sof_dsp_write(sdev, BDW_DSP_BAR, 0xe0, 0x300a); + + return 0; +} + +static void bdw_get_registers(struct snd_sof_dev *sdev, + struct sof_ipc_dsp_oops_xtensa *xoops, + struct sof_ipc_panic_info *panic_info, + u32 *stack, size_t stack_words) +{ + /* first read regsisters */ + bdw_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); + + /* then get panic info */ + bdw_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), + panic_info, sizeof(*panic_info)); + + /* then get the stack */ + bdw_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + + sizeof(*panic_info), stack, + stack_words * sizeof(u32)); +} + +static void bdw_dump(struct snd_sof_dev *sdev, u32 flags) +{ + struct sof_ipc_dsp_oops_xtensa xoops; + struct sof_ipc_panic_info panic_info; + u32 stack[BDW_STACK_DUMP_SIZE]; + u32 status, panic; + + /* now try generic SOF status messages */ + status = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD); + panic = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCX); + bdw_get_registers(sdev, &xoops, &panic_info, stack, + BDW_STACK_DUMP_SIZE); + snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, + BDW_STACK_DUMP_SIZE); +} + +/* + * IPC Doorbell IRQ handler and thread. + */ + +static irqreturn_t bdw_irq_handler(int irq, void *context) +{ + struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + u32 isr; + int ret = IRQ_NONE; + + /* Interrupt arrived, check src */ + isr = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_ISRX); + if (isr & SHIM_ISRX_DONE) { + /* Mask Done interrupt before return */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, + SHIM_IMRX, SHIM_IMRX_DONE, + SHIM_IMRX_DONE); + ret = IRQ_WAKE_THREAD; + } + + if (isr & SHIM_ISRX_BUSY) { + /* Mask Busy interrupt before return */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, + SHIM_IMRX, SHIM_IMRX_BUSY, + SHIM_IMRX_BUSY); + ret = IRQ_WAKE_THREAD; + } + + return ret; +} + +static irqreturn_t bdw_irq_thread(int irq, void *context) +{ + struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + u32 ipcx, ipcd, hdr; + + ipcx = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCX); + + /* reply message from DSP */ + if (ipcx & SHIM_IPCX_DONE) { + /* Handle Immediate reply from DSP Core */ + bdw_mailbox_read(sdev, sdev->host_box.offset, &hdr, + sizeof(hdr)); + + /* + * handle immediate reply from DSP core. If the msg is + * found, set done bit in cmd_done which is called at the + * end of message processing function, else set it here + * because the done bit can't be set in cmd_done function + * which is triggered by msg + */ + if (snd_sof_ipc_reply(sdev, hdr)) + bdw_cmd_done(sdev, SOF_IPC_DSP_REPLY); + } + + ipcd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD); + + /* new message from DSP */ + if (ipcd & SHIM_IPCD_BUSY) { + /* Handle messages from DSP Core */ + if ((ipcd & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { + snd_sof_dsp_panic(sdev, BDW_PANIC_OFFSET(ipcx) + + MBOX_OFFSET); + } else { + snd_sof_ipc_msgs_rx(sdev); + } + } + + return IRQ_HANDLED; +} + +/* + * IPC Firmware ready. + */ +static void bdw_get_windows(struct snd_sof_dev *sdev) +{ + struct sof_ipc_window_elem *elem; + u32 outbox_offset = 0; + u32 stream_offset = 0; + u32 inbox_offset = 0; + u32 outbox_size = 0; + u32 stream_size = 0; + u32 inbox_size = 0; + int i; + + if (!sdev->info_window) { + dev_err(sdev->dev, "error: have no window info\n"); + return; + } + + for (i = 0; i < sdev->info_window->num_windows; i++) { + elem = &sdev->info_window->window[i]; + + switch (elem->type) { + case SOF_IPC_REGION_UPBOX: + inbox_offset = elem->offset + MBOX_OFFSET; + inbox_size = elem->size; + snd_sof_debugfs_create_item(sdev, + sdev->bar[BDW_DSP_BAR] + + inbox_offset, + elem->size, "inbox"); + break; + case SOF_IPC_REGION_DOWNBOX: + outbox_offset = elem->offset + MBOX_OFFSET; + outbox_size = elem->size; + snd_sof_debugfs_create_item(sdev, + sdev->bar[BDW_DSP_BAR] + + outbox_offset, + elem->size, "outbox"); + break; + case SOF_IPC_REGION_TRACE: + snd_sof_debugfs_create_item(sdev, + sdev->bar[BDW_DSP_BAR] + + elem->offset + MBOX_OFFSET, + elem->size, "etrace"); + break; + case SOF_IPC_REGION_DEBUG: + snd_sof_debugfs_create_item(sdev, + sdev->bar[BDW_DSP_BAR] + + elem->offset + MBOX_OFFSET, + elem->size, "debug"); + break; + case SOF_IPC_REGION_STREAM: + stream_offset = elem->offset + MBOX_OFFSET; + stream_size = elem->size; + snd_sof_debugfs_create_item(sdev, + sdev->bar[BDW_DSP_BAR] + + stream_offset, + elem->size, "stream"); + break; + case SOF_IPC_REGION_REGS: + snd_sof_debugfs_create_item(sdev, + sdev->bar[BDW_DSP_BAR] + + elem->offset + MBOX_OFFSET, + elem->size, "regs"); + break; + case SOF_IPC_REGION_EXCEPTION: + sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; + snd_sof_debugfs_create_item(sdev, + sdev->bar[BDW_DSP_BAR] + + elem->offset + MBOX_OFFSET, + elem->size, "exception"); + break; + default: + dev_err(sdev->dev, "error: get illegal window info\n"); + return; + } + } + + if (outbox_size == 0 || inbox_size == 0) { + dev_err(sdev->dev, "error: get illegal mailbox window\n"); + return; + } + + snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, + outbox_offset, outbox_size); + sdev->stream_box.offset = stream_offset; + sdev->stream_box.size = stream_size; + + dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", + inbox_offset, inbox_size); + dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", + outbox_offset, outbox_size); + dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", + stream_offset, stream_size); +} + +static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; + struct sof_ipc_fw_version *v = &fw_ready->version; + u32 offset; + + /* mailbox must be on 4k boundary */ + offset = MBOX_OFFSET; + + dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset %d\n", + msg_id, offset); + + /* copy data from the DSP FW ready offset */ + bdw_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); + + snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, + fw_ready->dspbox_size, + fw_ready->hostbox_offset, + fw_ready->hostbox_size); + + dev_info(sdev->dev, + " Firmware info: version %d:%d-%s build %d on %s:%s\n", + v->major, v->minor, v->tag, v->build, v->date, v->time); + + /* now check for extended data */ + snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + + sizeof(struct sof_ipc_fw_ready)); + + bdw_get_windows(sdev); + + return 0; +} + +/* + * IPC Mailbox IO + */ + +static int bdw_is_ready(struct snd_sof_dev *sdev) +{ + u32 val; + + val = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCX); + if ((val & SHIM_IPCX_BUSY) || (val & SHIM_IPCX_DONE)) + return 0; + + return 1; +} + +static int bdw_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + /* send the message */ + bdw_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + snd_sof_dsp_write(sdev, BDW_DSP_BAR, SHIM_IPCX, SHIM_IPCX_BUSY); + + return 0; +} + +static int bdw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + struct sof_ipc_reply reply; + int ret = 0; + u32 size; + + /* get reply */ + bdw_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); + if (reply.error < 0) { + size = sizeof(reply); + ret = reply.error; + } else { + /* reply correct size ? */ + if (reply.hdr.size != msg->reply_size) { + dev_err(sdev->dev, "error: reply expected 0x%zx got 0x%x bytes\n", + msg->reply_size, reply.hdr.size); + size = msg->reply_size; + ret = -EINVAL; + } else { + size = reply.hdr.size; + } + } + + /* read the message */ + if (msg->msg_data && size > 0) + bdw_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, + size); + + return ret; +} + +static int bdw_cmd_done(struct snd_sof_dev *sdev, int dir) +{ + if (dir == SOF_IPC_HOST_REPLY) { + /* clear BUSY bit and set DONE bit - accept new messages */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCD, + SHIM_IPCD_BUSY | SHIM_IPCD_DONE, + SHIM_IPCD_DONE); + + /* unmask busy interrupt */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_BUSY, 0); + } else { + /* clear DONE bit - tell DSP we have completed */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCX, + SHIM_IPCX_DONE, 0); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_DONE, 0); + } + + return 0; +} + +/* + * Probe and remove. + */ +static int bdw_probe(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *pdata = sdev->pdata; + const struct sof_dev_desc *desc = pdata->desc; + struct platform_device *pdev = + container_of(sdev->parent, struct platform_device, dev); + struct resource *mmio; + u32 base, size; + int ret = 0; + + /* set DSP arch ops */ + sdev->arch_ops = &sof_xtensa_arch_ops; + + /* LPE base */ + mmio = platform_get_resource(pdev, IORESOURCE_MEM, + desc->resindex_lpe_base); + if (mmio) { + base = mmio->start; + size = resource_size(mmio); + } else { + dev_err(sdev->dev, "error: failed to get LPE base at idx %d\n", + desc->resindex_lpe_base); + return -EINVAL; + } + + dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); + sdev->bar[BDW_DSP_BAR] = ioremap(base, size); + if (!sdev->bar[BDW_DSP_BAR]) { + dev_err(sdev->dev, + "error: failed to ioremap LPE base 0x%x size 0x%x\n", + base, size); + return -ENODEV; + } + dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[BDW_DSP_BAR]); + + /* TODO: add offsets */ + sdev->mmio_bar = BDW_DSP_BAR; + sdev->mailbox_bar = BDW_DSP_BAR; + + /* PCI base */ + mmio = platform_get_resource(pdev, IORESOURCE_MEM, + desc->resindex_pcicfg_base); + if (mmio) { + base = mmio->start; + size = resource_size(mmio); + } else { + dev_err(sdev->dev, "error: failed to get PCI base at idx %d\n", + desc->resindex_pcicfg_base); + ret = -ENODEV; + goto pci_err; + } + + dev_dbg(sdev->dev, "PCI base at 0x%x size 0x%x", base, size); + sdev->bar[BDW_PCI_BAR] = ioremap(base, size); + if (!sdev->bar[BDW_PCI_BAR]) { + dev_err(sdev->dev, + "error: failed to ioremap PCI base 0x%x size 0x%x\n", + base, size); + ret = -ENODEV; + goto pci_err; + } + dev_dbg(sdev->dev, "PCI VADDR %p\n", sdev->bar[BDW_PCI_BAR]); + + /* register our IRQ */ + sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc); + if (sdev->ipc_irq < 0) { + dev_err(sdev->dev, "error: failed to get IRQ at index %d\n", + desc->irqindex_host_ipc); + ret = sdev->ipc_irq; + goto irq_err; + } + + dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); + ret = request_threaded_irq(sdev->ipc_irq, bdw_irq_handler, + bdw_irq_thread, IRQF_SHARED, "AudioDSP", + sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to register IRQ %d\n", + sdev->ipc_irq); + goto irq_err; + } + + /* enable the DSP SHIM */ + ret = bdw_set_dsp_D0(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DSP D0\n"); + return ret; + } + + /* DSP DMA can only access low 31 bits of host memory */ + ret = dma_coerce_mask_and_coherent(sdev->dev, DMA_BIT_MASK(31)); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DMA mask %d\n", ret); + return ret; + } + + /* set BARS */ + sdev->cl_bar = BDW_DSP_BAR; + + /* set default mailbox */ + snd_sof_dsp_mailbox_init(sdev, MBOX_OFFSET, MBOX_SIZE, 0, 0); + + return ret; + +irq_err: + iounmap(sdev->bar[BDW_DSP_BAR]); +pci_err: + iounmap(sdev->bar[BDW_PCI_BAR]); + return ret; +} + +static int bdw_remove(struct snd_sof_dev *sdev) +{ + iounmap(sdev->bar[BDW_DSP_BAR]); + iounmap(sdev->bar[BDW_PCI_BAR]); + free_irq(sdev->ipc_irq, sdev); + return 0; +} + +#define BDW_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +/* Broadwell DAIs */ +static struct snd_soc_dai_driver bdw_dai[] = { +{ + .name = "ssp0-port", + .playback = SOF_DAI_STREAM("ssp0 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BDW_FORMATS), + .capture = SOF_DAI_STREAM("ssp0 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BDW_FORMATS), +}, +{ + .name = "ssp1-port", + .playback = SOF_DAI_STREAM("ssp1 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BDW_FORMATS), + .capture = SOF_DAI_STREAM("ssp1 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BDW_FORMATS), +}, +}; + +/* broadwell ops */ +struct snd_sof_dsp_ops sof_bdw_ops = { + /*Device init */ + .probe = bdw_probe, + .remove = bdw_remove, + + /* DSP Core Control */ + .run = bdw_run, + .reset = bdw_reset, + + /* Register IO */ + .read = bdw_read, + .write = bdw_write, + .read64 = bdw_read64, + .write64 = bdw_write64, + + /* Block IO */ + .block_read = bdw_block_read, + .block_write = bdw_block_write, + + /* mailbox */ + .mailbox_read = bdw_mailbox_read, + .mailbox_write = bdw_mailbox_write, + + /* ipc */ + .send_msg = bdw_send_msg, + .get_reply = bdw_get_reply, + .fw_ready = bdw_fw_ready, + .is_ready = bdw_is_ready, + .cmd_done = bdw_cmd_done, + + /* debug */ + .debug_map = bdw_debugfs, + .debug_map_count = ARRAY_SIZE(bdw_debugfs), + .dbg_dump = bdw_dump, + + /* Module loading */ + .load_module = snd_sof_parse_module_memcpy, + + /*Firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + + /* DAI drivers */ + .drv = bdw_dai, + .num_drv = ARRAY_SIZE(bdw_dai) +}; +EXPORT_SYMBOL(sof_bdw_ops); + +MODULE_LICENSE("Dual BSD/GPL"); From def495ebdee55b550f127a5b694337b77eecffb4 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:38:27 +0000 Subject: [PATCH 0108/1995] ASoC: SOF: Intel: Add APL/CNL HW DSP support Add SOF hardware DSP support for Intel Apollolake and Cannonlake based devices. Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/hda.c | 712 ++++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 522 ++++++++++++++++++++++++++++ 2 files changed, 1234 insertions(+) create mode 100644 sound/soc/sof/intel/hda.c create mode 100644 sound/soc/sof/intel/hda.h diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c new file mode 100644 index 00000000000000..163194062ee45b --- /dev/null +++ b/sound/soc/sof/intel/hda.c @@ -0,0 +1,712 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Jeeja KP +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for generic Intel audio DSP HDA IP + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sof-priv.h" +#include "../ops.h" +#include "hda.h" +#include "../../codecs/hdac_hda.h" + +/* platform specific devices */ +#include "shim.h" + + + +/* + * Register IO + */ + +void hda_dsp_write(struct snd_sof_dev *sdev, void __iomem *addr, u32 value) +{ + writel(value, addr); +} + +u32 hda_dsp_read(struct snd_sof_dev *sdev, void __iomem *addr) +{ + return readl(addr); +} + +void hda_dsp_write64(struct snd_sof_dev *sdev, void __iomem *addr, u64 value) +{ + memcpy_toio(addr, &value, sizeof(value)); +} + +u64 hda_dsp_read64(struct snd_sof_dev *sdev, void __iomem *addr) +{ + u64 val; + + memcpy_fromio(&val, addr, sizeof(val)); + return val; +} + +/* + * Memory copy. + */ + +void hda_dsp_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, + size_t size) +{ + void __iomem *dest = sdev->bar[sdev->mmio_bar] + offset; + u32 tmp = 0; + int i, m, n; + const u8 *src_byte = src; + u8 *dst_byte; + + m = size / 4; + n = size % 4; + + /* __iowrite32_copy use 32bit size values so divide by 4 */ + __iowrite32_copy(dest, src, m); + + if (n) { + /* first read the 32bit data of dest, then change affected + * bytes, and write back to dest. For unaffected bytes, it + * should not be changed + */ + __ioread32_copy(&tmp, dest + m * 4, 1); + + dst_byte = (u8 *)&tmp; + for (i = 0; i < n; i++) + dst_byte[i] = src_byte[m * 4 + i]; + + __iowrite32_copy(dest + m * 4, &tmp, 1); + } +} + +void hda_dsp_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, + size_t size) +{ + void __iomem *src = sdev->bar[sdev->mmio_bar] + offset; + + memcpy_fromio(dest, src, size); +} + +/* + * Debug + */ + +struct hda_dsp_msg_code { + u32 code; + const char *msg; +}; + +static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = { + {HDA_DSP_ROM_FW_MANIFEST_LOADED, "status: manifest loaded"}, + {HDA_DSP_ROM_FW_FW_LOADED, "status: fw loaded"}, + {HDA_DSP_ROM_FW_ENTERED, "status: fw entered"}, + {HDA_DSP_ROM_CSE_ERROR, "error: cse error"}, + {HDA_DSP_ROM_CSE_WRONG_RESPONSE, "error: cse wrong response"}, + {HDA_DSP_ROM_IMR_TO_SMALL, "error: IMR too small"}, + {HDA_DSP_ROM_BASE_FW_NOT_FOUND, "error: base fw not found"}, + {HDA_DSP_ROM_CSE_VALIDATION_FAILED, "error: signature verification failed"}, + {HDA_DSP_ROM_IPC_FATAL_ERROR, "error: ipc fatal error"}, + {HDA_DSP_ROM_L2_CACHE_ERROR, "error: L2 cache error"}, + {HDA_DSP_ROM_LOAD_OFFSET_TO_SMALL, "error: load offset too small"}, + {HDA_DSP_ROM_API_PTR_INVALID, "error: API ptr invalid"}, + {HDA_DSP_ROM_BASEFW_INCOMPAT, "error: base fw incompatble"}, + {HDA_DSP_ROM_UNHANDLED_INTERRUPT, "error: unhandled interrupt"}, + {HDA_DSP_ROM_MEMORY_HOLE_ECC, "error: ECC memory hole"}, + {HDA_DSP_ROM_KERNEL_EXCEPTION, "error: kernel exception"}, + {HDA_DSP_ROM_USER_EXCEPTION, "error: user exception"}, + {HDA_DSP_ROM_UNEXPECTED_RESET, "error: unexpected reset"}, + {HDA_DSP_ROM_NULL_FW_ENTRY, "error: null FW entry point"}, +}; + +static void hda_dsp_get_status(struct snd_sof_dev *sdev) +{ + u32 status; + int i; + + status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_STATUS); + + for (i = 0; i < ARRAY_SIZE(hda_dsp_rom_msg); i++) { + if (status == hda_dsp_rom_msg[i].code) { + dev_err(sdev->dev, "%s - code %8.8x\n", + hda_dsp_rom_msg[i].msg, status); + return; + } + } + + /* not for us, must be generic sof message */ + dev_dbg(sdev->dev, "unknown ROM status value %8.8x\n", status); +} + +static void hda_dsp_get_registers(struct snd_sof_dev *sdev, + struct sof_ipc_dsp_oops_xtensa *xoops, + struct sof_ipc_panic_info *panic_info, + u32 *stack, size_t stack_words) +{ + /* first read registers */ + hda_dsp_block_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); + + /* then get panic info */ + hda_dsp_block_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), + panic_info, sizeof(*panic_info)); + + /* then get the stack */ + hda_dsp_block_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + + sizeof(*panic_info), stack, + stack_words * sizeof(u32)); +} + +void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) +{ + struct sof_ipc_dsp_oops_xtensa xoops; + struct sof_ipc_panic_info panic_info; + u32 stack[HDA_DSP_STACK_DUMP_SIZE]; + u32 status, panic; + + /* try APL specific status message types first */ + hda_dsp_get_status(sdev); + + /* now try generic SOF status messages */ + status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_FW_STATUS); + panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_TRACEP); + + if (sdev->boot_complete) { + hda_dsp_get_registers(sdev, &xoops, &panic_info, stack, + HDA_DSP_STACK_DUMP_SIZE); + snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, + stack, HDA_DSP_STACK_DUMP_SIZE); + } else { + dev_err(sdev->dev, "error: status = 0x%8.8x panic = 0x%8.8x\n", + status, panic); + hda_dsp_get_status(sdev); + } +} + +/* + * IPC Mailbox IO + */ + +void hda_dsp_mailbox_write(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes) +{ + void __iomem *dest = sdev->bar[sdev->mailbox_bar] + offset; + + memcpy_toio(dest, message, bytes); +} + +void hda_dsp_mailbox_read(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes) +{ + void __iomem *src = sdev->bar[sdev->mailbox_bar] + offset; + + memcpy_fromio(message, src, bytes); +} + +/* + * Supported devices. + */ + +static const struct sof_intel_dsp_desc chip_info[] = { +{ + /* Skylake */ + .id = 0x9d70, + .cores_num = 2, + .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1), + .ipc_req = HDA_DSP_REG_HIPCI, + .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY, + .ipc_ack = HDA_DSP_REG_HIPCIE, + .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, + .ipc_ctl = HDA_DSP_REG_HIPCCTL, + .ops = &sof_skl_ops, +}, +{ + /* Kabylake */ + .id = 0x9d71, + .cores_num = 2, + .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1), + .ipc_req = HDA_DSP_REG_HIPCI, + .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY, + .ipc_ack = HDA_DSP_REG_HIPCIE, + .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, + .ipc_ctl = HDA_DSP_REG_HIPCCTL, + .ops = &sof_skl_ops, +}, +{ + /* Apollolake - BXT-P */ + .id = 0x5a98, + .cores_num = 2, + .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1), + .ipc_req = HDA_DSP_REG_HIPCI, + .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY, + .ipc_ack = HDA_DSP_REG_HIPCIE, + .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, + .ipc_ctl = HDA_DSP_REG_HIPCCTL, + .ops = &sof_apl_ops, +}, +{ + /* BXT-M */ + .id = 0x1a98, + .cores_num = 2, + .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1), + .ipc_req = HDA_DSP_REG_HIPCI, + .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY, + .ipc_ack = HDA_DSP_REG_HIPCIE, + .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, + .ipc_ctl = HDA_DSP_REG_HIPCCTL, + .ops = &sof_apl_ops, +}, +{ + /* GeminiLake */ + .id = 0x3198, + .cores_num = 2, + .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1), + .ipc_req = HDA_DSP_REG_HIPCI, + .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY, + .ipc_ack = HDA_DSP_REG_HIPCIE, + .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, + .ipc_ctl = HDA_DSP_REG_HIPCCTL, + .ops = &sof_apl_ops, +}, +{ + /* Cannonlake */ + .id = 0x9dc8, + .cores_num = 4, + .cores_mask = HDA_DSP_CORE_MASK(0) | + HDA_DSP_CORE_MASK(1) | + HDA_DSP_CORE_MASK(2) | + HDA_DSP_CORE_MASK(3), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .ops = &sof_cnl_ops, +}, +{ + /* Icelake */ + .id = 0x34c8, + .cores_num = 4, + .cores_mask = HDA_DSP_CORE_MASK(0) | + HDA_DSP_CORE_MASK(1) | + HDA_DSP_CORE_MASK(2) | + HDA_DSP_CORE_MASK(3), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .ops = &sof_cnl_ops, +}, +}; + +static const struct sof_intel_dsp_desc *get_chip_info(int pci_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(chip_info); i++) { + if (chip_info[i].id == pci_id) + return &chip_info[i]; + } + + return NULL; +} + +static int hda_init(struct snd_sof_dev *sdev) +{ + struct hda_bus *hbus; + struct hdac_bus *bus; + struct hdac_ext_bus_ops *ext_ops = NULL; + struct pci_dev *pci = sdev->pci; + int ret; + + hbus = sof_to_hbus(sdev); + bus = sof_to_bus(sdev); + + /* HDA bus init */ +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDA) + ext_ops = snd_soc_hdac_hda_get_ops(); +#endif + sof_hda_bus_init(bus, &pci->dev, ext_ops); + bus->use_posbuf = 1; + bus->bdl_pos_adj = 0; + + mutex_init(&hbus->prepare_mutex); + hbus->pci = pci; + hbus->mixer_assigned = -1; + hbus->modelname = "sofbus"; + + /* initialise hdac bus */ + bus->addr = pci_resource_start(pci, 0); + bus->remap_addr = pci_ioremap_bar(pci, 0); + if (!bus->remap_addr) { + dev_err(bus->dev, "ioremap error\n"); + return -ENXIO; + } + + /* HDA base */ + sdev->bar[HDA_DSP_HDA_BAR] = bus->remap_addr; + + /* get controller capabilities */ + ret = hda_dsp_ctrl_get_caps(sdev); + if (ret < 0) + dev_err(&pci->dev, "error: get caps error\n"); + + return ret; +} + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + +static int hda_init_caps(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct pci_dev *pci = sdev->pci; + struct hdac_ext_link *hlink = NULL; + int ret = 0; + + /* The initialization process of HDA in SOF is: + * (1) init HDA to set up a context for i915 initialization + * then stop HDA bus. + */ + hda_dsp_ctrl_init_chip(sdev, true); + + device_disable_async_suspend(bus->dev); + + /* check if dsp is there */ + if (bus->ppcap) + dev_dbg(&pci->dev, "PP capbility, will probe DSP later.\n"); + + if (bus->mlcap) + snd_hdac_ext_bus_get_ml_capabilities(bus); + + snd_hdac_bus_stop_chip(bus); + + /* (2) probe i915 and HDA codecs, HDMI codecs */ + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { + ret = hda_codec_i915_init(sdev); + if (ret < 0) + return ret; + } + + /* only HDA analog codec is detected in step (1) and + * codec_mask would be set. At step(3) HDMI codec can't + * be detected because HDA framework only check codecs + * when codec_mask is zero. So now set codec_mask to zero + * to force HDA framework to check codecs again. + */ + bus->codec_mask = 0; + + /* (3) init HDA again to make everything ready so that all + * the codecs can be detected. + */ + ret = hda_dsp_ctrl_init_chip(sdev, true); + if (ret < 0) { + dev_err(bus->dev, "Init chip failed with ret: %d\n", ret); + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + snd_hdac_display_power(bus, false); + return ret; + } + + /* codec detection */ + if (!bus->codec_mask) + dev_info(bus->dev, "no hda codecs found!\n"); + + /* used by hda machine driver to create dai links */ + sdev->pdata->codec_mask = bus->codec_mask; + + /* create codec instances */ + hda_codec_probe_bus(sdev); + + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { + ret = snd_hdac_display_power(bus, false); + if (ret < 0) { + dev_err(bus->dev, "Cannot turn off display power on i915\n"); + return ret; + } + } + + /* + * we are done probing so decrement link counts + */ + list_for_each_entry(hlink, &bus->hlink_list, list) + snd_hdac_ext_bus_link_put(bus, hlink); + + return 0; +} + +#else + +static int hda_init_caps(struct snd_sof_dev *sdev) +{ + /* + * set CGCTL.MISCBDCGE to 0 during reset and set back to 1 + * when reset finished. + * TODO: maybe no need for init_caps? + */ + hda_dsp_ctrl_misc_clock_gating(sdev, 0); + + /* clear WAKESTS */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, + SOF_HDA_WAKESTS_INT_MASK, + SOF_HDA_WAKESTS_INT_MASK); + + return 0; +} + +#endif + +/* + * We don't need to do a full HDA codec probe as external HDA codec mode is + * considered legacy and will not be supported under SOF. HDMI/DP HDA will + * be supported in the DSP. + */ +int hda_dsp_probe(struct snd_sof_dev *sdev) +{ + struct pci_dev *pci = sdev->pci; + struct sof_intel_hda_dev *hdev; + struct hdac_bus *bus; + struct hdac_stream *stream; + const struct sof_intel_dsp_desc *chip; + int sd_offset, ret = 0; + + /* set DSP arch ops */ + sdev->arch_ops = &sof_xtensa_arch_ops; + + chip = get_chip_info(pci->device); + if (!chip) { + dev_err(sdev->dev, "no such device supported, chip id:%x\n", + pci->device); + ret = -EIO; + goto err; + } + + hdev = devm_kzalloc(&pci->dev, sizeof(*hdev), GFP_KERNEL); + if (!hdev) + return -ENOMEM; + sdev->hda = hdev; + hdev->desc = chip; + + /* + * use position update IPC if either it is forced + * or we don't have other choice + */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION) + hdev->no_ipc_position = 0; +#else + hdev->no_ipc_position = sdev->ops->pcm_pointer ? 1 : 0; +#endif + + /* set up HDA base */ + ret = hda_init(sdev); + if (ret < 0) + return ret; + + /* DSP base */ + sdev->bar[HDA_DSP_BAR] = pci_ioremap_bar(pci, HDA_DSP_BAR); + if (!sdev->bar[HDA_DSP_BAR]) { + dev_err(&pci->dev, "error: ioremap error\n"); + return -ENXIO; + } + + sdev->mmio_bar = HDA_DSP_BAR; + sdev->mailbox_bar = HDA_DSP_BAR; + + /* allow 64bit DMA address if supported by H/W */ + if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(64))) { + dev_dbg(&pci->dev, "DMA mask is 64 bit\n"); + dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(64)); + } else { + dev_dbg(&pci->dev, "DMA mask is 32 bit\n"); + dma_set_mask(&pci->dev, DMA_BIT_MASK(32)); + dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32)); + } + + /* init streams */ + ret = hda_dsp_stream_init(sdev); + if (ret < 0) { + dev_err(&pci->dev, "error: failed to init streams\n"); + /* + * not all errors are due to memory issues, but trying + * to free everything does not harm + */ + goto err; + } + + /* + * register our IRQ + * let's try to enable msi firstly + * if it fails, use legacy interrupt mode + * TODO: support interrupt mode selection with kernel parameter + * support msi multiple vectors + */ +// ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI); + /* todo: MSI mode doesn't work for HDMI yet, debug it later */ + ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_LEGACY); + if (ret < 0) { + dev_info(sdev->dev, "use legacy interrupt mode\n"); + sdev->hda->irq = pci->irq; + sdev->ipc_irq = pci->irq; + } else { + dev_info(sdev->dev, "use msi interrupt mode\n"); + sdev->hda->irq = pci_irq_vector(pci, 0); + /* ipc irq number is the same of hda irq */ + sdev->ipc_irq = sdev->hda->irq; + } + + bus = sof_to_bus(sdev); + dev_dbg(sdev->dev, "using HDA IRQ %d\n", sdev->hda->irq); + ret = request_threaded_irq(sdev->hda->irq, hda_dsp_stream_interrupt, + hda_dsp_stream_threaded_handler, + IRQF_SHARED, "AudioHDA", bus); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to register HDA IRQ %d\n", + sdev->hda->irq); + goto free_streams; + } + + dev_dbg(sdev->dev, "using IPC IRQ %d\n", sdev->ipc_irq); + ret = request_threaded_irq(sdev->ipc_irq, hda_dsp_ipc_irq_handler, + chip->ops->irq_thread, IRQF_SHARED, + "AudioDSP", sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to register IPC IRQ %d\n", + sdev->ipc_irq); + goto free_hda_irq; + } + + pci_set_master(pci); + synchronize_irq(pci->irq); + + /* + * clear TCSEL to clear playback on some HD Audio + * codecs. PCI TCSEL is defined in the Intel manuals. + */ + snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0); + + + /* init HDA capabilities */ + ret = hda_init_caps(sdev); + if (ret < 0) + goto free_ipc_irq; + + /* reset HDA controller */ + ret = hda_dsp_ctrl_link_reset(sdev); + if (ret < 0) { + dev_err(&pci->dev, "error: failed to reset HDA controller\n"); + goto free_ipc_irq; + } + + /* clear stream status */ + list_for_each_entry(stream, &bus->stream_list, list) { + sd_offset = SOF_STREAM_SD_OFFSET(stream); + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + + SOF_HDA_ADSP_REG_CL_SD_STS, + SOF_HDA_CL_DMA_SD_INT_MASK, + SOF_HDA_CL_DMA_SD_INT_MASK); + } + + /* clear WAKESTS */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, + SOF_HDA_WAKESTS_INT_MASK, + SOF_HDA_WAKESTS_INT_MASK); + + /* clear interrupt status register */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM); + + /* enable CIE and GIE interrupts */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); + + /* re-enable CGCTL.MISCBDCGE after reset */ + hda_dsp_ctrl_misc_clock_gating(sdev, true); + + device_disable_async_suspend(&pci->dev); + + /* enable DSP features */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + SOF_HDA_PPCTL_GPROCEN, SOF_HDA_PPCTL_GPROCEN); + + /* enable DSP IRQ */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + SOF_HDA_PPCTL_PIE, SOF_HDA_PPCTL_PIE); + + /* initialize waitq for code loading */ + init_waitqueue_head(&sdev->waitq); + + /* set default mailbox offset for FW ready message */ + sdev->dsp_box.offset = HDA_DSP_MBOX_UPLINK_OFFSET; + + return 0; + +free_ipc_irq: + free_irq(sdev->ipc_irq, sdev); +free_hda_irq: + free_irq(sdev->hda->irq, bus); + pci_free_irq_vectors(pci); +free_streams: + hda_dsp_stream_free(sdev); +err: + /* disable DSP */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + SOF_HDA_PPCTL_GPROCEN, 0); + return ret; +} + +int hda_dsp_remove(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct pci_dev *pci = sdev->pci; + const struct sof_intel_dsp_desc *chip = sdev->hda->desc; + + /* disable DSP IRQ */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + SOF_HDA_PPCTL_PIE, 0); + + /* disable CIE and GIE interrupts */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, 0); + + /* disable cores */ + if (chip) + hda_dsp_core_reset_power_down(sdev, chip->cores_mask); + + /* disable DSP */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + SOF_HDA_PPCTL_GPROCEN, 0); + + free_irq(sdev->ipc_irq, sdev); + free_irq(sdev->pci->irq, bus); + pci_free_irq_vectors(pci); + + hda_dsp_stream_free(sdev); + return 0; +} + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h new file mode 100644 index 00000000000000..73965b93680772 --- /dev/null +++ b/sound/soc/sof/intel/hda.h @@ -0,0 +1,522 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __SOF_INTEL_HDA_H +#define __SOF_INTEL_HDA_H + +#include + +/* PCI registers */ +#define PCI_TCSEL 0x44 +#define PCI_CGCTL 0x48 + +/* PCI_CGCTL bits */ +#define PCI_CGCTL_MISCBDCGE_MASK BIT(6) +#define PCI_CGCTL_LSRMD_MASK BIT(4) + +/* Legacy HDA registers and bits used - widths are variable */ +#define SOF_HDA_GCAP 0x0 +#define SOF_HDA_GCTL 0x8 +/* accept unsol. response enable */ +#define SOF_HDA_GCTL_UNSOL BIT(8) +#define SOF_HDA_LLCH 0x14 +#define SOF_HDA_INTCTL 0x20 +#define SOF_HDA_INTSTS 0x24 +#define SOF_HDA_WAKESTS 0x0E +#define SOF_HDA_WAKESTS_INT_MASK ((1 << 8) - 1) +#define SOF_HDA_RIRBSTS 0x5d + +/* SOF_HDA_GCTL register bist */ +#define SOF_HDA_GCTL_RESET BIT(0) + +/* SOF_HDA_INCTL and SOF_HDA_INTSTS regs */ +#define SOF_HDA_INT_GLOBAL_EN BIT(31) +#define SOF_HDA_INT_CTRL_EN BIT(30) +#define SOF_HDA_INT_ALL_STREAM 0xff + +#define SOF_HDA_MAX_CAPS 10 +#define SOF_HDA_CAP_ID_OFF 16 +#define SOF_HDA_CAP_ID_MASK (0xFFF << SOF_HDA_CAP_ID_OFF) +#define SOF_HDA_CAP_NEXT_MASK 0xFFFF + +#define SOF_HDA_GTS_CAP_ID 0x1 +#define SOF_HDA_ML_CAP_ID 0x2 + +#define SOF_HDA_PP_CAP_ID 0x3 +#define SOF_HDA_REG_PP_PPCH 0x10 +#define SOF_HDA_REG_PP_PPCTL 0x04 +#define SOF_HDA_PPCTL_PIE BIT(31) +#define SOF_HDA_PPCTL_GPROCEN BIT(30) + +/* DPIB entry size: 8 Bytes = 2 DWords */ +#define SOF_HDA_DPIB_ENTRY_SIZE 0x8 + +#define SOF_HDA_SPIB_CAP_ID 0x4 +#define SOF_HDA_DRSM_CAP_ID 0x5 + +#define SOF_HDA_SPIB_BASE 0x08 +#define SOF_HDA_SPIB_INTERVAL 0x08 +#define SOF_HDA_SPIB_SPIB 0x00 +#define SOF_HDA_SPIB_MAXFIFO 0x04 + +#define SOF_HDA_PPHC_BASE 0x10 +#define SOF_HDA_PPHC_INTERVAL 0x10 + +#define SOF_HDA_PPLC_BASE 0x10 +#define SOF_HDA_PPLC_MULTI 0x10 +#define SOF_HDA_PPLC_INTERVAL 0x10 + +#define SOF_HDA_DRSM_BASE 0x08 +#define SOF_HDA_DRSM_INTERVAL 0x08 + +/* Descriptor error interrupt */ +#define SOF_HDA_CL_DMA_SD_INT_DESC_ERR 0x10 + +/* FIFO error interrupt */ +#define SOF_HDA_CL_DMA_SD_INT_FIFO_ERR 0x08 + +/* Buffer completion interrupt */ +#define SOF_HDA_CL_DMA_SD_INT_COMPLETE 0x04 + +#define SOF_HDA_CL_DMA_SD_INT_MASK \ + (SOF_HDA_CL_DMA_SD_INT_DESC_ERR | \ + SOF_HDA_CL_DMA_SD_INT_FIFO_ERR | \ + SOF_HDA_CL_DMA_SD_INT_COMPLETE) +#define SOF_HDA_SD_CTL_DMA_START 0x02 /* Stream DMA start bit */ + +/* Intel HD Audio Code Loader DMA Registers */ +#define SOF_HDA_ADSP_LOADER_BASE 0x80 +#define SOF_HDA_ADSP_DPLBASE 0x70 +#define SOF_HDA_ADSP_DPUBASE 0x74 +#define SOF_HDA_ADSP_DPLBASE_ENABLE 0x01 + +/* Stream Registers */ +#define SOF_HDA_ADSP_REG_CL_SD_CTL 0x00 +#define SOF_HDA_ADSP_REG_CL_SD_STS 0x03 +#define SOF_HDA_ADSP_REG_CL_SD_LPIB 0x04 +#define SOF_HDA_ADSP_REG_CL_SD_CBL 0x08 +#define SOF_HDA_ADSP_REG_CL_SD_LVI 0x0C +#define SOF_HDA_ADSP_REG_CL_SD_FIFOW 0x0E +#define SOF_HDA_ADSP_REG_CL_SD_FIFOSIZE 0x10 +#define SOF_HDA_ADSP_REG_CL_SD_FORMAT 0x12 +#define SOF_HDA_ADSP_REG_CL_SD_FIFOL 0x14 +#define SOF_HDA_ADSP_REG_CL_SD_BDLPL 0x18 +#define SOF_HDA_ADSP_REG_CL_SD_BDLPU 0x1C +#define SOF_HDA_ADSP_SD_ENTRY_SIZE 0x20 + +/* CL: Software Position Based FIFO Capability Registers */ +#define SOF_DSP_REG_CL_SPBFIFO \ + (SOF_HDA_ADSP_LOADER_BASE + 0x20) +#define SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCH 0x0 +#define SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL 0x4 +#define SOF_HDA_ADSP_REG_CL_SPBFIFO_SPIB 0x8 +#define SOF_HDA_ADSP_REG_CL_SPBFIFO_MAXFIFOS 0xc + +/* Stream Number */ +#define SOF_HDA_CL_SD_CTL_STREAM_TAG_SHIFT 20 +#define SOF_HDA_CL_SD_CTL_STREAM_TAG_MASK \ + (0xf << SOF_HDA_CL_SD_CTL_STREAM_TAG_SHIFT) + +#define HDA_DSP_HDA_BAR 0 +#define HDA_DSP_PP_BAR 1 +#define HDA_DSP_SPIB_BAR 2 +#define HDA_DSP_DRSM_BAR 3 +#define HDA_DSP_BAR 4 + +#define SRAM_WINDOW_OFFSET(x) (0x80000 + (x) * 0x20000) + +#define HDA_DSP_MBOX_OFFSET SRAM_WINDOW_OFFSET(0) + +#define HDA_DSP_PANIC_OFFSET(x) \ + (((x) & 0xFFFFFF) + HDA_DSP_MBOX_OFFSET) + +/* SRAM window 0 FW "registers" */ +#define HDA_DSP_SRAM_REG_ROM_STATUS (HDA_DSP_MBOX_OFFSET + 0x0) +#define HDA_DSP_SRAM_REG_ROM_ERROR (HDA_DSP_MBOX_OFFSET + 0x4) +/* FW and ROM share offset 4 */ +#define HDA_DSP_SRAM_REG_FW_STATUS (HDA_DSP_MBOX_OFFSET + 0x4) +#define HDA_DSP_SRAM_REG_FW_TRACEP (HDA_DSP_MBOX_OFFSET + 0x8) +#define HDA_DSP_SRAM_REG_FW_END (HDA_DSP_MBOX_OFFSET + 0xc) + +#define HDA_DSP_MBOX_UPLINK_OFFSET 0x81000 + +#define HDA_DSP_STREAM_RESET_TIMEOUT 300 +#define HDA_DSP_CL_TRIGGER_TIMEOUT 300 + +#define HDA_DSP_SPIB_ENABLE 1 +#define HDA_DSP_SPIB_DISABLE 0 + +#define SOF_HDA_MAX_BUFFER_SIZE (32 * PAGE_SIZE) + +#define HDA_DSP_STACK_DUMP_SIZE 32 + +/* ROM status/error values */ +#define HDA_DSP_ROM_STS_MASK 0xf +#define HDA_DSP_ROM_INIT 0x1 +#define HDA_DSP_ROM_FW_MANIFEST_LOADED 0x3 +#define HDA_DSP_ROM_FW_FW_LOADED 0x4 +#define HDA_DSP_ROM_FW_ENTERED 0x5 +#define HDA_DSP_ROM_RFW_START 0xf +#define HDA_DSP_ROM_CSE_ERROR 40 +#define HDA_DSP_ROM_CSE_WRONG_RESPONSE 41 +#define HDA_DSP_ROM_IMR_TO_SMALL 42 +#define HDA_DSP_ROM_BASE_FW_NOT_FOUND 43 +#define HDA_DSP_ROM_CSE_VALIDATION_FAILED 44 +#define HDA_DSP_ROM_IPC_FATAL_ERROR 45 +#define HDA_DSP_ROM_L2_CACHE_ERROR 46 +#define HDA_DSP_ROM_LOAD_OFFSET_TO_SMALL 47 +#define HDA_DSP_ROM_API_PTR_INVALID 50 +#define HDA_DSP_ROM_BASEFW_INCOMPAT 51 +#define HDA_DSP_ROM_UNHANDLED_INTERRUPT 0xBEE00000 +#define HDA_DSP_ROM_MEMORY_HOLE_ECC 0xECC00000 +#define HDA_DSP_ROM_KERNEL_EXCEPTION 0xCAFE0000 +#define HDA_DSP_ROM_USER_EXCEPTION 0xBEEF0000 +#define HDA_DSP_ROM_UNEXPECTED_RESET 0xDECAF000 +#define HDA_DSP_ROM_NULL_FW_ENTRY 0x4c4c4e55 +#define HDA_DSP_IPC_PURGE_FW 0x01004000 + +/* various timeout values */ +#define HDA_DSP_PU_TIMEOUT 50 +#define HDA_DSP_PD_TIMEOUT 50 +#define HDA_DSP_RESET_TIMEOUT 50 +#define HDA_DSP_BASEFW_TIMEOUT 3000 +#define HDA_DSP_INIT_TIMEOUT 500 +#define HDA_DSP_CTRL_RESET_TIMEOUT 100 +#define HDA_DSP_WAIT_TIMEOUT 500 /* 500 msec */ + +#define HDA_DSP_ADSPIC_IPC 1 +#define HDA_DSP_ADSPIS_IPC 1 + +/* Intel HD Audio General DSP Registers */ +#define HDA_DSP_GEN_BASE 0x0 +#define HDA_DSP_REG_ADSPCS (HDA_DSP_GEN_BASE + 0x04) +#define HDA_DSP_REG_ADSPIC (HDA_DSP_GEN_BASE + 0x08) +#define HDA_DSP_REG_ADSPIS (HDA_DSP_GEN_BASE + 0x0C) +#define HDA_DSP_REG_ADSPIC2 (HDA_DSP_GEN_BASE + 0x10) +#define HDA_DSP_REG_ADSPIS2 (HDA_DSP_GEN_BASE + 0x14) + +/* Intel HD Audio Inter-Processor Communication Registers */ +#define HDA_DSP_IPC_BASE 0x40 +#define HDA_DSP_REG_HIPCT (HDA_DSP_IPC_BASE + 0x00) +#define HDA_DSP_REG_HIPCTE (HDA_DSP_IPC_BASE + 0x04) +#define HDA_DSP_REG_HIPCI (HDA_DSP_IPC_BASE + 0x08) +#define HDA_DSP_REG_HIPCIE (HDA_DSP_IPC_BASE + 0x0C) +#define HDA_DSP_REG_HIPCCTL (HDA_DSP_IPC_BASE + 0x10) + +/* HIPCI */ +#define HDA_DSP_REG_HIPCI_BUSY BIT(31) +#define HDA_DSP_REG_HIPCI_MSG_MASK 0x7FFFFFFF + +/* HIPCIE */ +#define HDA_DSP_REG_HIPCIE_DONE BIT(30) +#define HDA_DSP_REG_HIPCIE_MSG_MASK 0x3FFFFFFF + +/* HIPCCTL */ +#define HDA_DSP_REG_HIPCCTL_DONE BIT(1) +#define HDA_DSP_REG_HIPCCTL_BUSY BIT(0) + +/* HIPCT */ +#define HDA_DSP_REG_HIPCT_BUSY BIT(31) +#define HDA_DSP_REG_HIPCT_MSG_MASK 0x7FFFFFFF + +/* HIPCTE */ +#define HDA_DSP_REG_HIPCTE_MSG_MASK 0x3FFFFFFF + +#define HDA_DSP_ADSPIC_CL_DMA 0x2 +#define HDA_DSP_ADSPIS_CL_DMA 0x2 + +/* Delay before scheduling D0i3 entry */ +#define BXT_D0I3_DELAY 5000 + +#define FW_CL_STREAM_NUMBER 0x1 + +/* ADSPCS - Audio DSP Control & Status */ + +/* + * Core Reset - asserted high + * CRST Mask for a given core mask pattern, cm + */ +#define HDA_DSP_ADSPCS_CRST_SHIFT 0 +#define HDA_DSP_ADSPCS_CRST_MASK(cm) ((cm) << HDA_DSP_ADSPCS_CRST_SHIFT) + +/* + * Core run/stall - when set to '1' core is stalled + * CSTALL Mask for a given core mask pattern, cm + */ +#define HDA_DSP_ADSPCS_CSTALL_SHIFT 8 +#define HDA_DSP_ADSPCS_CSTALL_MASK(cm) ((cm) << HDA_DSP_ADSPCS_CSTALL_SHIFT) + +/* + * Set Power Active - when set to '1' turn cores on + * SPA Mask for a given core mask pattern, cm + */ +#define HDA_DSP_ADSPCS_SPA_SHIFT 16 +#define HDA_DSP_ADSPCS_SPA_MASK(cm) ((cm) << HDA_DSP_ADSPCS_SPA_SHIFT) + +/* + * Current Power Active - power status of cores, set by hardware + * CPA Mask for a given core mask pattern, cm + */ +#define HDA_DSP_ADSPCS_CPA_SHIFT 24 +#define HDA_DSP_ADSPCS_CPA_MASK(cm) ((cm) << HDA_DSP_ADSPCS_CPA_SHIFT) + +/* Mask for a given core index, c = 0.. number of supported cores - 1 */ +#define HDA_DSP_CORE_MASK(c) BIT(c) + +/* + * Mask for a given number of cores + * nc = number of supported cores + */ +#define SOF_DSP_CORES_MASK(nc) GENMASK(((nc) - 1), 0) + +/* Intel HD Audio Inter-Processor Communication Registers for Cannonlake*/ +#define CNL_DSP_IPC_BASE 0xc0 +#define CNL_DSP_REG_HIPCTDR (CNL_DSP_IPC_BASE + 0x00) +#define CNL_DSP_REG_HIPCTDA (CNL_DSP_IPC_BASE + 0x04) +#define CNL_DSP_REG_HIPCTDD (CNL_DSP_IPC_BASE + 0x08) +#define CNL_DSP_REG_HIPCIDR (CNL_DSP_IPC_BASE + 0x10) +#define CNL_DSP_REG_HIPCIDA (CNL_DSP_IPC_BASE + 0x14) +#define CNL_DSP_REG_HIPCCTL (CNL_DSP_IPC_BASE + 0x28) + +/* HIPCI */ +#define CNL_DSP_REG_HIPCIDR_BUSY BIT(31) +#define CNL_DSP_REG_HIPCIDR_MSG_MASK 0x7FFFFFFF + +/* HIPCIE */ +#define CNL_DSP_REG_HIPCIDA_DONE BIT(31) +#define CNL_DSP_REG_HIPCIDA_MSG_MASK 0x7FFFFFFF + +/* HIPCCTL */ +#define CNL_DSP_REG_HIPCCTL_DONE BIT(1) +#define CNL_DSP_REG_HIPCCTL_BUSY BIT(0) + +/* HIPCT */ +#define CNL_DSP_REG_HIPCTDR_BUSY BIT(31) +#define CNL_DSP_REG_HIPCTDR_MSG_MASK 0x7FFFFFFF + +/* HIPCTDA */ +#define CNL_DSP_REG_HIPCTDA_DONE BIT(31) +#define CNL_DSP_REG_HIPCTDA_MSG_MASK 0x7FFFFFFF + +/* HIPCTDD */ +#define CNL_DSP_REG_HIPCTDD_MSG_MASK 0x7FFFFFFF + +/* BDL */ +#define HDA_DSP_BDL_SIZE 4096 +#define HDA_DSP_MAX_BDL_ENTRIES \ + (HDA_DSP_BDL_SIZE / sizeof(struct sof_intel_dsp_bdl)) + +/* Number of DAIs */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +#define SOF_SKL_NUM_DAIS 14 +#else +#define SOF_SKL_NUM_DAIS 8 +#endif + +#define HDA_DSP_SRAM_REG_ROM_STATUS_SKL 0x8000 + +struct sof_intel_dsp_bdl { + u32 addr_l; + u32 addr_h; + u32 size; + u32 ioc; +} __attribute((packed)); + +/* DSP hardware descriptor */ +struct sof_intel_dsp_desc { + int id; + int cores_num; + int cores_mask; + int ipc_req; + int ipc_req_mask; + int ipc_ack; + int ipc_ack_mask; + int ipc_ctl; + struct snd_sof_dsp_ops *ops; +}; + +#define SOF_HDA_PLAYBACK_STREAMS 16 +#define SOF_HDA_CAPTURE_STREAMS 16 +#define SOF_HDA_PLAYBACK 0 +#define SOF_HDA_CAPTURE 1 + +/* represents DSP HDA controller frontend - i.e. host facing control */ +struct sof_intel_hda_dev { + + struct hda_bus hbus; + + /* hw config */ + const struct sof_intel_dsp_desc *desc; + + /*trace */ + struct hdac_ext_stream *dtrace_stream; + + /* if position update IPC needed */ + bool no_ipc_position; + + int irq; +}; + +#define bus_to_sof_hda(bus) \ + container_of(bus, struct sof_intel_hda_dev, hbus.core) + +#define SOF_STREAM_SD_OFFSET(s) \ + (SOF_HDA_ADSP_SD_ENTRY_SIZE * ((s)->index) \ + + SOF_HDA_ADSP_LOADER_BASE) + +/* + * DSP Core services. + */ +int hda_dsp_probe(struct snd_sof_dev *sdev); +int hda_dsp_remove(struct snd_sof_dev *sdev); +int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, + unsigned int core_mask); +int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, + unsigned int core_mask); +int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask); +int hda_dsp_core_stall_reset_skl(struct snd_sof_dev *sdev, + unsigned int core_mask); +int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask); +int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask); +int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask); +int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask); +bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, + unsigned int core_mask); +int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, + unsigned int core_mask); +int hda_dsp_suspend(struct snd_sof_dev *sdev, int state); +int hda_dsp_resume(struct snd_sof_dev *sdev); +int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state); +int hda_dsp_runtime_resume(struct snd_sof_dev *sdev); +void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags); + +/* + * DSP IO + */ +void hda_dsp_write(struct snd_sof_dev *sdev, void __iomem *addr, u32 value); +u32 hda_dsp_read(struct snd_sof_dev *sdev, void __iomem *addr); +void hda_dsp_write64(struct snd_sof_dev *sdev, void __iomem *addr, u64 value); +u64 hda_dsp_read64(struct snd_sof_dev *sdev, void __iomem *addr); +void hda_dsp_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, + size_t size); +void hda_dsp_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, + size_t size); +void hda_dsp_mailbox_write(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes); +void hda_dsp_mailbox_read(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes); + +/* + * DSP PCM Operations. + */ +int hda_dsp_pcm_open(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); +int hda_dsp_pcm_close(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); +int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct sof_ipc_stream_params *ipc_params); +int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, int cmd); +snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); + +/* + * DSP Stream Operations. + */ + +int hda_dsp_stream_init(struct snd_sof_dev *sdev); +void hda_dsp_stream_free(struct snd_sof_dev *sdev); +int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, + struct hdac_ext_stream *stream, + struct snd_dma_buffer *dmab, + struct snd_pcm_hw_params *params); +int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, + struct hdac_ext_stream *stream, int cmd); +irqreturn_t hda_dsp_stream_interrupt(int irq, void *context); +irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context); +int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab, + struct hdac_stream *stream); + +struct hdac_ext_stream * + hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction); +struct hdac_ext_stream * + hda_dsp_stream_get_cstream(struct snd_sof_dev *sdev); +struct hdac_ext_stream * + hda_dsp_stream_get_pstream(struct snd_sof_dev *sdev); +int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag); +int hda_dsp_stream_put_pstream(struct snd_sof_dev *sdev, int stream_tag); +int hda_dsp_stream_put_cstream(struct snd_sof_dev *sdev, int stream_tag); +int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, + struct hdac_ext_stream *stream, + int enable, u32 size); + +/* + * DSP IPC Operations. + */ +int hda_dsp_ipc_is_ready(struct snd_sof_dev *sdev); +int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg); +int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg); +int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id); +irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context); +irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context); +int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); + +/* + * DSP Code loader. + */ +int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, bool first_boot); +int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev); +int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev); + +/* + * HDA Controller Operations. + */ +int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev); +int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev); +void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable); +int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset); + +/* + * HDA bus operations. + */ +int sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, + const struct hdac_ext_bus_ops *ext_ops); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +/* + * HDA Codec operations. + */ +int hda_codec_probe_bus(struct snd_sof_dev *sdev); +int hda_codec_i915_init(struct snd_sof_dev *sdev); +#endif + +/* + * Trace Control. + */ +int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag); +int hda_dsp_trace_release(struct snd_sof_dev *sdev); +int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd); + +/* common dai driver */ +extern struct snd_soc_dai_driver skl_dai[]; + +/* + * Platform Specific HW abstraction Ops. + */ +extern struct snd_sof_dsp_ops sof_apl_ops; +extern struct snd_sof_dsp_ops sof_cnl_ops; +extern struct snd_sof_dsp_ops sof_skl_ops; + +#endif From 9d53e0f780bc9c36b0245205c4a78cf00e54e39b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 29 Oct 2018 12:53:31 -0500 Subject: [PATCH 0109/1995] ASoC: SOF: Intel: fix alignment issues in intel/hda.c Make checkpatch happy Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 163194062ee45b..a9baed1ec6ed80 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -40,8 +40,6 @@ /* platform specific devices */ #include "shim.h" - - /* * Register IO */ @@ -607,7 +605,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) */ snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0); - /* init HDA capabilities */ ret = hda_init_caps(sdev); if (ret < 0) From ef57a2297975d3761cab238c125d38bf047d2069 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 9 May 2018 17:14:11 +0100 Subject: [PATCH 0110/1995] ASoC: SOF: Intel: Add HDA controller for Intel DSP Support HDA controller operations for DSP and provide space for future DSP HDA FW integration. Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/hda-ctrl.c | 169 +++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 sound/soc/sof/intel/hda-ctrl.c diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c new file mode 100644 index 00000000000000..867bc3c4c7d3e9 --- /dev/null +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Jeeja KP +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for generic Intel audio DSP HDA IP + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sof-priv.h" +#include "../ops.h" +#include "hda.h" + +/* + * HDA Operations. + */ + +int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev) +{ + unsigned long timeout; + u32 gctl = 0; + + /* reset the HDA controller */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL, + SOF_HDA_GCTL_RESET, 0); + + /* wait for reset */ + timeout = jiffies + msecs_to_jiffies(HDA_DSP_CTRL_RESET_TIMEOUT); + while (time_before(jiffies, timeout)) { + usleep_range(500, 1000); + gctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL); + if ((gctl & SOF_HDA_GCTL_RESET) == 0) + goto clear; + } + + /* reset failed */ + dev_err(sdev->dev, "error: failed to reset HDA controller gctl 0x%x\n", + gctl); + return -EIO; + +clear: + /* wait for codec */ + usleep_range(500, 1000); + + /* now take controller out of reset */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL, + SOF_HDA_GCTL_RESET, SOF_HDA_GCTL_RESET); + + /* wait for controller to be ready */ + timeout = jiffies + msecs_to_jiffies(HDA_DSP_CTRL_RESET_TIMEOUT); + while (time_before(jiffies, timeout)) { + gctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL); + if ((gctl & SOF_HDA_GCTL_RESET) == 1) + return 0; + usleep_range(500, 1000); + } + + /* reset failed */ + dev_err(sdev->dev, "error: failed to ready HDA controller gctl 0x%x\n", + gctl); + return -EIO; +} + +int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + u32 cap, offset, feature; + int count = 0; + + offset = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_LLCH); + + do { + cap = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, offset); + + dev_dbg(sdev->dev, "checking for capabilities at offset 0x%x\n", + offset & SOF_HDA_CAP_NEXT_MASK); + + feature = (cap & SOF_HDA_CAP_ID_MASK) >> SOF_HDA_CAP_ID_OFF; + + switch (feature) { + case SOF_HDA_PP_CAP_ID: + dev_dbg(sdev->dev, "found DSP capability at 0x%x\n", + offset); + bus->ppcap = bus->remap_addr + offset; + sdev->bar[HDA_DSP_PP_BAR] = bus->ppcap; + break; + case SOF_HDA_SPIB_CAP_ID: + dev_dbg(sdev->dev, "found SPIB capability at 0x%x\n", + offset); + bus->spbcap = bus->remap_addr + offset; + sdev->bar[HDA_DSP_SPIB_BAR] = bus->spbcap; + break; + case SOF_HDA_DRSM_CAP_ID: + dev_dbg(sdev->dev, "found DRSM capability at 0x%x\n", + offset); + bus->drsmcap = bus->remap_addr + offset; + sdev->bar[HDA_DSP_DRSM_BAR] = bus->drsmcap; + break; + case SOF_HDA_GTS_CAP_ID: + dev_dbg(sdev->dev, "found GTS capability at 0x%x\n", + offset); + bus->gtscap = bus->remap_addr + offset; + break; + case SOF_HDA_ML_CAP_ID: + dev_dbg(sdev->dev, "found ML capability at 0x%x\n", + offset); + bus->mlcap = bus->remap_addr + offset; + break; + default: + dev_vdbg(sdev->dev, "found capability %d at 0x%x\n", + feature, offset); + break; + } + + offset = cap & SOF_HDA_CAP_NEXT_MASK; + } while (count++ <= SOF_HDA_MAX_CAPS && offset); + + return 0; +} + +void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable) +{ + u32 val = enable ? PCI_CGCTL_MISCBDCGE_MASK : 0; + + snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_MISCBDCGE_MASK, val); +} + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +/* + * While performing reset, controller may not come back properly and causing + * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset + * (init chip) and then again set CGCTL.MISCBDCGE to 1 + */ +int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int ret; + + hda_dsp_ctrl_misc_clock_gating(sdev, false); + ret = snd_hdac_bus_init_chip(bus, full_reset); + hda_dsp_ctrl_misc_clock_gating(sdev, true); + + return ret; +} +#endif + From 1ba479781d22f25a197a86dc83c48f9f5245622b Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 9 May 2018 17:14:12 +0100 Subject: [PATCH 0111/1995] ASoC: SOF: Intel: Add Intel specific HDA DSP HW operations Add support for various PM and core reset/run state transitions. Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/hda-dsp.c | 417 ++++++++++++++++++++++++++++++++++ 1 file changed, 417 insertions(+) create mode 100644 sound/soc/sof/intel/hda-dsp.c diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c new file mode 100644 index 00000000000000..0761375e7e6e00 --- /dev/null +++ b/sound/soc/sof/intel/hda-dsp.c @@ -0,0 +1,417 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Jeeja KP +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for generic Intel audio DSP HDA IP + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../sof-priv.h" +#include "../ops.h" +#include "hda.h" + +/* + * DSP Core control. + */ + +int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + u32 adspcs; + int ret; + + /* set reset bits for cores */ + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_CRST_MASK(core_mask), + HDA_DSP_ADSPCS_CRST_MASK(core_mask)); + + /* poll with timeout to check if operation successful */ + ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_CRST_MASK(core_mask), + HDA_DSP_ADSPCS_CRST_MASK(core_mask), + HDA_DSP_RESET_TIMEOUT); + + /* has core entered reset ? */ + adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS); + if ((adspcs & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) != + HDA_DSP_ADSPCS_CRST_MASK(core_mask)) { + dev_err(sdev->dev, + "error: reset enter failed: core_mask %x adspcs 0x%x\n", + core_mask, adspcs); + ret = -EIO; + } + + return ret; +} + +int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + u32 adspcs; + int ret; + + /* clear reset bits for cores */ + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_CRST_MASK(core_mask), + 0); + + /* poll with timeout to check if operation successful */ + ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_CRST_MASK(core_mask), 0, + HDA_DSP_RESET_TIMEOUT); + + /* has core left reset ? */ + adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS); + if ((adspcs & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) != 0) { + dev_err(sdev->dev, + "error: reset leave failed: core_mask %x adspcs 0x%x\n", + core_mask, adspcs); + ret = -EIO; + } + + return ret; +} + +int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + /* stall core */ + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_HDA_BAR, + HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_CSTALL_MASK(core_mask), + HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)); + + /* set reset state */ + return hda_dsp_core_reset_enter(sdev, core_mask); +} + +int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + int ret; + + /* leave reset state */ + ret = hda_dsp_core_reset_leave(sdev, core_mask); + if (ret < 0) + return ret; + + /* run core */ + dev_dbg(sdev->dev, "unstall/run core: core_mask = %x\n", core_mask); + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_CSTALL_MASK(core_mask), + 0); + + /* is core now running ? */ + if (!hda_dsp_core_is_enabled(sdev, core_mask)) { + hda_dsp_core_stall_reset(sdev, core_mask); + dev_err(sdev->dev, "error: DSP start core failed: core_mask %x\n", + core_mask); + ret = -EIO; + } + + return ret; +} + +/* + * Power Management. + */ + +int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + u32 adspcs; + int ret; + + /* update bits */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_SPA_MASK(core_mask), + HDA_DSP_ADSPCS_SPA_MASK(core_mask)); + + /* poll with timeout to check if operation successful */ + ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_CPA_MASK(core_mask), + HDA_DSP_ADSPCS_CPA_MASK(core_mask), + HDA_DSP_PU_TIMEOUT); + if (ret < 0) + dev_err(sdev->dev, "error: timeout on core powerup\n"); + + /* did core power up ? */ + adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS); + if ((adspcs & HDA_DSP_ADSPCS_CPA_MASK(core_mask)) != + HDA_DSP_ADSPCS_CPA_MASK(core_mask)) { + dev_err(sdev->dev, + "error: power up core failed core_mask %xadspcs 0x%x\n", + core_mask, adspcs); + ret = -EIO; + } + + return ret; +} + +int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + /* update bits */ + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_SPA_MASK(core_mask), 0); + + /* poll with timeout to check if operation successful */ + return snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, HDA_DSP_ADSPCS_CPA_MASK(core_mask), 0, + HDA_DSP_PD_TIMEOUT); +} + +bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, + unsigned int core_mask) +{ + int val; + bool is_enable; + + val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS); + + is_enable = ((val & HDA_DSP_ADSPCS_CPA_MASK(core_mask)) && + (val & HDA_DSP_ADSPCS_SPA_MASK(core_mask)) && + !(val & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) && + !(val & HDA_DSP_ADSPCS_CSTALL_MASK(core_mask))); + + dev_dbg(sdev->dev, "DSP core(s) enabled? %d : core_mask %x\n", + is_enable, core_mask); + + return is_enable; +} + +int hda_dsp_core_stall_reset_skl(struct snd_sof_dev *sdev, + unsigned int core_mask) +{ + /* stall core */ + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_CSTALL_MASK(core_mask), + HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)); + + /* set reset state */ + return hda_dsp_core_reset_enter(sdev, core_mask); +} + +int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + int ret; + + /* power up */ + ret = hda_dsp_core_power_up(sdev, core_mask); + if (ret < 0) { + dev_err(sdev->dev, "dsp core power up failed: core_mask %x\n", + core_mask); + return ret; + } + + return hda_dsp_core_run(sdev, core_mask); +} + +int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, + unsigned int core_mask) +{ + int ret; + + /* place core in reset prior to power down */ + ret = hda_dsp_core_stall_reset(sdev, core_mask); + if (ret < 0) { + dev_err(sdev->dev, "error: dsp core reset failed: core_mask %x\n", + core_mask); + return ret; + } + + /* power down core */ + ret = hda_dsp_core_power_down(sdev, core_mask); + if (ret < 0) { + dev_err(sdev->dev, "error: dsp core power down fail mask %x: %d\n", + core_mask, ret); + return ret; + } + + /* make sure we are in OFF state */ + if (hda_dsp_core_is_enabled(sdev, core_mask)) { + dev_err(sdev->dev, "error: dsp core disable fail mask %x: %d\n", + core_mask, ret); + ret = -EIO; + } + + return ret; +} + +static int hda_suspend(struct snd_sof_dev *sdev, int state) +{ + const struct sof_intel_dsp_desc *chip = sdev->hda->desc; + struct hdac_bus *bus = sof_to_bus(sdev); + int ret = 0; + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* power down all hda link */ + snd_hdac_ext_bus_link_power_down_all(bus); +#endif + + /* power down DSP */ + ret = hda_dsp_core_reset_power_down(sdev, chip->cores_mask); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to power down core during suspend\n"); + return ret; + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* disable ppcap interrupt */ + snd_hdac_ext_bus_ppcap_int_enable(bus, false); + snd_hdac_ext_bus_ppcap_enable(bus, false); + + /* disable hda bus irw and i/o */ + snd_hdac_bus_stop_chip(bus); +#endif + + /* disable LP retention mode */ + snd_sof_pci_update_bits(sdev, PCI_TCSEL, + PCI_CGCTL_LSRMD_MASK, PCI_CGCTL_LSRMD_MASK); + + return 0; +} + +static int hda_resume(struct snd_sof_dev *sdev) +{ + const struct sof_intel_dsp_desc *chip = sdev->hda->desc; + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_link *hlink = NULL; + int ret; + + /* + * clear TCSEL to clear playback on some HD Audio + * codecs. PCI TCSEL is defined in the Intel manuals. + */ + snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* reset and start hda controller */ + ret = hda_dsp_ctrl_init_chip(sdev, true); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to start controller after resume\n"); + return ret; + } + + hda_dsp_ctrl_misc_clock_gating(sdev, false); + + /* Reset stream-to-link mapping */ + list_for_each_entry(hlink, &bus->hlink_list, list) + bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); + + hda_dsp_ctrl_misc_clock_gating(sdev, true); + + /* enable ppcap interrupt */ + snd_hdac_ext_bus_ppcap_enable(bus, true); + snd_hdac_ext_bus_ppcap_int_enable(bus, true); +#endif + + /* power up the DSP */ + ret = hda_dsp_core_power_up(sdev, chip->cores_mask); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to power up core after resume\n"); + return ret; + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* turn off the links that were off before suspend */ + list_for_each_entry(hlink, &bus->hlink_list, list) { + if (!hlink->ref_count) + snd_hdac_ext_bus_link_power_down(hlink); + } + + /* check dma status and clean up CORB/RIRB buffers */ + if (!bus->cmd_dma_state) + snd_hdac_bus_stop_cmd_io(bus); +#endif + + return 0; +} + +int hda_dsp_resume(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int ret; + + /* turn display power on */ + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { + ret = snd_hdac_display_power(bus, true); + if (ret < 0) { + dev_err(bus->dev, "Cannot turn on display power on i915 after resume\n"); + return ret; + } + } + + /* init hda controller and power dsp up */ + return hda_resume(sdev); +} + +int hda_dsp_runtime_resume(struct snd_sof_dev *sdev) +{ + /* init hda controller and power dsp up */ + return hda_resume(sdev); +} + +int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state) +{ + /* stop hda controller and power dsp off */ + return hda_suspend(sdev, state); +} + +int hda_dsp_suspend(struct snd_sof_dev *sdev, int state) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int ret; + + /* stop hda controller and power dsp off */ + ret = hda_suspend(sdev, state); + if (ret < 0) { + dev_err(bus->dev, "error: suspending dsp\n"); + return ret; + } + + /* turn display power off */ + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { + ret = snd_hdac_display_power(bus, false); + if (ret < 0) { + dev_err(bus->dev, "Cannot turn on display power on i915 after resume\n"); + return ret; + } + } + + return 0; +} From ef4ccb552484390798fc1beeae438eba11220f9d Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 9 May 2018 17:14:13 +0100 Subject: [PATCH 0112/1995] ASoC: SOF: Intel: Add Intel specific HDA IPC mechanisms. Add HDA specific IPC mechanism for Intel DSP HW. Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/hda-ipc.c | 396 ++++++++++++++++++++++++++++++++++ 1 file changed, 396 insertions(+) create mode 100644 sound/soc/sof/intel/hda-ipc.c diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c new file mode 100644 index 00000000000000..dc2df7a99d03f2 --- /dev/null +++ b/sound/soc/sof/intel/hda-ipc.c @@ -0,0 +1,396 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Jeeja KP +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for generic Intel audio DSP HDA IP + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sof-priv.h" +#include "../ops.h" +#include "hda.h" + +int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir) +{ + if (dir == SOF_IPC_HOST_REPLY) { + /* + * tell DSP cmd is done - clear busy + * interrupt and send reply msg to dsp + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCT, + HDA_DSP_REG_HIPCT_BUSY, + HDA_DSP_REG_HIPCT_BUSY); + + /* unmask BUSY interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCCTL, + HDA_DSP_REG_HIPCCTL_BUSY, + HDA_DSP_REG_HIPCCTL_BUSY); + } else { + /* + * set DONE bit - tell DSP we have received the reply msg + * from DSP, and processed it, don't send more reply to host + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCIE, + HDA_DSP_REG_HIPCIE_DONE, + HDA_DSP_REG_HIPCIE_DONE); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCCTL, + HDA_DSP_REG_HIPCCTL_DONE, + HDA_DSP_REG_HIPCCTL_DONE); + } + + return 0; +} + +int hda_dsp_ipc_is_ready(struct snd_sof_dev *sdev) +{ + u64 busy, done; + + /* is DSP ready for next IPC command */ + busy = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI); + done = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE); + if ((busy & HDA_DSP_REG_HIPCI_BUSY) || + (done & HDA_DSP_REG_HIPCIE_DONE)) + return 0; + + return 1; +} + +int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + u32 cmd = msg->header; + + /* send IPC message to DSP */ + hda_dsp_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI, + cmd | HDA_DSP_REG_HIPCI_BUSY); + + return 0; +} + +int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg) +{ + struct sof_ipc_reply reply; + int ret = 0; + u32 size; + + /* get IPC reply from DSP in the mailbox */ + hda_dsp_mailbox_read(sdev, sdev->host_box.offset, &reply, + sizeof(reply)); + if (reply.error < 0) { + size = sizeof(reply); + ret = reply.error; + } else { + /* reply correct size ? */ + if (reply.hdr.size != msg->reply_size) { + dev_err(sdev->dev, "error: reply expected 0x%zx got 0x%x bytes\n", + msg->reply_size, reply.hdr.size); + size = msg->reply_size; + ret = -EINVAL; + } else { + size = reply.hdr.size; + } + } + + /* read the message */ + if (msg->msg_data && size > 0) + hda_dsp_mailbox_read(sdev, sdev->host_box.offset, + msg->reply_data, size); + + return ret; +} + +/* IPC handler thread */ +irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) +{ + struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + u32 hipci, hipcie, hipct, hipcte, msg = 0, msg_ext = 0; + irqreturn_t ret = IRQ_NONE; + int reply = -EINVAL; + + /* here we handle IPC interrupts only */ + if (!(sdev->irq_status & HDA_DSP_ADSPIS_IPC)) + return ret; + + /* read IPC status */ + hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCIE); + hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT); + + /* is this a reply message from the DSP */ + if (hipcie & HDA_DSP_REG_HIPCIE_DONE) { + + hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCI); + msg = hipci & HDA_DSP_REG_HIPCI_MSG_MASK; + msg_ext = hipcie & HDA_DSP_REG_HIPCIE_MSG_MASK; + + dev_vdbg(sdev->dev, + "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n", + msg, msg_ext); + + /* mask Done interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCCTL, + HDA_DSP_REG_HIPCCTL_DONE, 0); + + /* handle immediate reply from DSP core - ignore ROM messages */ + if (msg != 0x1004000) + reply = snd_sof_ipc_reply(sdev, msg); + + /* + * handle immediate reply from DSP core. If the msg is + * found, set done bit in cmd_done which is called at the + * end of message processing function, else set it here + * because the done bit can't be set in cmd_done function + * which is triggered by msg + */ + if (reply) + hda_dsp_ipc_cmd_done(sdev, SOF_IPC_DSP_REPLY); + + ret = IRQ_HANDLED; + } + + /* is this a new message from DSP */ + if (hipct & HDA_DSP_REG_HIPCT_BUSY) { + + hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCTE); + msg = hipct & HDA_DSP_REG_HIPCT_MSG_MASK; + msg_ext = hipcte & HDA_DSP_REG_HIPCTE_MSG_MASK; + + dev_vdbg(sdev->dev, + "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n", + msg, msg_ext); + + /* handle messages from DSP */ + if ((hipct & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { + /* this is a PANIC message !! */ + snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext)); + } else { + /* normal message - process normally*/ + snd_sof_ipc_msgs_rx(sdev); + } + + /* mask BUSY interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCCTL, + HDA_DSP_REG_HIPCCTL_BUSY, 0); + + ret = IRQ_HANDLED; + } + + if (ret == IRQ_HANDLED) { + /* reenable IPC interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); + } + + /* wake up sleeper if we are loading code */ + if (sdev->code_loading) { + sdev->code_loading = 0; + wake_up(&sdev->waitq); + } + + return ret; +} + +/* is this IRQ for ADSP ? - we only care about IPC here */ +irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) +{ + struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + int ret = IRQ_NONE; + + spin_lock(&sdev->hw_lock); + + /* store status */ + sdev->irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPIS); + + /* invalid message ? */ + if (sdev->irq_status == 0xffffffff) + goto out; + + /* IPC message ? */ + if (sdev->irq_status & HDA_DSP_ADSPIS_IPC) { + /* disable IPC interrupt */ + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_IPC, 0); + ret = IRQ_WAKE_THREAD; + } + +out: + spin_unlock(&sdev->hw_lock); + return ret; +} + +/* + * IPC Firmware ready. + */ + +static void ipc_get_windows(struct snd_sof_dev *sdev) +{ + struct sof_ipc_window_elem *elem; + u32 outbox_offset = 0; + u32 stream_offset = 0; + u32 inbox_offset = 0; + u32 outbox_size = 0; + u32 stream_size = 0; + u32 inbox_size = 0; + int i; + + if (!sdev->info_window) { + dev_err(sdev->dev, "error: have no window info\n"); + return; + } + + for (i = 0; i < sdev->info_window->num_windows; i++) { + elem = &sdev->info_window->window[i]; + + switch (elem->type) { + case SOF_IPC_REGION_UPBOX: + inbox_offset = + elem->offset + SRAM_WINDOW_OFFSET(elem->id); + inbox_size = elem->size; + snd_sof_debugfs_create_item(sdev, + sdev->bar[HDA_DSP_BAR] + + inbox_offset, + elem->size, "inbox"); + break; + case SOF_IPC_REGION_DOWNBOX: + outbox_offset = + elem->offset + SRAM_WINDOW_OFFSET(elem->id); + outbox_size = elem->size; + snd_sof_debugfs_create_item(sdev, + sdev->bar[HDA_DSP_BAR] + + outbox_offset, + elem->size, "outbox"); + break; + case SOF_IPC_REGION_TRACE: + snd_sof_debugfs_create_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "etrace"); + break; + case SOF_IPC_REGION_DEBUG: + snd_sof_debugfs_create_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "debug"); + break; + case SOF_IPC_REGION_STREAM: + stream_offset = + elem->offset + SRAM_WINDOW_OFFSET(elem->id); + stream_size = elem->size; + snd_sof_debugfs_create_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "stream"); + break; + case SOF_IPC_REGION_REGS: + snd_sof_debugfs_create_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "regs"); + break; + case SOF_IPC_REGION_EXCEPTION: + sdev->dsp_oops_offset = elem->offset + + SRAM_WINDOW_OFFSET(elem->id); + snd_sof_debugfs_create_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "exception"); + break; + default: + dev_err(sdev->dev, "error: get illegal window info\n"); + return; + } + } + + if (outbox_size == 0 || inbox_size == 0) { + dev_err(sdev->dev, "error: get illegal mailbox window\n"); + return; + } + + snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, + outbox_offset, outbox_size); + sdev->stream_box.offset = stream_offset; + sdev->stream_box.size = stream_size; + + dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", + inbox_offset, inbox_size); + dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", + outbox_offset, outbox_size); + dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", + stream_offset, stream_size); +} + +int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; + struct sof_ipc_fw_version *v = &fw_ready->version; + u32 offset; + + /* mailbox must be on 4k boundary */ + offset = HDA_DSP_MBOX_UPLINK_OFFSET; + + dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n", + msg_id, offset); + + /* copy data from the DSP FW ready offset */ + hda_dsp_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); + dev_info(sdev->dev, + " Firmware info: version %d.%d-%s build %d on %s:%s\n", + v->major, v->minor, v->tag, v->build, v->date, v->time); + + /* now check for extended data */ + snd_sof_fw_parse_ext_data(sdev, HDA_DSP_MBOX_UPLINK_OFFSET + + sizeof(struct sof_ipc_fw_ready)); + + if (sdev->first_boot) + ipc_get_windows(sdev); + + return 0; +} From 1bead6b369a760c4a96652c85c41c7048bc1ecdd Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 9 May 2018 17:14:14 +0100 Subject: [PATCH 0113/1995] ASoC: SOF: Intel: Add Intel specific HDA firmware loader Add support for loading DSP firmware on Intel HDA based platforms. Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/hda-loader.c | 374 +++++++++++++++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 sound/soc/sof/intel/hda-loader.c diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c new file mode 100644 index 00000000000000..76ac08d8d0883e --- /dev/null +++ b/sound/soc/sof/intel/hda-loader.c @@ -0,0 +1,374 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Jeeja KP +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for HDA DSP code loader + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sof-priv.h" +#include "../ops.h" +#include "hda.h" + +static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, + unsigned int size, struct snd_dma_buffer *dmab, + int direction) +{ + struct hdac_ext_stream *stream = NULL; + struct hdac_stream *hstream; + struct pci_dev *pci = sdev->pci; + int ret; + + if (direction == SNDRV_PCM_STREAM_PLAYBACK) { + stream = hda_dsp_stream_get_pstream(sdev); + } else { + dev_err(sdev->dev, "error: code loading DMA is playback only\n"); + return -EINVAL; + } + + if (!stream) { + dev_err(sdev->dev, "error: no stream available\n"); + return -ENODEV; + } + hstream = &stream->hstream; + + /* allocate DMA buffer */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab); + if (ret < 0) { + dev_err(sdev->dev, "error: memory alloc failed: %x\n", ret); + goto error; + } + + hstream->format_val = format; + hstream->bufsize = size; + + ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL); + if (ret < 0) { + dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret); + goto error; + } + + hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_ENABLE, size); + + return hstream->stream_tag; + +error: + hda_dsp_stream_put_pstream(sdev, hstream->stream_tag); + snd_dma_free_pages(dmab); + return ret; +} + +/* + * first boot sequence has some extra steps. core 0 waits for power + * status on core 1, so power up core 1 also momentarily, keep it in + * reset/stall and then turn it off + */ +static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, + u32 fwsize) +{ + int tag, ret, i; + u32 hipcie; + const struct sof_intel_dsp_desc *chip = sdev->hda->desc; + + /* prepare DMA for code loader stream */ + tag = cl_stream_prepare(sdev, 0x40, fwsize, &sdev->dmab, + SNDRV_PCM_STREAM_PLAYBACK); + + if (tag <= 0) { + dev_err(sdev->dev, "error: dma prepare for fw loading err: %x\n", + tag); + return tag; + } + + memcpy(sdev->dmab.area, fwdata, fwsize); + + /* step 1: power up corex */ + ret = hda_dsp_core_power_up(sdev, chip->cores_mask); + if (ret < 0) { + dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n"); + goto err; + } + + /* step 2: purge FW request */ + snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, + chip->ipc_req_mask | (HDA_DSP_IPC_PURGE_FW | + ((tag - 1) << 9))); + + /* step 3: unset core 0 reset state & unstall/run core 0 */ + ret = hda_dsp_core_run(sdev, HDA_DSP_CORE_MASK(0)); + if (ret < 0) { + dev_err(sdev->dev, "error: dsp core start failed %d\n", ret); + ret = -EIO; + goto err; + } + + /* step 4: wait for IPC DONE bit from ROM */ + for (i = HDA_DSP_INIT_TIMEOUT; i > 0; i--) { + hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + chip->ipc_ack); + + if (hipcie & chip->ipc_ack_mask) { + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + chip->ipc_ack, + chip->ipc_ack_mask, + chip->ipc_ack_mask); + goto step5; + } + mdelay(1); + } + + dev_err(sdev->dev, "error: waiting for HIPCIE done, reg: 0x%x\n", + hipcie); + goto err; + +step5: + /* step 5: power down corex */ + ret = hda_dsp_core_power_down(sdev, + chip->cores_mask & ~(HDA_DSP_CORE_MASK(0))); + if (ret < 0) { + dev_err(sdev->dev, "error: dsp core x power down failed\n"); + goto err; + } + + /* step 6: enable interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); + + /* enable IPC DONE interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, + HDA_DSP_REG_HIPCCTL_DONE, + HDA_DSP_REG_HIPCCTL_DONE); + + /* enable IPC BUSY interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, + HDA_DSP_REG_HIPCCTL_BUSY, + HDA_DSP_REG_HIPCCTL_BUSY); + + /* step 7: wait for ROM init */ + ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_STATUS, + HDA_DSP_ROM_STS_MASK, HDA_DSP_ROM_INIT, + HDA_DSP_INIT_TIMEOUT); + if (ret >= 0) + goto out; + + ret = -EIO; + +err: + hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); + //sdev->dsp_ops.cleanup(sdev->dev, &sdev->dmab, tag); + hda_dsp_core_reset_power_down(sdev, HDA_DSP_CORE_MASK(0) | + HDA_DSP_CORE_MASK(1)); + return ret; + +out: + return tag; +} + +static int cl_trigger(struct snd_sof_dev *sdev, + struct hdac_ext_stream *stream, int cmd) +{ + struct hdac_stream *hstream = &stream->hstream; + int sd_offset = SOF_STREAM_SD_OFFSET(hstream); + + /* code loader is special case that reuses stream ops */ + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + wait_event_timeout(sdev->waitq, !sdev->code_loading, + HDA_DSP_CL_TRIGGER_TIMEOUT); + + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + 1 << hstream->index, + 1 << hstream->index); + + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset, + SOF_HDA_SD_CTL_DMA_START | + SOF_HDA_CL_DMA_SD_INT_MASK, + SOF_HDA_SD_CTL_DMA_START | + SOF_HDA_CL_DMA_SD_INT_MASK); + + hstream->running = true; + return 0; + default: + return hda_dsp_stream_trigger(sdev, stream, cmd); + } +} + +static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, + struct hdac_ext_stream *stream) +{ + struct hdac_stream *hstream = &stream->hstream; + int sd_offset = SOF_STREAM_SD_OFFSET(hstream); + int ret; + + ret = hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); + + /* TODO: spin lock ?*/ + hstream->opened = 0; + hstream->running = 0; + hstream->substream = NULL; + + /* reset BDL address */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, 0); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0); + + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0); + snd_dma_free_pages(dmab); + dmab->area = NULL; + hstream->bufsize = 0; + hstream->format_val = 0; + + return ret; +} + +static int cl_copy_fw(struct snd_sof_dev *sdev, int tag) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_stream *stream = NULL; + struct hdac_stream *s; + int ret, status; + + /* get stream with tag */ + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == SNDRV_PCM_STREAM_PLAYBACK && + s->stream_tag == tag) { + stream = stream_to_hdac_ext_stream(s); + break; + } + } + + if (!stream) { + dev_err(sdev->dev, + "error: could not get stream with stream tag%d\n", + tag); + return -ENODEV; + } + + ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_START); + if (ret < 0) { + dev_err(sdev->dev, "error: DMA trigger start failed\n"); + return ret; + } + + status = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_STATUS, + HDA_DSP_ROM_STS_MASK, + HDA_DSP_ROM_FW_ENTERED, + HDA_DSP_BASEFW_TIMEOUT); + + ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_STOP); + if (ret < 0) { + dev_err(sdev->dev, "error: DMA trigger stop failed\n"); + return ret; + } + + ret = cl_cleanup(sdev, &sdev->dmab, stream); + if (ret < 0) { + dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); + return ret; + } + + return status; +} + +int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, bool first_boot) +{ + struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev); + const char *fw_filename; + + /* set code loading condition to true */ + sdev->code_loading = 1; + + switch (plat_data->type) { + case SOF_DEVICE_SPI: + fw_filename = plat_data->sof_machine->sof_fw_filename; + break; + default: + fw_filename = plat_data->machine->sof_fw_filename; + } + + return request_firmware(&plat_data->fw, fw_filename, sdev->dev); +} + +int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev); + struct firmware stripped_firmware; + int ret, tag; + + stripped_firmware.data = plat_data->fw->data; + stripped_firmware.size = plat_data->fw->size; + + tag = cl_dsp_init(sdev, stripped_firmware.data, + stripped_firmware.size); + + /* retry enabling core and ROM load. seemed to help */ + if (tag < 0) { + tag = cl_dsp_init(sdev, stripped_firmware.data, + stripped_firmware.size); + if (tag <= 0) { + dev_err(sdev->dev, "Error code=0x%x: FW status=0x%x\n", + snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_ERROR), + snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_STATUS)); + dev_err(sdev->dev, "Core En/ROM load fail:%d\n", + tag); + ret = tag; + goto irq_err; + } + } + + /* init for booting wait */ + init_waitqueue_head(&sdev->boot_wait); + sdev->boot_complete = false; + + /* at this point DSP ROM has been initialized and should be ready for + * code loading and firmware boot + */ + ret = cl_copy_fw(sdev, tag); + if (ret < 0) { + dev_err(sdev->dev, "error: load fw failed err: %d\n", ret); + goto irq_err; + } + + dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); + + return ret; + +irq_err: + hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); + + /* disable DSP */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + SOF_HDA_PPCTL_GPROCEN, 0); + dev_err(sdev->dev, "error: load fw failed err: %d\n", ret); + return ret; +} From cdae3b9a47aa69d2d01c72eb3d2d856d3232f5c9 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 9 May 2018 17:14:15 +0100 Subject: [PATCH 0114/1995] ASoC: SOF: Intel: Add Intel specific HDA PCM operations Add PCM operations for Intel HDA based DSPs. Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/hda-pcm.c | 250 ++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 sound/soc/sof/intel/hda-pcm.c diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c new file mode 100644 index 00000000000000..d5a09dcceeee4d --- /dev/null +++ b/sound/soc/sof/intel/hda-pcm.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Jeeja KP +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for generic Intel audio DSP HDA IP + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sof-priv.h" +#include "../ops.h" +#include "hda.h" + +#define SDnFMT_BASE(x) ((x) << 14) +#define SDnFMT_MULT(x) (((x) - 1) << 11) +#define SDnFMT_DIV(x) (((x) - 1) << 8) +#define SDnFMT_BITS(x) ((x) << 4) +#define SDnFMT_CHAN(x) ((x) << 0) + +static inline u32 get_mult_div(struct snd_sof_dev *sdev, int rate) +{ + switch (rate) { + case 8000: + return SDnFMT_DIV(6); + case 9600: + return SDnFMT_DIV(5); + case 11025: + return SDnFMT_BASE(1) | SDnFMT_DIV(4); + case 16000: + return SDnFMT_DIV(3); + case 22050: + return SDnFMT_BASE(1) | SDnFMT_DIV(2); + case 32000: + return SDnFMT_DIV(3) | SDnFMT_MULT(2); + case 44100: + return SDnFMT_BASE(1); + case 48000: + return 0; + case 88200: + return SDnFMT_BASE(1) | SDnFMT_MULT(2); + case 96000: + return SDnFMT_MULT(2); + case 176400: + return SDnFMT_BASE(1) | SDnFMT_MULT(4); + case 192000: + return SDnFMT_MULT(4); + default: + dev_warn(sdev->dev, "can't find div rate %d using 48kHz\n", + rate); + return 0; /* use 48KHz if not found */ + } +}; + +static inline u32 get_bits(struct snd_sof_dev *sdev, int sample_bits) +{ + switch (sample_bits) { + case 8: + return SDnFMT_BITS(0); + case 16: + return SDnFMT_BITS(1); + case 20: + return SDnFMT_BITS(2); + case 24: + return SDnFMT_BITS(3); + case 32: + return SDnFMT_BITS(4); + default: + dev_warn(sdev->dev, "can't find %d bits using 16bit\n", + sample_bits); + return SDnFMT_BITS(1); /* use 16bits format if not found */ + } +}; + +int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct sof_ipc_stream_params *ipc_params) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream); + struct snd_dma_buffer *dmab; + int ret; + u32 size, rate, bits; + + size = params_buffer_bytes(params); + rate = get_mult_div(sdev, params_rate(params)); + bits = get_bits(sdev, params_width(params)); + + hstream->substream = substream; + + dmab = substream->runtime->dma_buffer_p; + + hstream->format_val = rate | bits | (params_channels(params) - 1); + hstream->bufsize = size; + hstream->period_bytes = params_period_size(params); + hstream->no_period_wakeup = + (params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) && + (params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP); + + ret = hda_dsp_stream_hw_params(sdev, stream, dmab, params); + if (ret < 0) { + dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret); + return ret; + } + + /* disable SPIB, to enable buffer wrap for stream */ + hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); + + /* set host_period_bytes to 0 if no IPC position */ + if (sdev->hda && sdev->hda->no_ipc_position) + ipc_params->host_period_bytes = 0; + + ipc_params->stream_tag = hstream->stream_tag; + + return 0; +} + +int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, int cmd) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream); + + return hda_dsp_stream_trigger(sdev, stream, cmd); +} + +snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_sof_pcm *spcm = rtd->private; + snd_pcm_uframes_t pos = 0; + + if (!sdev->hda->no_ipc_position) { + /* read position from IPC position */ + pos = spcm->stream[substream->stream].posn.host_posn; + goto found; + } + + /* + * DPIB/posbuf position mode: + * For Playback, Use DPIB register from HDA space which + * reflects the actual data transferred. + * For Capture, Use the position buffer for pointer, as DPIB + * is not accurate enough, its update may be completed + * earlier than the data written to DDR. + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hstream->index)); + } else { + /* + * For capture stream, we need more workaround to fix the + * position incorrect issue: + * + * 1. Wait at least 20us before reading position buffer after + * the interrupt generated(IOC), to make sure position update + * happens on frame boundary i.e. 20.833uSec for 48KHz. + * 2. Perform a dummy Read to DPIB register to flush DMA + * position value. + * 3. Read the DMA Position from posbuf. Now the readback + * value should be >= period boundary. + */ + usleep_range(20, 21); + snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hstream->index)); + pos = snd_hdac_stream_get_pos_posbuf(hstream); + } + + if (pos >= hstream->bufsize) + pos = 0; + +found: + pos = bytes_to_frames(substream->runtime, pos); + + dev_vdbg(sdev->dev, "PCM: stream %d dir %d position %lu\n", + hstream->index, substream->stream, pos); + return pos; +} + +int hda_dsp_pcm_open(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct hdac_ext_stream *stream; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + stream = hda_dsp_stream_get_pstream(sdev); + else + stream = hda_dsp_stream_get_cstream(sdev); + + if (!stream) { + dev_err(sdev->dev, "error: no stream available\n"); + return -ENODEV; + } + + /* binding pcm substream to hda stream */ + substream->runtime->private_data = &stream->hstream; + return 0; +} + +int hda_dsp_pcm_close(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + int ret; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + ret = hda_dsp_stream_put_pstream(sdev, hstream->stream_tag); + else + ret = hda_dsp_stream_put_cstream(sdev, hstream->stream_tag); + + if (ret) { + dev_dbg(sdev->dev, "stream %s not opened!\n", substream->name); + return -ENODEV; + } + + /* unbinding pcm substream to hda stream */ + substream->runtime->private_data = NULL; + return 0; +} + From 10cf2bc4f3a02ee450a8d3a803fe9bd23d5eccfa Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 31 Aug 2018 14:14:32 +0800 Subject: [PATCH 0115/1995] ASoC: SOF: HDA: add hda bus initialization API Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-bus.c | 109 ++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 sound/soc/sof/intel/hda-bus.c diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c new file mode 100644 index 00000000000000..0518c0d09cc664 --- /dev/null +++ b/sound/soc/sof/intel/hda-bus.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Authors: Takashi Iwai + * Jeeja KP + * Keyon Jie + */ + +#include + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + +static const struct hdac_bus_ops bus_ops = { + .command = snd_hdac_bus_send_cmd, + .get_response = snd_hdac_bus_get_response, +}; + +#endif + +static void sof_hda_writel(u32 value, u32 __iomem *addr) +{ + writel(value, addr); +} + +static u32 sof_hda_readl(u32 __iomem *addr) +{ + return readl(addr); +} + +static void sof_hda_writew(u16 value, u16 __iomem *addr) +{ + writew(value, addr); +} + +static u16 sof_hda_readw(u16 __iomem *addr) +{ + return readw(addr); +} + +static void sof_hda_writeb(u8 value, u8 __iomem *addr) +{ + writeb(value, addr); +} + +static u8 sof_hda_readb(u8 __iomem *addr) +{ + return readb(addr); +} + +static int sof_hda_dma_alloc_pages(struct hdac_bus *bus, int type, + size_t size, struct snd_dma_buffer *buf) +{ + return snd_dma_alloc_pages(type, bus->dev, size, buf); +} + +static void sof_hda_dma_free_pages(struct hdac_bus *bus, + struct snd_dma_buffer *buf) +{ + snd_dma_free_pages(buf); +} + +static const struct hdac_io_ops io_ops = { + .reg_writel = sof_hda_writel, + .reg_readl = sof_hda_readl, + .reg_writew = sof_hda_writew, + .reg_readw = sof_hda_readw, + .reg_writeb = sof_hda_writeb, + .reg_readb = sof_hda_readb, + .dma_alloc_pages = sof_hda_dma_alloc_pages, + .dma_free_pages = sof_hda_dma_free_pages, +}; + +/* + * This can be used for both with/without hda link support. + * Returns 0 if successful, or a negative error code. + */ +int sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, + const struct hdac_ext_bus_ops *ext_ops) +{ + static int idx; + + memset(bus, 0, sizeof(*bus)); + bus->dev = dev; + bus->io_ops = &io_ops; + + INIT_LIST_HEAD(&bus->codec_list); + INIT_LIST_HEAD(&bus->stream_list); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + bus->ops = &bus_ops; + INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); +#endif + spin_lock_init(&bus->reg_lock); + mutex_init(&bus->cmd_mutex); + bus->irq = -1; + + bus->ext_ops = ext_ops; + INIT_LIST_HEAD(&bus->hlink_list); + bus->idx = idx++; + + mutex_init(&bus->lock); + bus->cmd_dma_state = true; + + return 0; +} From a4c6b6a3b4d22368ed4473e0912e1761b750a966 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Wed, 29 Aug 2018 19:03:30 +0800 Subject: [PATCH 0116/1995] ASoC: SOF: HDA: hdac_bus update Simpler version of initial patch (other files where squashed) FIXME: need to fix GPL issues and figure out if this patch is really needed Signed-off-by: Mengdong Lin Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-bus.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index 0518c0d09cc664..759f1e61a0309c 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -5,8 +5,7 @@ * * Copyright(c) 2018 Intel Corporation. All rights reserved. * - * Authors: Takashi Iwai - * Jeeja KP + * Authors: Jeeja KP * Keyon Jie */ @@ -52,13 +51,13 @@ static u8 sof_hda_readb(u8 __iomem *addr) } static int sof_hda_dma_alloc_pages(struct hdac_bus *bus, int type, - size_t size, struct snd_dma_buffer *buf) + size_t size, struct snd_dma_buffer *buf) { return snd_dma_alloc_pages(type, bus->dev, size, buf); } static void sof_hda_dma_free_pages(struct hdac_bus *bus, - struct snd_dma_buffer *buf) + struct snd_dma_buffer *buf) { snd_dma_free_pages(buf); } @@ -79,16 +78,16 @@ static const struct hdac_io_ops io_ops = { * Returns 0 if successful, or a negative error code. */ int sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, - const struct hdac_ext_bus_ops *ext_ops) + const struct hdac_ext_bus_ops *ext_ops) { static int idx; memset(bus, 0, sizeof(*bus)); bus->dev = dev; - bus->io_ops = &io_ops; - INIT_LIST_HEAD(&bus->codec_list); + bus->io_ops = &io_ops; INIT_LIST_HEAD(&bus->stream_list); + INIT_LIST_HEAD(&bus->codec_list); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) bus->ops = &bus_ops; From 4a7d41d609ab1de20ee7e159d2667b4bded2c926 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 9 May 2018 17:14:16 +0100 Subject: [PATCH 0117/1995] ASoC: SOF: Intel: Add Intel specific HDA stream operations Add support or HDA DSP stream operations for Intel HDA DSPs. Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/hda-stream.c | 761 +++++++++++++++++++++++++++++++ 1 file changed, 761 insertions(+) create mode 100644 sound/soc/sof/intel/hda-stream.c diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c new file mode 100644 index 00000000000000..42a986ce35a08f --- /dev/null +++ b/sound/soc/sof/intel/hda-stream.c @@ -0,0 +1,761 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Jeeja KP +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for generic Intel audio DSP HDA IP + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sof-priv.h" +#include "../ops.h" +#include "hda.h" + +/* + * set up one of BDL entries for a stream + */ +static int hda_setup_bdle(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab, + struct hdac_stream *stream, + struct sof_intel_dsp_bdl **bdlp, + int offset, int size, int ioc) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct sof_intel_dsp_bdl *bdl = *bdlp; + + while (size > 0) { + dma_addr_t addr; + int chunk; + + if (stream->frags >= HDA_DSP_MAX_BDL_ENTRIES) { + dev_err(sdev->dev, "error: stream frags exceeded\n"); + return -EINVAL; + } + + addr = snd_sgbuf_get_addr(dmab, offset); + /* program BDL addr */ + bdl->addr_l = lower_32_bits(addr); + bdl->addr_h = upper_32_bits(addr); + /* program BDL size */ + chunk = snd_sgbuf_get_chunk_size(dmab, offset, size); + /* one BDLE should not cross 4K boundary */ + if (bus->align_bdle_4k) { + u32 remain = 0x1000 - (offset & 0xfff); + + if (chunk > remain) + chunk = remain; + } + bdl->size = cpu_to_le32(chunk); + /* only program IOC when the whole segment is processed */ + size -= chunk; + bdl->ioc = (size || !ioc) ? 0 : cpu_to_le32(0x01); + bdl++; + stream->frags++; + offset += chunk; + + dev_vdbg(sdev->dev, "bdl, frags:%d, chunk size:0x%x;\n", + stream->frags, chunk); + } + + *bdlp = bdl; + return offset; +} + +/* + * set up Buffer Descriptor List (BDL) for host memory transfer + * BDL describes the location of the individual buffers and is little endian. + */ +int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab, + struct hdac_stream *stream) +{ + struct sof_intel_dsp_bdl *bdl; + int i, offset, period_bytes, periods; + int remain, ioc; + + period_bytes = stream->period_bytes; + dev_dbg(sdev->dev, "period_bytes:0x%x\n", period_bytes); + if (!period_bytes) + period_bytes = stream->bufsize; + + periods = stream->bufsize / period_bytes; + + dev_dbg(sdev->dev, "periods:%d\n", periods); + + remain = stream->bufsize % period_bytes; + if (remain) + periods++; + + /* program the initial BDL entries */ + bdl = (struct sof_intel_dsp_bdl *)stream->bdl.area; + offset = 0; + stream->frags = 0; + + /* + * set IOC if don't use position IPC + * and period_wakeup needed. + */ + ioc = sdev->hda->no_ipc_position ? + !stream->no_period_wakeup : 0; + + for (i = 0; i < periods; i++) { + if (i == (periods - 1) && remain) + /* set the last small entry */ + offset = hda_setup_bdle(sdev, dmab, + stream, &bdl, offset, + remain, 0); + else + offset = hda_setup_bdle(sdev, dmab, + stream, &bdl, offset, + period_bytes, ioc); + } + + return offset; +} + +int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, + struct hdac_ext_stream *stream, + int enable, u32 size) +{ + struct hdac_stream *hstream = &stream->hstream; + u32 mask = 0; + + if (!sdev->bar[HDA_DSP_SPIB_BAR]) { + dev_err(sdev->dev, "error: address of spib capability is NULL\n"); + return -EINVAL; + } + + mask |= (1 << hstream->index); + + /* enable/disable SPIB for the stream */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_SPIB_BAR, + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, mask, + enable << hstream->index); + + /* set the SPIB value */ + hda_dsp_write(sdev, stream->spib_addr, size); + + return 0; +} + +/* get next unused stream */ +struct hdac_ext_stream * +hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_stream *stream = NULL; + struct hdac_stream *s; + + /* get an unused playback stream */ + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == direction && !s->opened) { + s->opened = true; + stream = stream_to_hdac_ext_stream(s); + break; + } + } + + /* stream found ? */ + if (!stream) + dev_err(sdev->dev, "error: no free %s streams\n", + direction == SNDRV_PCM_STREAM_PLAYBACK ? + "playback" : "capture"); + + return stream; +} + +/* get next unused playback stream */ +struct hdac_ext_stream * +hda_dsp_stream_get_pstream(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_stream *stream = NULL; + struct hdac_stream *s; + + /* get an unused playback stream */ + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == SNDRV_PCM_STREAM_PLAYBACK && + !s->opened) { + s->opened = true; + stream = stream_to_hdac_ext_stream(s); + break; + } + } + + /* stream found ? */ + if (!stream) + dev_err(sdev->dev, "error: no free playback streams\n"); + + return stream; +} + +/* get next unused capture stream */ +struct hdac_ext_stream * +hda_dsp_stream_get_cstream(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_stream *stream = NULL; + struct hdac_stream *s; + + /* get an unused capture stream */ + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == SNDRV_PCM_STREAM_CAPTURE && + !s->opened) { + s->opened = true; + stream = stream_to_hdac_ext_stream(s); + break; + } + } + + /* stream found ? */ + if (!stream) + dev_err(sdev->dev, "error: no free capture streams\n"); + + return stream; +} + +/* free a stream */ +int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int tag) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *s; + + /* find used stream */ + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == direction && + s->opened && s->stream_tag == tag) { + s->opened = false; + return 0; + } + } + + dev_dbg(sdev->dev, "tag %d not opened!\n", tag); + return -ENODEV; +} + +/* free playback stream */ +int hda_dsp_stream_put_pstream(struct snd_sof_dev *sdev, int tag) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *s; + + /* find used playback stream */ + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == SNDRV_PCM_STREAM_PLAYBACK && + s->opened && s->stream_tag == tag) { + s->opened = false; + return 0; + } + } + + dev_dbg(sdev->dev, "tag %d not opened!\n", tag); + return -ENODEV; +} + +/* free capture stream */ +int hda_dsp_stream_put_cstream(struct snd_sof_dev *sdev, int tag) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *s; + + /* find used capture stream */ + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == SNDRV_PCM_STREAM_CAPTURE && + s->opened && s->stream_tag == tag) { + s->opened = false; + return 0; + } + } + + dev_dbg(sdev->dev, "tag %d not opened!\n", tag); + return -ENODEV; +} + +int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, + struct hdac_ext_stream *stream, int cmd) +{ + struct hdac_stream *hstream = &stream->hstream; + int sd_offset = SOF_STREAM_SD_OFFSET(hstream); + + /* cmd must be for audio stream */ + switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_START: + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + 1 << hstream->index, + 1 << hstream->index); + + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset, + SOF_HDA_SD_CTL_DMA_START | + SOF_HDA_CL_DMA_SD_INT_MASK, + SOF_HDA_SD_CTL_DMA_START | + SOF_HDA_CL_DMA_SD_INT_MASK); + + hstream->running = true; + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_STOP: + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset, + SOF_HDA_SD_CTL_DMA_START | + SOF_HDA_CL_DMA_SD_INT_MASK, 0x0); + + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset + + SOF_HDA_ADSP_REG_CL_SD_STS, + SOF_HDA_CL_DMA_SD_INT_MASK); + + hstream->running = false; + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + 1 << hstream->index, 0x0); + break; + default: + dev_err(sdev->dev, "error: unknown command: %d\n", cmd); + return -EINVAL; + } + + return 0; +} + +/* + * prepare for common hdac registers settings, for both code loader + * and normal stream. + */ +int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, + struct hdac_ext_stream *stream, + struct snd_dma_buffer *dmab, + struct snd_pcm_hw_params *params) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *hstream = &stream->hstream; + int sd_offset = SOF_STREAM_SD_OFFSET(hstream); + int ret, timeout = HDA_DSP_STREAM_RESET_TIMEOUT; + u32 val, mask; + + if (!stream) { + dev_err(sdev->dev, "error: no stream available\n"); + return -ENODEV; + } + + /* decouple host and link DMA */ + mask = 0x1 << hstream->index; + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + mask, mask); + + if (!dmab) { + dev_err(sdev->dev, "error: no dma buffer allocated!\n"); + return -ENODEV; + } + + /* clear stream status */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, + SOF_HDA_CL_DMA_SD_INT_MASK | + SOF_HDA_SD_CTL_DMA_START, 0); + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, + SOF_HDA_CL_DMA_SD_INT_MASK, + SOF_HDA_CL_DMA_SD_INT_MASK); + + /* stream reset */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, 0x1, + 0x1); + udelay(3); + do { + val = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, + sd_offset); + if (val & 0x1) + break; + } while (--timeout); + if (timeout == 0) { + dev_err(sdev->dev, "error: stream reset failed\n"); + return -ETIMEDOUT; + } + + timeout = HDA_DSP_STREAM_RESET_TIMEOUT; + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, 0x1, + 0x0); + + /* wait for hardware to report that stream is out of reset */ + udelay(3); + do { + val = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, + sd_offset); + if ((val & 0x1) == 0) + break; + } while (--timeout); + if (timeout == 0) { + dev_err(sdev->dev, "error: timeout waiting for stream reset\n"); + return -ETIMEDOUT; + } + + if (hstream->posbuf) + *hstream->posbuf = 0; + + /* reset BDL address */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, + 0x0); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, + 0x0); + + /* clear stream status */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, + SOF_HDA_CL_DMA_SD_INT_MASK | + SOF_HDA_SD_CTL_DMA_START, 0); + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, + SOF_HDA_CL_DMA_SD_INT_MASK, + SOF_HDA_CL_DMA_SD_INT_MASK); + + hstream->frags = 0; + + ret = hda_dsp_stream_setup_bdl(sdev, dmab, hstream); + if (ret < 0) { + dev_err(sdev->dev, "error: set up of BDL failed\n"); + return ret; + } + + /* set up stream descriptor for DMA */ + /* program stream tag */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, + SOF_HDA_CL_SD_CTL_STREAM_TAG_MASK, + hstream->stream_tag << + SOF_HDA_CL_SD_CTL_STREAM_TAG_SHIFT); + + /* program cyclic buffer length */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, + hstream->bufsize); + + /* program stream format */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + + SOF_HDA_ADSP_REG_CL_SD_FORMAT, + 0xffff, hstream->format_val); + + /* program last valid index */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, + 0xffff, (hstream->frags - 1)); + + /* program BDL address */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, + (u32)hstream->bdl.addr); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, + upper_32_bits(hstream->bdl.addr)); + + /* enable position buffer */ + if (!(snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE) + & SOF_HDA_ADSP_DPLBASE_ENABLE)) { + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPUBASE, + upper_32_bits(bus->posbuf.addr)); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE, + (u32)bus->posbuf.addr | + SOF_HDA_ADSP_DPLBASE_ENABLE); + } + + /* set interrupt enable bits */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, + SOF_HDA_CL_DMA_SD_INT_MASK, + SOF_HDA_CL_DMA_SD_INT_MASK); + + /* read FIFO size */ + if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK) { + hstream->fifo_size = + snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, + sd_offset + + SOF_HDA_ADSP_REG_CL_SD_FIFOSIZE); + hstream->fifo_size &= 0xffff; + hstream->fifo_size += 1; + } else { + hstream->fifo_size = 0; + } + + return ret; +} + +irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) +{ + struct hdac_bus *bus = (struct hdac_bus *)context; + u32 status; + + if (!pm_runtime_active(bus->dev)) + return IRQ_NONE; + + spin_lock(&bus->reg_lock); + + status = snd_hdac_chip_readl(bus, INTSTS); + if (status == 0 || status == 0xffffffff) { + spin_unlock(&bus->reg_lock); + return IRQ_NONE; + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* clear rirb int */ + status = snd_hdac_chip_readb(bus, RIRBSTS); + if (status & RIRB_INT_MASK) { + if (status & RIRB_INT_RESPONSE) + snd_hdac_bus_update_rirb(bus); + snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); + } +#endif + + spin_unlock(&bus->reg_lock); + + return snd_hdac_chip_readl(bus, INTSTS) ? IRQ_WAKE_THREAD : IRQ_HANDLED; +} + +irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) +{ + struct hdac_bus *bus = (struct hdac_bus *)context; + struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); + struct hdac_stream *s; + u32 status = snd_hdac_chip_readl(bus, INTSTS); + u32 sd_status; + + /* check streams */ + list_for_each_entry(s, &bus->stream_list, list) { + if (status & (1 << s->index) && s->opened) { + sd_status = snd_hdac_stream_readb(s, SD_STS); + + dev_vdbg(bus->dev, "stream %d status 0x%x\n", + s->index, sd_status); + + snd_hdac_stream_writeb(s, SD_STS, SD_INT_MASK); + + if (!s->substream || + !s->running || + (sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0) + continue; + + /* Inform ALSA only in case not do that with IPC */ + if (sof_hda->no_ipc_position) + snd_pcm_period_elapsed(s->substream); + + } + } + + return IRQ_HANDLED; +} + +int hda_dsp_stream_init(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_stream *stream; + struct hdac_stream *hstream; + struct pci_dev *pci = sdev->pci; + int sd_offset; + int i, num_playback, num_capture, num_total, ret; + u32 gcap; + + gcap = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCAP); + dev_dbg(sdev->dev, "hda global caps = 0x%x\n", gcap); + + /* get stream count from GCAP */ + num_capture = (gcap >> 8) & 0x0f; + num_playback = (gcap >> 12) & 0x0f; + num_total = num_playback + num_capture; + + dev_dbg(sdev->dev, "detected %d playback and %d capture streams\n", + num_playback, num_capture); + + if (num_playback >= SOF_HDA_PLAYBACK_STREAMS) { + dev_err(sdev->dev, "error: too many playback streams %d\n", + num_playback); + return -EINVAL; + } + + if (num_capture >= SOF_HDA_CAPTURE_STREAMS) { + dev_err(sdev->dev, "error: too many capture streams %d\n", + num_playback); + return -EINVAL; + } + + /* mem alloc for the position buffer */ + /* TODO: check position buffer update */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, + SOF_HDA_DPIB_ENTRY_SIZE * num_total, + &bus->posbuf); + if (ret < 0) { + dev_err(sdev->dev, "error: posbuffer dma alloc failed\n"); + return -ENOMEM; + } + + /* mem alloc for the CORB/RIRB ringbuffers */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, + PAGE_SIZE, &bus->rb); + if (ret < 0) { + dev_err(sdev->dev, "error: RB alloc failed\n"); + return -ENOMEM; + } + + /* create capture streams */ + for (i = 0; i < num_capture; i++) { + + stream = devm_kzalloc(sdev->dev, sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; + + stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] + + SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i; + + stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] + + SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total + + SOF_HDA_PPLC_INTERVAL * i; + + /* do we support SPIB */ + if (sdev->bar[HDA_DSP_SPIB_BAR]) { + stream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] + + SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + + SOF_HDA_SPIB_SPIB; + + stream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] + + SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + + SOF_HDA_SPIB_MAXFIFO; + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_DRSM) + /* FIXME: Remove? HDAC doesn't use DRSM so has no drsm_addr */ + /* do we support DRSM */ + if (sdev->bar[HDA_DSP_DRSM_BAR]) + stream->drsm_addr = sdev->bar[HDA_DSP_DRSM_BAR] + + SOF_HDA_DRSM_BASE + SOF_HDA_DRSM_INTERVAL * i; +#endif + + hstream = &stream->hstream; + hstream->bus = bus; + hstream->sd_int_sta_mask = 1 << i; + hstream->index = i; + sd_offset = SOF_STREAM_SD_OFFSET(hstream); + hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset; + hstream->stream_tag = i + 1; + hstream->opened = false; + hstream->running = false; + hstream->direction = SNDRV_PCM_STREAM_CAPTURE; + + /* memory alloc for stream BDL */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, + HDA_DSP_BDL_SIZE, &hstream->bdl); + if (ret < 0) { + dev_err(sdev->dev, "error: stream bdl dma alloc failed\n"); + return -ENOMEM; + } + hstream->posbuf = (__le32 *)(bus->posbuf.area + + (hstream->index) * 8); + + list_add_tail(&hstream->list, &bus->stream_list); + } + + /* create playback streams */ + for (i = num_capture; i < num_total; i++) { + + stream = devm_kzalloc(sdev->dev, sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; + + /* we always have DSP support */ + stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] + + SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i; + + stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] + + SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total + + SOF_HDA_PPLC_INTERVAL * i; + + /* do we support SPIB */ + if (sdev->bar[HDA_DSP_SPIB_BAR]) { + stream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] + + SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + + SOF_HDA_SPIB_SPIB; + + stream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] + + SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + + SOF_HDA_SPIB_MAXFIFO; + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_DRSM) + /* FIXME: Remove? HDAC doesn't use DRSM so has no drsm_addr */ + /* do we support DRSM */ + if (sdev->bar[HDA_DSP_DRSM_BAR]) + stream->drsm_addr = sdev->bar[HDA_DSP_DRSM_BAR] + + SOF_HDA_DRSM_BASE + SOF_HDA_DRSM_INTERVAL * i; +#endif + + hstream = &stream->hstream; + hstream->bus = bus; + hstream->sd_int_sta_mask = 1 << i; + hstream->index = i; + sd_offset = SOF_STREAM_SD_OFFSET(hstream); + hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset; + hstream->stream_tag = i - num_capture + 1; + hstream->opened = false; + hstream->running = false; + hstream->direction = SNDRV_PCM_STREAM_PLAYBACK; + + /* mem alloc for stream BDL */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, + HDA_DSP_BDL_SIZE, &hstream->bdl); + if (ret < 0) { + dev_err(sdev->dev, "error: stream bdl dma alloc failed\n"); + return -ENOMEM; + } + + hstream->posbuf = (__le32 *)(bus->posbuf.area + + (hstream->index) * 8); + + list_add_tail(&hstream->list, &bus->stream_list); + } + + return 0; +} + +void hda_dsp_stream_free(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *s, *_s; + struct hdac_ext_stream *stream; + + /* free position buffer */ + if (bus->posbuf.area) + snd_dma_free_pages(&bus->posbuf); + + list_for_each_entry_safe(s, _s, &bus->stream_list, list) { + /* TODO: decouple */ + + /* free bdl buffer */ + if (s->bdl.area) + snd_dma_free_pages(&s->bdl); + list_del(&s->list); + stream = stream_to_hdac_ext_stream(s); + devm_kfree(sdev->dev, stream); + } +} + From 05446fc54a878ee7f4644517903f5c237ec3dc72 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 9 May 2018 17:14:17 +0100 Subject: [PATCH 0118/1995] ASoC: SOF: Intel: Add Intel specific HDA trace operations Add trace operations for Intel based HDA DSPs Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/hda-trace.c | 92 +++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 sound/soc/sof/intel/hda-trace.c diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c new file mode 100644 index 00000000000000..a1c9f1b45dca14 --- /dev/null +++ b/sound/soc/sof/intel/hda-trace.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Jeeja KP +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for generic Intel audio DSP HDA IP + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sof-priv.h" +#include "../ops.h" +#include "hda.h" + +static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev) +{ + struct hdac_ext_stream *stream = sdev->hda->dtrace_stream; + struct hdac_stream *hstream = &stream->hstream; + struct snd_dma_buffer *dmab = &sdev->dmatb; + int ret; + + hstream->bufsize = sdev->dmatb.bytes; + + ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL); + if (ret < 0) + dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret); + + return ret; +} + +int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *tag) +{ + sdev->hda->dtrace_stream = hda_dsp_stream_get_cstream(sdev); + + if (!sdev->hda->dtrace_stream) { + dev_err(sdev->dev, + "error: no available capture stream for DMA trace\n"); + return -ENODEV; + } + + *tag = sdev->hda->dtrace_stream->hstream.stream_tag; + + /* + * initialize capture stream, set BDL address and return corresponding + * stream tag which will be sent to the firmware by IPC message. + */ + return hda_dsp_trace_prepare(sdev); +} + +int hda_dsp_trace_release(struct snd_sof_dev *sdev) +{ + struct hdac_stream *hstream; + + if (sdev->hda->dtrace_stream) { + hstream = &sdev->hda->dtrace_stream->hstream; + hstream->opened = false; + hda_dsp_stream_put_cstream(sdev, + hstream->stream_tag); + sdev->hda->dtrace_stream = NULL; + return 0; + } + + dev_dbg(sdev->dev, "DMA trace stream is not opened!\n"); + return -ENODEV; +} + +int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd) +{ + return hda_dsp_stream_trigger(sdev, sdev->hda->dtrace_stream, cmd); +} From 5c0058a9ac4af36f326354ab2059396e90643f97 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 22 Oct 2018 18:01:21 -0500 Subject: [PATCH 0119/1995] ASoC: SOF: Intel: add support for HDAudio codecs Add probe, init and cleanup routines for HDaudio. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-codec.c | 133 ++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 sound/soc/sof/intel/hda-codec.c diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c new file mode 100644 index 00000000000000..fbf64635b309e6 --- /dev/null +++ b/sound/soc/sof/intel/hda-codec.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Jeeja KP +// Rakesh Ughreja +// Keyon Jie +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../codecs/hdac_hda.h" + +#include "../sof-priv.h" +#include "../ops.h" +#include "hda.h" + +#define IDISP_VID_INTEL 0x80860000 + +/* load the legacy HDA codec driver */ +#ifdef MODULE +static void hda_codec_load_module(struct hda_codec *codec) +{ + char alias[MODULE_NAME_LEN]; + const char *module = alias; + + snd_hdac_codec_modalias(&codec->core, alias, sizeof(alias)); + dev_dbg(&codec->core.dev, "loading codec module: %s\n", module); + request_module(module); +} +#else +static void hda_codec_load_module(struct hda_codec *codec) {} +#endif + +/* probe individual codec */ +static int hda_codec_probe(struct snd_sof_dev *sdev, int address) +{ + struct hda_bus *hbus = sof_to_hbus(sdev); + struct hdac_device *hdev; + struct hdac_hda_priv *hda_priv; + u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) | + (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; + u32 resp = -1; + int ret; + + mutex_lock(&hbus->core.cmd_mutex); + snd_hdac_bus_send_cmd(&hbus->core, hda_cmd); + snd_hdac_bus_get_response(&hbus->core, address, &resp); + mutex_unlock(&hbus->core.cmd_mutex); + if (resp == -1) + return -EIO; + dev_dbg(sdev->dev, "HDA codec #%d probed OK: response: %x\n", + address, resp); + + hda_priv = devm_kzalloc(&hbus->pci->dev, sizeof(*hda_priv), + GFP_KERNEL); + if (!hda_priv) + return -ENOMEM; + + hda_priv->codec.bus = hbus; + hdev = &hda_priv->codec.core; + + ret = snd_hdac_ext_bus_device_init(&hbus->core, address, hdev); + if (ret < 0) + return ret; + + /* use legacy bus only for HDA codecs, idisp uses ext bus */ + if ((resp & 0xFFFF0000) != IDISP_VID_INTEL) { + hdev->type = HDA_DEV_LEGACY; + hda_codec_load_module(&hda_priv->codec); + } + + return 0; +} + +/* Codec initialization */ +int hda_codec_probe_bus(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int i, ret = 0; + + /* probe codecs in avail slots */ + for (i = 0; i < HDA_MAX_CODECS; i++) { + + if (!(bus->codec_mask & (1 << i))) + continue; + + ret = hda_codec_probe(sdev, i); + if (ret < 0) { + dev_err(bus->dev, "codec #%d probe error, ret: %d\n", + i, ret); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL(hda_codec_probe_bus); + +int hda_codec_i915_init(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int ret; + + /* i915 exposes a HDA codec for HDMI audio */ + ret = snd_hdac_i915_init(bus); + if (ret < 0) + return ret; + + ret = snd_hdac_display_power(bus, true); + if (ret < 0) + dev_err(bus->dev, "i915 HDAC power on failed %d\n", ret); + + return ret; +} +EXPORT_SYMBOL(hda_codec_i915_init); + +MODULE_LICENSE("Dual BSD/GPL"); From 4ab0b3272091f11a455083c32737ae26d4e51832 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Tue, 3 Jul 2018 10:41:41 +0800 Subject: [PATCH 0120/1995] ASoC: SOF: intel: SKL, CNL, APL platform DAIs Signed-off-by: Liam Girdwood Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-dai.c | 279 ++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 sound/soc/sof/intel/hda-dai.c diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c new file mode 100644 index 00000000000000..dd68cbf00014dd --- /dev/null +++ b/sound/soc/sof/intel/hda-dai.c @@ -0,0 +1,279 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Keyon Jie +// + +#include +#include +#include +#include "../sof-priv.h" +#include "hda.h" + +#define SKL_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + +struct hda_pipe_params { + u8 host_dma_id; + u8 link_dma_id; + u32 ch; + u32 s_freq; + u32 s_fmt; + u8 linktype; + snd_pcm_format_t format; + int link_index; + int stream; + unsigned int host_bps; + unsigned int link_bps; +}; + +/* TODO: add hda dai params in tplg, and configure this in topology parsing */ +static int hda_link_dma_params(struct hdac_ext_stream *stream, + struct hda_pipe_params *params) +{ + struct hdac_stream *hstream = &stream->hstream; + struct hdac_bus *bus = hstream->bus; + unsigned int format_val; + struct hdac_ext_link *link; + + snd_hdac_ext_stream_decouple(bus, stream, true); + snd_hdac_ext_link_stream_reset(stream); + + format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch, + params->format, + params->link_bps, 0); + + dev_dbg(bus->dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", + format_val, params->s_freq, params->ch, params->format); + + snd_hdac_ext_link_stream_setup(stream, format_val); + + list_for_each_entry(link, &bus->hlink_list, list) { + if (link->index == params->link_index) + snd_hdac_ext_link_set_stream_id(link, + hstream->stream_tag); + } + + stream->link_prepared = 1; + + return 0; +} + +static int hda_link_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_bus *bus = hstream->bus; + struct hdac_ext_stream *link_dev; + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct hda_pipe_params p_params = {0}; + struct hdac_ext_link *link; + int stream_tag; + + link_dev = snd_hdac_ext_stream_assign(bus, substream, + HDAC_EXT_STREAM_TYPE_LINK); + if (!link_dev) + return -EBUSY; + + snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); + + link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name); + if (!link) + return -EINVAL; + + stream_tag = hdac_stream(link_dev)->stream_tag; + + /* set the stream tag in the codec dai dma params */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0); + else + snd_soc_dai_set_tdm_slot(codec_dai, 0, stream_tag, 0, 0); + + p_params.s_fmt = snd_pcm_format_width(params_format(params)); + p_params.ch = params_channels(params); + p_params.s_freq = params_rate(params); + p_params.stream = substream->stream; + p_params.link_dma_id = stream_tag - 1; + p_params.link_index = link->index; + p_params.format = params_format(params); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + p_params.link_bps = codec_dai->driver->playback.sig_bits; + else + p_params.link_bps = codec_dai->driver->capture.sig_bits; + + return hda_link_dma_params(link_dev, &p_params); +} + +static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct hdac_ext_stream *link_dev = + snd_soc_dai_get_dma_data(dai, substream); + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_bus *bus = hstream->bus; + struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream); + + dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); + switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + snd_hdac_ext_link_stream_start(link_dev); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + snd_hdac_ext_link_stream_clear(link_dev); + if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) + snd_hdac_ext_stream_decouple(bus, stream, false); + break; + + default: + return -EINVAL; + } + return 0; +} + +static int hda_link_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_bus *bus = hstream->bus; + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct hdac_ext_stream *link_dev = + snd_soc_dai_get_dma_data(dai, substream); + struct hdac_ext_link *link; + + link = snd_hdac_ext_bus_get_link(bus, rtd->codec_dai->component->name); + if (!link) + return -EINVAL; + + snd_hdac_ext_link_clear_stream_id(link, + hdac_stream(link_dev)->stream_tag); + snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); + + link_dev->link_prepared = 0; + + return 0; +} + +static const struct snd_soc_dai_ops hda_link_dai_ops = { + .hw_params = hda_link_hw_params, + .hw_free = hda_link_hw_free, + .trigger = hda_link_pcm_trigger, +}; +#endif + +/* + * common dai driver for skl+ platforms. + * some products who use this DAI array only physically have a subset of + * the DAIs, but no harm is done here by adding the whole set. + */ +struct snd_soc_dai_driver skl_dai[] = { +{ + .name = "SSP0 Pin", + .playback = SOF_DAI_STREAM("ssp0 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), + .capture = SOF_DAI_STREAM("ssp0 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), +}, +{ + .name = "SSP1 Pin", + .playback = SOF_DAI_STREAM("ssp1 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), + .capture = SOF_DAI_STREAM("ssp1 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), +}, +{ + .name = "SSP2 Pin", + .playback = SOF_DAI_STREAM("ssp2 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), + .capture = SOF_DAI_STREAM("ssp2 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), +}, +{ + .name = "SSP3 Pin", + .playback = SOF_DAI_STREAM("ssp3 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), + .capture = SOF_DAI_STREAM("ssp3 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), +}, +{ + .name = "SSP4 Pin", + .playback = SOF_DAI_STREAM("ssp4 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), + .capture = SOF_DAI_STREAM("ssp4 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), +}, +{ + .name = "SSP5 Pin", + .playback = SOF_DAI_STREAM("ssp5 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), + .capture = SOF_DAI_STREAM("ssp5 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), +}, +{ + .name = "DMIC01 Pin", + .capture = SOF_DAI_STREAM("DMIC01 Rx", 1, 4, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), +}, +{ + .name = "DMIC16k Pin", + .capture = SOF_DAI_STREAM("DMIC16k Rx", 1, 4, + SNDRV_PCM_RATE_16000, SKL_FORMATS), +}, +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +{ + .name = "iDisp1 Pin", + .ops = &hda_link_dai_ops, + .playback = SOF_DAI_STREAM("iDisp1 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), +}, +{ + .name = "iDisp2 Pin", + .ops = &hda_link_dai_ops, + .playback = SOF_DAI_STREAM("iDisp2 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), +}, +{ + .name = "iDisp3 Pin", + .ops = &hda_link_dai_ops, + .playback = SOF_DAI_STREAM("iDisp3 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), +}, +{ + .name = "Analog CPU DAI", + .ops = &hda_link_dai_ops, + .playback = SOF_DAI_STREAM("Analog CPU Playback", 1, 16, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), + .capture = SOF_DAI_STREAM("Analog CPU Capture", 1, 16, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), +}, +{ + .name = "Digital CPU DAI", + .ops = &hda_link_dai_ops, + .playback = SOF_DAI_STREAM("Digital CPU Playback", 1, 16, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), + .capture = SOF_DAI_STREAM("Digital CPU Capture", 1, 16, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), +}, +{ + .name = "Alt Analog CPU DAI", + .ops = &hda_link_dai_ops, + .playback = SOF_DAI_STREAM("Alt Analog CPU Playback", 1, 16, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), + .capture = SOF_DAI_STREAM("Alt Analog CPU Capture", 1, 16, + SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), +}, +#endif +}; From 9e14b0284f6c0f2d6b3254f4c28fa9b25f45cf90 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 9 May 2018 17:14:18 +0100 Subject: [PATCH 0121/1995] ASoC: SOF: Intel: Add platform differentiation for SKL, APL and CNL Add platform differentiation operations for different Intel HDA DSP platforms. Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/apl.c | 107 ++++++++++++++++ sound/soc/sof/intel/cnl.c | 248 ++++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/skl.c | 100 +++++++++++++++ 3 files changed, 455 insertions(+) create mode 100644 sound/soc/sof/intel/apl.c create mode 100644 sound/soc/sof/intel/cnl.c create mode 100644 sound/soc/sof/intel/skl.c diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c new file mode 100644 index 00000000000000..82edc77eeac1f7 --- /dev/null +++ b/sound/soc/sof/intel/apl.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Jeeja KP +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for audio DSP on Apollolake and GeminiLake + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sof-priv.h" +#include "../ops.h" +#include "hda.h" + +static const struct snd_sof_debugfs_map apl_dsp_debugfs[] = { + {"hda", HDA_DSP_HDA_BAR, 0, 0x4000}, + {"pp", HDA_DSP_PP_BAR, 0, 0x1000}, + {"dsp", HDA_DSP_BAR, 0, 0x10000}, +}; + +/* apollolake ops */ +struct snd_sof_dsp_ops sof_apl_ops = { + /* probe and remove */ + .probe = hda_dsp_probe, + .remove = hda_dsp_remove, + + /* Register IO */ + .write = hda_dsp_write, + .read = hda_dsp_read, + .write64 = hda_dsp_write64, + .read64 = hda_dsp_read64, + + /* Block IO */ + .block_read = hda_dsp_block_read, + .block_write = hda_dsp_block_write, + + /* doorbell */ + .irq_handler = hda_dsp_ipc_irq_handler, + .irq_thread = hda_dsp_ipc_irq_thread, + + /* mailbox */ + .mailbox_read = hda_dsp_mailbox_read, + .mailbox_write = hda_dsp_mailbox_write, + + /* ipc */ + .send_msg = hda_dsp_ipc_send_msg, + .get_reply = hda_dsp_ipc_get_reply, + .fw_ready = hda_dsp_ipc_fw_ready, + .is_ready = hda_dsp_ipc_is_ready, + .cmd_done = hda_dsp_ipc_cmd_done, + + /* debug */ + .debug_map = apl_dsp_debugfs, + .debug_map_count = ARRAY_SIZE(apl_dsp_debugfs), + .dbg_dump = hda_dsp_dump, + + /* stream callbacks */ + .pcm_open = hda_dsp_pcm_open, + .pcm_close = hda_dsp_pcm_close, + .pcm_hw_params = hda_dsp_pcm_hw_params, + .pcm_trigger = hda_dsp_pcm_trigger, + .pcm_pointer = hda_dsp_pcm_pointer, + + /* firmware loading */ + .load_firmware = hda_dsp_cl_load_fw, + + /* firmware run */ + .run = hda_dsp_cl_boot_firmware, + + /* trace callback */ + .trace_init = hda_dsp_trace_init, + .trace_release = hda_dsp_trace_release, + .trace_trigger = hda_dsp_trace_trigger, + + /* DAI drivers */ + .drv = skl_dai, + .num_drv = SOF_SKL_NUM_DAIS, + + /* PM */ + .suspend = hda_dsp_suspend, + .resume = hda_dsp_resume, + .runtime_suspend = hda_dsp_runtime_suspend, + .runtime_resume = hda_dsp_runtime_resume, +}; +EXPORT_SYMBOL(sof_apl_ops); diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c new file mode 100644 index 00000000000000..0fb531b08ea3af --- /dev/null +++ b/sound/soc/sof/intel/cnl.c @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Jeeja KP +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for audio DSP on Cannonlake. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sof-priv.h" +#include "../ops.h" +#include "hda.h" + +static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = { + {"hda", HDA_DSP_HDA_BAR, 0, 0x4000}, + {"pp", HDA_DSP_PP_BAR, 0, 0x1000}, + {"dsp", HDA_DSP_BAR, 0, 0x10000}, +}; + +static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); + +static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) +{ + struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + u32 hipci, hipcida, hipctdr, hipctdd, msg = 0, msg_ext = 0; + irqreturn_t ret = IRQ_NONE; + + /* here we handle IPC interrupts only */ + if (!(sdev->irq_status & HDA_DSP_ADSPIS_IPC)) + return ret; + + hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); + + /* reply message from DSP */ + if (hipcida & CNL_DSP_REG_HIPCIDA_DONE) { + hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCIDR); + msg_ext = hipci & CNL_DSP_REG_HIPCIDR_MSG_MASK; + msg = hipcida & CNL_DSP_REG_HIPCIDA_MSG_MASK; + + dev_vdbg(sdev->dev, + "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n", + msg, msg_ext); + + /* mask Done interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCCTL, + CNL_DSP_REG_HIPCCTL_DONE, 0); + + /* + * handle immediate reply from DSP core. If the msg is + * found, set done bit in cmd_done which is called at the + * end of message processing function, else set it here + * because the done bit can't be set in cmd_done function + * which is triggered by msg + */ + if (snd_sof_ipc_reply(sdev, msg)) + cnl_ipc_cmd_done(sdev, SOF_IPC_DSP_REPLY); + + ret = IRQ_HANDLED; + } + + hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR); + + /* new message from DSP */ + if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) { + hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCTDD); + msg = hipctdr & CNL_DSP_REG_HIPCTDR_MSG_MASK; + msg_ext = hipctdd & CNL_DSP_REG_HIPCTDD_MSG_MASK; + + dev_vdbg(sdev->dev, + "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n", + msg, msg_ext); + + /* handle messages from DSP */ + if ((hipctdr & SOF_IPC_PANIC_MAGIC_MASK) == + SOF_IPC_PANIC_MAGIC) { + snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext)); + } else { + snd_sof_ipc_msgs_rx(sdev); + } + + /* + * clear busy interrupt to tell dsp controller this + * interrupt has been accepted, not trigger it again + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCTDR, + CNL_DSP_REG_HIPCTDR_BUSY, + CNL_DSP_REG_HIPCTDR_BUSY); + + ret = IRQ_HANDLED; + } + + if (ret == IRQ_HANDLED) { + /* reenable IPC interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); + } + + if (sdev->code_loading) { + sdev->code_loading = 0; + wake_up(&sdev->waitq); + } + + return ret; +} + +static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev, int dir) +{ + if (dir == SOF_IPC_HOST_REPLY) { + /* + * set done bit to ack dsp the msg has been + * processed and send reply msg to dsp + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCTDA, + CNL_DSP_REG_HIPCTDA_DONE, + CNL_DSP_REG_HIPCTDA_DONE); + } else { + /* + * set DONE bit - tell DSP we have received the reply msg + * from DSP, and processed it, don't send more reply to host + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCIDA, + CNL_DSP_REG_HIPCIDA_DONE, + CNL_DSP_REG_HIPCIDA_DONE); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCCTL, + CNL_DSP_REG_HIPCCTL_DONE, + CNL_DSP_REG_HIPCCTL_DONE); + } + + return 0; +} + +static int cnl_ipc_is_ready(struct snd_sof_dev *sdev) +{ + u64 busy, done; + + busy = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR); + done = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); + if ((busy & CNL_DSP_REG_HIPCIDR_BUSY) || + (done & CNL_DSP_REG_HIPCIDA_DONE)) + return 0; + + return 1; +} + +static int cnl_ipc_send_msg(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg) +{ + u32 cmd = msg->header; + + /* send the message */ + hda_dsp_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, + cmd | CNL_DSP_REG_HIPCIDR_BUSY); + + return 0; +} + +/* cannonlake ops */ +struct snd_sof_dsp_ops sof_cnl_ops = { + /* probe and remove */ + .probe = hda_dsp_probe, + .remove = hda_dsp_remove, + + /* Register IO */ + .write = hda_dsp_write, + .read = hda_dsp_read, + .write64 = hda_dsp_write64, + .read64 = hda_dsp_read64, + + /* Block IO */ + .block_read = hda_dsp_block_read, + .block_write = hda_dsp_block_write, + + /* doorbell */ + .irq_handler = hda_dsp_ipc_irq_handler, + .irq_thread = cnl_ipc_irq_thread, + + /* mailbox */ + .mailbox_read = hda_dsp_mailbox_read, + .mailbox_write = hda_dsp_mailbox_write, + + /* ipc */ + .send_msg = cnl_ipc_send_msg, + .get_reply = hda_dsp_ipc_get_reply, + .fw_ready = hda_dsp_ipc_fw_ready, + .is_ready = cnl_ipc_is_ready, + .cmd_done = cnl_ipc_cmd_done, + + /* debug */ + .debug_map = cnl_dsp_debugfs, + .debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs), + .dbg_dump = hda_dsp_dump, + + /* stream callbacks */ + .pcm_open = hda_dsp_pcm_open, + .pcm_close = hda_dsp_pcm_close, + .pcm_hw_params = hda_dsp_pcm_hw_params, + .pcm_trigger = hda_dsp_pcm_trigger, + + /* firmware loading */ + .load_firmware = hda_dsp_cl_load_fw, + + /* firmware run */ + .run = hda_dsp_cl_boot_firmware, + + /* trace callback */ + .trace_init = hda_dsp_trace_init, + .trace_release = hda_dsp_trace_release, + .trace_trigger = hda_dsp_trace_trigger, + + /* DAI drivers */ + .drv = skl_dai, + .num_drv = SOF_SKL_NUM_DAIS, +}; +EXPORT_SYMBOL(sof_cnl_ops); diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c new file mode 100644 index 00000000000000..43b0bc169438fe --- /dev/null +++ b/sound/soc/sof/intel/skl.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Jeeja KP +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for audio DSP on Skylake and Kabylake. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sof-priv.h" +#include "../ops.h" +#include "hda.h" + +static const struct snd_sof_debugfs_map skl_dsp_debugfs[] = { + {"hda", HDA_DSP_HDA_BAR, 0, 0x4000}, + {"pp", HDA_DSP_PP_BAR, 0, 0x1000}, + {"dsp", HDA_DSP_BAR, 0, 0x10000}, +}; + +/* skylake ops */ +struct snd_sof_dsp_ops sof_skl_ops = { + /* probe and remove */ + .probe = hda_dsp_probe, + .remove = hda_dsp_remove, + + /* Register IO */ + .write = hda_dsp_write, + .read = hda_dsp_read, + .write64 = hda_dsp_write64, + .read64 = hda_dsp_read64, + + /* Block IO */ + .block_read = hda_dsp_block_read, + .block_write = hda_dsp_block_write, + + /* doorbell */ + .irq_handler = hda_dsp_ipc_irq_handler, + .irq_thread = hda_dsp_ipc_irq_thread, + + /* mailbox */ + .mailbox_read = hda_dsp_mailbox_read, + .mailbox_write = hda_dsp_mailbox_write, + + /* ipc */ + .send_msg = hda_dsp_ipc_send_msg, + .get_reply = hda_dsp_ipc_get_reply, + .fw_ready = hda_dsp_ipc_fw_ready, + .is_ready = hda_dsp_ipc_is_ready, + .cmd_done = hda_dsp_ipc_cmd_done, + + /* debug */ + .debug_map = skl_dsp_debugfs, + .debug_map_count = ARRAY_SIZE(skl_dsp_debugfs), + .dbg_dump = hda_dsp_dump, + + /* stream callbacks */ + .pcm_open = hda_dsp_pcm_open, + .pcm_close = hda_dsp_pcm_close, + .pcm_hw_params = hda_dsp_pcm_hw_params, + .pcm_trigger = hda_dsp_pcm_trigger, + + /* firmware loading */ + .load_firmware = hda_dsp_cl_load_fw, + + /* firmware run */ + .run = hda_dsp_cl_boot_firmware_skl, + + /* trace callback */ + .trace_init = hda_dsp_trace_init, + .trace_release = hda_dsp_trace_release, + .trace_trigger = hda_dsp_trace_trigger, + + /* DAI drivers */ + .drv = skl_dai, + .num_drv = SOF_SKL_NUM_DAIS, +}; +EXPORT_SYMBOL(sof_skl_ops); From 84da746dd196d0f88a52f9b0bd307204ccf90263 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 22 Oct 2018 21:01:41 -0500 Subject: [PATCH 0122/1995] ASoC: SOF: Intel: add SKL-specific code loader The code loader is different on SKL/KBL and we need a dedicated loader. From APL onwards the same code loader will be used. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Zhu Yingjiang Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/hda-loader-skl.c | 590 +++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 1 + 2 files changed, 591 insertions(+) create mode 100644 sound/soc/sof/intel/hda-loader-skl.c diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c new file mode 100644 index 00000000000000..092bdd98e86960 --- /dev/null +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -0,0 +1,590 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Zhu Yingjiang +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sof-priv.h" +#include "../ops.h" +#include "hda.h" + +#define HDA_SKL_WAIT_TIMEOUT 500 /* 500 msec */ +#define HDA_SKL_CLDMA_MAX_BUFFER_SIZE (32 * PAGE_SIZE) + +/* Stream Reset */ +#define HDA_CL_SD_CTL_SRST_SHIFT 0 +#define HDA_CL_SD_CTL_SRST(x) (((x) & 0x1) << \ + HDA_CL_SD_CTL_SRST_SHIFT) + +/* Stream Run */ +#define HDA_CL_SD_CTL_RUN_SHIFT 1 +#define HDA_CL_SD_CTL_RUN(x) (((x) & 0x1) << \ + HDA_CL_SD_CTL_RUN_SHIFT) + +/* Interrupt On Completion Enable */ +#define HDA_CL_SD_CTL_IOCE_SHIFT 2 +#define HDA_CL_SD_CTL_IOCE(x) (((x) & 0x1) << \ + HDA_CL_SD_CTL_IOCE_SHIFT) + +/* FIFO Error Interrupt Enable */ +#define HDA_CL_SD_CTL_FEIE_SHIFT 3 +#define HDA_CL_SD_CTL_FEIE(x) (((x) & 0x1) << \ + HDA_CL_SD_CTL_FEIE_SHIFT) + +/* Descriptor Error Interrupt Enable */ +#define HDA_CL_SD_CTL_DEIE_SHIFT 4 +#define HDA_CL_SD_CTL_DEIE(x) (((x) & 0x1) << \ + HDA_CL_SD_CTL_DEIE_SHIFT) + +/* FIFO Limit Change */ +#define HDA_CL_SD_CTL_FIFOLC_SHIFT 5 +#define HDA_CL_SD_CTL_FIFOLC(x) (((x) & 0x1) << \ + HDA_CL_SD_CTL_FIFOLC_SHIFT) + +/* Stripe Control */ +#define HDA_CL_SD_CTL_STRIPE_SHIFT 16 +#define HDA_CL_SD_CTL_STRIPE(x) (((x) & 0x3) << \ + HDA_CL_SD_CTL_STRIPE_SHIFT) + +/* Traffic Priority */ +#define HDA_CL_SD_CTL_TP_SHIFT 18 +#define HDA_CL_SD_CTL_TP(x) (((x) & 0x1) << \ + HDA_CL_SD_CTL_TP_SHIFT) + +/* Bidirectional Direction Control */ +#define HDA_CL_SD_CTL_DIR_SHIFT 19 +#define HDA_CL_SD_CTL_DIR(x) (((x) & 0x1) << \ + HDA_CL_SD_CTL_DIR_SHIFT) + +/* Stream Number */ +#define HDA_CL_SD_CTL_STRM_SHIFT 20 +#define HDA_CL_SD_CTL_STRM(x) (((x) & 0xf) << \ + HDA_CL_SD_CTL_STRM_SHIFT) + +#define HDA_CL_SD_CTL_INT(x) \ + (HDA_CL_SD_CTL_IOCE(x) | \ + HDA_CL_SD_CTL_FEIE(x) | \ + HDA_CL_SD_CTL_DEIE(x)) + +#define HDA_CL_SD_CTL_INT_MASK \ + (HDA_CL_SD_CTL_IOCE(1) | \ + HDA_CL_SD_CTL_FEIE(1) | \ + HDA_CL_SD_CTL_DEIE(1)) + +#define DMA_ADDRESS_128_BITS_ALIGNMENT 7 +#define BDL_ALIGN(x) ((x) >> DMA_ADDRESS_128_BITS_ALIGNMENT) + +/* Buffer Descriptor List Lower Base Address */ +#define HDA_CL_SD_BDLPLBA_SHIFT 7 +#define HDA_CL_SD_BDLPLBA_MASK (0x1ffffff << HDA_CL_SD_BDLPLBA_SHIFT) +#define HDA_CL_SD_BDLPLBA(x) \ + ((BDL_ALIGN(lower_32_bits(x)) << HDA_CL_SD_BDLPLBA_SHIFT) & \ + HDA_CL_SD_BDLPLBA_MASK) + +/* Buffer Descriptor List Upper Base Address */ +#define HDA_CL_SD_BDLPUBA_SHIFT 0 +#define HDA_CL_SD_BDLPUBA_MASK (0xffffffff << HDA_CL_SD_BDLPUBA_SHIFT) +#define HDA_CL_SD_BDLPUBA(x) \ + ((upper_32_bits(x) << HDA_CL_SD_BDLPUBA_SHIFT) & \ + HDA_CL_SD_BDLPUBA_MASK) + +/* Software Position in Buffer Enable */ +#define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT 0 +#define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK \ + (1 << HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) + +#define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE(x) \ + (((x) << HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & \ + HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK) + +static int cl_skl_cldma_setup_bdle(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab_data, + u32 **bdlp, int size, int with_ioc) +{ + u32 *bdl = *bdlp; + int frags = 0; + + while (size > 0) { + phys_addr_t addr = virt_to_phys(dmab_data->area + + (frags * size)); + + bdl[0] = cpu_to_le32(lower_32_bits(addr)); + bdl[1] = cpu_to_le32(upper_32_bits(addr)); + + bdl[2] = cpu_to_le32(size); + + size -= size; + bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01); + + bdl += 4; + frags++; + } + + return frags; +} + +static void cl_skl_cldma_stream_run(struct snd_sof_dev *sdev, bool enable) +{ + unsigned char val; + int timeout; + int sd_offset = SOF_HDA_ADSP_LOADER_BASE; + u32 run = enable ? 0x1 : 0; + + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, + HDA_CL_SD_CTL_RUN(1), HDA_CL_SD_CTL_RUN(run)); + + udelay(3); + timeout = 300; + do { + /* waiting for hardware to report the stream Run bit set */ + val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL) + & HDA_CL_SD_CTL_RUN(1); + if (enable && val) + break; + else if (!enable && !val) + break; + udelay(3); + } while (--timeout); + + if (timeout == 0) + dev_err(sdev->dev, "error: failed to set Run bit=%d enable=%d\n", + val, enable); +} + +static void cl_skl_cldma_stream_clear(struct snd_sof_dev *sdev) +{ + int sd_offset = SOF_HDA_ADSP_LOADER_BASE; + + /* make sure Run bit is cleared before setting stream register */ + cl_skl_cldma_stream_run(sdev, 0); + + /* Disable the Interrupt On Completion, FIFO Error Interrupt, + * Descriptor Error Interrupt and set the cldma stream number to 0. + */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, + HDA_CL_SD_CTL_INT_MASK, HDA_CL_SD_CTL_INT(0)); + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, + HDA_CL_SD_CTL_STRM(0xf), HDA_CL_SD_CTL_STRM(0)); + + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, + HDA_CL_SD_BDLPLBA(0)); + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0); + + /* Set the Cyclic Buffer Length to 0. */ + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, 0); + /* Set the Last Valid Index. */ + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, 0); +} + +static void cl_skl_cldma_setup_spb(struct snd_sof_dev *sdev, + unsigned int size, bool enable) +{ + int sd_offset = SOF_DSP_REG_CL_SPBFIFO; + + if (enable) + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + sd_offset + + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, + HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, + HDA_CL_SPBFIFO_SPBFCCTL_SPIBE(1)); + + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPIB, size); +} + +static void cl_skl_cldma_set_intr(struct snd_sof_dev *sdev, bool enable) +{ + u32 val = enable ? HDA_DSP_ADSPIC_CL_DMA : 0; + + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_CL_DMA, val); +} + +static void cl_skl_cldma_cleanup_spb(struct snd_sof_dev *sdev) +{ + int sd_offset = SOF_DSP_REG_CL_SPBFIFO; + + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + sd_offset + + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, + HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, + HDA_CL_SPBFIFO_SPBFCCTL_SPIBE(0)); + + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPIB, 0); +} + +static void cl_skl_cldma_setup_controller(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab_bdl, + unsigned int max_size, u32 count) +{ + int sd_offset = SOF_HDA_ADSP_LOADER_BASE; + /* Clear the stream first and then set it. */ + cl_skl_cldma_stream_clear(sdev); + + /* setting the stream register */ + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, + HDA_CL_SD_BDLPLBA(dmab_bdl->addr)); + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, + HDA_CL_SD_BDLPUBA(dmab_bdl->addr)); + + /* Set the Cyclic Buffer Length. */ + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, max_size); + /* Set the Last Valid Index. */ + snd_sof_dsp_write(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, count - 1); + + /* Set the Interrupt On Completion, FIFO Error Interrupt, + * Descriptor Error Interrupt and the cldma stream number. + */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, + HDA_CL_SD_CTL_INT_MASK, HDA_CL_SD_CTL_INT(1)); + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, + HDA_CL_SD_CTL_STRM(0xf), + HDA_CL_SD_CTL_STRM(1)); +} + +static int cl_stream_prepare_skl(struct snd_sof_dev *sdev) +{ + struct pci_dev *pci = sdev->pci; + int frags = 0; + int ret = 0; + u32 *bdl; + unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; + + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, bufsize, + &sdev->dmab); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to alloc fw buffer: %x\n", + ret); + return ret; + } + + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, bufsize, + &sdev->dmab_bdl); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to alloc blde: %x\n", ret); + snd_dma_free_pages(&sdev->dmab); + return ret; + } + + bdl = (u32 *)sdev->dmab_bdl.area; + frags = cl_skl_cldma_setup_bdle(sdev, &sdev->dmab, &bdl, bufsize, 1); + cl_skl_cldma_setup_controller(sdev, &sdev->dmab_bdl, bufsize, frags); + + return ret; +} + +static void cl_cleanup_skl(struct snd_sof_dev *sdev) +{ + cl_skl_cldma_cleanup_spb(sdev); + cl_skl_cldma_stream_clear(sdev); + snd_dma_free_pages(&sdev->dmab); + snd_dma_free_pages(&sdev->dmab_bdl); + sdev->dmab.area = NULL; +} + +static int cl_dsp_init_skl(struct snd_sof_dev *sdev) +{ + const struct sof_intel_dsp_desc *chip = sdev->hda->desc; + int ret; + + /* check if the core is already enabled, if yes, reset and make it run, + * if not, powerdown and enable it again. + */ + if (hda_dsp_core_is_enabled(sdev, HDA_DSP_CORE_MASK(0))) { + + /* if enabled, reset it, and run the core. */ + ret = hda_dsp_core_stall_reset(sdev, HDA_DSP_CORE_MASK(0)); + if (ret < 0) + goto err; + + ret = hda_dsp_core_run(sdev, HDA_DSP_CORE_MASK(0)); + if (ret < 0) { + dev_err(sdev->dev, "error: dsp core start failed %d\n", + ret); + goto err; + } + } else { + /* if not enabled, power down it first and then powerup and run + * the core. + */ + ret = hda_dsp_core_reset_power_down(sdev, HDA_DSP_CORE_MASK(0)); + if (ret < 0) { + dev_err(sdev->dev, "dsp core0 disable fail: %d\n", ret); + goto err; + } + ret = hda_dsp_enable_core(sdev, HDA_DSP_CORE_MASK(0)); + if (ret < 0) { + dev_err(sdev->dev, "dsp core0 enable fail: %d\n", ret); + goto err; + } + } + + /* prepare DMA for code loader stream */ + ret = cl_stream_prepare_skl(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: dma prepare fw loading err: %x\n", + ret); + return ret; + } + + /* enable the interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); + + /* enable IPC DONE interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, + HDA_DSP_REG_HIPCCTL_DONE, + HDA_DSP_REG_HIPCCTL_DONE); + + /* enable IPC BUSY interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, + HDA_DSP_REG_HIPCCTL_BUSY, + HDA_DSP_REG_HIPCCTL_BUSY); + + /* polling the ROM init status information. */ + ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_STATUS_SKL, + HDA_DSP_ROM_STS_MASK, HDA_DSP_ROM_INIT, + HDA_DSP_INIT_TIMEOUT); + if (ret < 0) + goto err; + + return ret; + +err: + hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); + cl_cleanup_skl(sdev); + hda_dsp_core_reset_power_down(sdev, HDA_DSP_CORE_MASK(0)); + return ret; +} + +static void cl_skl_cldma_fill_buffer(struct snd_sof_dev *sdev, + unsigned int bufsize, + unsigned int copysize, + const void *curr_pos, + bool intr_enable) +{ + /* 1. copy the image into the buffer with the maximum buffer size. */ + unsigned int size = (bufsize == copysize) ? bufsize : copysize; + + memcpy(sdev->dmab.area, curr_pos, size); + + /* 2. Setting the wait condition for every load. */ + sdev->code_loading = 1; + + /* 3. Set the interrupt. */ + if (intr_enable) + cl_skl_cldma_set_intr(sdev, true); + + /* 4. Set the SPB. */ + cl_skl_cldma_setup_spb(sdev, size, true); + + /* 5. Trigger the code loading stream. */ + cl_skl_cldma_stream_run(sdev, true); +} + +static int cl_skl_cldma_wait_interruptible(struct snd_sof_dev *sdev) +{ + int ret = 0; + + if (!wait_event_timeout(sdev->waitq, + !sdev->code_loading, + msecs_to_jiffies(HDA_SKL_WAIT_TIMEOUT))) { + dev_err(sdev->dev, "cldma copy timeout\n"); + dev_err(sdev->dev, "ROM code=0x%x: FW status=0x%x\n", + snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_ERROR), + snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_STATUS)); + + /* TODO: temp debug to be removed */ + dev_err(sdev->dev, "ADSPCS=0x%x: ADSPIC=0x%x: ADSPIS=0x%x INTCTL=0x%x INTSTS=0x%x PPCTL=0x%x PPSTS=0x%x\n", + snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS), + snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPIC), + snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPIS), + snd_sof_dsp_read(sdev, HDA_DSP_BAR, + SOF_HDA_INTCTL), + snd_sof_dsp_read(sdev, HDA_DSP_BAR, + SOF_HDA_INTSTS), + snd_sof_dsp_read(sdev, HDA_DSP_PP_BAR, + SOF_HDA_REG_PP_PPCTL), + snd_sof_dsp_read(sdev, HDA_DSP_PP_BAR, + SOF_HDA_REG_PP_PPSTS)); + ret = -EIO; + goto cleanup; + } + + dev_dbg(sdev->dev, "cldma buffer copy complete\n"); + if (!sdev->code_loading) { + dev_err(sdev->dev, "error: cldma DMA copy failed\n"); + ret = -EIO; + } + +cleanup: + sdev->code_loading = 0; + return ret; +} + +static int +cl_skl_cldma_copy_to_buf(struct snd_sof_dev *sdev, const void *bin, + u32 total_size, u32 bufsize) +{ + int ret = 0; + unsigned int bytes_left = total_size; + const void *curr_pos = bin; + + if (total_size <= 0) + return -EINVAL; + + while (bytes_left > 0) { + + if (bytes_left > bufsize) { + + dev_dbg(sdev->dev, "cldma copy 0x%x bytes\n", + bufsize); + + cl_skl_cldma_fill_buffer(sdev, bufsize, bufsize, + curr_pos, true); + + ret = cl_skl_cldma_wait_interruptible(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: fw failed to load. 0x%x bytes remaining\n", + bytes_left); + cl_skl_cldma_stream_run(sdev, false); + return ret; + } + + bytes_left -= bufsize; + curr_pos += bufsize; + } else { + + dev_dbg(sdev->dev, "cldma copy 0x%x bytes\n", + bytes_left); + + cl_skl_cldma_set_intr(sdev, false); + cl_skl_cldma_fill_buffer(sdev, bufsize, bytes_left, + curr_pos, false); + return 0; + } + } + + return bytes_left; +} + +static int cl_copy_fw_skl(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev); + const struct firmware *fw = plat_data->fw; + unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; + int ret = 0; + + dev_dbg(sdev->dev, "firmware size: 0x%zx buffer size 0x%x\n", fw->size, + bufsize); + + ret = cl_skl_cldma_copy_to_buf(sdev, fw->data, fw->size, bufsize); + if (ret < 0) { + dev_err(sdev->dev, "error: fw copy failed %d\n", ret); + return ret; + } + + ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_STATUS_SKL, + HDA_DSP_ROM_STS_MASK, + HDA_DSP_ROM_FW_FW_LOADED, + HDA_DSP_BASEFW_TIMEOUT); + if (ret < 0) + dev_err(sdev->dev, "firmware transfer timeout!"); + + cl_skl_cldma_stream_run(sdev, false); + cl_cleanup_skl(sdev); + + return ret; +} + +int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev) +{ + int ret; + + ret = cl_dsp_init_skl(sdev); + + /* retry enabling core and ROM load. seemed to help */ + if (ret < 0) { + ret = cl_dsp_init_skl(sdev); + if (ret < 0) { + dev_err(sdev->dev, "Error code=0x%x: FW status=0x%x\n", + snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_ERROR), + snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_STATUS)); + dev_err(sdev->dev, "Core En/ROM load fail:%d\n", ret); + goto irq_err; + } + } + + dev_dbg(sdev->dev, "ROM init successful\n"); + + /* init for booting wait */ + init_waitqueue_head(&sdev->boot_wait); + sdev->boot_complete = false; + + /* at this point DSP ROM has been initialized and should be ready for + * code loading and firmware boot + */ + ret = cl_copy_fw_skl(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: load firmware failed : %d\n", ret); + goto irq_err; + } + + dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); + + return ret; + +irq_err: + hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); + + /* power down DSP */ + hda_dsp_core_reset_power_down(sdev, HDA_DSP_CORE_MASK(0)); + cl_cleanup_skl(sdev); + + dev_err(sdev->dev, "error: load fw failed err: %d\n", ret); + return ret; +} diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 73965b93680772..6a31a8b312a594 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -52,6 +52,7 @@ #define SOF_HDA_PP_CAP_ID 0x3 #define SOF_HDA_REG_PP_PPCH 0x10 #define SOF_HDA_REG_PP_PPCTL 0x04 +#define SOF_HDA_REG_PP_PPSTS 0x08 #define SOF_HDA_PPCTL_PIE BIT(31) #define SOF_HDA_PPCTL_GPROCEN BIT(30) From 0d69ea40914b3311f5e2ca3dd235c72e34a6c9a4 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:35:47 +0000 Subject: [PATCH 0123/1995] ASoC: SOF: Add VirtIO support Add support for running SOF on multiple VMs within the same HW. Signed-off-by: Liam Girdwood --- sound/soc/sof/virtio-be.c | 126 ++++++++++++++++++++++++++++++++++++ sound/soc/sof/virtio-fe.c | 130 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+) create mode 100644 sound/soc/sof/virtio-be.c create mode 100644 sound/soc/sof/virtio-fe.c diff --git a/sound/soc/sof/virtio-be.c b/sound/soc/sof/virtio-be.c new file mode 100644 index 00000000000000..4c07caeba41b0c --- /dev/null +++ b/sound/soc/sof/virtio-be.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * + * Author: Luo Xionghu + * Liam Girdwood + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sof-priv.h" +#include "ops.h" + +/* BE driver + * + * This driver will create IO Queues for communition from FE drivers. + * The FE driver will send real IPC structures over the queue and then + * the BE driver will send the structures directlt to the DSP. The BE will + * get the IPC reply from the DSP and send it back to the FE over the queue. + * + * The virt IO message Q handlers in this file will :- + * + * 1) Check that the message is valid and not for any componenets that don't + * belong to the guest. + * + * 2) Call snd_sof_dsp_tx_msg(struct snd_sof_dev *sdev, + * struct snd_sof_ipc_msg *msg) to send the message to the DSP. + * + * Replies will be sent back using a similar method. + */ + +static int sof_virtio_validate(struct virtio_device *dev) +{ + /* do we need this func ?? */ + return 0; +} + +static int sof_virtio_probe(struct virtio_device *dev) +{ + /* register fe device with sof core */ + //snd_sof_virtio_register_fe(dev); + + /* create our virtqueues */s + + /* send topology data to fe via virtq */ + + return 0; +} + +static void sof_virtio_remove(struct virtio_device *dev) +{ + /* remove topology from fe via virtqueue */ + + /* destroy virtqueue */ +} + +#ifdef CONFIG_PM +static int sof_virtio_freeze(struct virtio_device *dev) +{ + /* pause and suspend any streams for this FE */ + return 0; +} + +static int sof_virtio_restore(struct virtio_device *dev) +{ + /* restore and unpause any streams for this FE */ + return 0; +} +#endif + +/* IDs of FEs */ +static const struct virtio_device_id *fe_id_table[] + { +}; + +static struct virtio_driver sof_be_virtio_driver = { + .driver = { + .name = "sof-virtio-be", + .owner = THIS_MODULE, + }, + + .id_table = fe_id_table, + + //const unsigned int *feature_table; + //unsigned int feature_table_size; + //const unsigned int *feature_table_legacy; + //unsigned int feature_table_size_legacy; + + validate = sof_virtio_validate, + probe = sof_virtio_probe, + remove = sof_virtio_remove, + +#ifdef CONFIG_PM + freeze = sof_virtio_freeze, + restore = sof_virtio_restore, +#endif +}; + +/* this will be called by sof core when core is ready */ +int sof_virtio_register(struct snd_sof_dev *sdev) +{ + int ret; + + ret = register_virtio_driver(&sof_be_virtio_driver); + /* do we need to do anythig else here */ + return ret; +} + +/* called by sof core when driver is removed */ +void sof_virtio_unregister(struct snd_sof_dev *sdev) +{ + unregister_virtio_driver(&sof_be_virtio_driver); + /* do we need to do anythig else here */ +} diff --git a/sound/soc/sof/virtio-fe.c b/sound/soc/sof/virtio-fe.c new file mode 100644 index 00000000000000..1019e65876b923 --- /dev/null +++ b/sound/soc/sof/virtio-fe.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * + * Author: Luo Xionghu + * Liam Girdwood + */ + +/* + * virt IO FE driver + * + * The SOF driver thinks this driver is another audio DSP, however the calls + * made by the SOF driver core do not directly go to HW, but over a virtIO + * message Q to the virtIO BE driver. + * + * The virtIO message Q will use the *exact* same IPC structures as we currently + * use in the mailbox. + * + * Guest OS SOF core -> SOF FE -> virtIO Q -> SOF BE -> + * System OS SOF core -> DSP + * + * The mailbox IO and TX/RX msg functions below will do IO on the virt IO Q. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sof-priv.h" +#include "ops.h" +#include "intel.h" + +/* + * IPC Firmware ready. + */ +static int virtio_fe_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) +{ + /* not needed for FE ? */ + return 0; +} + +/* + * IPC Mailbox IO + */ + +static void virtio_fe_mailbox_write(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes) +{ + /* write data to message Q buffer before sending message */ +} + +static void virtio_fe_mailbox_read(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes) +{ + /* read data from message Q buffer after receiving message */ +} + +static int virtio_fe_tx_busy(struct snd_sof_dev *sdev) +{ + /* return 1 if tx message Q is busy */ +} + +static int virtio_fe_tx_msg(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg) +{ + /* write msg to the virtio queue message for BE */ + + return 0; +} + +static int virtio_fe_rx_msg(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg) +{ + /* read the virtio queue message from BE and copy to msg */ + return 0; +} + +/* + * Probe and remove. + */ + +static int virtio_fe_probe(struct snd_sof_dev *sdev) +{ + /* register virtio device */ + + /* conenct virt queues to BE */ +} + +static int virtio_fe_remove(struct snd_sof_dev *sdev) +{ + /* free virtio resurces and unregister device */ +} + +/* baytrail ops */ +struct snd_sof_dsp_ops snd_sof_virtio_fe_ops = { + /* device init */ + .probe = virtio_fe_probe, + .remove = virtio_fe_remove, + + /* mailbox */ + .mailbox_read = virtio_fe_mailbox_read, + .mailbox_write = virtio_fe_mailbox_write, + + /* ipc */ + .tx_msg = virtio_fe_tx_msg, + .rx_msg = virtio_fe_rx_msg, + .fw_ready = virtio_fe_fw_ready, + .tx_busy = virtio_fe_tx_busy, + + /* module loading */ +// .load_module = snd_sof_parse_module_memcpy, + + /*Firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, +}; +EXPORT_SYMBOL(snd_sof_virtio_fe_ops); + +MODULE_LICENSE("Dual BSD/GPL"); From a6b204b8fafdae3ac96d0b6751849b54b315d26d Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:36:46 +0000 Subject: [PATCH 0124/1995] ASoC: SOF: Add SPI device support Add support for SPI based DSP devices. Signed-off-by: Liam Girdwood --- sound/soc/sof/hw-spi.c | 317 ++++++++++++++++++++++++++++++++++++ sound/soc/sof/hw-spi.h | 6 + sound/soc/sof/sof-spi-dev.c | 195 ++++++++++++++++++++++ 3 files changed, 518 insertions(+) create mode 100644 sound/soc/sof/hw-spi.c create mode 100644 sound/soc/sof/hw-spi.h create mode 100644 sound/soc/sof/sof-spi-dev.c diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c new file mode 100644 index 00000000000000..75b8ff857dc7ce --- /dev/null +++ b/sound/soc/sof/hw-spi.c @@ -0,0 +1,317 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +/* + * Hardware interface for audio DSPs via SPI + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "sof-priv.h" +#include "ops.h" + +/* + * Memory copy. + */ + +static void spi_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, + size_t size) +{ + u8 *buf; + int ret; + + if (offset) { + buf = kmalloc(size + offset, GFP_KERNEL); + if (!buf) { + dev_err(sdev->dev, "Buffer allocation failed\n"); + return; + } + } else { + buf = dest; + } + + ret = spi_read(to_spi_device(sdev->dev), buf, size + offset); + if (ret < 0) + dev_err(sdev->dev, "SPI read failed: %d\n", ret); + + if (offset) { + memcpy(dest, buf + offset, size); + kfree(buf); + } +} + +static void spi_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, + size_t size) +{ + int ret; + u8 *buf; + + if (offset) { + buf = kmalloc(size + offset, GFP_KERNEL); + if (!buf) { + dev_err(sdev->dev, "Buffer allocation failed\n"); + return; + } + + /* Use Read-Modify-Wwrite */ + ret = spi_read(to_spi_device(sdev->dev), buf, size + offset); + if (ret < 0) { + dev_err(sdev->dev, "SPI read failed: %d\n", ret); + goto free; + } + + memcpy(buf + offset, src, size); + } else { + buf = src; + } + + ret = spi_write(to_spi_device(sdev->dev), buf, size + offset); + if (ret < 0) + dev_err(sdev->dev, "SPI write failed: %d\n", ret); + +free: + if (offset) + kfree(buf); +} + +/* + * IPC Firmware ready. + */ +static int spi_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; + struct sof_ipc_fw_version *v = &fw_ready->version; + + dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x\n", msg_id); + + // read local buffer with SPI data + + dev_info(sdev->dev, "Firmware info: version %d:%d-%s build %d on %s:%s\n", + v->major, v->minor, v->tag, v->build, v->date, v->time); + + return 0; +} + +/* + * IPC Mailbox IO + */ + +static void spi_mailbox_write(struct snd_sof_dev *sdev __maybe_unused, + u32 offset __maybe_unused, + void *message __maybe_unused, + size_t bytes __maybe_unused) +{ + /* + * this will copy to a local memory buffer that will be sent to DSP via + * SPI at next IPC + */ +} + +static void spi_mailbox_read(struct snd_sof_dev *sdev __maybe_unused, + u32 offset __maybe_unused, + void *message, size_t bytes) +{ + memset(message, 0, bytes); + + /* + * this will copy from a local memory buffer that was received from + * DSP via SPI at last IPC + */ +} + +/* + * IPC Doorbell IRQ handler and thread. + */ + +/* + * If the handler only has to wake up the thread, we might use the standard one + * as well + */ +static irqreturn_t spi_irq_handler(int irq __maybe_unused, void *context) +{ + const struct snd_sof_dev *sdev = context; + const struct platform_device *pdev = + container_of(sdev->parent, struct platform_device, dev); + struct snd_sof_pdata *sof_pdata = dev_get_platdata(&pdev->dev); + + // on SPI based devices this will likely come via a SoC GPIO IRQ + + // check if GPIO is assetred and if so run thread. + if (sof_pdata->gpio >= 0 && + gpio_get_value(sof_pdata->gpio) == sof_pdata->active) + return IRQ_WAKE_THREAD; + + return IRQ_NONE; +} + +static irqreturn_t spi_irq_thread(int irq __maybe_unused, void *context __maybe_unused) +{ + // read SPI data into local buffer and determine IPC cmd or reply + + /* + * if reply. Handle Immediate reply from DSP Core and set DSP + * state to ready + */ + + /* if cmd, Handle messages from DSP Core */ + + return IRQ_HANDLED; +} + +static int spi_is_ready(struct snd_sof_dev *sdev __maybe_unused) +{ + // use local variable to store DSP command state. either DSP is ready + // for new cmd or still processing current cmd. + + return 1; +} + +static int spi_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + /* send the message */ + spi_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + + return 0; +} + +static int spi_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + struct sof_ipc_reply reply; + int ret = 0; + u32 size; + + /* get reply */ + spi_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); + if (reply.error < 0) { + size = sizeof(reply); + ret = reply.error; + } else { + /* reply correct size ? */ + if (reply.hdr.size != msg->reply_size) { + dev_err(sdev->dev, "error: reply expected 0x%zx got 0x%x bytes\n", + msg->reply_size, reply.hdr.size); + size = msg->reply_size; + ret = -EINVAL; + } else { + size = reply.hdr.size; + } + } + + /* read the message */ + if (msg->msg_data && size > 0) + spi_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, + size); + + return ret; +} + +/* + * Probe and remove. + */ + +static int spi_sof_probe(struct snd_sof_dev *sdev) +{ + struct platform_device *pdev = + container_of(sdev->parent, struct platform_device, dev); + struct snd_sof_pdata *sof_pdata = dev_get_platdata(&pdev->dev); + /* get IRQ from Device tree or ACPI - register our IRQ */ + struct irq_data *irqd; + struct spi_device *spi = to_spi_device(pdev->dev.parent); + unsigned int irq_trigger, irq_sense; + int ret; + + sdev->ipc_irq = spi->irq; + dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); + irqd = irq_get_irq_data(sdev->ipc_irq); + if (!irqd) + return -EINVAL; + + irq_trigger = irqd_get_trigger_type(irqd); + irq_sense = irq_trigger & IRQ_TYPE_SENSE_MASK; + sof_pdata->active = irq_sense == IRQ_TYPE_EDGE_RISING || + irq_sense == IRQ_TYPE_LEVEL_HIGH; + + ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, + spi_irq_handler, spi_irq_thread, + irq_trigger | IRQF_ONESHOT, + "AudioDSP", sdev); + if (ret < 0) + dev_err(sdev->dev, "error: failed to register IRQ %d\n", + sdev->ipc_irq); + + return ret; +} + +static int spi_sof_remove(struct snd_sof_dev *sdev) +{ + return 0; +} + +static int spi_cmd_done(struct snd_sof_dev *sof_dev __maybe_unused, int dir __maybe_unused) +{ + return 0; +} + +/* SPI SOF ops */ +struct snd_sof_dsp_ops snd_sof_spi_ops = { + /* device init */ + .probe = spi_sof_probe, + .remove = spi_sof_remove, + + /* Block IO */ + .block_read = spi_block_read, + .block_write = spi_block_write, + + /* doorbell */ + .irq_handler = spi_irq_handler, + .irq_thread = spi_irq_thread, + + /* mailbox */ + .mailbox_read = spi_mailbox_read, + .mailbox_write = spi_mailbox_write, + + /* ipc */ + .send_msg = spi_send_msg, + .get_reply = spi_get_reply, + .fw_ready = spi_fw_ready, + .is_ready = spi_is_ready, + .cmd_done = spi_cmd_done, + + /* debug */ + .debug_map = NULL/*spi_debugfs*/, + .debug_map_count = 0/*ARRAY_SIZE(spi_debugfs)*/, + .dbg_dump = NULL/*spi_dump*/, + + /* module loading */ + .load_module = snd_sof_parse_module_memcpy, + + /*Firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, +}; +EXPORT_SYMBOL(snd_sof_spi_ops); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/hw-spi.h b/sound/soc/sof/hw-spi.h new file mode 100644 index 00000000000000..1929856eabec90 --- /dev/null +++ b/sound/soc/sof/hw-spi.h @@ -0,0 +1,6 @@ +#ifndef HW_SPI_H +#define HW_SPI_H + +extern struct snd_sof_dsp_ops snd_sof_spi_ops; + +#endif diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c new file mode 100644 index 00000000000000..dc5867b7fa4a4e --- /dev/null +++ b/sound/soc/sof/sof-spi-dev.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sof-priv.h" +#include "hw-spi.h" + +static const struct dev_pm_ops sof_spi_pm = { + SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) + SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, + NULL) + .suspend_late = snd_sof_suspend_late, +}; + +/* FIXME: replace with some meaningful values */ +static struct snd_sof_machine sof_spi_machines[] = { + { + .id = "INT343A", + .drv_name = "bxt_alc298s_i2s", + .sof_fw_filename = "intel/sof-spi.ri", + .sof_tplg_filename = "intel/sof-spi.tplg", + .asoc_plat_name = "0000:00:0e.0", + .ops = &snd_sof_spi_ops, + }, +}; + +static const struct sof_dev_desc spi_desc = { + .sof_machines = sof_spi_machines, + .nocodec_fw_filename = "intel/sof-spi.ri", + .nocodec_tplg_filename = "intel/sof-spi.tplg", + .resindex_lpe_base = -1, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, +}; + +static int sof_spi_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + const struct sof_dev_desc *desc = of_device_get_match_data(dev); + struct snd_sof_machine *machines; + struct snd_sof_machine *mach; + struct snd_sof_pdata *sof_pdata; + struct sof_platform_priv *priv; + const char *tplg, *fw; + struct gpio_desc *gpiod; + int ret, irq; + + if (!dev->of_node || !desc) + return -ENODEV; + + machines = desc->sof_machines; + if (!machines) + return -ENODEV; + + dev_dbg(&spi->dev, "SPI DSP detected"); + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + spi_set_drvdata(spi, priv); + + sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); + if (!sof_pdata) + return -ENOMEM; + + ret = of_property_read_string(dev->of_node, "tplg_filename", &tplg); + if (ret < 0 || !tplg) + return -EINVAL; + + ret = of_property_read_string(dev->of_node, "fw_filename", &fw); + if (ret < 0 || !fw) + return -EINVAL; + + /* + * Get an IRQ GPIO descriptor from an "irq-gpios" property + * If the IRQ is optional, use devm_gpiod_get_optional() + */ + gpiod = devm_gpiod_get(dev, "irq", GPIOD_IN); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + + sof_pdata->gpio = desc_to_gpio(gpiod); + + irq = gpiod_to_irq(gpiod); + if (irq < 0) + return irq; + + /* TODO: add any required regulators */ + + /* use nocodec machine atm */ + dev_err(dev, "No matching ASoC machine driver found - using nocodec\n"); + sof_pdata->drv_name = "sof-nocodec"; + mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); + if (!mach) + return -ENOMEM; + + mach->drv_name = "sof-nocodec"; + /* + * desc->nocodec_*_filename are selected as long as nocodec is used. + * Later machine->*_filename will have to be used. + */ + mach->sof_fw_filename = desc->nocodec_fw_filename; + mach->sof_tplg_filename = desc->nocodec_tplg_filename; + mach->ops = machines[0].ops; + mach->asoc_plat_name = "sof-platform"; + + sof_pdata->id = -1; + sof_pdata->name = dev_name(&spi->dev); + sof_pdata->sof_machine = mach; + sof_pdata->desc = desc; + priv->sof_pdata = sof_pdata; + sof_pdata->dev = dev; + sof_pdata->type = SOF_DEVICE_SPI; + + /* register sof-audio platform driver */ + ret = sof_create_platform_device(priv); + if (ret) { + dev_err(dev, "error: failed to create platform device!\n"); + return ret; + } + + spi->irq = irq; + + /* allow runtime_pm */ + pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY); + pm_runtime_use_autosuspend(dev); + pm_runtime_allow(dev); + + return ret; +} + +static int sof_spi_remove(struct spi_device *spi) +{ + struct sof_platform_priv *priv = spi_get_drvdata(spi); + struct snd_sof_pdata *sof_pdata = priv->sof_pdata; + + platform_device_unregister(sof_pdata->pdev_mach); + if (!IS_ERR_OR_NULL(priv->pdev_pcm)) + platform_device_unregister(priv->pdev_pcm); + release_firmware(sof_pdata->fw); + + return 0; +} + +const struct of_device_id sof_of_match[] = { + { .compatible = "sof,spi-sue-creek", .data = &spi_desc }, + { } +}; + +static struct spi_driver sof_spi_driver = { + .driver = { + .name = "sof-spi-dev", + .of_match_table = sof_of_match, + }, + .probe = sof_spi_probe, + .remove = sof_spi_remove, +}; + +static int __init sof_spi_modinit(void) +{ + int ret; + + ret = spi_register_driver(&sof_spi_driver); + if (ret != 0) + pr_err("Failed to register SOF SPI driver: %d\n", ret); + + return ret; +} +module_init(sof_spi_modinit); + +static void __exit sof_spi_modexit(void) +{ + spi_unregister_driver(&sof_spi_driver); +} +module_exit(sof_spi_modexit); + +MODULE_LICENSE("Dual BSD/GPL"); From 47c5d49978f8221c571db63b30b7ce5e7c7889a1 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:36:02 +0000 Subject: [PATCH 0125/1995] ASoC: SOF: Add ACPI device support Add support ACPI based SOF DSP devices. Signed-off-by: Liam Girdwood --- sound/soc/sof/sof-acpi-dev.c | 320 +++++++++++++++++++++++++++++++++++ 1 file changed, 320 insertions(+) create mode 100644 sound/soc/sof/sof-acpi-dev.c diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c new file mode 100644 index 00000000000000..7fe49c91c84fc2 --- /dev/null +++ b/sound/soc/sof/sof-acpi-dev.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sof-priv.h" + +/* platform specific devices */ +#include "intel/shim.h" +#include "intel/hda.h" + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL) +static struct sof_dev_desc sof_acpi_haswell_desc = { + .machines = snd_soc_acpi_intel_haswell_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = 1, + .resindex_imr_base = -1, + .irqindex_host_ipc = 0, + .nocodec_fw_filename = "intel/sof-hsw.ri", + .nocodec_tplg_filename = "intel/sof-hsw-nocodec.tplg" +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) +static struct sof_dev_desc sof_acpi_broadwell_desc = { + .machines = snd_soc_acpi_intel_broadwell_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = 1, + .resindex_imr_base = -1, + .irqindex_host_ipc = 0, + .nocodec_fw_filename = "intel/sof-bdw.ri", + .nocodec_tplg_filename = "intel/sof-bdw-nocodec.tplg" +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) + +/* BYTCR uses different IRQ index */ +static struct sof_dev_desc sof_acpi_baytrailcr_desc = { + .machines = snd_soc_acpi_intel_baytrail_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = 1, + .resindex_imr_base = 2, + .irqindex_host_ipc = 0, + .nocodec_fw_filename = "intel/sof-byt.ri", + .nocodec_tplg_filename = "intel/sof-byt-nocodec.tplg" +}; + +static struct sof_dev_desc sof_acpi_baytrail_desc = { + .machines = snd_soc_acpi_intel_baytrail_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = 1, + .resindex_imr_base = 2, + .irqindex_host_ipc = 5, + .nocodec_fw_filename = "intel/sof-byt.ri", + .nocodec_tplg_filename = "intel/sof-byt-nocodec.tplg" +}; + +static int is_byt_cr(struct device *dev) +{ + u32 bios_status; + int status; + + if (!IS_ENABLED(CONFIG_IOSF_MBI) || !iosf_mbi_available()) { + dev_info(dev, "IOSF_MBI not enabled - can't determine CPU variant\n"); + return -EIO; + } + + status = iosf_mbi_read(BT_MBI_UNIT_PMC, /* 0x04 PUNIT */ + MBI_REG_READ, /* 0x10 */ + 0x006, /* BIOS_CONFIG */ + &bios_status); + + if (status) { + dev_err(dev, "error: could not read PUNIT BIOS_CONFIG\n"); + return -EIO; + } + + /* bits 26:27 mirror PMIC options */ + bios_status = (bios_status >> 26) & 3; + + if (bios_status == 1 || bios_status == 3) { + dev_info(dev, "BYT-CR detected\n"); + return 1; + } + + dev_info(dev, "BYT-CR not detected\n"); + return 0; +} + +static struct sof_dev_desc sof_acpi_cherrytrail_desc = { + .machines = snd_soc_acpi_intel_cherrytrail_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = 1, + .resindex_imr_base = 2, + .irqindex_host_ipc = 5, + .nocodec_fw_filename = "intel/sof-cht.ri", + .nocodec_tplg_filename = "intel/sof-cht-nocodec.tplg" +}; +#endif + +static struct platform_device * + mfld_new_mach_data(struct snd_sof_pdata *sof_pdata) +{ + struct snd_soc_acpi_mach pmach; + struct device *dev = sof_pdata->dev; + const struct snd_soc_acpi_mach *mach = sof_pdata->machine; + struct platform_device *pdev = NULL; + + memset(&pmach, 0, sizeof(pmach)); + memcpy((void *)pmach.id, mach->id, ACPI_ID_LEN); + pmach.drv_name = mach->drv_name; + + pdev = platform_device_register_data(dev, mach->drv_name, -1, + &pmach, sizeof(pmach)); + return pdev; +} + +static const struct dev_pm_ops sof_acpi_pm = { + SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) + SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, + NULL) + .suspend_late = snd_sof_suspend_late, +}; + +static const struct sof_ops_table mach_ops[] = { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL) + {&sof_acpi_haswell_desc, &sof_hsw_ops}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) + {&sof_acpi_broadwell_desc, &sof_bdw_ops}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) + {&sof_acpi_baytrail_desc, &sof_byt_ops, mfld_new_mach_data}, + {&sof_acpi_baytrailcr_desc, &sof_byt_ops, mfld_new_mach_data}, + {&sof_acpi_cherrytrail_desc, &sof_cht_ops, mfld_new_mach_data}, +#endif +}; + +static struct snd_sof_dsp_ops * + sof_acpi_get_ops(const struct sof_dev_desc *d, + struct platform_device *(**new_mach_data) + (struct snd_sof_pdata *)) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mach_ops); i++) { + if (d == mach_ops[i].desc) { + *new_mach_data = mach_ops[i].new_data; + return mach_ops[i].ops; + } + } + + /* not found */ + return NULL; +} + +static int sof_acpi_probe(struct platform_device *pdev) +{ + const struct acpi_device_id *id; + struct device *dev = &pdev->dev; + const struct sof_dev_desc *desc; + struct snd_soc_acpi_mach *mach; + struct snd_sof_pdata *sof_pdata; + struct sof_platform_priv *priv; + struct snd_sof_dsp_ops *ops; + struct platform_device *(*new_mach_data)(struct snd_sof_pdata *pdata); + int ret = 0; + + dev_dbg(&pdev->dev, "ACPI DSP detected"); + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); + if (!sof_pdata) + return -ENOMEM; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!id) + return -ENODEV; + + desc = (const struct sof_dev_desc *)id->driver_data; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) + if (desc == &sof_acpi_baytrail_desc && is_byt_cr(dev)) + desc = &sof_acpi_baytrailcr_desc; +#endif + + /* get ops for platform */ + new_mach_data = NULL; + ops = sof_acpi_get_ops(desc, &new_mach_data); + if (!ops) { + dev_err(dev, "error: no matching ACPI descriptor ops\n"); + return -ENODEV; + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) + /* force nocodec mode */ + dev_warn(dev, "Force to use nocodec mode\n"); + mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); + ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); + if (ret < 0) + return ret; +#else + /* find machine */ + mach = snd_soc_acpi_find_machine(desc->machines); + if (!mach) { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) + /* fallback to nocodec mode */ + dev_warn(dev, "No matching ASoC machine driver found - using nocodec\n"); + mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); + ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); + if (ret < 0) + return ret; +#else + dev_warn(dev, "No matching ASoC machine driver found - falling back to HDA codec\n"); + mach = snd_soc_acpi_intel_hda_machines; + mach->sof_fw_filename = desc->nocodec_fw_filename; +#endif + } +#endif + + mach->pdata = ops; + mach->new_mach_data = (struct platform_device * + (*)(void *pdata)) new_mach_data; + + sof_pdata->machine = mach; + /* + * FIXME, this can't work for baytrail cr: + * sof_pdata->desc = (struct sof_dev_desc*) id->driver_data; + */ + sof_pdata->desc = desc; + priv->sof_pdata = sof_pdata; + sof_pdata->dev = &pdev->dev; + sof_pdata->type = SOF_DEVICE_APCI; + sof_pdata->platform = "sof-audio"; + dev_set_drvdata(&pdev->dev, priv); + + /* register sof-audio platform driver */ + ret = sof_create_platform_device(priv); + if (ret) { + platform_device_unregister(sof_pdata->pdev_mach); + dev_err(dev, "error: failed to create platform device!\n"); + return ret; + } + + /* allow runtime_pm */ + pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY); + pm_runtime_use_autosuspend(dev); + pm_runtime_allow(dev); + + return ret; +} + +static void sof_acpi_shutdown(struct platform_device *pdev) +{ + snd_sof_shutdown(&pdev->dev); +} + +static int sof_acpi_remove(struct platform_device *pdev) +{ + struct sof_platform_priv *priv = dev_get_drvdata(&pdev->dev); + struct snd_sof_pdata *sof_pdata = priv->sof_pdata; + + platform_device_unregister(sof_pdata->pdev_mach); + if (!IS_ERR_OR_NULL(priv->pdev_pcm)) + platform_device_unregister(priv->pdev_pcm); + release_firmware(sof_pdata->fw); + + return 0; +} + +static const struct acpi_device_id sof_acpi_match[] = { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL) + { "INT33C8", (unsigned long)&sof_acpi_haswell_desc }, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) + { "INT3438", (unsigned long)&sof_acpi_broadwell_desc }, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) + { "80860F28", (unsigned long)&sof_acpi_baytrail_desc }, + { "808622A8", (unsigned long)&sof_acpi_cherrytrail_desc }, +#endif + { } +}; +MODULE_DEVICE_TABLE(acpi, sof_acpi_match); + +/* acpi_driver definition */ +static struct platform_driver snd_sof_acpi_driver = { + .probe = sof_acpi_probe, + .remove = sof_acpi_remove, + .shutdown = sof_acpi_shutdown, + .driver = { + .name = "sof-audio-acpi", + .pm = &sof_acpi_pm, + .acpi_match_table = ACPI_PTR(sof_acpi_match), + }, +}; +module_platform_driver(snd_sof_acpi_driver); + +MODULE_LICENSE("Dual BSD/GPL"); From 3dc9e1621d853a287a250ccd923d9820566e1e30 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:36:19 +0000 Subject: [PATCH 0126/1995] ASoC: SOF: Add PCI device support Add support for PCI based DSP devices. Signed-off-by: Liam Girdwood --- sound/soc/sof/sof-pci-dev.c | 350 ++++++++++++++++++++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 sound/soc/sof/sof-pci-dev.c diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c new file mode 100644 index 00000000000000..98f041247b3922 --- /dev/null +++ b/sound/soc/sof/sof-pci-dev.c @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sof-priv.h" + +/* platform specific devices */ +#include "intel/shim.h" +#include "intel/hda.h" + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) +static struct sof_dev_desc bxt_desc = { + .machines = snd_soc_acpi_intel_bxt_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .nocodec_fw_filename = "intel/sof-apl.ri", + .nocodec_tplg_filename = "intel/sof-apl-nocodec.tplg" +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) +static struct sof_dev_desc glk_desc = { + .machines = snd_soc_acpi_intel_glk_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .nocodec_fw_filename = "intel/sof-glk.ri", + .nocodec_tplg_filename = "intel/sof-glk-nocodec.tplg" +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) +static struct snd_soc_acpi_mach sof_byt_machines[] = { + { + .id = "INT343A", + .drv_name = "edison", + .sof_fw_filename = "intel/sof-byt.ri", + .sof_tplg_filename = "intel/sof-byt.tplg", + .asoc_plat_name = "baytrail-pcm-audio", + }, + {} +}; + +static const struct sof_dev_desc byt_desc = { + .machines = sof_byt_machines, + .resindex_lpe_base = 3, /* IRAM, but subtract IRAM offset */ + .resindex_pcicfg_base = -1, + .resindex_imr_base = 0, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .nocodec_fw_filename = "intel/sof-byt.ri", + .nocodec_tplg_filename = "intel/sof-byt.tplg" +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) +static const struct sof_dev_desc cnl_desc = { + .machines = snd_soc_acpi_intel_cnl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .nocodec_fw_filename = "intel/sof-cnl.ri", + .nocodec_tplg_filename = "intel/sof-cnl.tplg" +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) +static struct sof_dev_desc skl_desc = { + .machines = snd_soc_acpi_intel_skl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .nocodec_fw_filename = "intel/sof-skl.ri", + .nocodec_tplg_filename = "intel/sof-skl-nocodec.tplg" +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) +static struct sof_dev_desc kbl_desc = { + .machines = snd_soc_acpi_intel_kbl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .nocodec_fw_filename = "intel/sof-kbl.ri", + .nocodec_tplg_filename = "intel/sof-kbl-nocodec.tplg" +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) +static const struct sof_dev_desc icl_desc = { + .machines = snd_soc_acpi_intel_icl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .nocodec_fw_filename = "intel/sof-icl.ri", + .nocodec_tplg_filename = "intel/sof-icl-nocodec.tplg" +}; +#endif + +static const struct dev_pm_ops sof_pci_pm = { + SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) + SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, + NULL) + .suspend_late = snd_sof_suspend_late, + .prepare = snd_sof_prepare, + +}; + +static const struct sof_ops_table mach_ops[] = { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) + {&bxt_desc, &sof_apl_ops}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) + {&glk_desc, &sof_apl_ops}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) + {&byt_desc, &sof_byt_ops}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) + {&cnl_desc, &sof_cnl_ops}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) + {&skl_desc, &sof_skl_ops}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) + {&kbl_desc, &sof_skl_ops}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) + {&icl_desc, &sof_cnl_ops}, +#endif +}; + +static struct snd_sof_dsp_ops *sof_pci_get_ops(const struct sof_dev_desc *d) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mach_ops); i++) { + if (d == mach_ops[i].desc) + return mach_ops[i].ops; + } + + /* not found */ + return NULL; +} + +static int sof_pci_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + struct device *dev = &pci->dev; + const struct sof_dev_desc *desc = + (const struct sof_dev_desc *)pci_id->driver_data; + struct snd_soc_acpi_mach *mach; + struct snd_sof_pdata *sof_pdata; + struct sof_platform_priv *priv; + struct snd_sof_dsp_ops *ops; + int ret = 0; + + dev_dbg(&pci->dev, "PCI DSP detected"); + + /* get ops for platform */ + ops = sof_pci_get_ops(desc); + if (!ops) { + dev_err(dev, "error: no matching PCI descriptor ops\n"); + return -ENODEV; + } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + pci_set_drvdata(pci, priv); + + sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); + if (!sof_pdata) + return -ENOMEM; + + ret = pci_enable_device(pci); + if (ret < 0) + return ret; + + ret = pci_request_regions(pci, "Audio DSP"); + if (ret < 0) + goto disable_dev; + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) + /* force nocodec mode */ + dev_warn(dev, "Force to use nocodec mode\n"); + mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); + ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); + if (ret < 0) + goto release_regions; +#else + /* find machine */ + mach = snd_soc_acpi_find_machine(desc->machines); + if (!mach) { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) + /* fallback to nocodec mode */ + dev_warn(dev, "No matching ASoC machine driver found - using nocodec\n"); + mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); + ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); + if (ret < 0) + goto release_regions; +#else + dev_warn(dev, "No matching ASoC machine driver found - falling back to HDA codec\n"); + mach = snd_soc_acpi_intel_hda_machines; + mach->sof_fw_filename = desc->nocodec_fw_filename; +#endif + } +#endif + + mach->pdata = ops; + + sof_pdata->id = pci_id->device; + sof_pdata->name = pci_name(pci); + sof_pdata->machine = mach; + sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data; + priv->sof_pdata = sof_pdata; + sof_pdata->dev = &pci->dev; + sof_pdata->type = SOF_DEVICE_PCI; + sof_pdata->platform = "sof-audio"; + + /* register sof-audio platform driver */ + ret = sof_create_platform_device(priv); + if (ret) { + dev_err(dev, "error: failed to create platform device!\n"); + goto release_regions; + } + + /* allow runtime_pm */ + pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY); + pm_runtime_use_autosuspend(dev); + pm_runtime_allow(dev); + + return ret; + +release_regions: + pci_release_regions(pci); +disable_dev: + pci_disable_device(pci); + + return ret; +} + +static void sof_pci_shutdown(struct pci_dev *pci) +{ + snd_sof_shutdown(&pci->dev); +} + +static void sof_pci_remove(struct pci_dev *pci) +{ + struct sof_platform_priv *priv = pci_get_drvdata(pci); + struct snd_sof_pdata *sof_pdata = priv->sof_pdata; + + /* unregister machine driver */ + platform_device_unregister(sof_pdata->pdev_mach); + + /* unregister sof-audio platform driver */ + if (!IS_ERR_OR_NULL(priv->pdev_pcm)) + platform_device_unregister(priv->pdev_pcm); + + /* release firmware */ + release_firmware(sof_pdata->fw); + + /* release pci regions and disable device */ + pci_release_regions(pci); + pci_disable_device(pci); +} + +/* PCI IDs */ +static const struct pci_device_id sof_pci_ids[] = { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) + /* BXT-P & Apollolake */ + { PCI_DEVICE(0x8086, 0x5a98), + .driver_data = (unsigned long)&bxt_desc}, + { PCI_DEVICE(0x8086, 0x1a98), + .driver_data = (unsigned long)&bxt_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) + { PCI_DEVICE(0x8086, 0x3198), + .driver_data = (unsigned long)&glk_desc}, +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) + { PCI_DEVICE(0x8086, 0x119a), + .driver_data = (unsigned long)&byt_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) + { PCI_DEVICE(0x8086, 0x9dc8), + .driver_data = (unsigned long)&cnl_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) + { PCI_DEVICE(0x8086, 0x9d71), + .driver_data = (unsigned long)&kbl_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) + { PCI_DEVICE(0x8086, 0x9d70), + .driver_data = (unsigned long)&skl_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) + { PCI_DEVICE(0x8086, 0x34C8), + .driver_data = (unsigned long)&icl_desc}, +#endif + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sof_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_driver = { + .name = "sof-audio-pci", + .id_table = sof_pci_ids, + .probe = sof_pci_probe, + .remove = sof_pci_remove, + .shutdown = sof_pci_shutdown, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_driver); + +MODULE_LICENSE("Dual BSD/GPL"); From fede7ff7ebf8a1e84533ec5da9f19eae32fb6372 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 20 Jul 2018 14:45:17 -0500 Subject: [PATCH 0127/1995] ASoC: SOF: add utils Signed-off-by: Keyon Jie Signed-off-by: Liam Girdwood --- sound/soc/sof/utils.c | 68 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 sound/soc/sof/utils.c diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c new file mode 100644 index 00000000000000..23597064b8e33b --- /dev/null +++ b/sound/soc/sof/utils.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Keyon Jie +// + +#include +#include +#include +#include +#include "sof-priv.h" + +int sof_bes_setup(struct device *dev, struct snd_sof_dsp_ops *ops, + struct snd_soc_dai_link *links, int link_num, + struct snd_soc_card *card) +{ + char name[32]; + int i; + + if (!ops || !links || !card) + return -EINVAL; + + /* set up BE dai_links */ + for (i = 0; i < link_num; i++) { + snprintf(name, 32, "NoCodec-%d", i); + links[i].name = devm_kstrdup(dev, name, GFP_KERNEL); + if (!links[i].name) + return -ENOMEM; + + links[i].id = i; + links[i].no_pcm = 1; + links[i].cpu_dai_name = ops->drv[i].name; + links[i].platform_name = "sof-audio"; + links[i].codec_dai_name = "snd-soc-dummy-dai"; + links[i].codec_name = "snd-soc-dummy"; + links[i].dpcm_playback = 1; + links[i].dpcm_capture = 1; + } + + card->dai_link = links; + card->num_links = link_num; + + return 0; +} +EXPORT_SYMBOL(sof_bes_setup); + +/* register sof platform device */ +int sof_create_platform_device(struct sof_platform_priv *priv) +{ + struct snd_sof_pdata *sof_pdata = priv->sof_pdata; + struct device *dev = sof_pdata->dev; + + priv->pdev_pcm = + platform_device_register_data(dev, "sof-audio", -1, + sof_pdata, sizeof(*sof_pdata)); + if (IS_ERR(priv->pdev_pcm)) { + dev_err(dev, "Cannot register device sof-audio. Error %d\n", + (int)PTR_ERR(priv->pdev_pcm)); + return PTR_ERR(priv->pdev_pcm); + } + + return 0; +} +EXPORT_SYMBOL(sof_create_platform_device); From 312df4b7408447f41872da2f4f777b2832671079 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 8 Jan 2018 20:40:02 +0000 Subject: [PATCH 0128/1995] ASoC: SOF: Add Build support for SOF core and Intel drivers Build SOF core and Intel-specific drivers. Signed-off-by: Liam Girdwood --- sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/sof/Kconfig | 86 ++++++++++++++++++++++++++ sound/soc/sof/Makefile | 21 +++++++ sound/soc/sof/intel/Kconfig | 116 +++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/Makefile | 17 +++++ 6 files changed, 242 insertions(+) create mode 100644 sound/soc/sof/Kconfig create mode 100644 sound/soc/sof/Makefile create mode 100644 sound/soc/sof/intel/Kconfig create mode 100644 sound/soc/sof/intel/Makefile diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 1cf11cf51e1dd6..32eab7d21aaa06 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -65,6 +65,7 @@ source "sound/soc/rockchip/Kconfig" source "sound/soc/samsung/Kconfig" source "sound/soc/sh/Kconfig" source "sound/soc/sirf/Kconfig" +source "sound/soc/sof/Kconfig" source "sound/soc/spear/Kconfig" source "sound/soc/sti/Kconfig" source "sound/soc/stm/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 62a5f87c3cfc43..cb336e803d5aaf 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_SND_SOC) += rockchip/ obj-$(CONFIG_SND_SOC) += samsung/ obj-$(CONFIG_SND_SOC) += sh/ obj-$(CONFIG_SND_SOC) += sirf/ +obj-$(CONFIG_SND_SOC) += sof/ obj-$(CONFIG_SND_SOC) += spear/ obj-$(CONFIG_SND_SOC) += sti/ obj-$(CONFIG_SND_SOC) += stm/ diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig new file mode 100644 index 00000000000000..8db9ce50a29018 --- /dev/null +++ b/sound/soc/sof/Kconfig @@ -0,0 +1,86 @@ +config SND_SOC_SOF_PCI + tristate + +config SND_SOC_SOF_ACPI + tristate + +config SND_SOC_SOF_SPI + tristate + +config SND_SOC_SOF + tristate "Sound Open Firmware Support" + select SND_SOC_TOPOLOGY + select SND_SOC_COMPRESS + help + This adds support for Sound Open Firmware (SOF). SOF is a free and + generic open source audio DSP firmware for multiple devices. + Say Y if you have such a device that is supported by SOF. + If unsure select "N". + +config SND_SOC_SOF_NOCODEC + tristate "SOF nocodec mode Support" + depends on SND_SOC_SOF + help + This adds support for a dummy/nocodec machine driver fallback + option if no known codec is detected. This is typically only + enabled for developers or devices where the sound card is + controlled externally + Say Y if you need this nocodec fallback option + If unsure select "N". + +config SND_SOC_SOF_DEBUG + bool "SOF debugging features" + depends on SND_SOC_SOF + help + This option can be used to enable or disable individual SOF firmware + and driver debugging options. + Say Y if you are debugging SOF FW or drivers. + If unsure select "N". + +config SND_SOC_SOF_FORCE_NOCODEC_MODE + bool "SOF force nocodec Mode" + depends on SND_SOC_SOF_NOCODEC + depends on SND_SOC_SOF_DEBUG + help + This forces SOF to use dummy/nocodec as machine driver, even + though there is a codec detected on the real platform. This is + typically only enabled for developers for debug purposes, before + codec/machine driver is ready, or to exclude the impact of those + drivers + Say Y if you need this force nocodec mode option + If unsure select "N". + +config SND_SOC_SOF_DEBUG_XRUN_STOP + bool "SOF stop on XRUN" + depends on SND_SOC_SOF_DEBUG + help + This option forces PCMs to stop on any XRUN event. This is useful to + preserve any trace data ond pipeline status prior to the XRUN. + Say Y if you are debugging SOF FW pipeline XRUNs. + If unsure select "N". + +config SND_SOC_SOF_DEBUG_VERBOSE_IPC + bool "SOF verbose IPC logs" + depends on SND_SOC_SOF_DEBUG + help + This option enables more verbose IPC logs, with command types in + human-readable form instead of just 32-bit hex dumps. This is useful + if you are trying to debug IPC with the DSP firmware. + If unsure select "N". + +config SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION + bool "SOF force to use IPC for position update on SKL+" + depends on SND_SOC_SOF_DEBUG + default n + help + This option force to handle stream position update IPCs and run pcm + elapse to inform ALSA about that, on platforms (e.g. Intel SKL+) that + with other approach (e.g. HDAC DPIB/posbuf) to elapse PCM. + On platforms (e.g. Intel SKL-) where position update IPC is the only + one choice, this setting won't impact anything. + if you are trying to debug pointer update with position IPCs or where + DPIB/posbuf is not ready, select "Y". + If unsure select "N". + +source "sound/soc/sof/intel/Kconfig" +source "sound/soc/sof/xtensa/Kconfig" diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile new file mode 100644 index 00000000000000..e2250db8baeba6 --- /dev/null +++ b/sound/soc/sof/Makefile @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) + +snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ + control.o trace.o compressed.o utils.o +snd-sof-spi-objs := hw-spi.o + +snd-sof-pci-objs := sof-pci-dev.o +snd-sof-acpi-objs := sof-acpi-dev.o +snd-sof-nocodec-objs := nocodec.o + +obj-$(CONFIG_SND_SOC_SOF) += snd-sof.o +obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o + +obj-$(CONFIG_SND_SOC_SOF_ACPI) += sof-acpi-dev.o +obj-$(CONFIG_SND_SOC_SOF_PCI) += sof-pci-dev.o +obj-$(CONFIG_SND_SOC_SOF_SPI) += sof-spi-dev.o + +obj-$(CONFIG_SND_SOC_SOF_SPIDSP) += snd-sof-spi.o + +obj-$(CONFIG_SND_SOC_SOF_INTEL) += intel/ +obj-$(CONFIG_SND_SOC_SOF_XTENSA) += xtensa/ diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig new file mode 100644 index 00000000000000..d777ddd80d893e --- /dev/null +++ b/sound/soc/sof/intel/Kconfig @@ -0,0 +1,116 @@ +config SND_SOC_SOF_INTEL + tristate "SOF support for Intel audio DSPs" + depends on SND_SOC_SOF + depends on SND_DMA_SGBUF + select SND_SOC_INTEL_MACH + select SND_SOC_SOF_XTENSA + help + This adds support for Sound Open Firmware for Intel(R) platforms. + Say Y if you have such a device. + If unsure select "N". + +if SND_SOC_SOF_INTEL + +config SND_SOC_SOF_BAYTRAIL + tristate "SOF support for Baytrail, Braswell and Cherrytrail" + select SND_SOC_SOF_ACPI + select SND_SOC_ACPI_INTEL_MATCH + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Baytrail, Braswell or Cherrytrail processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_HASWELL + tristate "SOF support for Haswell" + select SND_SOC_SOF_ACPI + select SND_SOC_ACPI_INTEL_MATCH + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Haswell processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_BROADWELL + tristate "SOF support for Broadwell" + depends on SND_SOC_SOF_INTEL + select SND_SOC_SOF_ACPI + select SND_SOC_ACPI_INTEL_MATCH + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Broadwell processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_APOLLOLAKE + tristate "SOF support for Apollolake" + select SND_SOC_SOF_HDA_COMMON + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Apollolake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_GEMINILAKE + tristate "SOF support for GeminiLake" + select SND_SOC_SOF_HDA_COMMON + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Geminilake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_CANNONLAKE + tristate "SOF support for Cannonlake" + select SND_SOC_SOF_HDA_COMMON + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Cannonlake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_KABYLAKE + tristate "SOF support for Kabylake" + select SND_SOC_SOF_HDA_COMMON + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Kabylake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_SKYLAKE + tristate "SOF support for Skylake" + select SND_SOC_SOF_HDA_COMMON + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Skylake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_ICELAKE + tristate "SOF support for Icelake" + select SND_SOC_SOF_HDA_COMMON + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Icelake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_HDA_COMMON + tristate + select SND_SOC_SOF_PCI + select SND_SOC_ACPI_INTEL_MATCH + +config SND_SOC_SOF_HDA + tristate "SOF support for HDA Links(HDA/HDMI)" + depends on SND_SOC_SOF_HDA_COMMON + select SND_HDA_EXT_CORE + select SND_SOC_HDAC_HDA + select SND_SOC_HDAC_HDMI + help + This adds support for HDA links(HDA/HDMI) with Sound Open Firmware + for Intel(R) platforms. + Say Y if you want to enble HDA links with SOF. + If unsure select "N". + +endif ## SND_SOC_SOF_INTEL diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile new file mode 100644 index 00000000000000..78f5fb3d3571c1 --- /dev/null +++ b/sound/soc/sof/intel/Makefile @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) + +snd-sof-intel-byt-objs := byt.o +snd-sof-intel-hsw-objs := hsw.o +snd-sof-intel-bdw-objs := bdw.o +snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ + hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \ + hda-dai.o hda-bus.o hda-loader-skl.o \ + skl.o apl.o cnl.o + +snd-sof-intel-hda-objs := hda-codec.o + +obj-$(CONFIG_SND_SOC_SOF_BAYTRAIL) += snd-sof-intel-byt.o +obj-$(CONFIG_SND_SOC_SOF_HASWELL) += snd-sof-intel-hsw.o +obj-$(CONFIG_SND_SOC_SOF_BROADWELL) += snd-sof-intel-bdw.o +obj-$(CONFIG_SND_SOC_SOF_HDA_COMMON) += snd-sof-intel-hda-common.o +obj-$(CONFIG_SND_SOC_SOF_HDA) += snd-sof-intel-hda.o From e1e6e54bef6257680e8e61c22d5ff57a69f77e6f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 31 May 2018 17:35:22 -0500 Subject: [PATCH 0129/1995] ASoC: Intel: Kconfig: disable SST and legacy drivers when SOF is selected Make sure distros don't run into issues with multiple incompatible drivers selected for the same hardware. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 0caa1f4eb94d7d..08f00058700023 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -61,7 +61,7 @@ config SND_SOC_INTEL_HASWELL config SND_SOC_INTEL_BAYTRAIL tristate "Baytrail (legacy) Platforms" - depends on DMADEVICES && ACPI && SND_SST_ATOM_HIFI2_PLATFORM=n + depends on DMADEVICES && ACPI && SND_SST_ATOM_HIFI2_PLATFORM=n && SND_SOC_SOF_BAYTRAIL=n select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST_ACPI select SND_SOC_INTEL_SST_FIRMWARE @@ -91,7 +91,7 @@ config SND_SST_ATOM_HIFI2_PLATFORM_PCI config SND_SST_ATOM_HIFI2_PLATFORM_ACPI tristate "ACPI HiFi2 (Baytrail, Cherrytrail) Platforms" default ACPI - depends on X86 && ACPI + depends on X86 && ACPI && SND_SOC_SOF_BAYTRAIL=n select SND_SST_IPC_ACPI select SND_SST_ATOM_HIFI2_PLATFORM select SND_SOC_ACPI_INTEL_MATCH From 6abc5d61a625d0dfec2bb831268651b4afa95ea8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 8 Mar 2018 18:36:30 -0600 Subject: [PATCH 0130/1995] ASoC: Intel: make bytcht_da7213 with SOF Disable hard-coded routes when SOF is enabled Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bytcht_da7213.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index 2179dedb28ad6d..1e90a9c4b1e892 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -56,6 +56,7 @@ static const struct snd_soc_dapm_route audio_map[] = { {"MIC1", NULL, "Headset Mic"}, {"MIC2", NULL, "Mic"}, +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) /* SOC-codec link */ {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, @@ -64,6 +65,7 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Playback", NULL, "ssp2 Tx"}, {"ssp2 Rx", NULL, "Capture"}, +#endif }; static int codec_fixup(struct snd_soc_pcm_runtime *rtd, From 648a3e606b4035bfa01930110c472f61ec644b87 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 8 Mar 2018 18:39:33 -0600 Subject: [PATCH 0131/1995] ASoC: Intel: make cht_bsw_max98090 work with SOF Disable hard-coded routes when SOF is enabled Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index db6976f4ddaa28..3d883289cb72de 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -88,12 +88,14 @@ static const struct snd_soc_dapm_route cht_audio_map[] = { {"Headphone", NULL, "HPR"}, {"Ext Spk", NULL, "SPKL"}, {"Ext Spk", NULL, "SPKR"}, +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) {"HiFi Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, {"codec_in0", NULL, "ssp2 Rx" }, {"codec_in1", NULL, "ssp2 Rx" }, {"ssp2 Rx", NULL, "HiFi Capture"}, +#endif {"Headphone", NULL, "Platform Clock"}, {"Headset Mic", NULL, "Platform Clock"}, {"Int Mic", NULL, "Platform Clock"}, From 4b5117980d46338d4638e4bb443847cb1883d48b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 10 Nov 2017 14:34:32 -0600 Subject: [PATCH 0132/1995] ASoC: Intel: cht-bsw-rt5645: work with SOF Disable hard-coded routes when SOF is selected TODO: bytcr is not yet supported Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/cht_bsw_rt5645.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index f5a5ea6a093c71..710a5a11215b52 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -160,35 +160,43 @@ static const struct snd_soc_dapm_route cht_rt5650_audio_map[] = { }; static const struct snd_soc_dapm_route cht_rt5645_ssp2_aif1_map[] = { +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) {"AIF1 Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, {"codec_in0", NULL, "ssp2 Rx" }, {"codec_in1", NULL, "ssp2 Rx" }, {"ssp2 Rx", NULL, "AIF1 Capture"}, +#endif }; static const struct snd_soc_dapm_route cht_rt5645_ssp2_aif2_map[] = { +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) {"AIF2 Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, {"codec_in0", NULL, "ssp2 Rx" }, {"codec_in1", NULL, "ssp2 Rx" }, {"ssp2 Rx", NULL, "AIF2 Capture"}, +#endif }; static const struct snd_soc_dapm_route cht_rt5645_ssp0_aif1_map[] = { +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) {"AIF1 Playback", NULL, "ssp0 Tx"}, {"ssp0 Tx", NULL, "modem_out"}, {"modem_in", NULL, "ssp0 Rx" }, {"ssp0 Rx", NULL, "AIF1 Capture"}, +#endif }; static const struct snd_soc_dapm_route cht_rt5645_ssp0_aif2_map[] = { +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) {"AIF2 Playback", NULL, "ssp0 Tx"}, {"ssp0 Tx", NULL, "modem_out"}, {"modem_in", NULL, "ssp0 Rx" }, {"ssp0 Rx", NULL, "AIF2 Capture"}, +#endif }; static const struct snd_kcontrol_new cht_mc_controls[] = { @@ -585,11 +593,13 @@ static int snd_cht_mc_probe(struct platform_device *pdev) * (will be overridden if DMI quirk is detected) */ if (is_valleyview()) { +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) /* FIXME: bytcr not supported yet */ struct sst_platform_info *p_info = mach->pdata; const struct sst_res_info *res_info = p_info->res_info; if (res_info->acpi_ipc_irq_index == 0) is_bytcr = true; +#endif } if (is_bytcr) { From 243088e5ce04a4092a6b2e3d21e88656948bce0b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 29 Nov 2017 19:14:19 -0600 Subject: [PATCH 0133/1995] ASoC: Intel: cht-bsw-rt5672: work with SOF Disable hard-coded routes when SOF is enabled Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/cht_bsw_rt5672.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 51f0d45d6f8f9d..406595e2448a95 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -128,12 +128,14 @@ static const struct snd_soc_dapm_route cht_audio_map[] = { {"Ext Spk", NULL, "SPOLN"}, {"Ext Spk", NULL, "SPORP"}, {"Ext Spk", NULL, "SPORN"}, +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) {"AIF1 Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, {"codec_in0", NULL, "ssp2 Rx"}, {"codec_in1", NULL, "ssp2 Rx"}, {"ssp2 Rx", NULL, "AIF1 Capture"}, +#endif {"Headphone", NULL, "Platform Clock"}, {"Headset Mic", NULL, "Platform Clock"}, {"Int Mic", NULL, "Platform Clock"}, From c41fdba682edd46eedac799a1b81c4237756c61e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 20 Dec 2017 18:36:49 -0600 Subject: [PATCH 0134/1995] ASoC: Intel: make bytcr_rt5640 work with SOF Disable hard-coded routes when SOF is enabled TODO: bytcr is not yet supported Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bytcr_rt5640.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 8587bd3d1cc17d..2d24317bf3a5f7 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -819,6 +819,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) if (ret) return ret; +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) { ret = snd_soc_dapm_add_routes(&card->dapm, byt_rt5640_ssp2_aif2_map, @@ -838,6 +839,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) } if (ret) return ret; +#endif if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) { ret = snd_soc_dapm_add_routes(&card->dapm, @@ -1152,11 +1154,13 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) * (will be overridden if DMI quirk is detected) */ if (is_valleyview()) { +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) /* FIXME: bytcr not supported yet */ struct sst_platform_info *p_info = mach->pdata; const struct sst_res_info *res_info = p_info->res_info; if (res_info->acpi_ipc_irq_index == 0) is_bytcr = true; +#endif } if (is_bytcr) { From 197f2f13a025c80f064bff52c2bfdf3e23e12fd5 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 7 Dec 2017 21:48:51 +0000 Subject: [PATCH 0135/1995] ASoC: Intel: Make sure HSW/BDW based machine drivers build for SOF HSW/BDW use hard coded IPC calls to set SSP, not needed in SOF as SSP is configured via topology. Signed-off-by: Liam Girdwood --- sound/soc/intel/boards/bdw-rt5677.c | 4 ++++ sound/soc/intel/boards/broadwell.c | 4 ++++ sound/soc/intel/boards/haswell.c | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index efcfd906c8562b..0654bd94389ca8 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -179,6 +179,7 @@ static const struct snd_soc_ops bdw_rt5677_ops = { .hw_params = bdw_rt5677_hw_params, }; +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); @@ -197,6 +198,7 @@ static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd) return 0; } +#endif static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) { @@ -264,7 +266,9 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { .dynamic = 1, .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) .init = bdw_rt5677_rtd_init, +#endif .trigger = { SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 68e6543e6cb026..56dd8463c75dc9 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -130,6 +130,7 @@ static const struct snd_soc_ops broadwell_rt286_ops = { .hw_params = broadwell_rt286_hw_params, }; +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); @@ -148,6 +149,7 @@ static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) return 0; } +#endif /* broadwell digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link broadwell_rt286_dais[] = { @@ -160,7 +162,9 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { .dynamic = 1, .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) .init = broadwell_rtd_init, +#endif .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dpcm_playback = 1, .dpcm_capture = 1, diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index eab1f439dd3f1a..ce7d7f6422bfb8 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -85,6 +85,7 @@ static const struct snd_soc_ops haswell_rt5640_ops = { .hw_params = haswell_rt5640_hw_params, }; +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); @@ -103,6 +104,7 @@ static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd) return 0; } +#endif static struct snd_soc_dai_link haswell_rt5640_dais[] = { /* Front End DAI links */ @@ -114,7 +116,9 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = { .dynamic = 1, .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) .init = haswell_rtd_init, +#endif .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dpcm_playback = 1, .dpcm_capture = 1, From 957c959f53877e21755c50fc8e579e55eff36fe6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 9 Jan 2018 13:40:20 -0600 Subject: [PATCH 0136/1995] ASoC: Intel: Kconfig: expose common option between SST and SOF drivers Both drivers rely on the same module, expose it for both configurations Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/Kconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 08f00058700023..2a4c4fca841864 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -117,13 +117,16 @@ config SND_SOC_INTEL_SKYLAKE GeminiLake or CannonLake platform with the DSP enabled in the BIOS then enable this option by saying Y or m. +endif ## SND_SOC_INTEL_SST_TOPLEVEL + +if SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL config SND_SOC_ACPI_INTEL_MATCH tristate select SND_SOC_ACPI if ACPI # this option controls the compilation of ACPI matching tables and # helpers and is not meant to be selected by the user. +endif ## SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL -endif ## SND_SOC_INTEL_SST_TOPLEVEL # ASoC codec drivers source "sound/soc/intel/boards/Kconfig" From c19a39c9a93bef5f3ee69040db087bc84c119f4f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 7 Dec 2017 21:46:33 +0000 Subject: [PATCH 0137/1995] ASoC: Intel: select relevant machine drivers for SOF SOF can only support specific machine drivers, handle dependencies Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 73ca1350aa3124..92e30a8db22f5a 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -1,6 +1,6 @@ menuconfig SND_SOC_INTEL_MACH bool "Intel Machine drivers" - depends on SND_SOC_INTEL_SST_TOPLEVEL + depends on SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL help Intel ASoC Machine Drivers. If you have a Intel machine that has an audio controller with a DSP and I2S or DMIC port, then @@ -12,7 +12,7 @@ menuconfig SND_SOC_INTEL_MACH if SND_SOC_INTEL_MACH -if SND_SOC_INTEL_HASWELL +if SND_SOC_INTEL_HASWELL || SND_SOC_SOF_HASWELL config SND_SOC_INTEL_HASWELL_MACH tristate "Haswell Lynxpoint" @@ -24,6 +24,10 @@ config SND_SOC_INTEL_HASWELL_MACH Say Y or m if you have such a device. If unsure select "N". +endif ## SND_SOC_INTEL_HASWELL || SND_SOC_SOF_HASWELL + +if SND_SOC_INTEL_HASWELL || SND_SOC_SOF_BROADWELL + config SND_SOC_INTEL_BDW_RT5677_MACH tristate "Broadwell with RT5677 codec" depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM && GPIOLIB @@ -43,7 +47,7 @@ config SND_SOC_INTEL_BROADWELL_MACH Ultrabook platforms. Say Y or m if you have such a device. This is a recommended option. If unsure select "N". -endif ## SND_SOC_INTEL_HASWELL +endif ## SND_SOC_INTEL_HASWELL || SND_SOC_SOF_BROADWELL if SND_SOC_INTEL_BAYTRAIL @@ -68,7 +72,7 @@ config SND_SOC_INTEL_BYT_RT5640_MACH endif ## SND_SOC_INTEL_BAYTRAIL -if SND_SST_ATOM_HIFI2_PLATFORM +if SND_SST_ATOM_HIFI2_PLATFORM || SND_SOC_SOF_BAYTRAIL config SND_SOC_INTEL_BYTCR_RT5640_MACH tristate "Baytrail and Baytrail-CR with RT5640 codec" @@ -158,6 +162,10 @@ config SND_SOC_INTEL_BYT_CHT_ES8316_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +endif ## SND_SST_ATOM_HIFI2_PLATFORM || SND_SOC_SOF_BAYTRAIL + +if SND_SST_ATOM_HIFI2_PLATFORM + config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH tristate "Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)" depends on X86_INTEL_LPSS && I2C && ACPI @@ -212,6 +220,10 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +endif ## SND_SOC_INTEL_SKYLAKE + +if SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_APOLLOLAKE + config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH tristate "Broxton with DA7219 and MAX98357A in I2S Mode" depends on MFD_INTEL_LPSS && I2C && ACPI @@ -239,6 +251,10 @@ config SND_SOC_INTEL_BXT_RT298_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +endif ## SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_APOLLOLAKE + +if SND_SOC_INTEL_SKYLAKE + config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH tristate "KBL with RT5663 and MAX98927 in I2S Mode" depends on MFD_INTEL_LPSS && I2C && ACPI @@ -293,6 +309,10 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH Say Y if you have such a device. If unsure select "N". +endif ## SND_SOC_INTEL_SKYLAKE + +if SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_HDA + config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH tristate "SKL/KBL/BXT/APL with HDA Codecs" select SND_SOC_HDAC_HDMI @@ -303,6 +323,10 @@ config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +endif ## SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_HDA + +if SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_GEMINILAKE + config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH tristate "GLK with RT5682 and MAX98357A in I2S Mode" depends on MFD_INTEL_LPSS && I2C && ACPI @@ -317,6 +341,6 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH Say Y if you have such a device. If unsure select "N". -endif ## SND_SOC_INTEL_SKYLAKE +endif ## SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_GEMINILAKE endif ## SND_SOC_INTEL_MACH From fe06f831760267d2b2cdff9cc18f2efd0a1e5fdf Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 23 Apr 2018 12:06:09 -0500 Subject: [PATCH 0138/1995] ASoC: Intel: add machine driver for BXT/APL with pcm512x codec This patch adds the machine driver for the Up2 board with the Hifiberry DAC+ codec. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 10 ++ sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/bxt_pcm512x.c | 184 +++++++++++++++++++++++++++ 3 files changed, 196 insertions(+) create mode 100644 sound/soc/intel/boards/bxt_pcm512x.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 92e30a8db22f5a..2a4b13b53d6c33 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -251,6 +251,16 @@ config SND_SOC_INTEL_BXT_RT298_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +config SND_SOC_INTEL_BXT_PCM512x_MACH + tristate "Broxton with TI PCM512x codec" + depends on MFD_INTEL_LPSS && I2C && ACPI + select SND_SOC_PCM512x_I2C + help + This adds support for ASoC machine driver for Broxton platforms + with TI PCM512x I2S audio codec. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + endif ## SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_APOLLOLAKE if SND_SOC_INTEL_SKYLAKE diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 5381e27df9cc76..bf663d98cd5486 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -6,6 +6,7 @@ snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o snd-soc-sst-broadwell-objs := broadwell.o snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o snd-soc-sst-bxt-rt298-objs := bxt_rt298.o +snd-soc-sst-bxt-pcm512x-objs := bxt_pcm512x.o snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o @@ -30,6 +31,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o +obj-$(CONFIG_SND_SOC_INTEL_BXT_PCM512x_MACH) += snd-soc-sst-bxt-pcm512x.o obj-$(CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH) += snd-soc-sst-glk-rt5682_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.o diff --git a/sound/soc/intel/boards/bxt_pcm512x.c b/sound/soc/intel/boards/bxt_pcm512x.c new file mode 100644 index 00000000000000..f8c734faef396d --- /dev/null +++ b/sound/soc/intel/boards/bxt_pcm512x.c @@ -0,0 +1,184 @@ +/* + * bxt-pcm512x.c - ASoc Machine driver for Intel Baytrail and + * Cherrytrail-based platforms, with TI PCM512x codec + * + * Copyright (C) 2016 Intel Corporation + * Author: Pierre-Louis Bossart + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/pcm512x.h" +#include "../atom/sst-atom-controls.h" + +static const struct snd_soc_dapm_widget dapm_widgets[] = { + SND_SOC_DAPM_SPK("Ext Spk", NULL), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + /* Speaker */ + {"Ext Spk", NULL, "OUTR"}, + {"Ext Spk", NULL, "OUTL"}, +}; + +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); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will covert the FE rate to 48k, stereo */ + rate->min = 48000; + rate->max = 48000; + channels->min = 2; + channels->max = 2; + + /* set SSP5 to 24 bit */ + snd_mask_none(fmt); + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +static int aif1_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + + snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); + + return snd_pcm_hw_constraint_single(substream->runtime, + SNDRV_PCM_HW_PARAM_RATE, 48000); +} + +static void aif1_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + + snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x00); +} + +static int init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec; + + snd_soc_update_bits(codec, PCM512x_GPIO_EN, 0x08, 0x08); + snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02); + snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); + + return 0; +} + +static const struct snd_soc_ops aif1_ops = { + .startup = aif1_startup, + .shutdown = aif1_shutdown, +}; + +static struct snd_soc_dai_link dailink[] = { + /* CODEC<->CODEC link */ + /* back ends */ + { + .name = "SSP5-Codec", + .id = 0, + .cpu_dai_name = "sof-audio", + .platform_name = "sof-audio", + .no_pcm = 1, + .codec_dai_name = "pcm512x-hifi", + .codec_name = "i2c-104C5122:00", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .init = init, + .be_hw_params_fixup = codec_fixup, + .nonatomic = true, + .dpcm_playback = 1, + }, +}; + +/* SoC card */ +static struct snd_soc_card bxt_pcm512x_card = { + .name = "bxt-pcm512x", + .owner = THIS_MODULE, + .dai_link = dailink, + .num_links = ARRAY_SIZE(dailink), + .dapm_widgets = dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(dapm_widgets), + .dapm_routes = audio_map, + .num_dapm_routes = ARRAY_SIZE(audio_map), +}; + + /* i2c-:00 with HID being 8 chars */ +static char codec_name[SND_ACPI_I2C_ID_LEN]; + +static int bxt_pcm512x_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card; + struct snd_soc_acpi_mach *mach; + const char *i2c_name = NULL; + int dai_index = 0; + int ret_val = 0, i; + + mach = (&pdev->dev)->platform_data; + card = &bxt_pcm512x_card; + card->dev = &pdev->dev; + + /* fix index of codec dai */ + for (i = 0; i < ARRAY_SIZE(dailink); i++) { + if (!strcmp(dailink[i].codec_name, "i2c-104C5122:00")) { + dai_index = i; + break; + } + } + + /* fixup codec name based on HID */ + i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); + if (i2c_name) { + 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 bxt_pcm521x_driver = { + .driver = { + .name = "bxt-pcm512x", + }, + .probe = bxt_pcm512x_probe, +}; +module_platform_driver(bxt_pcm521x_driver); + +MODULE_DESCRIPTION("ASoC Intel(R) Broxton + PCM512x Machine driver"); +MODULE_AUTHOR("Pierre-Louis Bossart"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:bxt-pcm512x"); From 8a8d04449e9e0edd2b7aad7540b3365b50b82109 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Thu, 7 Jun 2018 14:24:12 +0800 Subject: [PATCH 0139/1995] ASoC: Intel: replace snd_soc_codec to snd_soc_component in bxt-pcm512x Codec may be can not use now, use the component instead. Signed-off-by: Pan Xiuli --- sound/soc/intel/boards/bxt_pcm512x.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/boards/bxt_pcm512x.c b/sound/soc/intel/boards/bxt_pcm512x.c index f8c734faef396d..a54eb1de46c6d6 100644 --- a/sound/soc/intel/boards/bxt_pcm512x.c +++ b/sound/soc/intel/boards/bxt_pcm512x.c @@ -65,9 +65,10 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd, static int aif1_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_component *codec = rtd->codec_dai->component; - snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); + snd_soc_component_update_bits(codec, PCM512x_GPIO_CONTROL_1, + 0x08, 0x08); return snd_pcm_hw_constraint_single(substream->runtime, SNDRV_PCM_HW_PARAM_RATE, 48000); @@ -76,18 +77,20 @@ static int aif1_startup(struct snd_pcm_substream *substream) static void aif1_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_component *codec = rtd->codec_dai->component; - snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x00); + snd_soc_component_update_bits(codec, PCM512x_GPIO_CONTROL_1, + 0x08, 0x00); } static int init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_component *codec = rtd->codec_dai->component; - snd_soc_update_bits(codec, PCM512x_GPIO_EN, 0x08, 0x08); - snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02); - snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08, 0x08); + snd_soc_component_update_bits(codec, PCM512x_GPIO_EN, 0x08, 0x08); + snd_soc_component_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02); + snd_soc_component_update_bits(codec, PCM512x_GPIO_CONTROL_1, + 0x08, 0x08); return 0; } From 17c9650d86f9243529bdc1796c1f49e14730c1d4 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Tue, 10 Jul 2018 10:51:25 +0800 Subject: [PATCH 0140/1995] ASoC: Intel: fix dai link for bxt_pcm512x Change cpu dai name for SSP5 and add capture capability. Signed-off-by: Pan Xiuli --- sound/soc/intel/boards/bxt_pcm512x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bxt_pcm512x.c b/sound/soc/intel/boards/bxt_pcm512x.c index a54eb1de46c6d6..d2edbd9749d96a 100644 --- a/sound/soc/intel/boards/bxt_pcm512x.c +++ b/sound/soc/intel/boards/bxt_pcm512x.c @@ -106,7 +106,7 @@ static struct snd_soc_dai_link dailink[] = { { .name = "SSP5-Codec", .id = 0, - .cpu_dai_name = "sof-audio", + .cpu_dai_name = "SSP5 Pin", .platform_name = "sof-audio", .no_pcm = 1, .codec_dai_name = "pcm512x-hifi", @@ -117,6 +117,7 @@ static struct snd_soc_dai_link dailink[] = { .be_hw_params_fixup = codec_fixup, .nonatomic = true, .dpcm_playback = 1, + .dpcm_capture = 1, }, }; From 14dd930012dd725ce4692fa4a1fa4a4be8cc4a68 Mon Sep 17 00:00:00 2001 From: Guneshwor Singh Date: Wed, 23 Nov 2016 19:05:46 +0530 Subject: [PATCH 0141/1995] ASoC: Intel: Boards: Add CNL RT274 I2S machine driver Add the CNL I2S machine driver using Realtek ALC274 codec in I2S mode. Change-Id: Ife808f52d69e73a8156130c446a3ab0602fff63d Signed-off-by: Guneshwor Singh Reviewed-on: https://git-gar-1.devtools.intel.com/gerrit/12406 Reviewed-by: Kale, Sanyog R Reviewed-by: Kp, Jeeja Tested-by: Avati, Santosh Kumar --- sound/soc/intel/boards/Kconfig | 16 ++ sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/cnl_rt274.c | 385 +++++++++++++++++++++++++++++ 3 files changed, 403 insertions(+) create mode 100644 sound/soc/intel/boards/cnl_rt274.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 2a4b13b53d6c33..cff1f500b5571c 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -353,4 +353,20 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH endif ## SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_GEMINILAKE +if SND_SOC_INTEL_SKYLAKE + +config SND_SOC_INTEL_CNL_RT274_MACH + tristate "Cannonlake with RT274 I2S mode" + depends on MFD_INTEL_LPSS && I2C && ACPI + select SND_SOC_RT274 + select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC machine driver for Cannonlake platform + with RT274 I2S audio codec. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + +endif ## SND_SOC_INTEL_SKYLAKE + endif ## SND_SOC_INTEL_MACH diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index bf663d98cd5486..9a12cbd87d3096 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -25,6 +25,7 @@ snd-soc-skl_rt286-objs := skl_rt286.o snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o +snd-soc-cnl-rt274-objs := cnl_rt274.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o @@ -52,3 +53,4 @@ obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o +obj-$(CONFIG_SND_SOC_INTEL_CNL_RT274_MACH) += snd-soc-cnl-rt274.o diff --git a/sound/soc/intel/boards/cnl_rt274.c b/sound/soc/intel/boards/cnl_rt274.c new file mode 100644 index 00000000000000..1b788f8e59a22f --- /dev/null +++ b/sound/soc/intel/boards/cnl_rt274.c @@ -0,0 +1,385 @@ +/* + * cnl_rt274.c - ASOC Machine driver for CNL + * + * Copyright (C) 2016 Intel Corp + * Author: Guneshwor Singh + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../codecs/rt274.h" + +static struct snd_soc_jack cnl_headset; + +/* Headset jack detection DAPM pins */ +static struct snd_soc_jack_pin cnl_headset_pins[] = { + { + .pin = "Mic Jack", + .mask = SND_JACK_MICROPHONE, + }, + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, +}; + +static const struct snd_kcontrol_new cnl_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Mic Jack"), +}; + +static const struct snd_soc_dapm_widget cnl_rt274_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_MIC("SoC DMIC", NULL), +}; + +static int cnl_dmic_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + channels->min = channels->max = 2; + + return 0; +} + +static const struct snd_soc_dapm_route cnl_map[] = { + {"Headphone Jack", NULL, "HPO Pin"}, + {"MIC", NULL, "Mic Jack"}, + {"DMic", NULL, "SoC DMIC"}, + {"DMIC01 Rx", NULL, "Capture"}, + {"dmic01_hifi", NULL, "DMIC01 Rx"}, + + /* ssp2 path */ + {"Dummy Playback", NULL, "ssp2 Tx"}, + {"ssp2 Tx", NULL, "ssp2_out"}, + + {"ssp2 Rx", NULL, "Dummy Capture"}, + {"ssp2_in", NULL, "ssp2 Rx"}, + + /* ssp1 path */ + {"Dummy Playback", NULL, "ssp1 Tx"}, + {"ssp1 Tx", NULL, "ssp1_out"}, + + {"AIF1 Playback", NULL, "ssp0 Tx"}, + {"ssp0 Tx", NULL, "codec1_out"}, + {"ssp0 Tx", NULL, "codec0_out"}, + + {"ssp0 Rx", NULL, "AIF1 Capture"}, + {"codec0_in", NULL, "ssp0 Rx"}, +}; + +static int cnl_rt274_init(struct snd_soc_pcm_runtime *runtime) +{ + int ret; + struct snd_soc_codec *codec = runtime->codec; + struct snd_soc_card *card = runtime->card; + struct snd_soc_dai *codec_dai = runtime->codec_dai; + + ret = snd_soc_card_jack_new(runtime->card, "Headset", + SND_JACK_HEADSET, &cnl_headset, + cnl_headset_pins, ARRAY_SIZE(cnl_headset_pins)); + + if (ret) + return ret; + + snd_soc_codec_set_jack(codec, &cnl_headset, NULL); + + /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); + if (ret < 0) { + dev_err(runtime->dev, "can't set codec pcm format %d\n", ret); + return ret; + } + + card->dapm.idle_bias_off = true; + + return 0; +} + +static unsigned int rates_supported[] = { + 48000, + 32000, + 24000, + 16000, + 8000, +}; + +static struct snd_pcm_hw_constraint_list rate_constraints = { + .count = ARRAY_SIZE(rates_supported), + .list = rates_supported, +}; + +static int cnl_fe_startup(struct snd_pcm_substream *substream) +{ + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &rate_constraints); +} + +static struct snd_soc_ops cnl_fe_ops = { + .startup = cnl_fe_startup, +}; + +static int cnl_be_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); + + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + snd_mask_none(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT)); + snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), + (unsigned int __force)SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +#define CNL_FREQ_OUT 19200000 + +static int rt274_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, ratio = 100; + + snd_soc_dai_set_bclk_ratio(codec_dai, ratio); + + ret = snd_soc_dai_set_pll(codec_dai, 0, RT274_PLL2_S_BCLK, + ratio * params_rate(params), CNL_FREQ_OUT); + if (ret != 0) { + dev_err(rtd->dev, "Failed to enable PLL2 with Ref Clock Loop: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, RT274_SCLK_S_PLL2, CNL_FREQ_OUT, + SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret); + + return ret; +} + +static struct snd_soc_ops rt274_ops = { + .hw_params = rt274_hw_params, +}; + +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL_FPGA) +static const char pname[] = "0000:02:18.0"; +static const char cname[] = "rt274.0-001c"; +#else +static const char pname[] = "0000:00:1f.3"; +static const char cname[] = "i2c-INT34C2:00"; +#endif + +static struct snd_soc_dai_link cnl_rt274_msic_dailink[] = { + { + .name = "CNL Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "System Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = pname, + .ignore_suspend = 1, + .nonatomic = 1, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &cnl_fe_ops, + }, + { + .name = "CNL Deepbuffer Port", + .stream_name = "Deep Buffer Audio", + .cpu_dai_name = "Deepbuffer Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = pname, + .dpcm_playback = 1, + .ignore_suspend = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &cnl_fe_ops, + }, + { + .name = "CNL Reference Port", + .stream_name = "Reference Capture", + .cpu_dai_name = "Reference Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = pname, + .dpcm_capture = 1, + .ignore_suspend = 1, + .nonatomic = 1, + .dynamic = 1, + }, + /* Trace Buffer DAI links */ + { + .name = "CNL Trace Buffer0", + .stream_name = "Core 0 Trace Buffer", + .cpu_dai_name = "TraceBuffer0 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = pname, + .capture_only = true, + .ignore_suspend = 1, + }, + { + .name = "CNL Trace Buffer1", + .stream_name = "Core 1 Trace Buffer", + .cpu_dai_name = "TraceBuffer1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = pname, + .capture_only = true, + .ignore_suspend = 1, + }, + { + .name = "CNL Trace Buffer2", + .stream_name = "Core 2 Trace Buffer", + .cpu_dai_name = "TraceBuffer2 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = pname, + .capture_only = true, + .ignore_suspend = 1, + }, + { + .name = "CNL Trace Buffer3", + .stream_name = "Core 3 Trace Buffer", + .cpu_dai_name = "TraceBuffer3 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = pname, + .capture_only = true, + .ignore_suspend = 1, + }, + /* Probe DAI-links */ + { + .name = "CNL Compress Probe playback", + .stream_name = "Probe Playback", + .cpu_dai_name = "Compress Probe0 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = pname, + .init = NULL, + .ignore_suspend = 1, + .nonatomic = 1, + }, + { + .name = "CNL Compress Probe capture", + .stream_name = "Probe Capture", + .cpu_dai_name = "Compress Probe1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = pname, + .init = NULL, + .ignore_suspend = 1, + .nonatomic = 1, + }, + /* back ends */ + { + .name = "SSP0-Codec", + .id = 1, + .cpu_dai_name = "SSP0 Pin", + .codec_name = cname, + .codec_dai_name = "rt274-aif1", + .platform_name = pname, + .be_hw_params_fixup = cnl_be_fixup, + .ignore_suspend = 1, + .no_pcm = 1, + .dai_fmt = SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = cnl_rt274_init, + .ops = &rt274_ops, + }, + { + .name = "SSP1-Codec", + .id = 2, + .cpu_dai_name = "SSP1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = pname, + .be_hw_params_fixup = cnl_be_fixup, + .ignore_suspend = 1, + .no_pcm = 1, + .dpcm_playback = 1, + }, + { + .name = "dmic01", + .id = 3, + .cpu_dai_name = "DMIC01 Pin", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", + .platform_name = pname, + .ignore_suspend = 1, + .no_pcm = 1, + .dpcm_capture = 1, + .be_hw_params_fixup = cnl_dmic_fixup, + }, +}; + +/* SoC card */ +static struct snd_soc_card snd_soc_card_cnl = { + .name = "cnl-audio", + .dai_link = cnl_rt274_msic_dailink, + .num_links = ARRAY_SIZE(cnl_rt274_msic_dailink), + .dapm_widgets = cnl_rt274_widgets, + .num_dapm_widgets = ARRAY_SIZE(cnl_rt274_widgets), + .dapm_routes = cnl_map, + .num_dapm_routes = ARRAY_SIZE(cnl_map), + .controls = cnl_controls, + .num_controls = ARRAY_SIZE(cnl_controls), +}; + +static int snd_cnl_rt274_mc_probe(struct platform_device *pdev) +{ + snd_soc_card_cnl.dev = &pdev->dev; + return devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cnl); +} + +static struct platform_driver snd_cnl_rt274_driver = { + .driver = { + .name = "cnl_rt274", + .pm = &snd_soc_pm_ops, + }, + .probe = snd_cnl_rt274_mc_probe, +}; + +module_platform_driver(snd_cnl_rt274_driver); + +MODULE_AUTHOR("Guneshwor Singh "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cnl_rt274"); From da28fa27d85b785b2ca522fdf6e4589649d896ab Mon Sep 17 00:00:00 2001 From: Guneshwor Singh Date: Mon, 27 Feb 2017 09:09:37 +0530 Subject: [PATCH 0142/1995] ASoC: Intel: board: Add support for dynamic FE dai link in cnl_rt274 machine FE dai links now come from topology, so remove them from machine driver. Additionally register ops to initialize dai link. Rate constraint is not required as rates will come from topology. So remove the startup ops as well which sets the rate constraint. Change-Id: I0fb07c74450bf55415323539e383ef39ed3ff4c4 Signed-off-by: Guneshwor Singh Reviewed-on: https://git-gar-1.devtools.intel.com/gerrit/13924 Reviewed-by: Koul, Vinod Reviewed-by: Prusty, Subhransu S Reviewed-by: Kp, Jeeja Reviewed-by: Nc, Shreyas Reviewed-by: Diwakar, Praveen Tested-by: Sm, Bhadur A --- sound/soc/intel/boards/cnl_rt274.c | 73 ++++-------------------------- 1 file changed, 10 insertions(+), 63 deletions(-) diff --git a/sound/soc/intel/boards/cnl_rt274.c b/sound/soc/intel/boards/cnl_rt274.c index 1b788f8e59a22f..436a11d9a4f8c1 100644 --- a/sound/soc/intel/boards/cnl_rt274.c +++ b/sound/soc/intel/boards/cnl_rt274.c @@ -124,30 +124,6 @@ static int cnl_rt274_init(struct snd_soc_pcm_runtime *runtime) return 0; } -static unsigned int rates_supported[] = { - 48000, - 32000, - 24000, - 16000, - 8000, -}; - -static struct snd_pcm_hw_constraint_list rate_constraints = { - .count = ARRAY_SIZE(rates_supported), - .list = rates_supported, -}; - -static int cnl_fe_startup(struct snd_pcm_substream *substream) -{ - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &rate_constraints); -} - -static struct snd_soc_ops cnl_fe_ops = { - .startup = cnl_fe_startup, -}; - static int cnl_be_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -204,45 +180,6 @@ static const char cname[] = "i2c-INT34C2:00"; #endif static struct snd_soc_dai_link cnl_rt274_msic_dailink[] = { - { - .name = "CNL Audio Port", - .stream_name = "Audio", - .cpu_dai_name = "System Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = pname, - .ignore_suspend = 1, - .nonatomic = 1, - .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, - .ops = &cnl_fe_ops, - }, - { - .name = "CNL Deepbuffer Port", - .stream_name = "Deep Buffer Audio", - .cpu_dai_name = "Deepbuffer Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = pname, - .dpcm_playback = 1, - .ignore_suspend = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &cnl_fe_ops, - }, - { - .name = "CNL Reference Port", - .stream_name = "Reference Capture", - .cpu_dai_name = "Reference Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = pname, - .dpcm_capture = 1, - .ignore_suspend = 1, - .nonatomic = 1, - .dynamic = 1, - }, /* Trace Buffer DAI links */ { .name = "CNL Trace Buffer0", @@ -351,6 +288,15 @@ static struct snd_soc_dai_link cnl_rt274_msic_dailink[] = { }, }; +static int +cnl_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) +{ + link->platform_name = pname; + link->nonatomic = 1; + + return 0; +} + /* SoC card */ static struct snd_soc_card snd_soc_card_cnl = { .name = "cnl-audio", @@ -362,6 +308,7 @@ static struct snd_soc_card snd_soc_card_cnl = { .num_dapm_routes = ARRAY_SIZE(cnl_map), .controls = cnl_controls, .num_controls = ARRAY_SIZE(cnl_controls), + .add_dai_link = cnl_add_dai_link, }; static int snd_cnl_rt274_mc_probe(struct platform_device *pdev) From 411cc11e0b1bf33870673dba681a62b9ab048f5d Mon Sep 17 00:00:00 2001 From: Guneshwor Singh Date: Tue, 4 Apr 2017 08:34:51 +0530 Subject: [PATCH 0143/1995] ASoC: Intel: board: Move cnl_rt274 clock setting to supply widget During BE-BE loop, codec clocks were not set as it was a part of dai link ops hw_params and no sound was heard due to this reason when use cases involve BE-BE loop. So, move codec clock setting as a part of supply widget and define routes appropriately. Also use macro to define BE rate fixup and use it for both fixup as well as clock computation. Change-Id: Id5a08d2bd6024a61b601dbbe70ad99a52149da5e Signed-off-by: Guneshwor Singh Reviewed-on: https://git-gar-1.devtools.intel.com/gerrit/14595 Reviewed-by: Prusty, Subhransu S Reviewed-by: Kale, Sanyog R Reviewed-by: R, Dharageswari Reviewed-by: Diwakar, Praveen Tested-by: Avati, Santosh Kumar --- sound/soc/intel/boards/cnl_rt274.c | 89 +++++++++++++++++++----------- 1 file changed, 57 insertions(+), 32 deletions(-) diff --git a/sound/soc/intel/boards/cnl_rt274.c b/sound/soc/intel/boards/cnl_rt274.c index 436a11d9a4f8c1..b67330dcfa07d8 100644 --- a/sound/soc/intel/boards/cnl_rt274.c +++ b/sound/soc/intel/boards/cnl_rt274.c @@ -35,6 +35,56 @@ #include "../../codecs/rt274.h" +#define CNL_FREQ_OUT 19200000 +#define CNL_BE_FIXUP_RATE 48000 +#define RT274_CODEC_DAI "rt274-aif1" + +static struct snd_soc_dai *cnl_get_codec_dai(struct snd_soc_card *card, + const char *dai_name) +{ + struct snd_soc_pcm_runtime *rtd; + + list_for_each_entry(rtd, &card->rtd_list, list) { + if (!strcmp(rtd->codec_dai->name, dai_name)) + return rtd->codec_dai; + } + + return NULL; +} + +static int cnl_rt274_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + int ret = 0, ratio = 100; + struct snd_soc_dai *codec_dai = cnl_get_codec_dai(card, + RT274_CODEC_DAI); + + /* Codec needs clock for Jack detection and button press */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT274_SCLK_S_PLL2, + CNL_FREQ_OUT, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, "set codec sysclk failed: %d\n", ret); + return ret; + } + + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_dai_set_bclk_ratio(codec_dai, ratio); + + ret = snd_soc_dai_set_pll(codec_dai, 0, RT274_PLL2_S_BCLK, + CNL_BE_FIXUP_RATE * ratio, + CNL_FREQ_OUT); + if (ret) { + dev_err(codec_dai->dev, + "failed to enable PLL2: %d\n", ret); + return ret; + } + } + + return ret; +} + static struct snd_soc_jack cnl_headset; /* Headset jack detection DAPM pins */ @@ -58,6 +108,9 @@ static const struct snd_soc_dapm_widget cnl_rt274_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Mic Jack", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + cnl_rt274_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), }; static int cnl_dmic_fixup(struct snd_soc_pcm_runtime *rtd, @@ -94,6 +147,9 @@ static const struct snd_soc_dapm_route cnl_map[] = { {"ssp0 Rx", NULL, "AIF1 Capture"}, {"codec0_in", NULL, "ssp0 Rx"}, + + {"Headphone Jack", NULL, "Platform Clock"}, + {"MIC", NULL, "Platform Clock"}, }; static int cnl_rt274_init(struct snd_soc_pcm_runtime *runtime) @@ -132,7 +188,7 @@ static int cnl_be_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - rate->min = rate->max = 48000; + rate->min = rate->max = CNL_BE_FIXUP_RATE; channels->min = channels->max = 2; snd_mask_none(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT)); snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), @@ -141,36 +197,6 @@ static int cnl_be_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -#define CNL_FREQ_OUT 19200000 - -static int rt274_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, ratio = 100; - - snd_soc_dai_set_bclk_ratio(codec_dai, ratio); - - ret = snd_soc_dai_set_pll(codec_dai, 0, RT274_PLL2_S_BCLK, - ratio * params_rate(params), CNL_FREQ_OUT); - if (ret != 0) { - dev_err(rtd->dev, "Failed to enable PLL2 with Ref Clock Loop: %d\n", ret); - return ret; - } - - ret = snd_soc_dai_set_sysclk(codec_dai, RT274_SCLK_S_PLL2, CNL_FREQ_OUT, - SND_SOC_CLOCK_IN); - if (ret < 0) - dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret); - - return ret; -} - -static struct snd_soc_ops rt274_ops = { - .hw_params = rt274_hw_params, -}; - #if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL_FPGA) static const char pname[] = "0000:02:18.0"; static const char cname[] = "rt274.0-001c"; @@ -260,7 +286,6 @@ static struct snd_soc_dai_link cnl_rt274_msic_dailink[] = { .dpcm_playback = 1, .dpcm_capture = 1, .init = cnl_rt274_init, - .ops = &rt274_ops, }, { .name = "SSP1-Codec", From 4db2c54797bac3bbbe62a84065e3fcbc98eeed91 Mon Sep 17 00:00:00 2001 From: Guneshwor Singh Date: Thu, 15 Jun 2017 15:08:06 +0530 Subject: [PATCH 0144/1995] ASoC: Intel: boards: Remove SSP1-codec dai link from cnl_rt274 machine Since NHLT does not have SSP1 endpoint, remove it from the dai link definitions Change-Id: I7b08f43d21eeff9decb5722e3af4f142f800b3f7 Signed-off-by: Guneshwor Singh Reviewed-on: https://git-gar-1.devtools.intel.com/gerrit/15999 Reviewed-by: Prusty, Subhransu S Reviewed-by: Koul, Vinod Reviewed-by: Babu, Ramesh Reviewed-by: audio_build Reviewed-by: Diwakar, Praveen Tested-by: Sm, Bhadur A --- sound/soc/intel/boards/cnl_rt274.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/sound/soc/intel/boards/cnl_rt274.c b/sound/soc/intel/boards/cnl_rt274.c index b67330dcfa07d8..677724273c2630 100644 --- a/sound/soc/intel/boards/cnl_rt274.c +++ b/sound/soc/intel/boards/cnl_rt274.c @@ -287,21 +287,9 @@ static struct snd_soc_dai_link cnl_rt274_msic_dailink[] = { .dpcm_capture = 1, .init = cnl_rt274_init, }, - { - .name = "SSP1-Codec", - .id = 2, - .cpu_dai_name = "SSP1 Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = pname, - .be_hw_params_fixup = cnl_be_fixup, - .ignore_suspend = 1, - .no_pcm = 1, - .dpcm_playback = 1, - }, { .name = "dmic01", - .id = 3, + .id = 2, .cpu_dai_name = "DMIC01 Pin", .codec_name = "dmic-codec", .codec_dai_name = "dmic-hifi", From 800b0f3fd9ccb60586281eca9496499e3113987d Mon Sep 17 00:00:00 2001 From: Pankaj Bharadiya Date: Wed, 6 Sep 2017 14:04:55 +0530 Subject: [PATCH 0145/1995] ASoC: Intel: Skylake: Fix codec_dai NULL pointer dereferening Pointer 'codec_dai' returned from call to cnl_get_codec_dai() can be NULL. Check for the valid pointer before dereferencing. Change-Id: I783b6220e32a9b8bf7655b92df7a4b034175a509 Signed-off-by: Pankaj Bharadiya Reviewed-on: https://git-gar-1.devtools.intel.com/gerrit/18681 Reviewed-by: Prusty, Subhransu S Reviewed-by: audio_build Reviewed-by: Koul, Vinod Tested-by: Sm, Bhadur A --- sound/soc/intel/boards/cnl_rt274.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/intel/boards/cnl_rt274.c b/sound/soc/intel/boards/cnl_rt274.c index 677724273c2630..6a048213cf509c 100644 --- a/sound/soc/intel/boards/cnl_rt274.c +++ b/sound/soc/intel/boards/cnl_rt274.c @@ -60,6 +60,8 @@ static int cnl_rt274_clock_control(struct snd_soc_dapm_widget *w, int ret = 0, ratio = 100; struct snd_soc_dai *codec_dai = cnl_get_codec_dai(card, RT274_CODEC_DAI); + if (!codec_dai) + return -EINVAL; /* Codec needs clock for Jack detection and button press */ ret = snd_soc_dai_set_sysclk(codec_dai, RT274_SCLK_S_PLL2, From 0be639595a9f52983d2f0219f7754833f7702019 Mon Sep 17 00:00:00 2001 From: Shahina Shaik Date: Mon, 30 Apr 2018 18:47:02 +0530 Subject: [PATCH 0146/1995] ASoC: Intel: Boards: Replace codec to component in RT274 machine driver As the framework is changed in kernel 4.17 version, replace codec variable with component and use component specific function to set jack. Change-Id: Id6d1cda7968a5d524a3210f1b38221214c2bb67d Signed-off-by: Shahina Shaik --- sound/soc/intel/boards/cnl_rt274.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/cnl_rt274.c b/sound/soc/intel/boards/cnl_rt274.c index 6a048213cf509c..0926e6c4b6ebc1 100644 --- a/sound/soc/intel/boards/cnl_rt274.c +++ b/sound/soc/intel/boards/cnl_rt274.c @@ -157,7 +157,7 @@ static const struct snd_soc_dapm_route cnl_map[] = { static int cnl_rt274_init(struct snd_soc_pcm_runtime *runtime) { int ret; - struct snd_soc_codec *codec = runtime->codec; + struct snd_soc_component *component = runtime->codec_dai->component;; struct snd_soc_card *card = runtime->card; struct snd_soc_dai *codec_dai = runtime->codec_dai; @@ -168,7 +168,7 @@ static int cnl_rt274_init(struct snd_soc_pcm_runtime *runtime) if (ret) return ret; - snd_soc_codec_set_jack(codec, &cnl_headset, NULL); + snd_soc_component_set_jack(component, &cnl_headset, NULL); /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); From d61d35b3590b5b4bb65c773de5768eabee0ad1c4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 23 Jun 2018 09:50:50 -0500 Subject: [PATCH 0147/1995] ASoC: Intel: cnl-rt274: fix compilation warning Needs to be squashed with component model update, kept separate to avoid merge issues with SST code Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/cnl_rt274.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/cnl_rt274.c b/sound/soc/intel/boards/cnl_rt274.c index 0926e6c4b6ebc1..2d55e4d878b70e 100644 --- a/sound/soc/intel/boards/cnl_rt274.c +++ b/sound/soc/intel/boards/cnl_rt274.c @@ -157,7 +157,7 @@ static const struct snd_soc_dapm_route cnl_map[] = { static int cnl_rt274_init(struct snd_soc_pcm_runtime *runtime) { int ret; - struct snd_soc_component *component = runtime->codec_dai->component;; + struct snd_soc_component *component = runtime->codec_dai->component; struct snd_soc_card *card = runtime->card; struct snd_soc_dai *codec_dai = runtime->codec_dai; From e3c829749d3450ff3efb4751b90abf4964ad9787 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 23 Jun 2018 09:27:25 -0500 Subject: [PATCH 0148/1995] ASoC: Intel: cnl-rt274: fix clock settings Use 24MHz instead of 19.2 (Mandatory rework) and use helper to find the dai Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/cnl_rt274.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/sound/soc/intel/boards/cnl_rt274.c b/sound/soc/intel/boards/cnl_rt274.c index 2d55e4d878b70e..0dacf9401e087e 100644 --- a/sound/soc/intel/boards/cnl_rt274.c +++ b/sound/soc/intel/boards/cnl_rt274.c @@ -35,30 +35,19 @@ #include "../../codecs/rt274.h" -#define CNL_FREQ_OUT 19200000 +#define CNL_FREQ_OUT 24000000 #define CNL_BE_FIXUP_RATE 48000 #define RT274_CODEC_DAI "rt274-aif1" -static struct snd_soc_dai *cnl_get_codec_dai(struct snd_soc_card *card, - const char *dai_name) -{ - struct snd_soc_pcm_runtime *rtd; - - list_for_each_entry(rtd, &card->rtd_list, list) { - if (!strcmp(rtd->codec_dai->name, dai_name)) - return rtd->codec_dai; - } - - return NULL; -} - static int cnl_rt274_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) + struct snd_kcontrol *k, int event) { struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; - int ret = 0, ratio = 100; - struct snd_soc_dai *codec_dai = cnl_get_codec_dai(card, + int ret = 0; + int ratio = 100; + + struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, RT274_CODEC_DAI); if (!codec_dai) return -EINVAL; From b0173303d612d574919f4bca90e42fa49c494f61 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 17 May 2018 20:43:51 -0500 Subject: [PATCH 0149/1995] ASoC: Intel: make cnl_rt274 work with SOF (1)refine machine driver to make it work with sof (2)disable DMIC for it is not ready now Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 4 ++-- sound/soc/intel/boards/cnl_rt274.c | 26 +++++++++++++++++--------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index cff1f500b5571c..5e8cdf393cbd3c 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -353,7 +353,7 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH endif ## SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_GEMINILAKE -if SND_SOC_INTEL_SKYLAKE +if SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_CANNONLAKE config SND_SOC_INTEL_CNL_RT274_MACH tristate "Cannonlake with RT274 I2S mode" @@ -367,6 +367,6 @@ config SND_SOC_INTEL_CNL_RT274_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". -endif ## SND_SOC_INTEL_SKYLAKE +endif ## SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_CANNONLAKE endif ## SND_SOC_INTEL_MACH diff --git a/sound/soc/intel/boards/cnl_rt274.c b/sound/soc/intel/boards/cnl_rt274.c index 0dacf9401e087e..98a7b3015c0d23 100644 --- a/sound/soc/intel/boards/cnl_rt274.c +++ b/sound/soc/intel/boards/cnl_rt274.c @@ -100,10 +100,11 @@ static const struct snd_soc_dapm_widget cnl_rt274_widgets[] = { SND_SOC_DAPM_MIC("Mic Jack", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - cnl_rt274_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), + cnl_rt274_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), }; +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) static int cnl_dmic_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -113,6 +114,7 @@ static int cnl_dmic_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } +#endif static const struct snd_soc_dapm_route cnl_map[] = { {"Headphone Jack", NULL, "HPO Pin"}, @@ -151,8 +153,9 @@ static int cnl_rt274_init(struct snd_soc_pcm_runtime *runtime) struct snd_soc_dai *codec_dai = runtime->codec_dai; ret = snd_soc_card_jack_new(runtime->card, "Headset", - SND_JACK_HEADSET, &cnl_headset, - cnl_headset_pins, ARRAY_SIZE(cnl_headset_pins)); + SND_JACK_HEADSET, &cnl_headset, + cnl_headset_pins, + ARRAY_SIZE(cnl_headset_pins)); if (ret) return ret; @@ -172,15 +175,17 @@ static int cnl_rt274_init(struct snd_soc_pcm_runtime *runtime) } static int cnl_be_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) + 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); - rate->min = rate->max = CNL_BE_FIXUP_RATE; - channels->min = channels->max = 2; + rate->min = CNL_BE_FIXUP_RATE; + rate->max = CNL_BE_FIXUP_RATE; + channels->min = 2; + channels->max = 2; snd_mask_none(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT)); snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), (unsigned int __force)SNDRV_PCM_FORMAT_S24_LE); @@ -197,6 +202,7 @@ static const char cname[] = "i2c-INT34C2:00"; #endif static struct snd_soc_dai_link cnl_rt274_msic_dailink[] = { +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) /* Trace Buffer DAI links */ { .name = "CNL Trace Buffer0", @@ -261,6 +267,7 @@ static struct snd_soc_dai_link cnl_rt274_msic_dailink[] = { .ignore_suspend = 1, .nonatomic = 1, }, +#endif /* back ends */ { .name = "SSP0-Codec", @@ -268,7 +275,6 @@ static struct snd_soc_dai_link cnl_rt274_msic_dailink[] = { .cpu_dai_name = "SSP0 Pin", .codec_name = cname, .codec_dai_name = "rt274-aif1", - .platform_name = pname, .be_hw_params_fixup = cnl_be_fixup, .ignore_suspend = 1, .no_pcm = 1, @@ -278,18 +284,19 @@ static struct snd_soc_dai_link cnl_rt274_msic_dailink[] = { .dpcm_capture = 1, .init = cnl_rt274_init, }, +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) { .name = "dmic01", .id = 2, .cpu_dai_name = "DMIC01 Pin", .codec_name = "dmic-codec", .codec_dai_name = "dmic-hifi", - .platform_name = pname, .ignore_suspend = 1, .no_pcm = 1, .dpcm_capture = 1, .be_hw_params_fixup = cnl_dmic_fixup, }, +#endif }; static int @@ -313,6 +320,7 @@ static struct snd_soc_card snd_soc_card_cnl = { .controls = cnl_controls, .num_controls = ARRAY_SIZE(cnl_controls), .add_dai_link = cnl_add_dai_link, + .fully_routed = true, }; static int snd_cnl_rt274_mc_probe(struct platform_device *pdev) From fa0343ae257b0c8d28d1c5a99f9bc67236b095fb Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 29 Jun 2018 14:24:51 +0800 Subject: [PATCH 0150/1995] Asoc: Intel: refine rt274 machine driver for SOF Add SOF platform name Signed-off-by: Rander Wang --- sound/soc/intel/boards/cnl_rt274.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/intel/boards/cnl_rt274.c b/sound/soc/intel/boards/cnl_rt274.c index 98a7b3015c0d23..0689c63304ea46 100644 --- a/sound/soc/intel/boards/cnl_rt274.c +++ b/sound/soc/intel/boards/cnl_rt274.c @@ -197,7 +197,11 @@ static int cnl_be_fixup(struct snd_soc_pcm_runtime *rtd, static const char pname[] = "0000:02:18.0"; static const char cname[] = "rt274.0-001c"; #else +#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) +static const char pname[] = "sof-audio"; +#else static const char pname[] = "0000:00:1f.3"; +#endif static const char cname[] = "i2c-INT34C2:00"; #endif From 0145658ff1a20978b0548a7751ab28db337dfee5 Mon Sep 17 00:00:00 2001 From: "Wagner, Steffen" Date: Tue, 15 May 2018 17:14:50 +0800 Subject: [PATCH 0151/1995] ASoC: tdf8532: NXP TDF8532 audio class-D amplifier driver This is a basic driver to register the codec, expose the codec DAI and control the power mode of the amplifier. Change-Id: Ie6ab037cd4d6c87e8e139b6d8af6cd4295445bf2 Signed-off-by: Mohit Sinha Signed-off-by: Steffen Wagner Reviewed-on: https://git-gar-1.devtools.intel.com/gerrit/15296 Reviewed-by: B, Jayachandran Reviewed-by: Shaik, Kareem M Reviewed-by: Koul, Vinod Tested-by: Sm, Bhadur A --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tdf8532.c | 379 +++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tdf8532.h | 101 ++++++++++ 4 files changed, 487 insertions(+) create mode 100644 sound/soc/codecs/tdf8532.c create mode 100644 sound/soc/codecs/tdf8532.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index bf0b949eb7e82a..a228f33633ef5a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -164,6 +164,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TAS5720 if I2C select SND_SOC_TAS6424 if I2C select SND_SOC_TDA7419 if I2C + select SND_SOC_TDF8532 if I2C select SND_SOC_TFA9879 if I2C select SND_SOC_TLV320AIC23_I2C if I2C select SND_SOC_TLV320AIC23_SPI if SPI_MASTER @@ -993,6 +994,10 @@ config SND_SOC_TDA7419 depends on I2C select REGMAP_I2C +config SND_SOC_TDF8532 + tristate + depends on I2C + config SND_SOC_TFA9879 tristate "NXP Semiconductors TFA9879 amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 3046b33ca9d308..3680e19672d7e0 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -175,6 +175,7 @@ snd-soc-tas571x-objs := tas571x.o snd-soc-tas5720-objs := tas5720.o snd-soc-tas6424-objs := tas6424.o snd-soc-tda7419-objs := tda7419.o +snd-soc-tdf8532-objs := tdf8532.o snd-soc-tfa9879-objs := tfa9879.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o @@ -435,6 +436,7 @@ obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o obj-$(CONFIG_SND_SOC_TAS6424) += snd-soc-tas6424.o obj-$(CONFIG_SND_SOC_TDA7419) += snd-soc-tda7419.o +obj-$(CONFIG_SND_SOC_TDF8532) += snd-soc-tdf8532.o obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o diff --git a/sound/soc/codecs/tdf8532.c b/sound/soc/codecs/tdf8532.c new file mode 100644 index 00000000000000..59db83da37587a --- /dev/null +++ b/sound/soc/codecs/tdf8532.c @@ -0,0 +1,379 @@ +/* + * Codec driver for NXP Semiconductors - TDF8532 + * Copyright (c) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tdf8532.h" + +static int __tdf8532_build_pkt(struct tdf8532_priv *dev_data, + va_list valist, u8 *payload) +{ + int param; + u8 len; + u8 *cmd_payload; + const u8 cmd_offset = 3; + + payload[HEADER_TYPE] = MSG_TYPE_STX; + payload[HEADER_PKTID] = dev_data->pkt_id; + + cmd_payload = &(payload[cmd_offset]); + + param = va_arg(valist, int); + len = 0; + + while (param != END) { + cmd_payload[len] = param; + + len++; + + param = va_arg(valist, int); + } + + payload[HEADER_LEN] = len; + + return len + cmd_offset; +} + +static int __tdf8532_single_write(struct tdf8532_priv *dev_data, + int dummy, ...) +{ + va_list valist; + int ret; + u8 len; + u8 payload[255]; + + va_start(valist, dummy); + + len = __tdf8532_build_pkt(dev_data, valist, payload); + + va_end(valist); + + print_hex_dump_debug("tdf8532-codec: Tx:", DUMP_PREFIX_NONE, 32, 1, + payload, len, false); + ret = i2c_master_send(dev_data->i2c, payload, len); + + dev_data->pkt_id++; + + if (ret < 0) { + dev_err(&(dev_data->i2c->dev), + "i2c send packet returned: %d\n", ret); + + return ret; + } + + return 0; +} + + +static uint8_t tdf8532_read_wait_ack(struct tdf8532_priv *dev_data, + unsigned long timeout) +{ + uint8_t ack_repl[HEADER_SIZE] = {0, 0, 0}; + unsigned long timeout_point = jiffies + timeout; + int ret; + + do { + ret = i2c_master_recv(dev_data->i2c, ack_repl, HEADER_SIZE); + if (ret < 0) + goto out; + } while (time_before(jiffies, timeout_point) && + ack_repl[0] != MSG_TYPE_ACK); + + if (ack_repl[0] != MSG_TYPE_ACK) + return -ETIME; + else + return ack_repl[2]; + +out: + return ret; +} + +static uint8_t tdf8532_single_read(struct tdf8532_priv *dev_data, + char **repl_buff) +{ + int ret; + uint8_t len; + + struct device *dev = &(dev_data->i2c->dev); + + ret = tdf8532_read_wait_ack(dev_data, msecs_to_jiffies(ACK_TIMEOUT)); + + if (ret < 0) { + dev_err(dev, + "Error waiting for ACK reply: %d\n", ret); + goto out; + } + + len = ret + HEADER_SIZE; + + *repl_buff = kzalloc(len, GFP_KERNEL); + + ret = i2c_master_recv(dev_data->i2c, *repl_buff, len); + + print_hex_dump_debug("tdf8532-codec: Rx:", DUMP_PREFIX_NONE, 32, 1, + *repl_buff, len, false); + + if (ret < 0 || ret != len) { + dev_err(dev, + "i2c recv packet returned: %d (expected: %d)\n", + ret, len); + goto out_free; + } + + return len; + +out_free: + kfree(*repl_buff); + repl_buff = NULL; +out: + return ret; +} + +static int tdf8532_get_state(struct tdf8532_priv *dev_data, + struct get_dev_status_repl **status_repl) +{ + int ret = 0; + char *repl_buff = NULL; + + ret = tdf8532_amp_write(dev_data, GET_DEV_STATUS); + if (ret < 0) + goto out; + + ret = tdf8532_single_read(dev_data, &repl_buff); + if (ret < 0) + goto out; + + *status_repl = (struct get_dev_status_repl *) repl_buff; + +out: + return ret; +} + +static int tdf8532_wait_state(struct tdf8532_priv *dev_data, u8 req_state, + unsigned long timeout) +{ + unsigned long timeout_point = jiffies + msecs_to_jiffies(timeout); + int ret; + struct get_dev_status_repl *status_repl; + struct device *dev = &(dev_data->i2c->dev); + + do { + ret = tdf8532_get_state(dev_data, &status_repl); + if (ret < 0) + goto out; + + print_hex_dump_debug("tdf8532-codec: wait_state: ", + DUMP_PREFIX_NONE, 32, 1, status_repl, + 6, false); + } while (time_before(jiffies, timeout_point) + && status_repl->state != req_state); + + if (status_repl->state == req_state) + return 0; + + ret = -ETIME; + + dev_err(dev, "tdf8532-codec: state: %u, req_state: %u, ret: %d\n", + status_repl->state, req_state, ret); + +out: + kfree(status_repl); + return ret; +} + +static int tdf8532_start_play(struct tdf8532_priv *tdf8532) +{ + int ret; + + ret = tdf8532_amp_write(tdf8532, SET_CLK_STATE, CLK_CONNECT); + if (ret < 0) + return ret; + + ret = tdf8532_amp_write(tdf8532, SET_CHNL_ENABLE, + CHNL_MASK(tdf8532->channels)); + + if (ret >= 0) + ret = tdf8532_wait_state(tdf8532, STATE_PLAY, ACK_TIMEOUT); + + return ret; +} + + +static int tdf8532_stop_play(struct tdf8532_priv *tdf8532) +{ + int ret; + + ret = tdf8532_amp_write(tdf8532, SET_CHNL_DISABLE, + CHNL_MASK(tdf8532->channels)); + if (ret < 0) + goto out; + + ret = tdf8532_wait_state(tdf8532, STATE_STBY, ACK_TIMEOUT); + if (ret < 0) + goto out; + + ret = tdf8532_amp_write(tdf8532, SET_CLK_STATE, CLK_DISCONNECT); + if (ret < 0) + goto out; + + ret = tdf8532_wait_state(tdf8532, STATE_IDLE, ACK_TIMEOUT); + +out: + return ret; +} + + +static int tdf8532_dai_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + int ret = 0; + struct snd_soc_codec *codec = dai->codec; + struct tdf8532_priv *tdf8532 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s: cmd = %d\n", __func__, cmd); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + ret = tdf8532_start_play(tdf8532); + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + ret = tdf8532_stop_play(tdf8532); + break; + } + + return ret; +} + +static int tdf8532_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + struct tdf8532_priv *tdf8532 = snd_soc_codec_get_drvdata(dai->codec); + + dev_dbg(codec->dev, "%s\n", __func__); + + if (mute) + return tdf8532_amp_write(tdf8532, SET_CHNL_MUTE, + CHNL_MASK(CHNL_MAX)); + else + return tdf8532_amp_write(tdf8532, SET_CHNL_UNMUTE, + CHNL_MASK(CHNL_MAX)); +} + +static const struct snd_soc_dai_ops tdf8532_dai_ops = { + .trigger = tdf8532_dai_trigger, + .digital_mute = tdf8532_mute, +}; + +static struct snd_soc_codec_driver soc_codec_tdf8532; + +static struct snd_soc_dai_driver tdf8532_dai[] = { + { + .name = "tdf8532-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 4, + .channels_max = 4, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &tdf8532_dai_ops, + } +}; + +static int tdf8532_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + int ret; + struct tdf8532_priv *dev_data; + struct device *dev = &(i2c->dev); + + dev_dbg(&i2c->dev, "%s\n", __func__); + + dev_data = devm_kzalloc(dev, sizeof(struct tdf8532_priv), GFP_KERNEL); + + if (!dev_data) { + ret = -ENOMEM; + goto out; + } + + if (ret < 0) + dev_err(&i2c->dev, "Failed to set fast mute option: %d\n", ret); + + dev_data->i2c = i2c; + dev_data->pkt_id = 0; + dev_data->channels = 4; + + i2c_set_clientdata(i2c, dev_data); + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_tdf8532, + tdf8532_dai, ARRAY_SIZE(tdf8532_dai)); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); + goto out; + } + +out: + return ret; +} + +static int tdf8532_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +static const struct i2c_device_id tdf8532_i2c_id[] = { + { "tdf8532", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, tdf8532_i2c_id); + +#if CONFIG_ACPI +static const struct acpi_device_id tdf8532_acpi_match[] = { + {"INT34C3", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(acpi, tdf8532_acpi_match); +#endif + +static struct i2c_driver tdf8532_i2c_driver = { + .driver = { + .name = "tdf8532-codec", + .owner = THIS_MODULE, + .acpi_match_table = ACPI_PTR(tdf8532_acpi_match), + }, + .probe = tdf8532_i2c_probe, + .remove = tdf8532_i2c_remove, + .id_table = tdf8532_i2c_id, +}; + +module_i2c_driver(tdf8532_i2c_driver); + +MODULE_DESCRIPTION("ASoC NXP Semiconductors TDF8532 driver"); +MODULE_AUTHOR("Steffen Wagner "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/tdf8532.h b/sound/soc/codecs/tdf8532.h new file mode 100644 index 00000000000000..6e3f2c147eace9 --- /dev/null +++ b/sound/soc/codecs/tdf8532.h @@ -0,0 +1,101 @@ +/* + * tdf8532.h - Codec driver for NXP Semiconductors + * Copyright (c) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + + +#ifndef __TDF8532_H_ +#define __TDF8532_H_ + +#define ACK_TIMEOUT 300 + +#define CHNL_MAX 5 + +#define AMP_MOD 0x80 +#define END -1 + +#define MSG_TYPE_STX 0x02 +#define MSG_TYPE_NAK 0x15 +#define MSG_TYPE_ACK 0x6 + +#define HEADER_SIZE 3 +#define HEADER_TYPE 0 +#define HEADER_PKTID 1 +#define HEADER_LEN 2 + +/* Set commands */ +#define SET_CLK_STATE 0x1A +#define CLK_DISCONNECT 0x00 +#define CLK_CONNECT 0x01 + +#define SET_CHNL_ENABLE 0x26 +#define SET_CHNL_DISABLE 0x27 + +#define SET_CHNL_MUTE 0x42 +#define SET_CHNL_UNMUTE 0x43 + +struct header_repl { + u8 msg_type; + u8 pkt_id; + u8 len; +} __packed; + +#define GET_IDENT 0xE0 + +struct get_ident_repl { + struct header_repl header; + u8 module_id; + u8 cmd_id; + u8 type_name; + u8 hw_major; + u8 hw_minor; + u8 sw_major; + u8 sw_minor; + u8 sw_sub; +} __packed; + +#define GET_ERROR 0xE2 + +struct get_error_repl { + struct header_repl header; + u8 module_id; + u8 cmd_id; + u8 last_cmd_id; + u8 error; + u8 status; +} __packed; + +#define GET_DEV_STATUS 0x80 + +enum dev_state {STATE_BOOT, STATE_IDLE, STATE_STBY, STATE_LDAG, STATE_PLAY, + STATE_PROT, STATE_SDWN, STATE_CLFA, STATE_NONE }; + +struct get_dev_status_repl { + struct header_repl header; + u8 module_id; + u8 cmd_id; + u8 state; +} __packed; + +/* Helpers */ +#define CHNL_MASK(channels) (u8)((0x00FF << channels) >> 8) + +#define tdf8532_amp_write(dev_data, ...)\ + __tdf8532_single_write(dev_data, 0, AMP_MOD, __VA_ARGS__, END) + +struct tdf8532_priv { + struct i2c_client *i2c; + u8 channels; + u8 pkt_id; +}; + +#endif From 9da1f872c1e79d8a869cc73a8141eca934007200 Mon Sep 17 00:00:00 2001 From: "Gogineni, GiribabuX" Date: Tue, 15 May 2018 17:14:51 +0800 Subject: [PATCH 0152/1995] ASoC: tdf8532: Fix compilation warnings Initialized the reported variables, listed below warning: 'ret' may be used uninitialized in this function warning: 'status_repl' may be used uninitialized in this function Change-Id: I6ca5a6e017402a582239d75959c122ffaa9f7298 Signed-off-by: Gogineni, GiribabuX Reviewed-on: https://git-gar-1.devtools.intel.com/gerrit/17572 Reviewed-by: Singh, Guneshwor O Reviewed-by: Sinha, Mohit Reviewed-by: Shaik, Kareem M Reviewed-by: Koul, Vinod Tested-by: Sm, Bhadur A --- sound/soc/codecs/tdf8532.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/codecs/tdf8532.c b/sound/soc/codecs/tdf8532.c index 59db83da37587a..5f072079fbb76b 100644 --- a/sound/soc/codecs/tdf8532.c +++ b/sound/soc/codecs/tdf8532.c @@ -172,7 +172,7 @@ static int tdf8532_wait_state(struct tdf8532_priv *dev_data, u8 req_state, { unsigned long timeout_point = jiffies + msecs_to_jiffies(timeout); int ret; - struct get_dev_status_repl *status_repl; + struct get_dev_status_repl *status_repl = NULL; struct device *dev = &(dev_data->i2c->dev); do { @@ -318,9 +318,6 @@ static int tdf8532_i2c_probe(struct i2c_client *i2c, goto out; } - if (ret < 0) - dev_err(&i2c->dev, "Failed to set fast mute option: %d\n", ret); - dev_data->i2c = i2c; dev_data->pkt_id = 0; dev_data->channels = 4; From 2eae6234c1950d5a341e119b37dca62a86330a6e Mon Sep 17 00:00:00 2001 From: "Gogineni, GiribabuX" Date: Tue, 15 May 2018 17:14:52 +0800 Subject: [PATCH 0153/1995] ASoC: tdf8532: Add delay while reading a packet from I2C While doing the continuous play and stop, the codec may not be ready for I2C reading after successive writes. This triggers BE failure, because I2C reading value is incorrect. Fix this by adding 10ms delay to ensure the smooth I2C read and write. Change-Id: If918e263bc799fecc2c807229f5b4b165e011fa6 Signed-off-by: Gogineni, GiribabuX Reviewed-on: https://git-gar-1.devtools.intel.com/gerrit/20404 Reviewed-by: Shaik, Kareem M Reviewed-by: Sinha, Mohit Reviewed-by: Nc, Shreyas Reviewed-by: Periyasamy, SriramX Reviewed-by: Kale, Sanyog R Tested-by: Sm, Bhadur A --- sound/soc/codecs/tdf8532.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/tdf8532.c b/sound/soc/codecs/tdf8532.c index 5f072079fbb76b..1860e8264ebab8 100644 --- a/sound/soc/codecs/tdf8532.c +++ b/sound/soc/codecs/tdf8532.c @@ -90,6 +90,7 @@ static uint8_t tdf8532_read_wait_ack(struct tdf8532_priv *dev_data, unsigned long timeout_point = jiffies + timeout; int ret; + usleep_range(10000,20000); do { ret = i2c_master_recv(dev_data->i2c, ack_repl, HEADER_SIZE); if (ret < 0) From c208f946779ede831092356d95eddb3e538b2056 Mon Sep 17 00:00:00 2001 From: Liu Changcheng Date: Fri, 11 May 2018 17:24:01 +0800 Subject: [PATCH 0154/1995] ASoC: tdf8532: fix memleak in tdf8532_wait_state Fix kmemleak issue in tdf8532_wait_state function by releasing the memory getting allocated continuosly in instance of get_dev_status_repl i.e. status_repl before exiting the function. kernel memory leakage in audio stack/kmemleak backtrace: unreferenced object 0xffff88006227cc20 (size 32): comm "irq/25-snd_soc_", pid 2302, jiffies 4294679082 (age 5506.010s) hex dump (first 32 bytes): 02 00 03 80 80 02 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [] kmemleak_alloc+0x4a/0xa0 [] __kmalloc+0x128/0x210 [] tdf8532_wait_state.constprop.5+0x116/0x260 [snd_soc_tdf8532] [] tdf8532_dai_trigger+0xab/0x15a [snd_soc_tdf8532] [] soc_pcm_trigger+0x75/0x130 [] dpcm_do_trigger.isra.6+0x29/0x90 [] dpcm_be_dai_trigger+0x18d/0x350 Change-Id: I550897d6b1efbd5ebbe15ab47038adf99581a82f Tracked-On: https://jira01.devtools.intel.com/browse/OAM-62665 Signed-off-by: Liu Changcheng Reviewed-on: https://git-gar-1.devtools.intel.com/gerrit/23270 Reviewed-by: Shaik, ShahinaX Reviewed-by: Singh, Guneshwor O Reviewed-by: Gogineni, GiribabuX Reviewed-by: Tewani, Pradeep D Reviewed-by: Kesapragada, Pardha Saradhi Reviewed-by: Kp, Jeeja Tested-by: Madiwalar, MadiwalappaX --- sound/soc/codecs/tdf8532.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/tdf8532.c b/sound/soc/codecs/tdf8532.c index 1860e8264ebab8..aaf7254672cbeb 100644 --- a/sound/soc/codecs/tdf8532.c +++ b/sound/soc/codecs/tdf8532.c @@ -174,29 +174,31 @@ static int tdf8532_wait_state(struct tdf8532_priv *dev_data, u8 req_state, unsigned long timeout_point = jiffies + msecs_to_jiffies(timeout); int ret; struct get_dev_status_repl *status_repl = NULL; + u8 cur_state = STATE_NONE; struct device *dev = &(dev_data->i2c->dev); do { ret = tdf8532_get_state(dev_data, &status_repl); if (ret < 0) goto out; - + cur_state = status_repl->state; print_hex_dump_debug("tdf8532-codec: wait_state: ", DUMP_PREFIX_NONE, 32, 1, status_repl, 6, false); + + kfree(status_repl); + status_repl = NULL; } while (time_before(jiffies, timeout_point) - && status_repl->state != req_state); + && cur_state != req_state); - if (status_repl->state == req_state) + if (cur_state == req_state) return 0; +out: ret = -ETIME; dev_err(dev, "tdf8532-codec: state: %u, req_state: %u, ret: %d\n", - status_repl->state, req_state, ret); - -out: - kfree(status_repl); + cur_state, req_state, ret); return ret; } From fcaee9d8527187082f81a6ff4e5c9f983976d894 Mon Sep 17 00:00:00 2001 From: Liu Changcheng Date: Fri, 11 May 2018 17:11:42 +0800 Subject: [PATCH 0155/1995] ASoC: tdf8532: right free allocated space in case of error 1. Check allocated space before using it. 2. The repl_buff parameter in tdf8523_single_read is used to store the read data from i2c interface. When the data isn't right read, the pre-allocate space should be freed and the content of repl_buff should be set as NULL in case of being wrong used by the caller. 3. In the wrong case i.e. ret != len, return -EINVAL Change-Id: I3d0e12a9fcb6516716efc92eb734a0248ab3fb28 Tracked-On: https://jira01.devtools.intel.com/browse/OAM-62665 Signed-off-by: Liu Changcheng Reviewed-on: https://git-gar-1.devtools.intel.com/gerrit/23266 Reviewed-by: Shaik, ShahinaX Reviewed-by: Kesapragada, Pardha Saradhi Reviewed-by: Gogineni, GiribabuX Reviewed-by: Singh, Guneshwor O Reviewed-by: Tewani, Pradeep D Reviewed-by: Kp, Jeeja Tested-by: Madiwalar, MadiwalappaX --- sound/soc/codecs/tdf8532.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/tdf8532.c b/sound/soc/codecs/tdf8532.c index aaf7254672cbeb..685a20d98b6b6a 100644 --- a/sound/soc/codecs/tdf8532.c +++ b/sound/soc/codecs/tdf8532.c @@ -107,11 +107,11 @@ static uint8_t tdf8532_read_wait_ack(struct tdf8532_priv *dev_data, return ret; } -static uint8_t tdf8532_single_read(struct tdf8532_priv *dev_data, +static int tdf8532_single_read(struct tdf8532_priv *dev_data, char **repl_buff) { int ret; - uint8_t len; + int len; struct device *dev = &(dev_data->i2c->dev); @@ -126,6 +126,10 @@ static uint8_t tdf8532_single_read(struct tdf8532_priv *dev_data, len = ret + HEADER_SIZE; *repl_buff = kzalloc(len, GFP_KERNEL); + if (*repl_buff == NULL) { + ret = -ENOMEM; + goto out; + } ret = i2c_master_recv(dev_data->i2c, *repl_buff, len); @@ -136,6 +140,8 @@ static uint8_t tdf8532_single_read(struct tdf8532_priv *dev_data, dev_err(dev, "i2c recv packet returned: %d (expected: %d)\n", ret, len); + + ret = -EINVAL; goto out_free; } @@ -143,7 +149,7 @@ static uint8_t tdf8532_single_read(struct tdf8532_priv *dev_data, out_free: kfree(*repl_buff); - repl_buff = NULL; + *repl_buff = NULL; out: return ret; } From dacdab5c9f1f41afaeb7fb4ce60ff8acf34dde3d Mon Sep 17 00:00:00 2001 From: Wu Zhigang Date: Tue, 15 May 2018 17:14:53 +0800 Subject: [PATCH 0156/1995] ASoC: tdf8532: Fix the codec status error issue on APL-GPMRB Based on the TDF8532 manual: If the wait_state result is ok, we should send CLK_DISCONNECT command to force codec from STANDBY(2) to IDLE(1). If the wait_state result is timeout, the codec state should be at Clockfail(7), we still should send CLK_DISCONNECT command force the codec from Clockfail(7) to Idle(1). Signed-off-by: Wu Zhigang Reviewed-by: Keyon Jie --- sound/soc/codecs/tdf8532.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/tdf8532.c b/sound/soc/codecs/tdf8532.c index 685a20d98b6b6a..0ef8fe406270a5 100644 --- a/sound/soc/codecs/tdf8532.c +++ b/sound/soc/codecs/tdf8532.c @@ -236,8 +236,14 @@ static int tdf8532_stop_play(struct tdf8532_priv *tdf8532) goto out; ret = tdf8532_wait_state(tdf8532, STATE_STBY, ACK_TIMEOUT); - if (ret < 0) - goto out; + + /* Refer to TDF8532 manual: + * If the wait_state result is ok, we should send CLK_DISCONNECT + * command to force codec from STANDBY(2) to IDLE(1). + * If the wait_state result is timeout, the codec state should be + * at Clockfail(7), we still should send CLK_DISCONNECT command + * force the codec from Clockfail(7) to Idle(1). + */ ret = tdf8532_amp_write(tdf8532, SET_CLK_STATE, CLK_DISCONNECT); if (ret < 0) From 3e2e4b6b40263174390a9f650093b0ee8cb79c11 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 23 Jun 2018 08:45:49 -0500 Subject: [PATCH 0157/1995] ASoC: codecs: tdf8532: move to component model Needs to be squashed for 4.18+ Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/tdf8532.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/tdf8532.c b/sound/soc/codecs/tdf8532.c index 0ef8fe406270a5..8a5928a894ca24 100644 --- a/sound/soc/codecs/tdf8532.c +++ b/sound/soc/codecs/tdf8532.c @@ -260,10 +260,10 @@ static int tdf8532_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { int ret = 0; - struct snd_soc_codec *codec = dai->codec; - struct tdf8532_priv *tdf8532 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = dai->component; + struct tdf8532_priv *tdf8532 = snd_soc_component_get_drvdata(component); - dev_dbg(codec->dev, "%s: cmd = %d\n", __func__, cmd); + dev_dbg(component->dev, "%s: cmd = %d\n", __func__, cmd); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -283,10 +283,10 @@ static int tdf8532_dai_trigger(struct snd_pcm_substream *substream, int cmd, static int tdf8532_mute(struct snd_soc_dai *dai, int mute) { - struct snd_soc_codec *codec = dai->codec; - struct tdf8532_priv *tdf8532 = snd_soc_codec_get_drvdata(dai->codec); + struct snd_soc_component *component = dai->component; + struct tdf8532_priv *tdf8532 = snd_soc_component_get_drvdata(component); - dev_dbg(codec->dev, "%s\n", __func__); + dev_dbg(component->dev, "%s\n", __func__); if (mute) return tdf8532_amp_write(tdf8532, SET_CHNL_MUTE, @@ -301,7 +301,7 @@ static const struct snd_soc_dai_ops tdf8532_dai_ops = { .digital_mute = tdf8532_mute, }; -static struct snd_soc_codec_driver soc_codec_tdf8532; +static struct snd_soc_component_driver soc_component_tdf8532; static struct snd_soc_dai_driver tdf8532_dai[] = { { @@ -339,7 +339,7 @@ static int tdf8532_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, dev_data); - ret = snd_soc_register_codec(&i2c->dev, &soc_codec_tdf8532, + ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_tdf8532, tdf8532_dai, ARRAY_SIZE(tdf8532_dai)); if (ret != 0) { dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); @@ -352,8 +352,6 @@ static int tdf8532_i2c_probe(struct i2c_client *i2c, static int tdf8532_i2c_remove(struct i2c_client *i2c) { - snd_soc_unregister_codec(&i2c->dev); - return 0; } From 161a5cb3e7323391202057e9bb7eeff3d52b6941 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Tue, 22 May 2018 18:23:43 +0800 Subject: [PATCH 0158/1995] ASoC: Intel: Boards: Add BXTP MRB machine driver for NXP TDF8532 This is the machine driver for NXP TDF8532 Change-Id: Ieee7ba1fc2dab6fbe43836b65def88c81360d48f Signed-off-by: Mohit Sinha Signed-off-by: Markus Schweikhardt Reviewed-on: https://git-gar-1.devtools.intel.com/gerrit/15375 Reviewed-by: Shaik, Kareem M Reviewed-by: B, Jayachandran Reviewed-by: Koul, Vinod Tested-by: Sm, Bhadur A --- sound/soc/intel/boards/Kconfig | 10 ++ sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/bxt_tdf8532.c | 209 +++++++++++++++++++++++++++ 3 files changed, 221 insertions(+) create mode 100644 sound/soc/intel/boards/bxt_tdf8532.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 5e8cdf393cbd3c..f7ba8a312649d4 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -261,6 +261,16 @@ config SND_SOC_INTEL_BXT_PCM512x_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +config SND_SOC_INTEL_BXT_TDF8532_MACH + tristate "ASoC Audio driver for BXT with TDF8532 in I2S mode" + depends on X86 && ACPI && I2C + select SND_SOC_TDF8532 + select SND_SOC_COMPRESS + help + This adds support for ASoC machine driver for Broxton IVI GP MRB platform + Say Y if you have such a device. + If unsure select "N". + endif ## SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_APOLLOLAKE if SND_SOC_INTEL_SKYLAKE diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 9a12cbd87d3096..e511979f279641 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -7,6 +7,7 @@ snd-soc-sst-broadwell-objs := broadwell.o snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o snd-soc-sst-bxt-rt298-objs := bxt_rt298.o snd-soc-sst-bxt-pcm512x-objs := bxt_pcm512x.o +snd-soc-sst_bxt_tdf8532-objs := bxt_tdf8532.o snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o @@ -33,6 +34,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o obj-$(CONFIG_SND_SOC_INTEL_BXT_PCM512x_MACH) += snd-soc-sst-bxt-pcm512x.o +obj-$(CONFIG_SND_SOC_INTEL_BXT_TDF8532_MACH) += snd-soc-sst_bxt_tdf8532.o obj-$(CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH) += snd-soc-sst-glk-rt5682_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.o diff --git a/sound/soc/intel/boards/bxt_tdf8532.c b/sound/soc/intel/boards/bxt_tdf8532.c new file mode 100644 index 00000000000000..027060b17322a3 --- /dev/null +++ b/sound/soc/intel/boards/bxt_tdf8532.c @@ -0,0 +1,209 @@ +/* + * Intel Broxton-P I2S Machine Driver for IVI reference platform + * Copyright (c) 2017, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include + +static const struct snd_kcontrol_new broxton_tdf8532_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +static const struct snd_soc_dapm_widget broxton_tdf8532_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_MIC("DiranaCp", NULL), + SND_SOC_DAPM_HP("DiranaPb", NULL), + SND_SOC_DAPM_MIC("HdmiIn", NULL), + SND_SOC_DAPM_MIC("TestPinCp", NULL), + SND_SOC_DAPM_HP("TestPinPb", NULL), + SND_SOC_DAPM_MIC("BtHfpDl", NULL), + SND_SOC_DAPM_HP("BtHfpUl", NULL), + SND_SOC_DAPM_MIC("ModemDl", NULL), + SND_SOC_DAPM_HP("ModemUl", NULL), +}; + +static const struct snd_soc_dapm_route broxton_tdf8532_map[] = { + + /* Speaker BE connections */ + { "Speaker", NULL, "ssp4 Tx"}, + { "ssp4 Tx", NULL, "codec0_out"}, + + { "dirana_in", NULL, "ssp2 Rx"}, + { "ssp2 Rx", NULL, "DiranaCp"}, + + { "dirana_aux_in", NULL, "ssp2 Rx"}, + { "ssp2 Rx", NULL, "DiranaCp"}, + + { "dirana_tuner_in", NULL, "ssp2 Rx"}, + { "ssp2 Rx", NULL, "DiranaCp"}, + + { "DiranaPb", NULL, "ssp2 Tx"}, + { "ssp2 Tx", NULL, "dirana_out"}, + + { "hdmi_ssp1_in", NULL, "ssp1 Rx"}, + { "ssp1 Rx", NULL, "HdmiIn"}, + + { "TestPin_ssp5_in", NULL, "ssp5 Rx"}, + { "ssp5 Rx", NULL, "TestPinCp"}, + + { "TestPinPb", NULL, "ssp5 Tx"}, + { "ssp5 Tx", NULL, "TestPin_ssp5_out"}, + + { "BtHfp_ssp0_in", NULL, "ssp0 Rx"}, + { "ssp0 Rx", NULL, "BtHfpDl"}, + + { "BtHfpUl", NULL, "ssp0 Tx"}, + { "ssp0 Tx", NULL, "BtHfp_ssp0_out"}, + + { "Modem_ssp3_in", NULL, "ssp3 Rx"}, + { "ssp3 Rx", NULL, "ModemDl"}, + + { "ModemUl", NULL, "ssp3 Tx"}, + { "ssp3 Tx", NULL, "Modem_ssp3_out"}, +}; + +/* broxton digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link broxton_tdf8532_dais[] = { + /* Back End DAI links */ + { + /* SSP0 - BT */ + .name = "SSP0-Codec", + .id = 0, + .cpu_dai_name = "SSP0 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:0e.0", + .ignore_suspend = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + /* SSP1 - HDMI-In */ + .name = "SSP1-Codec", + .id = 1, + .cpu_dai_name = "SSP1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:0e.0", + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + }, + { + /* SSP2 - Dirana */ + .name = "SSP2-Codec", + .id = 2, + .cpu_dai_name = "SSP2 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:0e.0", + .ignore_suspend = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + /* SSP3 - Modem */ + .name = "SSP3-Codec", + .id = 3, + .cpu_dai_name = "SSP3 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:0e.0", + .ignore_suspend = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + /* SSP4 - Amplifier */ + .name = "SSP4-Codec", + .id = 4, + .cpu_dai_name = "SSP4 Pin", + .codec_name = "i2c-INT34C3:00", + .codec_dai_name = "tdf8532-hifi", + .platform_name = "0000:00:0e.0", + .ignore_suspend = 1, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + /* SSP5 - TestPin */ + .name = "SSP5-Codec", + .id = 5, + .cpu_dai_name = "SSP5 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:0e.0", + .ignore_suspend = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +static int bxt_add_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *link) +{ + link->platform_name = "0000:00:0e.0"; + link->nonatomic = 1; + return 0; +} + +/* broxton audio machine driver for TDF8532 */ +static struct snd_soc_card broxton_tdf8532 = { + .name = "broxton_tdf8532", + .dai_link = broxton_tdf8532_dais, + .num_links = ARRAY_SIZE(broxton_tdf8532_dais), + .controls = broxton_tdf8532_controls, + .num_controls = ARRAY_SIZE(broxton_tdf8532_controls), + .dapm_widgets = broxton_tdf8532_widgets, + .num_dapm_widgets = ARRAY_SIZE(broxton_tdf8532_widgets), + .dapm_routes = broxton_tdf8532_map, + .num_dapm_routes = ARRAY_SIZE(broxton_tdf8532_map), + .fully_routed = true, + .add_dai_link = bxt_add_dai_link, +}; + +static int broxton_tdf8532_audio_probe(struct platform_device *pdev) +{ + dev_info(&pdev->dev, "%s registering %s\n", __func__, pdev->name); + broxton_tdf8532.dev = &pdev->dev; + return snd_soc_register_card(&broxton_tdf8532); +} + +static int broxton_tdf8532_audio_remove(struct platform_device *pdev) +{ + snd_soc_unregister_card(&broxton_tdf8532); + return 0; +} + +static struct platform_driver broxton_tdf8532_audio = { + .probe = broxton_tdf8532_audio_probe, + .remove = broxton_tdf8532_audio_remove, + .driver = { + .name = "bxt_tdf8532", + }, +}; + +module_platform_driver(broxton_tdf8532_audio) + +/* Module information */ +MODULE_DESCRIPTION("Intel SST Audio for Broxton GP MRB"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:gpmrb_machine"); From bf582993044e99ec82b91dcf566fe4759aa3ef75 Mon Sep 17 00:00:00 2001 From: "Sinha, Mohit" Date: Thu, 6 Jul 2017 16:10:32 +0530 Subject: [PATCH 0159/1995] ASoC: Intel: Board: DAI links for probe in GPMRB machine driver Added two DAI links for probe playback and capture Change-Id: I0bf364eba3b6a2b779625a6fd1b664c2530a1ab2 Signed-off-by: Sinha, Mohit --- sound/soc/intel/boards/bxt_tdf8532.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/sound/soc/intel/boards/bxt_tdf8532.c b/sound/soc/intel/boards/bxt_tdf8532.c index 027060b17322a3..1e2b8be0012707 100644 --- a/sound/soc/intel/boards/bxt_tdf8532.c +++ b/sound/soc/intel/boards/bxt_tdf8532.c @@ -78,6 +78,27 @@ static const struct snd_soc_dapm_route broxton_tdf8532_map[] = { /* broxton digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link broxton_tdf8532_dais[] = { + /* Probe DAI links*/ + { + .name = "Bxt Compress Probe playback", + .stream_name = "Probe Playback", + .cpu_dai_name = "Compress Probe0 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:0e.0", + .init = NULL, + .nonatomic = 1, + }, + { + .name = "Bxt Compress Probe capture", + .stream_name = "Probe Capture", + .cpu_dai_name = "Compress Probe1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:0e.0", + .init = NULL, + .nonatomic = 1, + }, /* Back End DAI links */ { /* SSP0 - BT */ From 1b3ece9dcfa3fbcb20548cc0281601918e86f2c9 Mon Sep 17 00:00:00 2001 From: "Sinha, Mohit" Date: Thu, 6 Jul 2017 16:21:19 +0530 Subject: [PATCH 0160/1995] ASoC: Intel: Boards: Add FW logging DAI-links for GPMRB Add two FW logging DAI for each DSP core Change-Id: Ic825ecb4afbbcacabda6b74e2e5f2969fc722a1f Signed-off-by: Sinha, Mohit --- sound/soc/intel/boards/bxt_tdf8532.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/sound/soc/intel/boards/bxt_tdf8532.c b/sound/soc/intel/boards/bxt_tdf8532.c index 1e2b8be0012707..325b59adaf1c05 100644 --- a/sound/soc/intel/boards/bxt_tdf8532.c +++ b/sound/soc/intel/boards/bxt_tdf8532.c @@ -99,6 +99,27 @@ static struct snd_soc_dai_link broxton_tdf8532_dais[] = { .init = NULL, .nonatomic = 1, }, + /* Trace Buffer DAI links */ + { + .name = "Bxt Trace Buffer0", + .stream_name = "Core 0 Trace Buffer", + .cpu_dai_name = "TraceBuffer0 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:0e.0", + .capture_only = true, + .ignore_suspend = 1, + }, + { + .name = "Bxt Trace Buffer1", + .stream_name = "Core 1 Trace Buffer", + .cpu_dai_name = "TraceBuffer1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:0e.0", + .capture_only = true, + .ignore_suspend = 1, + }, /* Back End DAI links */ { /* SSP0 - BT */ From 38c7c0884997490162c5a65d6ef48e55744dfaae Mon Sep 17 00:00:00 2001 From: "Kareem,Shaik" Date: Wed, 30 Aug 2017 16:46:40 +0530 Subject: [PATCH 0161/1995] ASoC: Intel: Board: Add pm_ops to fix suspend/resume issue Audio playback not resumed after it is suspended. Add snd_soc_pm_ops to execute power management operation. Change-Id: I84ccf6a0ac7e35c1f79971ee59555f24024d4309 Signed-off-by: Mohit Sinha Reviewed-on: https://git-gar-1.devtools.intel.com/gerrit/17914 Reviewed-by: Shaik, Kareem M Reviewed-by: Prusty, Subhransu S Reviewed-by: H S, Vijay Reviewed-by: Kp, Jeeja Reviewed-by: audio_build Reviewed-by: Koul, Vinod Tested-by: Avati, Santosh Kumar --- sound/soc/intel/boards/bxt_tdf8532.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/boards/bxt_tdf8532.c b/sound/soc/intel/boards/bxt_tdf8532.c index 325b59adaf1c05..c7b7fe3f9ed7c4 100644 --- a/sound/soc/intel/boards/bxt_tdf8532.c +++ b/sound/soc/intel/boards/bxt_tdf8532.c @@ -240,6 +240,7 @@ static struct platform_driver broxton_tdf8532_audio = { .remove = broxton_tdf8532_audio_remove, .driver = { .name = "bxt_tdf8532", + .pm = &snd_soc_pm_ops, }, }; From edf16a8cc358e106bde7c6934a0e1d2385da02c7 Mon Sep 17 00:00:00 2001 From: Mohit Sinha Date: Mon, 4 Sep 2017 23:31:17 +0530 Subject: [PATCH 0162/1995] ASoC: Intel: Board: Add fixup for 32 bit masking Fixup function does the masking of the format to set the SSP2 to 32 bit Change-Id: I1c5f20ce1244f9c3a47a47342d46184fdd718290 Signed-off-by: Mohit Sinha Reviewed-on: https://git-gar-1.devtools.intel.com/gerrit/18076 Reviewed-by: Gogineni, GiribabuX Reviewed-by: Shaik, Kareem M Reviewed-by: Koul, Vinod Tested-by: Sm, Bhadur A --- sound/soc/intel/boards/bxt_tdf8532.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/boards/bxt_tdf8532.c b/sound/soc/intel/boards/bxt_tdf8532.c index c7b7fe3f9ed7c4..27361e8f72d3f0 100644 --- a/sound/soc/intel/boards/bxt_tdf8532.c +++ b/sound/soc/intel/boards/bxt_tdf8532.c @@ -76,6 +76,18 @@ static const struct snd_soc_dapm_route broxton_tdf8532_map[] = { { "ssp3 Tx", NULL, "Modem_ssp3_out"}, }; +static int bxt_tdf8532_ssp2_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* set SSP to 32 bit */ + snd_mask_none(fmt); + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S32_LE); + + return 0; +} + /* broxton digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link broxton_tdf8532_dais[] = { /* Probe DAI links*/ @@ -158,6 +170,7 @@ static struct snd_soc_dai_link broxton_tdf8532_dais[] = { .dpcm_capture = 1, .dpcm_playback = 1, .no_pcm = 1, + .be_hw_params_fixup = bxt_tdf8532_ssp2_fixup, }, { /* SSP3 - Modem */ From f5aa0a7cb8e787ab19418f4b6338315de53c17e8 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Tue, 22 May 2018 18:23:44 +0800 Subject: [PATCH 0163/1995] ASoC: Intel: bxt-tdf8532: reuse machine driver for GP-MRB Signed-off-by: Keyon Jie --- sound/soc/intel/boards/bxt_tdf8532.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/boards/bxt_tdf8532.c b/sound/soc/intel/boards/bxt_tdf8532.c index 27361e8f72d3f0..4dd73d356740f4 100644 --- a/sound/soc/intel/boards/bxt_tdf8532.c +++ b/sound/soc/intel/boards/bxt_tdf8532.c @@ -263,3 +263,4 @@ module_platform_driver(broxton_tdf8532_audio) MODULE_DESCRIPTION("Intel SST Audio for Broxton GP MRB"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:gpmrb_machine"); +MODULE_ALIAS("platform:bxt_tdf8532"); From f2fa47b375f5b40c7a452c0542c5e94de9e2289c Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Mon, 28 May 2018 13:43:18 +0800 Subject: [PATCH 0164/1995] ASoC: Intel: bxt-tdf8532: FIX: don't use add_dai_link() for SOF We set ignore_machine for SOF soc platform driver, which will trigger overriding FEs in soc_check_tplg_fes(), but this overriding may be overidden again by add_dai_link() in bxt_tdf8532, e.g. platform_name will be modified to be "0000:00:0e.0", which is not exist in SOF. Here add #ifdef to bypass add_dai_link() for using the machine driver with SOF to fix the overridden again issue. Signed-off-by: Keyon Jie --- sound/soc/intel/boards/bxt_tdf8532.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/intel/boards/bxt_tdf8532.c b/sound/soc/intel/boards/bxt_tdf8532.c index 4dd73d356740f4..dd8bdfd352b2d1 100644 --- a/sound/soc/intel/boards/bxt_tdf8532.c +++ b/sound/soc/intel/boards/bxt_tdf8532.c @@ -212,6 +212,7 @@ static struct snd_soc_dai_link broxton_tdf8532_dais[] = { }, }; +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) static int bxt_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) { @@ -219,6 +220,7 @@ static int bxt_add_dai_link(struct snd_soc_card *card, link->nonatomic = 1; return 0; } +#endif /* broxton audio machine driver for TDF8532 */ static struct snd_soc_card broxton_tdf8532 = { @@ -232,7 +234,9 @@ static struct snd_soc_card broxton_tdf8532 = { .dapm_routes = broxton_tdf8532_map, .num_dapm_routes = ARRAY_SIZE(broxton_tdf8532_map), .fully_routed = true, +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) .add_dai_link = bxt_add_dai_link, +#endif }; static int broxton_tdf8532_audio_probe(struct platform_device *pdev) From d9aaa77867e6db150b6d5273220cf613403cdbc3 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 20 Jun 2018 16:50:51 +0800 Subject: [PATCH 0165/1995] ASoC: Intel: bxt-tdf8532: change probe and trace buffer dai_links to dynamic We should use .dynamic for all FE dai_links, so change probe and trace buffer ones here to align to that. Signed-off-by: Keyon Jie --- sound/soc/intel/boards/bxt_tdf8532.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/intel/boards/bxt_tdf8532.c b/sound/soc/intel/boards/bxt_tdf8532.c index dd8bdfd352b2d1..abdc04e389a8fb 100644 --- a/sound/soc/intel/boards/bxt_tdf8532.c +++ b/sound/soc/intel/boards/bxt_tdf8532.c @@ -100,6 +100,7 @@ static struct snd_soc_dai_link broxton_tdf8532_dais[] = { .platform_name = "0000:00:0e.0", .init = NULL, .nonatomic = 1, + .dynamic = 1, }, { .name = "Bxt Compress Probe capture", @@ -110,6 +111,7 @@ static struct snd_soc_dai_link broxton_tdf8532_dais[] = { .platform_name = "0000:00:0e.0", .init = NULL, .nonatomic = 1, + .dynamic = 1, }, /* Trace Buffer DAI links */ { @@ -121,6 +123,7 @@ static struct snd_soc_dai_link broxton_tdf8532_dais[] = { .platform_name = "0000:00:0e.0", .capture_only = true, .ignore_suspend = 1, + .dynamic = 1, }, { .name = "Bxt Trace Buffer1", @@ -131,6 +134,7 @@ static struct snd_soc_dai_link broxton_tdf8532_dais[] = { .platform_name = "0000:00:0e.0", .capture_only = true, .ignore_suspend = 1, + .dynamic = 1, }, /* Back End DAI links */ { From 331fec9f0c66e8805c922d25de28831402fff404 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 2 Jul 2018 13:31:56 -0500 Subject: [PATCH 0166/1995] ASoC: codecs: TDF8532: use Linux style Make checkpatch happy, no functionality change Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/tdf8532.c | 82 ++++++++++++++++---------------------- sound/soc/codecs/tdf8532.h | 13 +----- 2 files changed, 37 insertions(+), 58 deletions(-) diff --git a/sound/soc/codecs/tdf8532.c b/sound/soc/codecs/tdf8532.c index 8a5928a894ca24..d8ae9ff441c8d9 100644 --- a/sound/soc/codecs/tdf8532.c +++ b/sound/soc/codecs/tdf8532.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Codec driver for NXP Semiconductors - TDF8532 * Copyright (c) 2017, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include @@ -24,7 +16,7 @@ #include "tdf8532.h" static int __tdf8532_build_pkt(struct tdf8532_priv *dev_data, - va_list valist, u8 *payload) + va_list valist, u8 *payload) { int param; u8 len; @@ -34,7 +26,7 @@ static int __tdf8532_build_pkt(struct tdf8532_priv *dev_data, payload[HEADER_TYPE] = MSG_TYPE_STX; payload[HEADER_PKTID] = dev_data->pkt_id; - cmd_payload = &(payload[cmd_offset]); + cmd_payload = &payload[cmd_offset]; param = va_arg(valist, int); len = 0; @@ -53,7 +45,7 @@ static int __tdf8532_build_pkt(struct tdf8532_priv *dev_data, } static int __tdf8532_single_write(struct tdf8532_priv *dev_data, - int dummy, ...) + int dummy, ...) { va_list valist; int ret; @@ -67,14 +59,14 @@ static int __tdf8532_single_write(struct tdf8532_priv *dev_data, va_end(valist); print_hex_dump_debug("tdf8532-codec: Tx:", DUMP_PREFIX_NONE, 32, 1, - payload, len, false); + payload, len, false); ret = i2c_master_send(dev_data->i2c, payload, len); dev_data->pkt_id++; if (ret < 0) { - dev_err(&(dev_data->i2c->dev), - "i2c send packet returned: %d\n", ret); + dev_err(&dev_data->i2c->dev, + "i2c send packet returned: %d\n", ret); return ret; } @@ -82,15 +74,14 @@ static int __tdf8532_single_write(struct tdf8532_priv *dev_data, return 0; } - -static uint8_t tdf8532_read_wait_ack(struct tdf8532_priv *dev_data, - unsigned long timeout) +static u8 tdf8532_read_wait_ack(struct tdf8532_priv *dev_data, + unsigned long timeout) { - uint8_t ack_repl[HEADER_SIZE] = {0, 0, 0}; + u8 ack_repl[HEADER_SIZE] = {0, 0, 0}; unsigned long timeout_point = jiffies + timeout; int ret; - usleep_range(10000,20000); + usleep_range(10000, 20000); do { ret = i2c_master_recv(dev_data->i2c, ack_repl, HEADER_SIZE); if (ret < 0) @@ -108,18 +99,18 @@ static uint8_t tdf8532_read_wait_ack(struct tdf8532_priv *dev_data, } static int tdf8532_single_read(struct tdf8532_priv *dev_data, - char **repl_buff) + char **repl_buff) { int ret; int len; - struct device *dev = &(dev_data->i2c->dev); + struct device *dev = &dev_data->i2c->dev; ret = tdf8532_read_wait_ack(dev_data, msecs_to_jiffies(ACK_TIMEOUT)); if (ret < 0) { dev_err(dev, - "Error waiting for ACK reply: %d\n", ret); + "Error waiting for ACK reply: %d\n", ret); goto out; } @@ -134,12 +125,12 @@ static int tdf8532_single_read(struct tdf8532_priv *dev_data, ret = i2c_master_recv(dev_data->i2c, *repl_buff, len); print_hex_dump_debug("tdf8532-codec: Rx:", DUMP_PREFIX_NONE, 32, 1, - *repl_buff, len, false); + *repl_buff, len, false); if (ret < 0 || ret != len) { dev_err(dev, - "i2c recv packet returned: %d (expected: %d)\n", - ret, len); + "i2c recv packet returned: %d (expected: %d)\n", + ret, len); ret = -EINVAL; goto out_free; @@ -155,10 +146,10 @@ static int tdf8532_single_read(struct tdf8532_priv *dev_data, } static int tdf8532_get_state(struct tdf8532_priv *dev_data, - struct get_dev_status_repl **status_repl) + struct get_dev_status_repl **status_repl) { - int ret = 0; char *repl_buff = NULL; + int ret = 0; ret = tdf8532_amp_write(dev_data, GET_DEV_STATUS); if (ret < 0) @@ -168,20 +159,20 @@ static int tdf8532_get_state(struct tdf8532_priv *dev_data, if (ret < 0) goto out; - *status_repl = (struct get_dev_status_repl *) repl_buff; + *status_repl = (struct get_dev_status_repl *)repl_buff; out: return ret; } static int tdf8532_wait_state(struct tdf8532_priv *dev_data, u8 req_state, - unsigned long timeout) + unsigned long timeout) { unsigned long timeout_point = jiffies + msecs_to_jiffies(timeout); - int ret; + struct device *dev = &dev_data->i2c->dev; struct get_dev_status_repl *status_repl = NULL; u8 cur_state = STATE_NONE; - struct device *dev = &(dev_data->i2c->dev); + int ret; do { ret = tdf8532_get_state(dev_data, &status_repl); @@ -189,13 +180,12 @@ static int tdf8532_wait_state(struct tdf8532_priv *dev_data, u8 req_state, goto out; cur_state = status_repl->state; print_hex_dump_debug("tdf8532-codec: wait_state: ", - DUMP_PREFIX_NONE, 32, 1, status_repl, - 6, false); + DUMP_PREFIX_NONE, 32, 1, status_repl, + 6, false); kfree(status_repl); status_repl = NULL; - } while (time_before(jiffies, timeout_point) - && cur_state != req_state); + } while (time_before(jiffies, timeout_point) && cur_state != req_state); if (cur_state == req_state) return 0; @@ -204,7 +194,7 @@ static int tdf8532_wait_state(struct tdf8532_priv *dev_data, u8 req_state, ret = -ETIME; dev_err(dev, "tdf8532-codec: state: %u, req_state: %u, ret: %d\n", - cur_state, req_state, ret); + cur_state, req_state, ret); return ret; } @@ -217,7 +207,7 @@ static int tdf8532_start_play(struct tdf8532_priv *tdf8532) return ret; ret = tdf8532_amp_write(tdf8532, SET_CHNL_ENABLE, - CHNL_MASK(tdf8532->channels)); + CHNL_MASK(tdf8532->channels)); if (ret >= 0) ret = tdf8532_wait_state(tdf8532, STATE_PLAY, ACK_TIMEOUT); @@ -225,13 +215,12 @@ static int tdf8532_start_play(struct tdf8532_priv *tdf8532) return ret; } - static int tdf8532_stop_play(struct tdf8532_priv *tdf8532) { int ret; ret = tdf8532_amp_write(tdf8532, SET_CHNL_DISABLE, - CHNL_MASK(tdf8532->channels)); + CHNL_MASK(tdf8532->channels)); if (ret < 0) goto out; @@ -255,13 +244,12 @@ static int tdf8532_stop_play(struct tdf8532_priv *tdf8532) return ret; } - static int tdf8532_dai_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) + struct snd_soc_dai *dai) { - int ret = 0; struct snd_soc_component *component = dai->component; struct tdf8532_priv *tdf8532 = snd_soc_component_get_drvdata(component); + int ret = 0; dev_dbg(component->dev, "%s: cmd = %d\n", __func__, cmd); @@ -301,7 +289,7 @@ static const struct snd_soc_dai_ops tdf8532_dai_ops = { .digital_mute = tdf8532_mute, }; -static struct snd_soc_component_driver soc_component_tdf8532; +static const struct snd_soc_component_driver soc_component_tdf8532; static struct snd_soc_dai_driver tdf8532_dai[] = { { @@ -318,11 +306,11 @@ static struct snd_soc_dai_driver tdf8532_dai[] = { }; static int tdf8532_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { int ret; struct tdf8532_priv *dev_data; - struct device *dev = &(i2c->dev); + struct device *dev = &i2c->dev; dev_dbg(&i2c->dev, "%s\n", __func__); @@ -340,7 +328,7 @@ static int tdf8532_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, dev_data); ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_tdf8532, - tdf8532_dai, ARRAY_SIZE(tdf8532_dai)); + tdf8532_dai, ARRAY_SIZE(tdf8532_dai)); if (ret != 0) { dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); goto out; diff --git a/sound/soc/codecs/tdf8532.h b/sound/soc/codecs/tdf8532.h index 6e3f2c147eace9..8818252dcda6fa 100644 --- a/sound/soc/codecs/tdf8532.h +++ b/sound/soc/codecs/tdf8532.h @@ -1,18 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * tdf8532.h - Codec driver for NXP Semiconductors * Copyright (c) 2017, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ - #ifndef __TDF8532_H_ #define __TDF8532_H_ @@ -87,7 +78,7 @@ struct get_dev_status_repl { } __packed; /* Helpers */ -#define CHNL_MASK(channels) (u8)((0x00FF << channels) >> 8) +#define CHNL_MASK(channels) (u8)((0x00FF << (channels)) >> 8) #define tdf8532_amp_write(dev_data, ...)\ __tdf8532_single_write(dev_data, 0, AMP_MOD, __VA_ARGS__, END) From 71e7adcc06d22186d2d2765a40f8e14bb691d54b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 2 Jul 2018 13:38:08 -0500 Subject: [PATCH 0167/1995] ASoC: Intel: bxt-tdf8532: use Linux style Make checkpatch happy, no functionality change Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bxt_tdf8532.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/sound/soc/intel/boards/bxt_tdf8532.c b/sound/soc/intel/boards/bxt_tdf8532.c index abdc04e389a8fb..336205309e2c8b 100644 --- a/sound/soc/intel/boards/bxt_tdf8532.c +++ b/sound/soc/intel/boards/bxt_tdf8532.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Intel Broxton-P I2S Machine Driver for IVI reference platform * Copyright (c) 2017, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. */ #include @@ -37,7 +29,6 @@ static const struct snd_soc_dapm_widget broxton_tdf8532_widgets[] = { }; static const struct snd_soc_dapm_route broxton_tdf8532_map[] = { - /* Speaker BE connections */ { "Speaker", NULL, "ssp4 Tx"}, { "ssp4 Tx", NULL, "codec0_out"}, @@ -77,7 +68,7 @@ static const struct snd_soc_dapm_route broxton_tdf8532_map[] = { }; static int bxt_tdf8532_ssp2_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) + struct snd_pcm_hw_params *params) { struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); @@ -218,7 +209,7 @@ static struct snd_soc_dai_link broxton_tdf8532_dais[] = { #if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) static int bxt_add_dai_link(struct snd_soc_card *card, - struct snd_soc_dai_link *link) + struct snd_soc_dai_link *link) { link->platform_name = "0000:00:0e.0"; link->nonatomic = 1; From 840f33d5b952711d040435e6d8d85e95909cffb0 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Wed, 6 Jun 2018 16:11:26 +0800 Subject: [PATCH 0168/1995] ASoC: Intel: bytcr_rt5651: work with sof only with SSP2 AIF1 bytcr_rt5651 can work with ssp0 and ssp2, disable ssp0 support for SOF only support SSP2 AIF1 now. Also disable hard code routing for SSP2 AIF1. Signed-off-by: Pan Xiuli Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bytcr_rt5651.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 8dffeecda55b88..8e2d54cf2ebcf0 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -306,6 +306,7 @@ static const struct snd_soc_dapm_route byt_rt5651_ssp0_aif2_map[] = { }; static const struct snd_soc_dapm_route byt_rt5651_ssp2_aif1_map[] = { +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, {"codec_in0", NULL, "ssp2 Rx"}, @@ -313,6 +314,7 @@ static const struct snd_soc_dapm_route byt_rt5651_ssp2_aif1_map[] = { {"AIF1 Playback", NULL, "ssp2 Tx"}, {"ssp2 Rx", NULL, "AIF1 Capture"}, +#endif }; static const struct snd_soc_dapm_route byt_rt5651_ssp2_aif2_map[] = { @@ -877,7 +879,9 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) struct device *codec_dev; const char *i2c_name = NULL; const char *hp_swapped; +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) bool is_bytcr = false; +#endif int ret_val = 0; int dai_index = 0; int i; @@ -915,6 +919,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) if (!codec_dev) return -EPROBE_DEFER; +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) /* * swap SSP0 if bytcr is detected * (will be overridden if DMI quirk is detected) @@ -973,6 +978,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) byt_rt5651_quirk |= BYT_RT5651_SSP0_AIF2; } } +#endif /* check quirks before creating card */ dmi_check_system(byt_rt5651_quirk_table); From a6421cec33268ce60ede76c6e345d3412cad215d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 12 Jun 2018 18:51:28 -0500 Subject: [PATCH 0169/1995] acpi: blacklist: remove quirk for Dell XPS13 when SOF is enabled Audio works well in I2S mode with SOF (Sound Open Firmware), no need for this quirk Signed-off-by: Pierre-Louis Bossart --- drivers/acpi/blacklist.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 995c4d8922b12e..edf821bc582baa 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -91,6 +91,7 @@ static int __init dmi_enable_rev_override(const struct dmi_system_id *d) static const struct dmi_system_id acpi_rev_dmi_table[] __initconst = { #ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) /* * DELL XPS 13 (2015) switches sound between HDA and I2S * depending on the ACPI _REV callback. If userspace supports @@ -105,6 +106,7 @@ static const struct dmi_system_id acpi_rev_dmi_table[] __initconst = { DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343"), }, }, +#endif { .callback = dmi_enable_rev_override, .ident = "DELL Precision 5520", From 80a535e23fc52f792555979ff6d1592806d5f68e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 31 Jul 2018 16:47:49 -0500 Subject: [PATCH 0170/1995] ASoC: Intel: boards: bxt_da7219_max: remove dependency on dmic-codec Not sure why this was ever needed, there are no GPIO controlling the DMICs. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 6f052fc8d1e25a..78131be2f7a7cb 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -488,8 +488,8 @@ static struct snd_soc_dai_link broxton_dais[] = { .name = "dmic01", .id = 2, .cpu_dai_name = "DMIC01 Pin", - .codec_name = "dmic-codec", - .codec_dai_name = "dmic-hifi", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", .platform_name = "0000:00:0e.0", .ignore_suspend = 1, .be_hw_params_fixup = broxton_dmic_fixup, From a29b55c7fe216898576f74eb5fb7f1cf36d8535b Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 3 Nov 2017 20:56:42 +0000 Subject: [PATCH 0171/1995] ALSA: HACK: Fix rmmod crash Something appears to corrupt the runtime->status on second playback... Signed-off-by: Liam Girdwood --- sound/core/pcm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index fdb9b92fc8d6b3..2bff19f35addb5 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -1155,6 +1155,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) list_del_init(&pcm->list); for (cidx = 0; cidx < 2; cidx++) { for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) { +#if 0 snd_pcm_stream_lock_irq(substream); if (substream->runtime) { if (snd_pcm_running(substream)) @@ -1166,6 +1167,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) wake_up(&substream->runtime->tsleep); } snd_pcm_stream_unlock_irq(substream); +#endif } } From 1549754e0d76c3c3c72235131de754fe54bf94d4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 16 Apr 2018 13:20:32 -0500 Subject: [PATCH 0172/1995] [NOT FOR UPSTREAM] ASoC: SOF: enable DEBUG by default better to use dynamic debug for products but it's really convenient Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/Makefile | 2 ++ sound/soc/sof/intel/Makefile | 2 ++ sound/soc/sof/xtensa/Makefile | 2 ++ 3 files changed, 6 insertions(+) diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index e2250db8baeba6..b8f6c67fbb7b70 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -1,5 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +ccflags-y += -DDEBUG + snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ control.o trace.o compressed.o utils.o snd-sof-spi-objs := hw-spi.o diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index 78f5fb3d3571c1..a7a7c0cf7663aa 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -1,5 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +ccflags-y += -DDEBUG + snd-sof-intel-byt-objs := byt.o snd-sof-intel-hsw-objs := hsw.o snd-sof-intel-bdw-objs := bdw.o diff --git a/sound/soc/sof/xtensa/Makefile b/sound/soc/sof/xtensa/Makefile index cc89c7472a3802..34b27be0f7be07 100644 --- a/sound/soc/sof/xtensa/Makefile +++ b/sound/soc/sof/xtensa/Makefile @@ -1,5 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +ccflags-y += -DDEBUG + snd-sof-xtensa-dsp-objs := core.o obj-$(CONFIG_SND_SOC_SOF_XTENSA) += snd-sof-xtensa-dsp.o From 956d06ac7925d0a465827c840e764459607ce888 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 21 May 2018 18:19:44 -0500 Subject: [PATCH 0173/1995] ASoC: Intel: boards: initial support for Hifiberry Digiplus w/ WM8804 Based on code from sound/soc/bcm/hifiberry-digi.c in RPI tree TODO: add support for DIGI+ IO (capture) and Digi+ PRO Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 10 ++ sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/bxt_wm8804.c | 263 ++++++++++++++++++++++++++++ 3 files changed, 275 insertions(+) create mode 100644 sound/soc/intel/boards/bxt_wm8804.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index f7ba8a312649d4..08166bf048ec51 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -261,6 +261,16 @@ config SND_SOC_INTEL_BXT_PCM512x_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +config SND_SOC_INTEL_BXT_WM8804_MACH + tristate "Broxton with Wolfson/Cirrus WM8804 codec for Hifiberry Digi+" + depends on MFD_INTEL_LPSS && I2C && ACPI + select SND_SOC_WM8804_I2C + help + This adds support for ASoC machine driver for Broxton platforms + with Hifiberry Digiplus w/ Wolfson/Cirrus WM8804 I2S audio codec. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + config SND_SOC_INTEL_BXT_TDF8532_MACH tristate "ASoC Audio driver for BXT with TDF8532 in I2S mode" depends on X86 && ACPI && I2C diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index e511979f279641..93a1e132c73bb3 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -7,6 +7,7 @@ snd-soc-sst-broadwell-objs := broadwell.o snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o snd-soc-sst-bxt-rt298-objs := bxt_rt298.o snd-soc-sst-bxt-pcm512x-objs := bxt_pcm512x.o +snd-soc-sst-bxt-wm8804-objs := bxt_wm8804.o snd-soc-sst_bxt_tdf8532-objs := bxt_tdf8532.o snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o @@ -34,6 +35,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o obj-$(CONFIG_SND_SOC_INTEL_BXT_PCM512x_MACH) += snd-soc-sst-bxt-pcm512x.o +obj-$(CONFIG_SND_SOC_INTEL_BXT_WM8804_MACH) += snd-soc-sst-bxt-wm8804.o obj-$(CONFIG_SND_SOC_INTEL_BXT_TDF8532_MACH) += snd-soc-sst_bxt_tdf8532.o obj-$(CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH) += snd-soc-sst-glk-rt5682_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o diff --git a/sound/soc/intel/boards/bxt_wm8804.c b/sound/soc/intel/boards/bxt_wm8804.c new file mode 100644 index 00000000000000..de6a4669731bd2 --- /dev/null +++ b/sound/soc/intel/boards/bxt_wm8804.c @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * bxt-wm8804.c - ASoC machine driver for Up and Up2 board + * based on WM8804/Hifiberry Digi+ + * Copyright (c) 2018, Intel Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/wm8804.h" +#include "../atom/sst-atom-controls.h" +#include + +#include "../../codecs/wm8804.h" + +static short int auto_shutdown_output; +module_param(auto_shutdown_output, short, 0660); +MODULE_PARM_DESC(auto_shutdown_output, "Shutdown SP/DIF output if playback is stopped"); + +#define CLK_44EN_RATE 22579200UL +#define CLK_48EN_RATE 24576000UL + +static bool snd_rpi_hifiberry_is_digipro; +static struct gpio_desc *snd_rpi_hifiberry_clk44gpio; +static struct gpio_desc *snd_rpi_hifiberry_clk48gpio; + +static int samplerate = 44100; + +static uint32_t snd_rpi_hifiberry_digi_enable_clock(int sample_rate) +{ + switch (sample_rate) { + case 11025: + case 22050: + case 44100: + case 88200: + case 176400: + gpiod_set_value_cansleep(snd_rpi_hifiberry_clk44gpio, 1); + gpiod_set_value_cansleep(snd_rpi_hifiberry_clk48gpio, 0); + return CLK_44EN_RATE; + default: + gpiod_set_value_cansleep(snd_rpi_hifiberry_clk48gpio, 1); + gpiod_set_value_cansleep(snd_rpi_hifiberry_clk44gpio, 0); + return CLK_48EN_RATE; + } +} + +static int snd_rpi_hifiberry_digi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *codec = rtd->codec_dai->component; + + /* enable TX output */ + snd_soc_component_update_bits(codec, WM8804_PWRDN, 0x4, 0x0); + + /* Initialize Digi+ Pro hardware */ + if (snd_rpi_hifiberry_is_digipro) { + struct snd_soc_dai_link *dai = rtd->dai_link; + + dai->name = "HiFiBerry Digi+ Pro"; + dai->stream_name = "HiFiBerry Digi+ Pro HiFi"; + } + + return 0; +} + +static int snd_rpi_hifiberry_digi_startup(struct snd_pcm_substream *substream) +{ + /* turn on digital output */ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *codec = rtd->codec_dai->component; + + snd_soc_component_update_bits(codec, WM8804_PWRDN, 0x3c, 0x00); + return 0; +} + +static void snd_rpi_hifiberry_digi_shutdown(struct snd_pcm_substream *substream) +{ + /* turn off output */ + if (auto_shutdown_output) { + /* turn off output */ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *codec = rtd->codec_dai->component; + + snd_soc_component_update_bits(codec, WM8804_PWRDN, 0x3c, 0x3c); + } +} + +static int snd_rpi_hifiberry_digi_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; + struct snd_soc_component *codec = codec_dai->component; + + int sysclk = 27000000; /* This is fixed on this board */ + + long mclk_freq = 0; + int mclk_div = 1; + int sampling_freq = 1; + + int ret; + + samplerate = params_rate(params); + + if (samplerate <= 96000) { + mclk_freq = samplerate * 256; + mclk_div = WM8804_MCLKDIV_256FS; + } else { + mclk_freq = samplerate * 128; + mclk_div = WM8804_MCLKDIV_128FS; + } + + if (snd_rpi_hifiberry_is_digipro) + sysclk = snd_rpi_hifiberry_digi_enable_clock(samplerate); + + switch (samplerate) { + case 32000: + sampling_freq = 0x03; + break; + case 44100: + sampling_freq = 0x00; + break; + case 48000: + sampling_freq = 0x02; + break; + case 88200: + sampling_freq = 0x08; + break; + case 96000: + sampling_freq = 0x0a; + break; + case 176400: + sampling_freq = 0x0c; + break; + case 192000: + sampling_freq = 0x0e; + break; + default: + dev_err(codec->dev, + "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n", + samplerate); + } + + snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div); + snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq); + + ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL, + sysclk, SND_SOC_CLOCK_OUT); + + if (ret < 0) { + dev_err(codec->dev, + "Failed to set WM8804 SYSCLK: %d\n", ret); + return ret; + } + + /* Enable TX output */ + snd_soc_component_update_bits(codec, WM8804_PWRDN, 0x4, 0x0); + + /* Power on */ + snd_soc_component_update_bits(codec, WM8804_PWRDN, 0x9, 0); + + /* set sampling frequency status bits */ + snd_soc_component_update_bits(codec, WM8804_SPDTX4, 0x0f, + sampling_freq); + + return 0; +} + +/* machine stream operations */ +static struct snd_soc_ops snd_rpi_hifiberry_digi_ops = { + .hw_params = snd_rpi_hifiberry_digi_hw_params, + .startup = snd_rpi_hifiberry_digi_startup, + .shutdown = snd_rpi_hifiberry_digi_shutdown, +}; + +static struct snd_soc_dai_link dailink[] = { + /* CODEC<->CODEC link */ + /* back ends */ + { + .name = "SSP5-Codec", + .id = 0, + .cpu_dai_name = "SSP5 Pin", + .platform_name = "sof-audio", + .no_pcm = 1, + .codec_dai_name = "wm8804-spdif", + .codec_name = "i2c-1AEC8804:00", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFM, + .nonatomic = true, + .dpcm_playback = 1, + .ops = &snd_rpi_hifiberry_digi_ops, + .init = snd_rpi_hifiberry_digi_init, + }, +}; + +/* SoC card */ +static struct snd_soc_card bxt_wm8804_card = { + .name = "bxt-wm8804", + .owner = THIS_MODULE, + .dai_link = dailink, + .num_links = ARRAY_SIZE(dailink), +}; + + /* i2c-:00 with HID being 8 chars */ +static char codec_name[SND_ACPI_I2C_ID_LEN]; + +static int bxt_wm8804_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card; + struct snd_soc_acpi_mach *mach; + const char *i2c_name = NULL; + int dai_index = 0; + int ret_val = 0; + int i; + + mach = (&pdev->dev)->platform_data; + card = &bxt_wm8804_card; + card->dev = &pdev->dev; + + /* fix index of codec dai */ + for (i = 0; i < ARRAY_SIZE(dailink); i++) { + if (!strcmp(dailink[i].codec_name, "i2c-1AEC8804:00")) { + dai_index = i; + break; + } + } + + /* fixup codec name based on HID */ + i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); + if (i2c_name) { + 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 bxt_wm8804_driver = { + .driver = { + .name = "bxt-wm8804", + }, + .probe = bxt_wm8804_probe, +}; +module_platform_driver(bxt_wm8804_driver); + +MODULE_DESCRIPTION("ASoC Intel(R) Broxton + WM8804 Machine driver"); +MODULE_AUTHOR("Pierre-Louis Bossart"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:bxt-wm8804"); From 3bc3c1fb3a0c6e7b3938ee9629dfa0e8b94a7d32 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 24 Oct 2018 14:49:46 -0500 Subject: [PATCH 0174/1995] boards/skl_hda_dsp_generic Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/skl_hda_dsp_generic.c | 21 ++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index b415dd4c85f5ac..399d1b03595959 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "../../codecs/hdac_hdmi.h" #include "../skylake/skl.h" #include "skl_hda_dsp_common.h" @@ -101,17 +102,17 @@ static struct snd_soc_card hda_soc_card = { #define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2) #define IDISP_CODEC_MASK 0x4 -static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) +static int skl_hda_fill_card_info(const char *platform, + unsigned long codec_mask) { struct snd_soc_card *card = &hda_soc_card; struct snd_soc_dai_link *dai_link; - u32 codec_count, codec_mask; + u32 codec_count; int i, num_links, num_route; - codec_mask = pdata->codec_mask; codec_count = hweight_long(codec_mask); - if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) { + if (codec_count == 1 && codec_mask & IDISP_CODEC_MASK) { num_links = IDISP_DAI_COUNT; num_route = IDISP_ROUTE_COUNT; } else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) { @@ -127,17 +128,22 @@ static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) card->num_dapm_routes = num_route; for_each_card_prelinks(card, i, dai_link) - dai_link->platform_name = pdata->platform; + dai_link->platform_name = platform; return 0; } static int skl_hda_audio_probe(struct platform_device *pdev) { - struct skl_machine_pdata *pdata; struct skl_hda_private *ctx; int ret; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) + struct snd_sof_pdata *pdata = dev_get_platdata(&pdev->dev); +#else + struct skl_machine_pdata *pdata = dev_get_drvdata(&pdev->dev); +#endif + dev_dbg(&pdev->dev, "%s: entry\n", __func__); ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); @@ -146,11 +152,10 @@ static int skl_hda_audio_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - pdata = dev_get_drvdata(&pdev->dev); if (!pdata) return -EINVAL; - ret = skl_hda_fill_card_info(pdata); + ret = skl_hda_fill_card_info(pdata->platform, pdata->codec_mask); if (ret < 0) { dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n"); return ret; From e3d3cac260dbe625015173b4524b2ef9a5d01805 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 24 Oct 2018 14:50:14 -0500 Subject: [PATCH 0175/1995] sklylake/skl.h Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/skylake/skl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 8d48cd7c56c835..9a9688dcf26010 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -122,7 +122,7 @@ struct skl_machine_pdata { u32 dmic_num; bool use_tplg_pcm; /* use dais and dai links from topology */ const char *platform; - u32 codec_mask; + unsigned long codec_mask; }; struct skl_dsp_ops { From ec4e4a9305869f3962b11c2556ba3b5b4dd794e9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 24 Oct 2018 14:51:47 -0500 Subject: [PATCH 0176/1995] ASOC: SOF: intel: enable SPI compilation Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/Kconfig | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index d777ddd80d893e..d41d60b037426e 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -9,6 +9,17 @@ config SND_SOC_SOF_INTEL Say Y if you have such a device. If unsure select "N". +config SND_SOC_SOF_SPIDSP + tristate "SOF support over the SPI bus" + depends on SND_SOC_SOF + depends on SPI + select SND_SOC_SOF_SPI + help + This adds support for Sound Open Firmware over SPI for Device + Tree based systems. + Say Y if you have such a device. + If unsure select "N". + if SND_SOC_SOF_INTEL config SND_SOC_SOF_BAYTRAIL From 7af711b952284ee41fcda0c4ba9f6ea831ea170a Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 10 Aug 2018 19:30:30 +0800 Subject: [PATCH 0177/1995] ASoC: SOF: topology: continue parsing when num_hw_configs is not 1 Only give warning and continue parsing when num_hw_configs is not 1. this is needed for HDA dai parsing. Signed-off-by: Mengdong Lin Signed-off-by: Keyon Jie --- sound/soc/sof/topology.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index c71ad4ab962367..02ef68d64a8092 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2078,12 +2078,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, if (!link->no_pcm) return 0; - /* only support 1 config atm */ - if (le32_to_cpu(cfg->num_hw_configs) != 1) { - dev_err(sdev->dev, "error: unexpected DAI config count %d\n", - le32_to_cpu(cfg->num_hw_configs)); - return -EINVAL; - } + /* usually we use 1 config, but for HDA it may be 0 ATM */ + if (le32_to_cpu(cfg->num_hw_configs) != 1) + dev_warn(sdev->dev, "warn: unexpected DAI config count %d!\n", + le32_to_cpu(cfg->num_hw_configs)); /* check we have some tokens - we need at least DAI type */ if (le32_to_cpu(private->size) == 0) { From 9ea168fca3e0d4cd9e70614db085a3ecc59938f7 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Thu, 27 Sep 2018 18:22:33 +0800 Subject: [PATCH 0178/1995] ASoC: Intel: Add HDMI support to bxt_pcm512x Add HDMI support to bxt_pcm512x. Signed-off-by: Pan Xiuli --- sound/soc/intel/boards/bxt_pcm512x.c | 110 +++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/sound/soc/intel/boards/bxt_pcm512x.c b/sound/soc/intel/boards/bxt_pcm512x.c index d2edbd9749d96a..258dcfd34e8336 100644 --- a/sound/soc/intel/boards/bxt_pcm512x.c +++ b/sound/soc/intel/boards/bxt_pcm512x.c @@ -27,9 +27,23 @@ #include #include #include +#include +#include "../../codecs/hdac_hdmi.h" #include "../../codecs/pcm512x.h" #include "../atom/sst-atom-controls.h" +static struct snd_soc_jack broxton_hdmi[3]; + +struct bxt_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct bxt_card_private { + struct list_head hdmi_pcm_list; +}; + static const struct snd_soc_dapm_widget dapm_widgets[] = { SND_SOC_DAPM_SPK("Ext Spk", NULL), }; @@ -100,6 +114,24 @@ static const struct snd_soc_ops aif1_ops = { .shutdown = aif1_shutdown, }; +static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct bxt_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct bxt_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = dai->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + static struct snd_soc_dai_link dailink[] = { /* CODEC<->CODEC link */ /* back ends */ @@ -119,8 +151,76 @@ static struct snd_soc_dai_link dailink[] = { .dpcm_playback = 1, .dpcm_capture = 1, }, + { + .name = "iDisp1", + .id = 1, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:0e.0", + .init = broxton_hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .id = 2, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .platform_name = "0000:00:0e.0", + .init = broxton_hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .id = 3, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .platform_name = "0000:00:0e.0", + .init = broxton_hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + }; +#define NAME_SIZE 32 +static int bxt_card_late_probe(struct snd_soc_card *card) +{ + struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card); + struct bxt_hdmi_pcm *pcm; + struct snd_soc_component *component = NULL; + int err, i = 0; + char jack_name[NAME_SIZE]; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &broxton_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &broxton_hdmi[i]); + if (err < 0) + return err; + + i++; + } + + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); +} + /* SoC card */ static struct snd_soc_card bxt_pcm512x_card = { .name = "bxt-pcm512x", @@ -131,6 +231,7 @@ static struct snd_soc_card bxt_pcm512x_card = { .num_dapm_widgets = ARRAY_SIZE(dapm_widgets), .dapm_routes = audio_map, .num_dapm_routes = ARRAY_SIZE(audio_map), + .late_probe = bxt_card_late_probe, }; /* i2c-:00 with HID being 8 chars */ @@ -140,10 +241,17 @@ static int bxt_pcm512x_probe(struct platform_device *pdev) { struct snd_soc_card *card; struct snd_soc_acpi_mach *mach; + struct bxt_card_private *ctx; const char *i2c_name = NULL; int dai_index = 0; int ret_val = 0, i; + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + mach = (&pdev->dev)->platform_data; card = &bxt_pcm512x_card; card->dev = &pdev->dev; @@ -164,6 +272,8 @@ static int bxt_pcm512x_probe(struct platform_device *pdev) dailink[dai_index].codec_name = codec_name; } + snd_soc_card_set_drvdata(card, ctx); + ret_val = devm_snd_soc_register_card(&pdev->dev, card); if (ret_val) { dev_err(&pdev->dev, From 0f616e210e182a5fc60cf320554e0fba3c7f4bf6 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 18 Oct 2018 14:29:11 +0100 Subject: [PATCH 0179/1995] ASoC: SOF: Intel HDA: continue probe if no HDMI devices found Normal flow if no HDMI devices are connected. Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/hda.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index a9baed1ec6ed80..f6153d5447d7c5 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -406,8 +406,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) /* (2) probe i915 and HDA codecs, HDMI codecs */ if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { ret = hda_codec_i915_init(sdev); - if (ret < 0) - return ret; + dev_dbg(&pci->dev, "no HDMI audio devices found\n"); } /* only HDA analog codec is detected in step (1) and From c661a48dfcdef0f9f08e6ac28cbdc76b24429482 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 5 Sep 2018 15:15:24 +0200 Subject: [PATCH 0180/1995] rpi: add a sample DT node for SPI SOF This sample SPI SOF DT node is solely an illustration to accompany respective SOF changes, all values are completely fictitious. Signed-off-by: Guennadi Liakhovetski --- arch/arm/boot/dts/bcm283x-rpi-sof.dtsi | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 arch/arm/boot/dts/bcm283x-rpi-sof.dtsi diff --git a/arch/arm/boot/dts/bcm283x-rpi-sof.dtsi b/arch/arm/boot/dts/bcm283x-rpi-sof.dtsi new file mode 100644 index 00000000000000..1b69ac517f95bb --- /dev/null +++ b/arch/arm/boot/dts/bcm283x-rpi-sof.dtsi @@ -0,0 +1,17 @@ +// FIXME: which SPI bus is the card connected to? +@spi { + status = "okay"; + + sue-creek: sof-sue-creek@0 { + reg = <0>; + compatible = "sof,spi-sue-creek"; + // FIXME: frequency value + spi-max-frequency = <54000000>; + fw_filename = "intel/sof-spi.ri"; + tplg_filename = "intel/sof-spi.tplg"; + // FIXME: GPIO controller and IRQ number and sense + interrupt-parent = <&gpio1>; + interrupts = <9 IRQ_TYPE_EDGE_FALLING>; + irq-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; + }; +}; From c3ef264b4c5b3a7149b1fa661dce6cabc02bfb23 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 5 Sep 2018 19:27:16 +0200 Subject: [PATCH 0181/1995] rpi: include SOF DT nodes Add SOF DT nodes to Raspberry Pi 2-B. Signed-off-by: Guennadi Liakhovetski --- arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts index 2fef70a099535d..490efdcebefbe7 100644 --- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts +++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts @@ -4,6 +4,7 @@ #include "bcm2835-rpi.dtsi" #include "bcm283x-rpi-smsc9514.dtsi" #include "bcm283x-rpi-usb-host.dtsi" +#include "bcm283x-rpi-sof.dtsi" / { compatible = "raspberrypi,2-model-b", "brcm,bcm2836"; From 7e41d538a7b254ebe006bf55f34c24cfe65862b2 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 6 Sep 2018 17:30:28 +0200 Subject: [PATCH 0182/1995] rpi: temporarily disable SOF DT The SOF DT doesn't compile yet, it's only provided as an example, disable it for now to prevent automated builds from failing. Signed-off-by: Guennadi Liakhovetski --- arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts index 490efdcebefbe7..f0b2b4117e7b72 100644 --- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts +++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts @@ -4,7 +4,7 @@ #include "bcm2835-rpi.dtsi" #include "bcm283x-rpi-smsc9514.dtsi" #include "bcm283x-rpi-usb-host.dtsi" -#include "bcm283x-rpi-sof.dtsi" +//#include "bcm283x-rpi-sof.dtsi" / { compatible = "raspberrypi,2-model-b", "brcm,bcm2836"; From 5d7f0748e16d7b59e26707314a11357c52598d27 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 31 Oct 2018 13:46:41 -0500 Subject: [PATCH 0183/1995] ASoC: SOF: hda: manually register/unregister dmic device The Intel machine drivers make use of the "dmic-codec", which isn't currently ACPI enumerated. While there is no control capability for the dmic, this dmic-codec allows for the use of parameters such as wake-up time. Rather than add conditional code in all machine drivers, add registration/unregistration for this platform device in the HDaudio support of SOF. This code would become conditional if there is ever an ACPI support added to the DMIC. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 10 ++++++++++ sound/soc/sof/intel/hda.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index f6153d5447d7c5..2d84784e12ac7c 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -507,6 +507,13 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) sdev->hda = hdev; hdev->desc = chip; + hdev->dmic_dev = platform_device_register_data(&pci->dev, "dmic-codec", + -1, NULL, 0); + if (IS_ERR(hdev->dmic_dev)) { + dev_err(&pci->dev, "Failed to create DMIC device\n"); + return PTR_ERR(hdev->dmic_dev); + } + /* * use position update IPC if either it is forced * or we don't have other choice @@ -681,6 +688,9 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) struct pci_dev *pci = sdev->pci; const struct sof_intel_dsp_desc *chip = sdev->hda->desc; + if (sdev->hda && (!IS_ERR_OR_NULL(sdev->hda->dmic_dev))) + platform_device_unregister(sdev->hda->dmic_dev); + /* disable DSP IRQ */ snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, SOF_HDA_PPCTL_PIE, 0); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 6a31a8b312a594..c9c3e52508f00f 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -363,6 +363,9 @@ struct sof_intel_hda_dev { bool no_ipc_position; int irq; + + /* DMIC device */ + struct platform_device *dmic_dev; }; #define bus_to_sof_hda(bus) \ From a5ddc3d78b47b4d3e77ac371b6f016f3a6a9278c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 31 Oct 2018 13:13:36 -0500 Subject: [PATCH 0184/1995] ASoC: SOF: hda: fix comments copy-paste and typo. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-dsp.c | 4 ++-- sound/soc/sof/intel/hda.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 0761375e7e6e00..aeaa1af787dbae 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -293,7 +293,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state) snd_hdac_ext_bus_ppcap_int_enable(bus, false); snd_hdac_ext_bus_ppcap_enable(bus, false); - /* disable hda bus irw and i/o */ + /* disable hda bus irq and i/o */ snd_hdac_bus_stop_chip(bus); #endif @@ -408,7 +408,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state) if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { ret = snd_hdac_display_power(bus, false); if (ret < 0) { - dev_err(bus->dev, "Cannot turn on display power on i915 after resume\n"); + dev_err(bus->dev, "Cannot turn OFF display power on i915 during suspend\n"); return ret; } } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 2d84784e12ac7c..89fbb3321b55ec 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -396,7 +396,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) /* check if dsp is there */ if (bus->ppcap) - dev_dbg(&pci->dev, "PP capbility, will probe DSP later.\n"); + dev_dbg(&pci->dev, "PP capability, will probe DSP later.\n"); if (bus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(bus); From af44aa9b7208f75d57f9173e397d0fd0e7773f1b Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Thu, 1 Nov 2018 19:31:23 +0800 Subject: [PATCH 0185/1995] [DEBUG]CI: Travis: Enable Travis CI for linux kernel Add checkpatch for pull-request only. Build x86_64 kernel with kconfig sof base config. Signed-off-by: Pan Xiuli --- .travis.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000000000..410da51203c6c6 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,29 @@ +language: c + +git: + depth: false + +before_install: + - sudo apt-get update -qq + - sudo apt-get install python-ply python-git libelf-dev codespell + - git clone https://github.com/thesofproject/kconfig.git + +jobs: + include: + - if: type = pull_request + name: checkpatch + script: scripts/checkpatch.pl --strict --codespell -g $TRAVIS_COMMIT_RANGE + - name: "BUILD SOF Kernel x86_64" + script: + - export ARCH=x86_64 + - make defconfig + - scripts/kconfig/merge_config.sh .config kconfig/base-defconfig kconfig/sof-defconfig + - echo `getconf _NPROCESSORS_ONLN` + - make -j`getconf _NPROCESSORS_ONLN` + - name: "BUILD SST Kernel x86_64" + script: + - export ARCH=x86_64 + - make defconfig + - scripts/kconfig/merge_config.sh .config kconfig/base-defconfig kconfig/sst-defconfig + - echo `getconf _NPROCESSORS_ONLN` + - make -j`getconf _NPROCESSORS_ONLN` From 6ec97fc5218baa2c12fafc6bbc7fe8ba4b32c4ce Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Fri, 2 Nov 2018 18:41:54 +0800 Subject: [PATCH 0186/1995] ASoC: SOF: sof-priv.h: add fw_version in sof_dev Store fw_version for logger to use Signed-off-by: Pan Xiuli --- sound/soc/sof/sof-priv.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 0f7ddf19bf8a15..318762d1349fea 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -336,6 +336,7 @@ struct snd_sof_dev { struct snd_dma_buffer dmab; struct snd_dma_buffer dmab_bdl; struct sof_ipc_fw_ready fw_ready; + struct sof_ipc_fw_version fw_version; /* topology */ struct snd_soc_tplg_ops *tplg_ops; From 506233f2bdc9bd5ca2e4a853b5ce896c07bafaec Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Fri, 2 Nov 2018 18:42:03 +0800 Subject: [PATCH 0187/1995] ASoC: SOF: Intel: Store fw_version when first boot Signed-off-by: Pan Xiuli --- sound/soc/sof/intel/bdw.c | 4 ++++ sound/soc/sof/intel/byt.c | 4 ++++ sound/soc/sof/intel/hda-ipc.c | 4 ++++ sound/soc/sof/intel/hsw.c | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 8068a48c90cc9b..0a0892afaffd77 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -519,6 +519,10 @@ static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) " Firmware info: version %d:%d-%s build %d on %s:%s\n", v->major, v->minor, v->tag, v->build, v->date, v->time); + /* only copy the fw_version into debugfs at first boot */ + if (sdev->first_boot) + memcpy(&sdev->fw_version, v, sizeof(*v)); + /* now check for extended data */ snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + sizeof(struct sof_ipc_fw_ready)); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 25d5bf0ed6f31c..292eed4eeead43 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -279,6 +279,10 @@ static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) " Firmware info: version %d:%d-%s build %d on %s:%s\n", v->major, v->minor, v->tag, v->build, v->date, v->time); + /* only copy the fw_version into debugfs at first boot */ + if (sdev->first_boot) + memcpy(&sdev->fw_version, v, sizeof(*v)); + /* now check for extended data */ snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + sizeof(struct sof_ipc_fw_ready)); diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index dc2df7a99d03f2..e025da964ef59e 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -385,6 +385,10 @@ int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) " Firmware info: version %d.%d-%s build %d on %s:%s\n", v->major, v->minor, v->tag, v->build, v->date, v->time); + /* only copy the fw_version into debugfs at first boot */ + if (sdev->first_boot) + memcpy(&sdev->fw_version, v, sizeof(*v)); + /* now check for extended data */ snd_sof_fw_parse_ext_data(sdev, HDA_DSP_MBOX_UPLINK_OFFSET + sizeof(struct sof_ipc_fw_ready)); diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index fef9aa0c8ec249..2299686db32c50 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -521,6 +521,10 @@ static int hsw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) " Firmware info: version %d:%d-%s build %d on %s:%s\n", v->major, v->minor, v->tag, v->build, v->date, v->time); + /* only copy the fw_version into debugfs at first boot */ + if (sdev->first_boot) + memcpy(&sdev->fw_version, v, sizeof(*v)); + /* now check for extended data */ snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + sizeof(struct sof_ipc_fw_ready)); From 6ff8e4d74c1f59713f7534aa9f9813e81f916b9f Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Fri, 2 Nov 2018 18:42:14 +0800 Subject: [PATCH 0188/1995] ASoC: SOF: loader: create debugfs fw_version at first boot Create the debugfs to store the first boot fw verion info. Signed-off-by: Pan Xiuli --- sound/soc/sof/loader.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index e30531026209e9..6828d9e9b1a0d1 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -284,6 +284,18 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) init_waitqueue_head(&sdev->boot_wait); sdev->boot_complete = false; + /* create fw_version debugfs to store boot version info */ + if (sdev->first_boot) { + ret = snd_sof_debugfs_create_item(sdev, &sdev->fw_version, + sizeof(sdev->fw_version), + "fw_version"); + + if (ret < 0) { + dev_err(sdev->dev, "cannot create debugfs for fw_version\n"); + return ret; + } + } + dev_dbg(sdev->dev, "booting DSP firmware\n"); /* boot the firmware on the DSP */ From 4badf19ec779b5607ec59ee956145e3bae839626 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Thu, 8 Nov 2018 16:22:51 +0200 Subject: [PATCH 0189/1995] ASoC: SOF: topology: set default values to volume control Currently volume control doesn't have any default values when it is created. This will cause an issue when PM kicks in and in resume the non-existing values are set to firmware. Signed-off-by: Jaska Uimonen --- sound/soc/sof/topology.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 02ef68d64a8092..51d7294b974654 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -33,9 +33,12 @@ /* 40th root of 10 in Q1.16 fixed-point notation*/ #define VOL_FORTIETH_ROOT_OF_TEN 69419 /* Volume fractional word length */ +/* Define to 16 sets the volume linear gain value to use Qx.16 format */ #define VOLUME_FWL 16 /* 0.5 dB step value in topology TLV */ #define VOL_HALF_DB_STEP 50 +/* Full volume for default values */ +#define VOL_ZERO_DB BIT(VOLUME_FWL) /* TLV data items */ #define TLV_ITEMS 3 @@ -1193,8 +1196,10 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, const struct snd_kcontrol_new *kc = NULL; struct soc_mixer_control *sm; struct snd_sof_control *scontrol; + struct sof_ipc_ctrl_data *cdata; const unsigned int *p; int ret, tlv[TLV_ITEMS]; + unsigned int i; volume = kzalloc(sizeof(*volume), GFP_KERNEL); if (!volume) @@ -1258,6 +1263,13 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, goto err; } + /* set default volume values to 0dB in control */ + cdata = scontrol->control_data; + for (i = 0; i < scontrol->num_channels; i++) { + cdata->chanv[i].channel = i; + cdata->chanv[i].value = VOL_ZERO_DB; + } + sof_dbg_comp_config(scomp, &volume->config); swidget->private = (void *)volume; From 7b47adf6449238b1561aaf5b584e01d7f940b0b1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 8 Nov 2018 19:34:42 -0600 Subject: [PATCH 0190/1995] ASoC: Intel: Power down links before turning off display audio power On certain platforms, Display HDMI HDA codec was not going to sleep state after the use when links are powered down after turning off the display power. As per the HW recommendation, links are powered down before turning off the display power to ensure that the codec goes to sleep state. This patch was updated from an earlier version submitted upstream [1] which conflicted with the changes merged for HDaudio codec support with the Intel DSP. [1] https://patchwork.kernel.org/patch/10540213/ Signed-off-by: Sriram Periyasamy Signed-off-by: Sanyog Kale Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/hdac_hdmi.c | 13 +++++++------ sound/soc/intel/skylake/skl.c | 12 ++++++------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 4e9854889a9570..e0fe682cea04a1 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2187,11 +2187,6 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) */ snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - err = snd_hdac_display_power(bus, false); - if (err < 0) { - dev_err(dev, "Cannot turn on display power on i915\n"); - return err; - } hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev)); if (!hlink) { @@ -2201,7 +2196,13 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) snd_hdac_ext_bus_link_put(bus, hlink); - return 0; + err = snd_hdac_display_power(bus, false); + if (err < 0) { + dev_err(dev, "Cannot turn off display power on i915\n"); + return err; + } + + return err; } static int hdac_hdmi_runtime_resume(struct device *dev) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 29225623b4b40d..1586c97d94508a 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -815,6 +815,12 @@ static void skl_probe_work(struct work_struct *work) } } + /* + * we are done probing so decrement link counts + */ + list_for_each_entry(hlink, &bus->hlink_list, list) + snd_hdac_ext_bus_link_put(bus, hlink); + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { err = snd_hdac_display_power(bus, false); if (err < 0) { @@ -824,12 +830,6 @@ static void skl_probe_work(struct work_struct *work) } } - /* - * we are done probing so decrement link counts - */ - list_for_each_entry(hlink, &bus->hlink_list, list) - snd_hdac_ext_bus_link_put(bus, hlink); - /* configure PM */ pm_runtime_put_noidle(bus->dev); pm_runtime_allow(bus->dev); From fee7a89eb6f63f0a20c95b15ad130aaffa1344c7 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 22 Oct 2018 16:43:55 +0800 Subject: [PATCH 0191/1995] ASoC: SOF: Intel HDA - clear up redundant hda functions hda_dsp_stream_get|put_cstream and get|put_pstream could be replaced by hda_dsp_stream_get|put. Signed-off-by: Rander Wang --- sound/soc/sof/intel/hda-loader.c | 14 ++--- sound/soc/sof/intel/hda-pcm.c | 18 +++---- sound/soc/sof/intel/hda-stream.c | 90 +------------------------------- sound/soc/sof/intel/hda-trace.c | 8 +-- sound/soc/sof/intel/hda.h | 6 --- 5 files changed, 20 insertions(+), 116 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 76ac08d8d0883e..987632759d5358 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -38,23 +38,23 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, unsigned int size, struct snd_dma_buffer *dmab, int direction) { - struct hdac_ext_stream *stream = NULL; + struct hdac_ext_stream *dsp_stream = NULL; struct hdac_stream *hstream; struct pci_dev *pci = sdev->pci; int ret; if (direction == SNDRV_PCM_STREAM_PLAYBACK) { - stream = hda_dsp_stream_get_pstream(sdev); + dsp_stream = hda_dsp_stream_get(sdev, direction); } else { dev_err(sdev->dev, "error: code loading DMA is playback only\n"); return -EINVAL; } - if (!stream) { + if (!dsp_stream) { dev_err(sdev->dev, "error: no stream available\n"); return -ENODEV; } - hstream = &stream->hstream; + hstream = &dsp_stream->hstream; /* allocate DMA buffer */ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab); @@ -66,18 +66,18 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, hstream->format_val = format; hstream->bufsize = size; - ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL); + ret = hda_dsp_stream_hw_params(sdev, dsp_stream, dmab, NULL); if (ret < 0) { dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret); goto error; } - hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_ENABLE, size); + hda_dsp_stream_spib_config(sdev, dsp_stream, HDA_DSP_SPIB_ENABLE, size); return hstream->stream_tag; error: - hda_dsp_stream_put_pstream(sdev, hstream->stream_tag); + hda_dsp_stream_put(sdev, direction, hstream->stream_tag); snd_dma_free_pages(dmab); return ret; } diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index d5a09dcceeee4d..99d2586ddcc933 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -210,20 +210,18 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, int hda_dsp_pcm_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { - struct hdac_ext_stream *stream; + struct hdac_ext_stream *dsp_stream; + int direction = substream->stream; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - stream = hda_dsp_stream_get_pstream(sdev); - else - stream = hda_dsp_stream_get_cstream(sdev); + dsp_stream = hda_dsp_stream_get(sdev, direction); - if (!stream) { + if (!dsp_stream) { dev_err(sdev->dev, "error: no stream available\n"); return -ENODEV; } /* binding pcm substream to hda stream */ - substream->runtime->private_data = &stream->hstream; + substream->runtime->private_data = &dsp_stream->hstream; return 0; } @@ -231,12 +229,10 @@ int hda_dsp_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { struct hdac_stream *hstream = substream->runtime->private_data; + int direction = substream->stream; int ret; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - ret = hda_dsp_stream_put_pstream(sdev, hstream->stream_tag); - else - ret = hda_dsp_stream_put_cstream(sdev, hstream->stream_tag); + ret = hda_dsp_stream_put(sdev, direction, hstream->stream_tag); if (ret) { dev_dbg(sdev->dev, "stream %s not opened!\n", substream->name); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 42a986ce35a08f..49725fcd5590ed 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -170,7 +170,7 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction) struct hdac_ext_stream *stream = NULL; struct hdac_stream *s; - /* get an unused playback stream */ + /* get an unused stream */ list_for_each_entry(s, &bus->stream_list, list) { if (s->direction == direction && !s->opened) { s->opened = true; @@ -188,56 +188,6 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction) return stream; } -/* get next unused playback stream */ -struct hdac_ext_stream * -hda_dsp_stream_get_pstream(struct snd_sof_dev *sdev) -{ - struct hdac_bus *bus = sof_to_bus(sdev); - struct hdac_ext_stream *stream = NULL; - struct hdac_stream *s; - - /* get an unused playback stream */ - list_for_each_entry(s, &bus->stream_list, list) { - if (s->direction == SNDRV_PCM_STREAM_PLAYBACK && - !s->opened) { - s->opened = true; - stream = stream_to_hdac_ext_stream(s); - break; - } - } - - /* stream found ? */ - if (!stream) - dev_err(sdev->dev, "error: no free playback streams\n"); - - return stream; -} - -/* get next unused capture stream */ -struct hdac_ext_stream * -hda_dsp_stream_get_cstream(struct snd_sof_dev *sdev) -{ - struct hdac_bus *bus = sof_to_bus(sdev); - struct hdac_ext_stream *stream = NULL; - struct hdac_stream *s; - - /* get an unused capture stream */ - list_for_each_entry(s, &bus->stream_list, list) { - if (s->direction == SNDRV_PCM_STREAM_CAPTURE && - !s->opened) { - s->opened = true; - stream = stream_to_hdac_ext_stream(s); - break; - } - } - - /* stream found ? */ - if (!stream) - dev_err(sdev->dev, "error: no free capture streams\n"); - - return stream; -} - /* free a stream */ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int tag) { @@ -257,44 +207,6 @@ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int tag) return -ENODEV; } -/* free playback stream */ -int hda_dsp_stream_put_pstream(struct snd_sof_dev *sdev, int tag) -{ - struct hdac_bus *bus = sof_to_bus(sdev); - struct hdac_stream *s; - - /* find used playback stream */ - list_for_each_entry(s, &bus->stream_list, list) { - if (s->direction == SNDRV_PCM_STREAM_PLAYBACK && - s->opened && s->stream_tag == tag) { - s->opened = false; - return 0; - } - } - - dev_dbg(sdev->dev, "tag %d not opened!\n", tag); - return -ENODEV; -} - -/* free capture stream */ -int hda_dsp_stream_put_cstream(struct snd_sof_dev *sdev, int tag) -{ - struct hdac_bus *bus = sof_to_bus(sdev); - struct hdac_stream *s; - - /* find used capture stream */ - list_for_each_entry(s, &bus->stream_list, list) { - if (s->direction == SNDRV_PCM_STREAM_CAPTURE && - s->opened && s->stream_tag == tag) { - s->opened = false; - return 0; - } - } - - dev_dbg(sdev->dev, "tag %d not opened!\n", tag); - return -ENODEV; -} - int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream, int cmd) { diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c index a1c9f1b45dca14..3d36db3b1aa22e 100644 --- a/sound/soc/sof/intel/hda-trace.c +++ b/sound/soc/sof/intel/hda-trace.c @@ -52,7 +52,8 @@ static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev) int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *tag) { - sdev->hda->dtrace_stream = hda_dsp_stream_get_cstream(sdev); + sdev->hda->dtrace_stream = hda_dsp_stream_get(sdev, + SNDRV_PCM_STREAM_CAPTURE); if (!sdev->hda->dtrace_stream) { dev_err(sdev->dev, @@ -76,8 +77,9 @@ int hda_dsp_trace_release(struct snd_sof_dev *sdev) if (sdev->hda->dtrace_stream) { hstream = &sdev->hda->dtrace_stream->hstream; hstream->opened = false; - hda_dsp_stream_put_cstream(sdev, - hstream->stream_tag); + hda_dsp_stream_put(sdev, + SNDRV_PCM_STREAM_CAPTURE, + hstream->stream_tag); sdev->hda->dtrace_stream = NULL; return 0; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index c9c3e52508f00f..b4938816034060 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -453,13 +453,7 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, struct hdac_ext_stream * hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction); -struct hdac_ext_stream * - hda_dsp_stream_get_cstream(struct snd_sof_dev *sdev); -struct hdac_ext_stream * - hda_dsp_stream_get_pstream(struct snd_sof_dev *sdev); int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag); -int hda_dsp_stream_put_pstream(struct snd_sof_dev *sdev, int stream_tag); -int hda_dsp_stream_put_cstream(struct snd_sof_dev *sdev, int stream_tag); int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream, int enable, u32 size); From d8cd6e2c4529bb67ec92285f37d9e336fa3197c0 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Thu, 8 Nov 2018 18:58:52 +0800 Subject: [PATCH 0192/1995] ASoC: Intel: hdac_hdmi: add Icelake support Add Icelake device id. Also, Icelake's pin2port mapping table is complicated. So we use a mapping table to do the pin2port mapping. Signed-off-by: Bard liao --- sound/soc/codecs/hdac_hdmi.c | 63 ++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index e0fe682cea04a1..a129eea09aecdd 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -121,8 +121,16 @@ struct hdac_hdmi_dai_port_map { struct hdac_hdmi_cvt *cvt; }; +/* + * pin to port mapping table where the value indicate the pin number and + * the index indicate the port number with 1 base. + */ +static const int icl_pin2port_map[] = {0x4, 0x6, 0x8, 0xa, 0xb}; + struct hdac_hdmi_drv_data { unsigned int vendor_nid; + const int *port_map; /* pin to port mapping table */ + int port_num; }; struct hdac_hdmi_priv { @@ -1329,11 +1337,12 @@ static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid) return 0; } -#define INTEL_VENDOR_NID 0x08 -#define INTEL_GLK_VENDOR_NID 0x0b +#define INTEL_VENDOR_NID_0x2 0x02 +#define INTEL_VENDOR_NID_0x8 0x08 +#define INTEL_VENDOR_NID_0xb 0x0b #define INTEL_GET_VENDOR_VERB 0xf81 #define INTEL_SET_VENDOR_VERB 0x781 -#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ +#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ #define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdev) @@ -1538,7 +1547,26 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev, static int hdac_hdmi_pin2port(void *aptr, int pin) { - return pin - 4; /* map NID 0x05 -> port #1 */ + struct hdac_device *hdev = aptr; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); + const int *map = hdmi->drv_data->port_map; + int i; + + if (!hdmi->drv_data->port_num) + return pin - 4; /* map NID 0x05 -> port #1 */ + + /* + * looking for the pin number in the mapping table and return + * the index which indicate the port number + */ + for (i = 0; i < hdmi->drv_data->port_num; i++) { + if (pin == map[i]) + return i + 1; + } + + /* return -1 if pin number exceeds our expectation */ + dev_err(&hdev->dev, "Can't find the port for pin %d\n", pin); + return -1; } static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) @@ -1549,9 +1577,18 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) struct hdac_hdmi_port *hport = NULL; struct snd_soc_component *component = hdmi->component; int i; - - /* Don't know how this mapping is derived */ - hda_nid_t pin_nid = port + 0x04; + hda_nid_t pin_nid; + + if (!hdmi->drv_data->port_num) { + /* for legacy platforms */ + pin_nid = port + 0x04; + } else if (port < hdmi->drv_data->port_num) { + /* get pin number from the pin2port mapping table */ + pin_nid = hdmi->drv_data->port_map[port - 1]; + } else { + dev_err(&hdev->dev, "Can't find the pin for port %d\n", port); + return; + } dev_dbg(&hdev->dev, "%s: for pin:%d port=%d\n", __func__, pin_nid, pipe); @@ -1973,12 +2010,18 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx) return port->eld.info.spk_alloc; } +static struct hdac_hdmi_drv_data intel_icl_drv_data = { + .vendor_nid = INTEL_VENDOR_NID_0x2, + .port_map = icl_pin2port_map, + .port_num = ARRAY_SIZE(icl_pin2port_map), +}; + static struct hdac_hdmi_drv_data intel_glk_drv_data = { - .vendor_nid = INTEL_GLK_VENDOR_NID, + .vendor_nid = INTEL_VENDOR_NID_0xb, }; static struct hdac_hdmi_drv_data intel_drv_data = { - .vendor_nid = INTEL_VENDOR_NID, + .vendor_nid = INTEL_VENDOR_NID_0x8, }; static int hdac_hdmi_dev_probe(struct hdac_device *hdev) @@ -2260,6 +2303,8 @@ static const struct hda_device_id hdmi_list[] = { &intel_glk_drv_data), HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI", &intel_glk_drv_data), + HDA_CODEC_EXT_ENTRY(0x8086280f, 0x100000, "Icelake HDMI", + &intel_icl_drv_data), {} }; From 3277edc95b72047d6b026605814686556ca38773 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 31 Oct 2018 13:08:55 +0800 Subject: [PATCH 0193/1995] ASoC: SOF: remove workaround for HDA The correct sequence to initialize HDA is i915 should be initialized before hda bus Signed-off-by: Rander Wang --- sound/soc/sof/intel/hda.c | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 89fbb3321b55ec..e86332095c6467 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -386,12 +386,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) struct hdac_ext_link *hlink = NULL; int ret = 0; - /* The initialization process of HDA in SOF is: - * (1) init HDA to set up a context for i915 initialization - * then stop HDA bus. - */ - hda_dsp_ctrl_init_chip(sdev, true); - device_disable_async_suspend(bus->dev); /* check if dsp is there */ @@ -401,25 +395,15 @@ static int hda_init_caps(struct snd_sof_dev *sdev) if (bus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(bus); - snd_hdac_bus_stop_chip(bus); - - /* (2) probe i915 and HDA codecs, HDMI codecs */ + /* init i915 and HDMI codecs */ if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { ret = hda_codec_i915_init(sdev); - dev_dbg(&pci->dev, "no HDMI audio devices found\n"); + if (ret < 0) { + dev_err(&pci->dev, "no HDMI audio devices found\n"); + return ret; + } } - /* only HDA analog codec is detected in step (1) and - * codec_mask would be set. At step(3) HDMI codec can't - * be detected because HDA framework only check codecs - * when codec_mask is zero. So now set codec_mask to zero - * to force HDA framework to check codecs again. - */ - bus->codec_mask = 0; - - /* (3) init HDA again to make everything ready so that all - * the codecs can be detected. - */ ret = hda_dsp_ctrl_init_chip(sdev, true); if (ret < 0) { dev_err(bus->dev, "Init chip failed with ret: %d\n", ret); From 3dab44da239899abb841b90893085ae7774adf87 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Fri, 9 Nov 2018 14:27:58 +0800 Subject: [PATCH 0194/1995] ASoC:SOF:kbl add kbl dump function add kbl dump function, modify the registers base address of kbl,to get the FW status for debug info. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-loader-skl.c | 16 ++++----- sound/soc/sof/intel/hda.c | 50 ++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 7 +++- sound/soc/sof/intel/skl.c | 2 +- 4 files changed, 65 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 092bdd98e86960..cf6c6f6cf1b530 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -378,7 +378,7 @@ static int cl_dsp_init_skl(struct snd_sof_dev *sdev) /* polling the ROM init status information. */ ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_DSP_SRAM_REG_ROM_STATUS_SKL, + HDA_ADSP_FW_STATUS_SKL, HDA_DSP_ROM_STS_MASK, HDA_DSP_ROM_INIT, HDA_DSP_INIT_TIMEOUT); if (ret < 0) @@ -387,7 +387,7 @@ static int cl_dsp_init_skl(struct snd_sof_dev *sdev) return ret; err: - hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); + hda_dsp_dump_skl(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); cl_cleanup_skl(sdev); hda_dsp_core_reset_power_down(sdev, HDA_DSP_CORE_MASK(0)); return ret; @@ -428,9 +428,9 @@ static int cl_skl_cldma_wait_interruptible(struct snd_sof_dev *sdev) dev_err(sdev->dev, "cldma copy timeout\n"); dev_err(sdev->dev, "ROM code=0x%x: FW status=0x%x\n", snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_DSP_SRAM_REG_ROM_ERROR), + HDA_ADSP_ERROR_CODE_SKL), snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_DSP_SRAM_REG_ROM_STATUS)); + HDA_ADSP_FW_STATUS_SKL)); /* TODO: temp debug to be removed */ dev_err(sdev->dev, "ADSPCS=0x%x: ADSPIC=0x%x: ADSPIS=0x%x INTCTL=0x%x INTSTS=0x%x PPCTL=0x%x PPSTS=0x%x\n", @@ -526,7 +526,7 @@ static int cl_copy_fw_skl(struct snd_sof_dev *sdev) } ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_DSP_SRAM_REG_ROM_STATUS_SKL, + HDA_ADSP_FW_STATUS_SKL, HDA_DSP_ROM_STS_MASK, HDA_DSP_ROM_FW_FW_LOADED, HDA_DSP_BASEFW_TIMEOUT); @@ -551,9 +551,9 @@ int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "Error code=0x%x: FW status=0x%x\n", snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_DSP_SRAM_REG_ROM_ERROR), + HDA_ADSP_ERROR_CODE_SKL), snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_DSP_SRAM_REG_ROM_STATUS)); + HDA_ADSP_FW_STATUS_SKL)); dev_err(sdev->dev, "Core En/ROM load fail:%d\n", ret); goto irq_err; } @@ -579,7 +579,7 @@ int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev) return ret; irq_err: - hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); + hda_dsp_dump_skl(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); /* power down DSP */ hda_dsp_core_reset_power_down(sdev, HDA_DSP_CORE_MASK(0)); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index e86332095c6467..d7311f480635b3 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -140,6 +140,26 @@ static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = { {HDA_DSP_ROM_NULL_FW_ENTRY, "error: null FW entry point"}, }; +static void hda_dsp_get_status_skl(struct snd_sof_dev *sdev) +{ + u32 status; + int i; + + status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_ADSP_FW_STATUS_SKL); + + for (i = 0; i < ARRAY_SIZE(hda_dsp_rom_msg); i++) { + if (status == hda_dsp_rom_msg[i].code) { + dev_err(sdev->dev, "%s - code %8.8x\n", + hda_dsp_rom_msg[i].msg, status); + return; + } + } + + /* not for us, must be generic sof message */ + dev_dbg(sdev->dev, "unknown ROM status value %8.8x\n", status); +} + static void hda_dsp_get_status(struct snd_sof_dev *sdev) { u32 status; @@ -178,6 +198,36 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev, stack_words * sizeof(u32)); } +void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags) +{ + struct sof_ipc_dsp_oops_xtensa xoops; + struct sof_ipc_panic_info panic_info; + u32 stack[HDA_DSP_STACK_DUMP_SIZE]; + u32 status, panic; + + /* try APL specific status message types first */ + hda_dsp_get_status_skl(sdev); + + /* now try generic SOF status messages */ + status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_ADSP_ERROR_CODE_SKL); + + /*TODO: Check: there is no define in spec, but it is used in the code*/ + panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_ADSP_ERROR_CODE_SKL + 0x4); + + if (sdev->boot_complete) { + hda_dsp_get_registers(sdev, &xoops, &panic_info, stack, + HDA_DSP_STACK_DUMP_SIZE); + snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, + stack, HDA_DSP_STACK_DUMP_SIZE); + } else { + dev_err(sdev->dev, "error: status = 0x%8.8x panic = 0x%8.8x\n", + status, panic); + hda_dsp_get_status_skl(sdev); + } +} + void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) { struct sof_ipc_dsp_oops_xtensa xoops; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index b4938816034060..6d7ea621ed5147 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -321,7 +321,12 @@ #define SOF_SKL_NUM_DAIS 8 #endif -#define HDA_DSP_SRAM_REG_ROM_STATUS_SKL 0x8000 +/* Intel HD Audio SRAM Window 0*/ +#define HDA_ADSP_SRAM0_BASE_SKL 0x8000 + +/* Firmware status window */ +#define HDA_ADSP_FW_STATUS_SKL HDA_ADSP_SRAM0_BASE_SKL +#define HDA_ADSP_ERROR_CODE_SKL (HDA_ADSP_FW_STATUS_SKL + 0x4) struct sof_intel_dsp_bdl { u32 addr_l; diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 43b0bc169438fe..c51923d019bb69 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -74,7 +74,7 @@ struct snd_sof_dsp_ops sof_skl_ops = { /* debug */ .debug_map = skl_dsp_debugfs, .debug_map_count = ARRAY_SIZE(skl_dsp_debugfs), - .dbg_dump = hda_dsp_dump, + .dbg_dump = hda_dsp_dump_skl, /* stream callbacks */ .pcm_open = hda_dsp_pcm_open, From b0d2f97beeb0d2cb15102c817a2695f70a69ce05 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Fri, 9 Nov 2018 15:04:16 +0800 Subject: [PATCH 0195/1995] ASoC:SOF: kbl fix bug in hda_dsp_core_stall_reset fix base address bug, change HDA_DSP_HDA_BAR to HDA_DSP_BAR, remove hda_dsp_core_stall_reset_skl Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-dsp.c | 15 +-------------- sound/soc/sof/intel/hda.h | 3 +-- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index aeaa1af787dbae..265d34b2247e75 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -105,7 +105,7 @@ int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask) int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask) { /* stall core */ - snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_HDA_BAR, + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, HDA_DSP_ADSPCS_CSTALL_MASK(core_mask), HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)); @@ -210,19 +210,6 @@ bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, return is_enable; } -int hda_dsp_core_stall_reset_skl(struct snd_sof_dev *sdev, - unsigned int core_mask) -{ - /* stall core */ - snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, - HDA_DSP_REG_ADSPCS, - HDA_DSP_ADSPCS_CSTALL_MASK(core_mask), - HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)); - - /* set reset state */ - return hda_dsp_core_reset_enter(sdev, core_mask); -} - int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask) { int ret; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 6d7ea621ed5147..c759842eae99f0 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -390,8 +390,6 @@ int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask); int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask); -int hda_dsp_core_stall_reset_skl(struct snd_sof_dev *sdev, - unsigned int core_mask); int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask); int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask); int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask); @@ -404,6 +402,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state); int hda_dsp_resume(struct snd_sof_dev *sdev); int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state); int hda_dsp_runtime_resume(struct snd_sof_dev *sdev); +void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags); void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags); /* From 69ae10cde7d2aa6e6a12847bac598674a38d72e1 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Fri, 9 Nov 2018 18:10:14 +0800 Subject: [PATCH 0196/1995] ASoC: SOF: kbl using poll mode For the interrupt have not come out, using polling mode to get the firmware status, and remove interrupt wait condition. The firmware status is now 0x4 (manifest verified). Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-loader-skl.c | 66 ++++------------------------ 1 file changed, 9 insertions(+), 57 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index cf6c6f6cf1b530..40e2b776e63e19 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -397,70 +397,23 @@ static void cl_skl_cldma_fill_buffer(struct snd_sof_dev *sdev, unsigned int bufsize, unsigned int copysize, const void *curr_pos, - bool intr_enable) + bool intr_enable, bool trigger) { /* 1. copy the image into the buffer with the maximum buffer size. */ unsigned int size = (bufsize == copysize) ? bufsize : copysize; memcpy(sdev->dmab.area, curr_pos, size); - /* 2. Setting the wait condition for every load. */ - sdev->code_loading = 1; - - /* 3. Set the interrupt. */ + /* 2. Set the interrupt. */ if (intr_enable) cl_skl_cldma_set_intr(sdev, true); - /* 4. Set the SPB. */ - cl_skl_cldma_setup_spb(sdev, size, true); - - /* 5. Trigger the code loading stream. */ - cl_skl_cldma_stream_run(sdev, true); -} - -static int cl_skl_cldma_wait_interruptible(struct snd_sof_dev *sdev) -{ - int ret = 0; + /* 3. Set the SPB. */ + cl_skl_cldma_setup_spb(sdev, size, trigger); - if (!wait_event_timeout(sdev->waitq, - !sdev->code_loading, - msecs_to_jiffies(HDA_SKL_WAIT_TIMEOUT))) { - dev_err(sdev->dev, "cldma copy timeout\n"); - dev_err(sdev->dev, "ROM code=0x%x: FW status=0x%x\n", - snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_ADSP_ERROR_CODE_SKL), - snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_ADSP_FW_STATUS_SKL)); - - /* TODO: temp debug to be removed */ - dev_err(sdev->dev, "ADSPCS=0x%x: ADSPIC=0x%x: ADSPIS=0x%x INTCTL=0x%x INTSTS=0x%x PPCTL=0x%x PPSTS=0x%x\n", - snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_DSP_REG_ADSPCS), - snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_DSP_REG_ADSPIC), - snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_DSP_REG_ADSPIS), - snd_sof_dsp_read(sdev, HDA_DSP_BAR, - SOF_HDA_INTCTL), - snd_sof_dsp_read(sdev, HDA_DSP_BAR, - SOF_HDA_INTSTS), - snd_sof_dsp_read(sdev, HDA_DSP_PP_BAR, - SOF_HDA_REG_PP_PPCTL), - snd_sof_dsp_read(sdev, HDA_DSP_PP_BAR, - SOF_HDA_REG_PP_PPSTS)); - ret = -EIO; - goto cleanup; - } - - dev_dbg(sdev->dev, "cldma buffer copy complete\n"); - if (!sdev->code_loading) { - dev_err(sdev->dev, "error: cldma DMA copy failed\n"); - ret = -EIO; - } - -cleanup: - sdev->code_loading = 0; - return ret; + /* 4. Trigger the code loading stream. */ + if (trigger) + cl_skl_cldma_stream_run(sdev, true); } static int @@ -482,9 +435,8 @@ cl_skl_cldma_copy_to_buf(struct snd_sof_dev *sdev, const void *bin, bufsize); cl_skl_cldma_fill_buffer(sdev, bufsize, bufsize, - curr_pos, true); + curr_pos, true, true); - ret = cl_skl_cldma_wait_interruptible(sdev); if (ret < 0) { dev_err(sdev->dev, "error: fw failed to load. 0x%x bytes remaining\n", bytes_left); @@ -501,7 +453,7 @@ cl_skl_cldma_copy_to_buf(struct snd_sof_dev *sdev, const void *bin, cl_skl_cldma_set_intr(sdev, false); cl_skl_cldma_fill_buffer(sdev, bufsize, bytes_left, - curr_pos, false); + curr_pos, false, false); return 0; } } From 7ce1ad60ae5add4199f1a0e96d8428cc3ef0d9f1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 7 Nov 2018 13:28:07 -0600 Subject: [PATCH 0197/1995] ASoC: Intel: bxt_pcm512x: make HDMI optional Make sure we can test without the HDMI/HDAC dependencies Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bxt_pcm512x.c | 116 +++++++++++++++------------ 1 file changed, 63 insertions(+), 53 deletions(-) diff --git a/sound/soc/intel/boards/bxt_pcm512x.c b/sound/soc/intel/boards/bxt_pcm512x.c index 258dcfd34e8336..728a53876374ce 100644 --- a/sound/soc/intel/boards/bxt_pcm512x.c +++ b/sound/soc/intel/boards/bxt_pcm512x.c @@ -32,6 +32,7 @@ #include "../../codecs/pcm512x.h" #include "../atom/sst-atom-controls.h" +#ifdef CONFIG_SND_SOC_HDAC_HDMI static struct snd_soc_jack broxton_hdmi[3]; struct bxt_hdmi_pcm { @@ -40,6 +41,64 @@ struct bxt_hdmi_pcm { int device; }; +static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct bxt_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct bxt_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = dai->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +#define NAME_SIZE 32 +static int bxt_card_late_probe(struct snd_soc_card *card) +{ + struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card); + struct bxt_hdmi_pcm *pcm; + struct snd_soc_component *component = NULL; + int err, i = 0; + char jack_name[NAME_SIZE]; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &broxton_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &broxton_hdmi[i]); + if (err < 0) + return err; + + i++; + } + + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); +} +#else +static int bxt_card_late_probe(struct snd_soc_card *card) +{ + return 0; +} +#endif + struct bxt_card_private { struct list_head hdmi_pcm_list; }; @@ -114,24 +173,6 @@ static const struct snd_soc_ops aif1_ops = { .shutdown = aif1_shutdown, }; -static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct bxt_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = rtd->codec_dai; - struct bxt_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = dai->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - static struct snd_soc_dai_link dailink[] = { /* CODEC<->CODEC link */ /* back ends */ @@ -151,6 +192,7 @@ static struct snd_soc_dai_link dailink[] = { .dpcm_playback = 1, .dpcm_capture = 1, }, +#ifdef CONFIG_SND_SOC_HDAC_HDMI { .name = "iDisp1", .id = 1, @@ -184,42 +226,9 @@ static struct snd_soc_dai_link dailink[] = { .dpcm_playback = 1, .no_pcm = 1, }, - +#endif }; -#define NAME_SIZE 32 -static int bxt_card_late_probe(struct snd_soc_card *card) -{ - struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card); - struct bxt_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &broxton_hdmi[i], - NULL, 0); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &broxton_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} /* SoC card */ static struct snd_soc_card bxt_pcm512x_card = { @@ -250,7 +259,8 @@ static int bxt_pcm512x_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); mach = (&pdev->dev)->platform_data; card = &bxt_pcm512x_card; From 5d64330545c3398c7fd8ace707727939f138c6ca Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 7 Nov 2018 14:03:43 -0600 Subject: [PATCH 0198/1995] ASoC: SOF: core: unregister machine device on remove Make sure the machine driver goes through its .remove step. This enables load/unload module cases. Tested on Up2 with Hifiberry DAC+ (no HDA/HDMI to avoid HDAC contagion) Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index edd5ea3e505fa8..c528246c96e5b8 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -379,6 +379,10 @@ static int sof_probe(struct platform_device *pdev) static int sof_remove(struct platform_device *pdev) { struct snd_sof_dev *sdev = dev_get_drvdata(&pdev->dev); + struct snd_sof_pdata *pdata = sdev->pdata; + + if (pdata && !IS_ERR(pdata->pdev_mach)) + platform_device_unregister(pdata->pdev_mach); snd_soc_unregister_component(&pdev->dev); snd_sof_fw_unload(sdev); From 7078e5f036d5b87767f2f6df998f21bc7ff5e57b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 8 Nov 2018 14:51:13 -0600 Subject: [PATCH 0199/1995] ASoC: SOF: pci: don't unregister machine platform device The machine platform device is unregistered in the SOF core .remove. Doing this here creates problems with sysfs, likely due to a device hierarchy issue (only the parent should unregister the child?) Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-pci-dev.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 98f041247b3922..d3ecbc8b6bc46f 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -281,9 +281,6 @@ static void sof_pci_remove(struct pci_dev *pci) struct sof_platform_priv *priv = pci_get_drvdata(pci); struct snd_sof_pdata *sof_pdata = priv->sof_pdata; - /* unregister machine driver */ - platform_device_unregister(sof_pdata->pdev_mach); - /* unregister sof-audio platform driver */ if (!IS_ERR_OR_NULL(priv->pdev_pcm)) platform_device_unregister(priv->pdev_pcm); From 4c6bb2b6f60510900f39c2b40b40b245aa1fe540 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 8 Nov 2018 15:09:28 -0600 Subject: [PATCH 0200/1995] ASoC: SOF: pci: use IS_ERR to test platform device platform_device_register_data only returns an ERR_PTR Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-pci-dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index d3ecbc8b6bc46f..450de9d779a951 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -282,7 +282,7 @@ static void sof_pci_remove(struct pci_dev *pci) struct snd_sof_pdata *sof_pdata = priv->sof_pdata; /* unregister sof-audio platform driver */ - if (!IS_ERR_OR_NULL(priv->pdev_pcm)) + if (!IS_ERR(priv->pdev_pcm)) platform_device_unregister(priv->pdev_pcm); /* release firmware */ From 917422f578d21a92ab26ed299e2a082d20cd00ac Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 8 Nov 2018 14:59:55 -0600 Subject: [PATCH 0201/1995] ASoC: SOF: acpi: don't unregister machine platform device The machine platform device is unregistered in the SOF core .remove Also remove an error case handling which isn't possible. If the platform device creation fails then the machine platform device isn't created either. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-acpi-dev.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 7fe49c91c84fc2..1d5e4faea29858 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -258,7 +258,6 @@ static int sof_acpi_probe(struct platform_device *pdev) /* register sof-audio platform driver */ ret = sof_create_platform_device(priv); if (ret) { - platform_device_unregister(sof_pdata->pdev_mach); dev_err(dev, "error: failed to create platform device!\n"); return ret; } @@ -281,7 +280,6 @@ static int sof_acpi_remove(struct platform_device *pdev) struct sof_platform_priv *priv = dev_get_drvdata(&pdev->dev); struct snd_sof_pdata *sof_pdata = priv->sof_pdata; - platform_device_unregister(sof_pdata->pdev_mach); if (!IS_ERR_OR_NULL(priv->pdev_pcm)) platform_device_unregister(priv->pdev_pcm); release_firmware(sof_pdata->fw); From 4f44769e9f450ac73d08e378bb41e00d7573eccd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 8 Nov 2018 15:11:25 -0600 Subject: [PATCH 0202/1995] ASoC: SOF: acpi: use IS_ERR to test platform device platform_device_register_data only returns an ERR_PTR Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-acpi-dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 1d5e4faea29858..dc44c5c1146f88 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -280,7 +280,7 @@ static int sof_acpi_remove(struct platform_device *pdev) struct sof_platform_priv *priv = dev_get_drvdata(&pdev->dev); struct snd_sof_pdata *sof_pdata = priv->sof_pdata; - if (!IS_ERR_OR_NULL(priv->pdev_pcm)) + if (!IS_ERR(priv->pdev_pcm)) platform_device_unregister(priv->pdev_pcm); release_firmware(sof_pdata->fw); From 36cc4aeb72b279f9493daaa620feb40797671218 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 8 Nov 2018 15:03:33 -0600 Subject: [PATCH 0203/1995] ASoC: SOF: spi: don't unregister machine platform device The machine platform device is unregistered in the SOF core .remove Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-spi-dev.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index dc5867b7fa4a4e..3556bb35764f0a 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -152,7 +152,6 @@ static int sof_spi_remove(struct spi_device *spi) struct sof_platform_priv *priv = spi_get_drvdata(spi); struct snd_sof_pdata *sof_pdata = priv->sof_pdata; - platform_device_unregister(sof_pdata->pdev_mach); if (!IS_ERR_OR_NULL(priv->pdev_pcm)) platform_device_unregister(priv->pdev_pcm); release_firmware(sof_pdata->fw); From 9d8ecab0c48ff68e4f7679f191b5e53f020a31ec Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 8 Nov 2018 15:11:42 -0600 Subject: [PATCH 0204/1995] ASoC: SOF: spi: use IS_ERR to test platform device platform_device_register_data only returns an ERR_PTR Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-spi-dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index 3556bb35764f0a..4445a91a732683 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -152,7 +152,7 @@ static int sof_spi_remove(struct spi_device *spi) struct sof_platform_priv *priv = spi_get_drvdata(spi); struct snd_sof_pdata *sof_pdata = priv->sof_pdata; - if (!IS_ERR_OR_NULL(priv->pdev_pcm)) + if (!IS_ERR(priv->pdev_pcm)) platform_device_unregister(priv->pdev_pcm); release_firmware(sof_pdata->fw); From 0b79ceb0035977599bd3dd0e085b8ba41bf4fa9d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 8 Nov 2018 15:12:04 -0600 Subject: [PATCH 0205/1995] ASoC: SOF: intel: hda use IS_ERR to test platform device platform_device_register_data only returns an ERR_PTR Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index d7311f480635b3..e3e0ebe85a096c 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -722,7 +722,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) struct pci_dev *pci = sdev->pci; const struct sof_intel_dsp_desc *chip = sdev->hda->desc; - if (sdev->hda && (!IS_ERR_OR_NULL(sdev->hda->dmic_dev))) + if (sdev->hda && (!IS_ERR(sdev->hda->dmic_dev))) platform_device_unregister(sdev->hda->dmic_dev); /* disable DSP IRQ */ From 0face4aa3852b978ad07c7a33a425581919a5523 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 7 Nov 2018 16:51:33 -0600 Subject: [PATCH 0206/1995] ASoC: SOF: nocodec: fix card prefix The "sof-" prefix is added by the code, don't add it to the card name. This helps make sure the card is named "sof-nocodec" instead of "sof-sof-nocodec", e.g. root@ubilinux4:~# aplay -l **** List of PLAYBACK Hardware Devices **** card 0: sofnocodec [sof-nocodec], device 0: Port0 (*) [] Subdevices: 1/1 Subdevice #0: subdevice #0 Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/nocodec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index 3ec658f96b3d08..d3ea428ab8e262 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -23,7 +23,7 @@ #include "sof-priv.h" static struct snd_soc_card sof_nocodec_card = { - .name = "sof-nocodec", + .name = "nocodec", /* the sof- prefix is added by the core */ }; int sof_nocodec_setup(struct device *dev, From de5bcc2d3e5be54e2673e7c544af902b0295c879 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 6 Nov 2018 17:49:39 -0800 Subject: [PATCH 0207/1995] ASoC: SOF: move pci dev pm idle call to pci probe The patch does the following: 1. Move the runtime_put call for the pci dev to its probe routine 2. Use pm_runtime_put_noidle and pm_runtime_get_noresume in pci probe/remove Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 4 ---- sound/soc/sof/sof-pci-dev.c | 11 +++++++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index c528246c96e5b8..1935bd1f1ad38f 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -355,10 +355,6 @@ static int sof_probe(struct platform_device *pdev) pm_runtime_mark_last_busy(sdev->dev); pm_runtime_put_autosuspend(sdev->dev); - /* autosuspend pci/acpi/spi device */ - pm_runtime_mark_last_busy(plat_data->dev); - pm_runtime_put_autosuspend(plat_data->dev); - return 0; comp_err: diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 450de9d779a951..a652bc2f424896 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -259,8 +259,16 @@ static int sof_pci_probe(struct pci_dev *pci, /* allow runtime_pm */ pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY); pm_runtime_use_autosuspend(dev); + + /* + * runtime pm for pci device is "forbidden" by default. + * so call pm_runtime_allow() to enable it. + */ pm_runtime_allow(dev); + /* follow recommendation in pci-driver.c to decrement usage counter */ + pm_runtime_put_noidle(dev); + return ret; release_regions: @@ -288,6 +296,9 @@ static void sof_pci_remove(struct pci_dev *pci) /* release firmware */ release_firmware(sof_pdata->fw); + /* follow recommendation in pci-driver.c to increment usage counter */ + pm_runtime_get_noresume(&pci->dev); + /* release pci regions and disable device */ pci_release_regions(pci); pci_disable_device(pci); From eaa1599af79e62c2e46489d8c9e9e94689a901ff Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 6 Nov 2018 17:58:21 -0800 Subject: [PATCH 0208/1995] ASOC: SOF: hda: add/update PGCTL/CGCTL bits for clock gating and power gating Add CGCTL/PGCTL bits that will be used for enabling/disabling clock gating and power gating respectively. Also, LP SRAM retention mode is enabled/disabled by BIT(4) of PGCTL register. So, fix the error in its name from PCI_CGCTL_LSRMD_MASK to PCI_PGCTL_LSRMD_MASK. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dsp.c | 4 ++-- sound/soc/sof/intel/hda.h | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 265d34b2247e75..f9d128636c49c9 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -285,8 +285,8 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state) #endif /* disable LP retention mode */ - snd_sof_pci_update_bits(sdev, PCI_TCSEL, - PCI_CGCTL_LSRMD_MASK, PCI_CGCTL_LSRMD_MASK); + snd_sof_pci_update_bits(sdev, PCI_PGCTL, + PCI_PGCTL_LSRMD_MASK, PCI_PGCTL_LSRMD_MASK); return 0; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index c759842eae99f0..dae873180cec67 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -15,11 +15,16 @@ /* PCI registers */ #define PCI_TCSEL 0x44 +#define PCI_PGCTL PCI_TCSEL #define PCI_CGCTL 0x48 +/* PCI_PGCTL bits */ +#define PCI_PGCTL_ADSPPGD BIT(2) +#define PCI_PGCTL_LSRMD_MASK BIT(4) + /* PCI_CGCTL bits */ #define PCI_CGCTL_MISCBDCGE_MASK BIT(6) -#define PCI_CGCTL_LSRMD_MASK BIT(4) +#define PCI_CGCTL_ADSPDCGE BIT(1) /* Legacy HDA registers and bits used - widths are variable */ #define SOF_HDA_GCAP 0x0 From 5a2e4407959b9ca0de245fd49a7a4159446376ac Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 7 Nov 2018 20:29:09 -0800 Subject: [PATCH 0209/1995] ASoC: SOF: add pre/post fw run ops Add pre/post ops that will be called to perform actions before and after fw run routine. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/loader.c | 14 ++++++++++++++ sound/soc/sof/ops.h | 17 +++++++++++++++++ sound/soc/sof/sof-priv.h | 4 ++++ 3 files changed, 35 insertions(+) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 6828d9e9b1a0d1..3bbbd3c0e0398b 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -296,6 +296,13 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) } } + /* perform pre fw run operations */ + ret = snd_sof_dsp_pre_fw_run(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed pre fw run op\n"); + return ret; + } + dev_dbg(sdev->dev, "booting DSP firmware\n"); /* boot the firmware on the DSP */ @@ -317,6 +324,13 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) dev_info(sdev->dev, "firmware boot complete\n"); + /* perform post fw run operations */ + ret = snd_sof_dsp_post_fw_run(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed post fw run op\n"); + return ret; + } + return 0; } EXPORT_SYMBOL(snd_sof_run_firmware); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 5bd6e3921b5510..78bca5ad419f2d 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -61,6 +61,23 @@ static inline int snd_sof_dsp_reset(struct snd_sof_dev *sdev) return 0; } +/* pre/post fw load */ +static inline int snd_sof_dsp_pre_fw_run(struct snd_sof_dev *sdev) +{ + if (sdev->ops->pre_fw_run) + return sdev->ops->pre_fw_run(sdev); + else + return 0; +} + +static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev) +{ + if (sdev->ops->post_fw_run) + return sdev->ops->post_fw_run(sdev); + else + return 0; +} + /* power management */ static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 318762d1349fea..a4e6624d317088 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -78,6 +78,10 @@ struct snd_sof_dsp_ops { int (*stall)(struct snd_sof_dev *sof_dev); int (*reset)(struct snd_sof_dev *sof_dev); + /* pre/post firmware run */ + int (*pre_fw_run)(struct snd_sof_dev *sof_dev); + int (*post_fw_run)(struct snd_sof_dev *sof_dev); + /* DSP PM */ int (*suspend)(struct snd_sof_dev *sof_dev, int state); int (*resume)(struct snd_sof_dev *sof_dev); From 9e1dec61d71b045ec8993c966436c2482cde320f Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 7 Nov 2018 20:33:52 -0800 Subject: [PATCH 0210/1995] ASoC: SOF: define pre/post fw run ops for SKL+ This patch defines pre/post fw run ops for SKL+ platforms. Disable clock gating, power gating and L1 support in pre_fw_run. Re-enable these in post_fw_run. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/apl.c | 4 ++++ sound/soc/sof/intel/cnl.c | 4 ++++ sound/soc/sof/intel/hda-ctrl.c | 28 ++++++++++++++++++++++++++++ sound/soc/sof/intel/hda-loader.c | 14 ++++++++++++++ sound/soc/sof/intel/hda.h | 6 ++++++ sound/soc/sof/intel/skl.c | 4 ++++ 6 files changed, 60 insertions(+) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 82edc77eeac1f7..19e98726060548 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -89,6 +89,10 @@ struct snd_sof_dsp_ops sof_apl_ops = { /* firmware run */ .run = hda_dsp_cl_boot_firmware, + /* pre/post fw run */ + .pre_fw_run = hda_dsp_pre_fw_run, + .post_fw_run = hda_dsp_post_fw_run, + /* trace callback */ .trace_init = hda_dsp_trace_init, .trace_release = hda_dsp_trace_release, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 0fb531b08ea3af..e6f53afb1638c7 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -233,6 +233,10 @@ struct snd_sof_dsp_ops sof_cnl_ops = { /* firmware loading */ .load_firmware = hda_dsp_cl_load_fw, + /* pre/post fw run */ + .pre_fw_run = hda_dsp_pre_fw_run, + .post_fw_run = hda_dsp_post_fw_run, + /* firmware run */ .run = hda_dsp_cl_boot_firmware, diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 867bc3c4c7d3e9..7fe431277b9533 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "../sof-priv.h" #include "../ops.h" @@ -148,6 +149,33 @@ void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable) snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_MISCBDCGE_MASK, val); } +/* + * enable/disable audio dsp clock gating and power gating bits. + * This allows the HW to opportunistically power and clock gate + * the audio dsp when it is idle + */ +int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + u32 val; + + /* enable/disable audio dsp clock gating */ + val = enable ? PCI_CGCTL_ADSPDCGE : 0; + snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_ADSPDCGE, val); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* enable/disable L1 support */ + val = enable ? SOF_HDA_VS_EM2_L1SEN : 0; + snd_hdac_chip_updatel(bus, VS_EM2, SOF_HDA_VS_EM2_L1SEN, val); +#endif + + /* enable/disable audio dsp power gating */ + val = enable ? 0 : PCI_PGCTL_ADSPPGD; + snd_sof_pci_update_bits(sdev, PCI_PGCTL, PCI_PGCTL_ADSPPGD, val); + + return 0; +} + #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* * While performing reset, controller may not come back properly and causing diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 987632759d5358..5b2da821b5c245 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -372,3 +372,17 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) dev_err(sdev->dev, "error: load fw failed err: %d\n", ret); return ret; } + +/* pre fw run operations */ +int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev) +{ + /* disable clock gating and power gating */ + return hda_dsp_ctrl_clock_power_gating(sdev, false); +} + +/* post fw run operations */ +int hda_dsp_post_fw_run(struct snd_sof_dev *sdev) +{ + /* re-enable clock gating and power gating */ + return hda_dsp_ctrl_clock_power_gating(sdev, true); +} diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index dae873180cec67..7d60ec1d66985e 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -37,6 +37,7 @@ #define SOF_HDA_WAKESTS 0x0E #define SOF_HDA_WAKESTS_INT_MASK ((1 << 8) - 1) #define SOF_HDA_RIRBSTS 0x5d +#define SOF_HDA_VS_EM2_L1SEN BIT(13) /* SOF_HDA_GCTL register bist */ #define SOF_HDA_GCTL_RESET BIT(0) @@ -487,12 +488,17 @@ int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, bool first_boot); int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev); int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev); +/* pre and post fw run ops */ +int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev); +int hda_dsp_post_fw_run(struct snd_sof_dev *sdev); + /* * HDA Controller Operations. */ int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev); int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev); void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable); +int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable); int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset); /* diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index c51923d019bb69..f9c33b23c9abcb 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -85,6 +85,10 @@ struct snd_sof_dsp_ops sof_skl_ops = { /* firmware loading */ .load_firmware = hda_dsp_cl_load_fw, + /* pre/post fw run */ + .pre_fw_run = hda_dsp_pre_fw_run, + .post_fw_run = hda_dsp_post_fw_run, + /* firmware run */ .run = hda_dsp_cl_boot_firmware_skl, From ec905d8993f5c99dcf5e0d09bfb87773425520ea Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 6 Nov 2018 18:04:09 -0800 Subject: [PATCH 0211/1995] ASoC: SOF: reset HDA controller during suspend This patch does the following: 1. Reset HDA controller during suspend so that the PGD1 can be power gated. 2.Take controller out of reset during resume 3. This patch modifies the hda_dsp_ctrl_link_reset() method so it can be called to reset the controller during suspend. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-ctrl.c | 40 ++++++++++------------------------ sound/soc/sof/intel/hda-dsp.c | 24 ++++++++++++++++++++ sound/soc/sof/intel/hda.c | 9 +++++++- sound/soc/sof/intel/hda.h | 2 +- 4 files changed, 44 insertions(+), 31 deletions(-) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 7fe431277b9533..3414e50bf4fb7e 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -39,49 +39,31 @@ * HDA Operations. */ -int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev) +int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset) { unsigned long timeout; u32 gctl = 0; + u32 val; - /* reset the HDA controller */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL, - SOF_HDA_GCTL_RESET, 0); - - /* wait for reset */ - timeout = jiffies + msecs_to_jiffies(HDA_DSP_CTRL_RESET_TIMEOUT); - while (time_before(jiffies, timeout)) { - usleep_range(500, 1000); - gctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL); - if ((gctl & SOF_HDA_GCTL_RESET) == 0) - goto clear; - } - - /* reset failed */ - dev_err(sdev->dev, "error: failed to reset HDA controller gctl 0x%x\n", - gctl); - return -EIO; - -clear: - /* wait for codec */ - usleep_range(500, 1000); + /* 0 to enter reset and 1 to exit reset */ + val = reset ? 0 : SOF_HDA_GCTL_RESET; - /* now take controller out of reset */ + /* enter/exit HDA controller reset */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL, - SOF_HDA_GCTL_RESET, SOF_HDA_GCTL_RESET); + SOF_HDA_GCTL_RESET, val); - /* wait for controller to be ready */ + /* wait to enter/exit reset */ timeout = jiffies + msecs_to_jiffies(HDA_DSP_CTRL_RESET_TIMEOUT); while (time_before(jiffies, timeout)) { gctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL); - if ((gctl & SOF_HDA_GCTL_RESET) == 1) + if ((gctl & SOF_HDA_GCTL_RESET) == val) return 0; usleep_range(500, 1000); } - /* reset failed */ - dev_err(sdev->dev, "error: failed to ready HDA controller gctl 0x%x\n", - gctl); + /* enter/exit reset failed */ + dev_err(sdev->dev, "error: failed to %s HDA controller gctl 0x%x\n", + reset ? "reset" : "ready", gctl); return -EIO; } diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index f9d128636c49c9..8311c1bb455075 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -288,6 +288,14 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state) snd_sof_pci_update_bits(sdev, PCI_PGCTL, PCI_PGCTL_LSRMD_MASK, PCI_PGCTL_LSRMD_MASK); + /* reset controller */ + ret = hda_dsp_ctrl_link_reset(sdev, true); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to reset controller during suspend\n"); + return ret; + } + return 0; } @@ -326,6 +334,22 @@ static int hda_resume(struct snd_sof_dev *sdev) snd_hdac_ext_bus_ppcap_int_enable(bus, true); #endif + /* reset controller */ + ret = hda_dsp_ctrl_link_reset(sdev, true); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to reset controller during resume\n"); + return ret; + } + + /* take controller out of reset */ + ret = hda_dsp_ctrl_link_reset(sdev, false); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to ready controller during resume\n"); + return ret; + } + /* power up the DSP */ ret = hda_dsp_core_power_up(sdev, chip->cores_mask); if (ret < 0) { diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index e3e0ebe85a096c..5451ba0cfc72dc 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -651,12 +651,19 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) goto free_ipc_irq; /* reset HDA controller */ - ret = hda_dsp_ctrl_link_reset(sdev); + ret = hda_dsp_ctrl_link_reset(sdev, true); if (ret < 0) { dev_err(&pci->dev, "error: failed to reset HDA controller\n"); goto free_ipc_irq; } + /* exit HDA controller reset */ + ret = hda_dsp_ctrl_link_reset(sdev, false); + if (ret < 0) { + dev_err(&pci->dev, "error: failed to exit HDA controller reset\n"); + goto free_ipc_irq; + } + /* clear stream status */ list_for_each_entry(stream, &bus->stream_list, list) { sd_offset = SOF_STREAM_SD_OFFSET(stream); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 7d60ec1d66985e..cfe88ecd44778c 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -496,7 +496,7 @@ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev); * HDA Controller Operations. */ int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev); -int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev); +int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset); void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable); int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable); int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset); From 57a2bf7b2f3cb5e016f4984fcc00726c70d7cc36 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 8 Nov 2018 12:42:18 -0800 Subject: [PATCH 0212/1995] ASoC: SOF: remove duplicate runtime autosuspend call for sof device Runtime PM for sof device in enabled in pcm_probe() after the topology load has completed. So autosuspend should be called after pm_runtime_enable() here. Remove the call to autosuspend() in sof_probe as this should be done after topology load has been completed. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 4 ---- sound/soc/sof/pcm.c | 4 +++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 1935bd1f1ad38f..fa8ea61d3fe296 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -351,10 +351,6 @@ static int sof_probe(struct platform_device *pdev) dev_dbg(sdev->dev, "created machine %s\n", dev_name(&plat_data->pdev_mach->dev)); - /* autosuspend sof device */ - pm_runtime_mark_last_busy(sdev->dev); - pm_runtime_put_autosuspend(sdev->dev); - return 0; comp_err: diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index f2e256d129bf50..f873c9bffac6b1 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -712,7 +712,9 @@ static int sof_pcm_probe(struct snd_soc_component *component) SND_SOF_SUSPEND_DELAY); pm_runtime_use_autosuspend(component->dev); pm_runtime_enable(component->dev); - err = pm_runtime_idle(component->dev); + + pm_runtime_mark_last_busy(component->dev); + err = pm_runtime_put_autosuspend(component->dev); if (err < 0) dev_err(sdev->dev, "error: failed to enter PM idle %d\n", err); From 48435ad4cd29941d373afbe5f774b761c98f4323 Mon Sep 17 00:00:00 2001 From: Ricardo Biehl Pasquali Date: Sat, 25 Aug 2018 16:53:23 -0300 Subject: [PATCH 0213/1995] ALSA: pcm: Return 0 when size < start_threshold in capture In __snd_pcm_lib_xfer(), when capture, if state is PREPARED and size is less than start_threshold nothing can be done. As there is no error, 0 is returned. Signed-off-by: Ricardo Biehl Pasquali Signed-off-by: Takashi Iwai (cherry picked from commit 62ba568f7aef4beb0eda945a2b2a91b7a2b8f215) --- sound/core/pcm_lib.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 4e6110d778bd25..7f71c2449af5ec 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2173,11 +2173,16 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, goto _end_unlock; if (!is_playback && - runtime->status->state == SNDRV_PCM_STATE_PREPARED && - size >= runtime->start_threshold) { - err = snd_pcm_start(substream); - if (err < 0) + runtime->status->state == SNDRV_PCM_STATE_PREPARED) { + if (size >= runtime->start_threshold) { + err = snd_pcm_start(substream); + if (err < 0) + goto _end_unlock; + } else { + /* nothing to do */ + err = 0; goto _end_unlock; + } } runtime->twake = runtime->control->avail_min ? : 1; From 69b2311a93f247f519b725d3dc79e4b69eb1ff90 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Aug 2018 16:56:46 +0200 Subject: [PATCH 0214/1995] ALSA: memalloc: Don't align the size to power-of-two The size passed to dma_alloc_coherent() doesn't have to be aligned with power-of-two, rather it should be the raw size. As a minor optimization, remove the size adjustment in the current code. Signed-off-by: Takashi Iwai (cherry picked from commit 03486830c577d3fe49c1f2c316414552a549ff00) --- sound/core/memalloc.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 753d5fc4b284fa..d85df01bf0551e 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -84,29 +84,24 @@ EXPORT_SYMBOL(snd_free_pages); /* allocate the coherent DMA pages */ static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma) { - int pg; gfp_t gfp_flags; if (WARN_ON(!dma)) return NULL; - pg = get_order(size); gfp_flags = GFP_KERNEL | __GFP_COMP /* compound page lets parts be mapped */ | __GFP_NORETRY /* don't trigger OOM-killer */ | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ - return dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags); + return dma_alloc_coherent(dev, size, dma, gfp_flags); } /* free the coherent DMA pages */ static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, dma_addr_t dma) { - int pg; - if (ptr == NULL) return; - pg = get_order(size); - dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma); + dma_free_coherent(dev, size, ptr, dma); } #ifdef CONFIG_GENERIC_ALLOCATOR From 88093bef0e111bb118b1b62299bb98e0e383a2ee Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 10 Aug 2018 14:43:37 +0200 Subject: [PATCH 0215/1995] ALSA: memalloc: Simplify snd_malloc_dev_pages() calls snd_malloc_dev_pages() and snd_free_dev_pages() are local functions and the parameters passed there are all contained in snd_dma_buffer object. As a code-simplification, pass snd_dma_buffer object and assign the address there like other allocators do (except for snd_malloc_pages() which is called from outside, hence we can't change easily). Only code refactoring, no functional changes. Signed-off-by: Takashi Iwai (cherry picked from commit 28f3f4f685d7d7226ba4ed4f78e04c75dd3a5b27) --- sound/core/memalloc.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index d85df01bf0551e..cc051bfe2f6fa7 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -82,26 +82,22 @@ EXPORT_SYMBOL(snd_free_pages); #ifdef CONFIG_HAS_DMA /* allocate the coherent DMA pages */ -static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma) +static void snd_malloc_dev_pages(struct snd_dma_buffer *dmab, size_t size) { gfp_t gfp_flags; - if (WARN_ON(!dma)) - return NULL; gfp_flags = GFP_KERNEL | __GFP_COMP /* compound page lets parts be mapped */ | __GFP_NORETRY /* don't trigger OOM-killer */ | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ - return dma_alloc_coherent(dev, size, dma, gfp_flags); + dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr, + gfp_flags); } /* free the coherent DMA pages */ -static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, - dma_addr_t dma) +static void snd_free_dev_pages(struct snd_dma_buffer *dmab) { - if (ptr == NULL) - return; - dma_free_coherent(dev, size, ptr, dma); + dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); } #ifdef CONFIG_GENERIC_ALLOCATOR @@ -195,7 +191,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, dmab->dev.type = SNDRV_DMA_TYPE_DEV; #endif /* CONFIG_GENERIC_ALLOCATOR */ case SNDRV_DMA_TYPE_DEV: - dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr); + snd_malloc_dev_pages(dmab, size); break; #endif #ifdef CONFIG_SND_DMA_SGBUF @@ -270,7 +266,7 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) break; #endif /* CONFIG_GENERIC_ALLOCATOR */ case SNDRV_DMA_TYPE_DEV: - snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); + snd_free_dev_pages(dmab); break; #endif #ifdef CONFIG_SND_DMA_SGBUF From 04f39c7b85a43e8b067e00fd5acb180822b8aed0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 Aug 2018 17:01:00 +0200 Subject: [PATCH 0216/1995] ALSA: memalloc: Add non-cached buffer type In some cases (mainly for x86), we need the DMA coherent buffer with non-cached pages. Although this has been done in each driver side like HD-audio and intel8x0, it can be done cleaner in the core memory allocator. This patch adds the new types, SNDRV_DMA_TYPE_DEV_UC and SNDRV_DMA_TYPE_DEV_UC_SG, for allocating such non-cached buffer pages. On non-x86 architectures, they work as same as the standard SNDRV_DMA_TYPE_DEV and *_SG. One additional change by this move is that we can assure to pass the non-cached pgprot to the vmapped buffer, too. It eventually fixes the case like non-snoop mode without mmap access on HD-audio. Signed-off-by: Takashi Iwai (cherry picked from commit 42e748a0b3251cca0de2c269ca106884907eb289) --- include/sound/memalloc.h | 3 +++ sound/core/memalloc.c | 17 +++++++++++++++++ sound/core/sgbuf.c | 15 +++++++++++++-- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h index 67561b99791508..af3fa577fa066a 100644 --- a/include/sound/memalloc.h +++ b/include/sound/memalloc.h @@ -47,10 +47,13 @@ struct snd_dma_device { #define SNDRV_DMA_TYPE_UNKNOWN 0 /* not defined */ #define SNDRV_DMA_TYPE_CONTINUOUS 1 /* continuous no-DMA memory */ #define SNDRV_DMA_TYPE_DEV 2 /* generic device continuous */ +#define SNDRV_DMA_TYPE_DEV_UC 5 /* continuous non-cahced */ #ifdef CONFIG_SND_DMA_SGBUF #define SNDRV_DMA_TYPE_DEV_SG 3 /* generic device SG-buffer */ +#define SNDRV_DMA_TYPE_DEV_UC_SG 6 /* SG non-cached */ #else #define SNDRV_DMA_TYPE_DEV_SG SNDRV_DMA_TYPE_DEV /* no SG-buf support */ +#define SNDRV_DMA_TYPE_DEV_UC_SG SNDRV_DMA_TYPE_DEV_UC #endif #ifdef CONFIG_GENERIC_ALLOCATOR #define SNDRV_DMA_TYPE_DEV_IRAM 4 /* generic device iram-buffer */ diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index cc051bfe2f6fa7..aa266907ec9ba9 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -25,6 +25,9 @@ #include #include #include +#ifdef CONFIG_X86 +#include +#endif #include /* @@ -92,11 +95,21 @@ static void snd_malloc_dev_pages(struct snd_dma_buffer *dmab, size_t size) | __GFP_NOWARN; /* no stack trace print - this call is non-critical */ dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr, gfp_flags); +#ifdef CONFIG_X86 + if (dmab->area && dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC) + set_memory_wc((unsigned long)dmab->area, + PAGE_ALIGN(size) >> PAGE_SHIFT); +#endif } /* free the coherent DMA pages */ static void snd_free_dev_pages(struct snd_dma_buffer *dmab) { +#ifdef CONFIG_X86 + if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC) + set_memory_wb((unsigned long)dmab->area, + PAGE_ALIGN(dmab->bytes) >> PAGE_SHIFT); +#endif dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); } @@ -191,11 +204,13 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, dmab->dev.type = SNDRV_DMA_TYPE_DEV; #endif /* CONFIG_GENERIC_ALLOCATOR */ case SNDRV_DMA_TYPE_DEV: + case SNDRV_DMA_TYPE_DEV_UC: snd_malloc_dev_pages(dmab, size); break; #endif #ifdef CONFIG_SND_DMA_SGBUF case SNDRV_DMA_TYPE_DEV_SG: + case SNDRV_DMA_TYPE_DEV_UC_SG: snd_malloc_sgbuf_pages(device, size, dmab, NULL); break; #endif @@ -266,11 +281,13 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab) break; #endif /* CONFIG_GENERIC_ALLOCATOR */ case SNDRV_DMA_TYPE_DEV: + case SNDRV_DMA_TYPE_DEV_UC: snd_free_dev_pages(dmab); break; #endif #ifdef CONFIG_SND_DMA_SGBUF case SNDRV_DMA_TYPE_DEV_SG: + case SNDRV_DMA_TYPE_DEV_UC_SG: snd_free_sgbuf_pages(dmab); break; #endif diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c index 84fffabdd129de..c1cfaa01a5cb81 100644 --- a/sound/core/sgbuf.c +++ b/sound/core/sgbuf.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -43,6 +44,8 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab) dmab->area = NULL; tmpb.dev.type = SNDRV_DMA_TYPE_DEV; + if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG) + tmpb.dev.type = SNDRV_DMA_TYPE_DEV_UC; tmpb.dev.dev = sgbuf->dev; for (i = 0; i < sgbuf->pages; i++) { if (!(sgbuf->table[i].addr & ~PAGE_MASK)) @@ -72,12 +75,20 @@ void *snd_malloc_sgbuf_pages(struct device *device, struct snd_dma_buffer tmpb; struct snd_sg_page *table; struct page **pgtable; + int type = SNDRV_DMA_TYPE_DEV; + pgprot_t prot = PAGE_KERNEL; dmab->area = NULL; dmab->addr = 0; dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL); if (! sgbuf) return NULL; + if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG) { + type = SNDRV_DMA_TYPE_DEV_UC; +#ifdef pgprot_noncached + prot = pgprot_noncached(PAGE_KERNEL); +#endif + } sgbuf->dev = device; pages = snd_sgbuf_aligned_pages(size); sgbuf->tblsize = sgbuf_align_table(pages); @@ -98,7 +109,7 @@ void *snd_malloc_sgbuf_pages(struct device *device, if (chunk > maxpages) chunk = maxpages; chunk <<= PAGE_SHIFT; - if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, device, + if (snd_dma_alloc_pages_fallback(type, device, chunk, &tmpb) < 0) { if (!sgbuf->pages) goto _failed; @@ -125,7 +136,7 @@ void *snd_malloc_sgbuf_pages(struct device *device, } sgbuf->size = size; - dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, PAGE_KERNEL); + dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, prot); if (! dmab->area) goto _failed; if (res_size) From 36b4ebe9911a36c011f6a59c4a3df20fb3b48200 Mon Sep 17 00:00:00 2001 From: David Frey Date: Sat, 1 Sep 2018 09:50:41 -0700 Subject: [PATCH 0217/1995] regmap: split up regmap_config.use_single_rw Split regmap_config.use_single_rw into use_single_read and use_single_write. This change enables drivers of devices which only support bulk operations in one direction to use the regmap_bulk_*() functions for both directions and have their bulk operation split into single operations only when necessary. Update all struct regmap_config instances where use_single_rw==true to instead set both use_single_read and use_single_write. No attempt was made to evaluate whether it is possible to set only one of use_single_read or use_single_write. Signed-off-by: David Frey Signed-off-by: Mark Brown (cherry picked from commit 1c96a2f67cd9b617b013f0a7580d76aae7dcd0d7) --- drivers/base/regmap/regmap.c | 4 ++-- drivers/edac/altera_edac.c | 3 ++- drivers/hwmon/lm75.c | 3 ++- drivers/hwmon/lm95245.c | 3 ++- drivers/hwmon/tmp102.c | 3 ++- drivers/hwmon/tmp108.c | 3 ++- drivers/iio/light/apds9960.c | 3 ++- drivers/iio/light/max44000.c | 23 ++++++++++++----------- drivers/iio/temperature/mlx90632.c | 3 ++- drivers/input/touchscreen/tsc200x-core.c | 3 ++- drivers/mfd/altera-a10sr.c | 3 ++- drivers/mfd/da9052-spi.c | 3 ++- drivers/mfd/mc13xxx-spi.c | 3 ++- drivers/mfd/twl6040.c | 3 ++- drivers/regulator/ltc3589.c | 3 ++- drivers/regulator/ltc3676.c | 3 ++- include/linux/regmap.h | 12 ++++++++---- sound/hda/hdac_regmap.c | 3 ++- sound/soc/codecs/cs35l33.c | 3 ++- sound/soc/codecs/cs35l35.c | 3 ++- sound/soc/codecs/cs43130.c | 4 +++- sound/soc/codecs/es8328.c | 3 ++- sound/soc/codecs/rt1305.c | 3 ++- sound/soc/codecs/rt5514.c | 3 ++- sound/soc/codecs/rt5616.c | 3 ++- sound/soc/codecs/rt5640.c | 3 ++- sound/soc/codecs/rt5645.c | 9 ++++++--- sound/soc/codecs/rt5651.c | 3 ++- sound/soc/codecs/rt5660.c | 3 ++- sound/soc/codecs/rt5663.c | 9 ++++++--- sound/soc/codecs/rt5665.c | 3 ++- sound/soc/codecs/rt5668.c | 3 ++- sound/soc/codecs/rt5670.c | 3 ++- sound/soc/codecs/rt5682.c | 3 ++- 34 files changed, 93 insertions(+), 52 deletions(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 0360a90ad6b623..78a778c08f9221 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -762,8 +762,8 @@ struct regmap *__regmap_init(struct device *dev, map->reg_stride_order = ilog2(map->reg_stride); else map->reg_stride_order = -1; - map->use_single_read = config->use_single_rw || !bus || !bus->read; - map->use_single_write = config->use_single_rw || !bus || !bus->write; + map->use_single_read = config->use_single_read || !bus || !bus->read; + map->use_single_write = config->use_single_write || !bus || !bus->write; map->can_multi_write = config->can_multi_write && bus && bus->write; if (bus) { map->max_raw_read = bus->max_raw_read; diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 5762c3c383f2ee..ab7c5a937ab00b 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -599,7 +599,8 @@ static const struct regmap_config s10_sdram_regmap_cfg = { .volatile_reg = s10_sdram_volatile_reg, .reg_read = s10_protected_reg_read, .reg_write = s10_protected_reg_write, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static int altr_s10_sdram_probe(struct platform_device *pdev) diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 49f4b33a5685a8..542dc4058831f6 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -254,7 +254,8 @@ static const struct regmap_config lm75_regmap_config = { .volatile_reg = lm75_is_volatile_reg, .val_format_endian = REGMAP_ENDIAN_BIG, .cache_type = REGCACHE_RBTREE, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static void lm75_remove(void *data) diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c index 27cb06d6559468..996b502461754b 100644 --- a/drivers/hwmon/lm95245.c +++ b/drivers/hwmon/lm95245.c @@ -541,7 +541,8 @@ static const struct regmap_config lm95245_regmap_config = { .writeable_reg = lm95245_is_writeable_reg, .volatile_reg = lm95245_is_volatile_reg, .cache_type = REGCACHE_RBTREE, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static const u32 lm95245_chip_config[] = { diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index dfc40c740d07b7..6778283e36f9ae 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -212,7 +212,8 @@ static const struct regmap_config tmp102_regmap_config = { .volatile_reg = tmp102_is_volatile_reg, .val_format_endian = REGMAP_ENDIAN_BIG, .cache_type = REGCACHE_RBTREE, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static int tmp102_probe(struct i2c_client *client, diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c index 91bb946392869e..429bfeae4ca835 100644 --- a/drivers/hwmon/tmp108.c +++ b/drivers/hwmon/tmp108.c @@ -345,7 +345,8 @@ static const struct regmap_config tmp108_regmap_config = { .volatile_reg = tmp108_is_volatile_reg, .val_format_endian = REGMAP_ENDIAN_BIG, .cache_type = REGCACHE_RBTREE, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static int tmp108_probe(struct i2c_client *client, diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index 1f112ae15f3c37..b09b8b60bd83b6 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -206,7 +206,8 @@ static const struct regmap_config apds9960_regmap_config = { .name = APDS9960_REGMAP_NAME, .reg_bits = 8, .val_bits = 8, - .use_single_rw = 1, + .use_single_read = true, + .use_single_write = true, .volatile_table = &apds9960_volatile_table, .precious_table = &apds9960_precious_table, diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c index bcdb0eb9e5371f..4067dff2ff6aca 100644 --- a/drivers/iio/light/max44000.c +++ b/drivers/iio/light/max44000.c @@ -473,17 +473,18 @@ static bool max44000_precious_reg(struct device *dev, unsigned int reg) } static const struct regmap_config max44000_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = MAX44000_REG_PRX_DATA, - .readable_reg = max44000_readable_reg, - .writeable_reg = max44000_writeable_reg, - .volatile_reg = max44000_volatile_reg, - .precious_reg = max44000_precious_reg, - - .use_single_rw = 1, - .cache_type = REGCACHE_RBTREE, + .reg_bits = 8, + .val_bits = 8, + + .max_register = MAX44000_REG_PRX_DATA, + .readable_reg = max44000_readable_reg, + .writeable_reg = max44000_writeable_reg, + .volatile_reg = max44000_volatile_reg, + .precious_reg = max44000_precious_reg, + + .use_single_read = true, + .use_single_write = true, + .cache_type = REGCACHE_RBTREE, }; static irqreturn_t max44000_trigger_handler(int irq, void *p) diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c index 9851311aa3fdc9..be03be719efe4e 100644 --- a/drivers/iio/temperature/mlx90632.c +++ b/drivers/iio/temperature/mlx90632.c @@ -140,7 +140,8 @@ static const struct regmap_config mlx90632_regmap = { .rd_table = &mlx90632_readable_regs_tbl, .wr_table = &mlx90632_writeable_regs_tbl, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .reg_format_endian = REGMAP_ENDIAN_BIG, .val_format_endian = REGMAP_ENDIAN_BIG, .cache_type = REGCACHE_RBTREE, diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c index e0fde590df8e5f..62973ac0138154 100644 --- a/drivers/input/touchscreen/tsc200x-core.c +++ b/drivers/input/touchscreen/tsc200x-core.c @@ -68,7 +68,8 @@ const struct regmap_config tsc200x_regmap_config = { .read_flag_mask = TSC200X_REG_READ, .write_flag_mask = TSC200X_REG_PND0, .wr_table = &tsc200x_writable_table, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; EXPORT_SYMBOL_GPL(tsc200x_regmap_config); diff --git a/drivers/mfd/altera-a10sr.c b/drivers/mfd/altera-a10sr.c index 96e7d2cb7b8982..400e0b51844b7a 100644 --- a/drivers/mfd/altera-a10sr.c +++ b/drivers/mfd/altera-a10sr.c @@ -108,7 +108,8 @@ static const struct regmap_config altr_a10sr_regmap_config = { .cache_type = REGCACHE_NONE, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .read_flag_mask = 1, .write_flag_mask = 0, diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c index abfb11818fdc5c..fdae1288bc6d9a 100644 --- a/drivers/mfd/da9052-spi.c +++ b/drivers/mfd/da9052-spi.c @@ -46,7 +46,8 @@ static int da9052_spi_probe(struct spi_device *spi) config.reg_bits = 7; config.pad_bits = 1; config.val_bits = 8; - config.use_single_rw = 1; + config.use_single_read = true; + config.use_single_write = true; da9052->regmap = devm_regmap_init_spi(spi, &config); if (IS_ERR(da9052->regmap)) { diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c index cbc1e5ed599c09..ee3411cc5ce410 100644 --- a/drivers/mfd/mc13xxx-spi.c +++ b/drivers/mfd/mc13xxx-spi.c @@ -57,7 +57,8 @@ static const struct regmap_config mc13xxx_regmap_spi_config = { .max_register = MC13XXX_NUMREGS, .cache_type = REGCACHE_NONE, - .use_single_rw = 1, + .use_single_read = true, + .use_single_write = true, }; static int mc13xxx_spi_read(void *context, const void *reg, size_t reg_size, diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index dd19f17a1b6375..7c3c5fd5fcd047 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -613,7 +613,8 @@ static const struct regmap_config twl6040_regmap_config = { .writeable_reg = twl6040_writeable_reg, .cache_type = REGCACHE_RBTREE, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static const struct regmap_irq twl6040_irqs[] = { diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c index 18d5b01ddcb20d..63f724f260ef76 100644 --- a/drivers/regulator/ltc3589.c +++ b/drivers/regulator/ltc3589.c @@ -404,7 +404,8 @@ static const struct regmap_config ltc3589_regmap_config = { .max_register = LTC3589_L2DTV2, .reg_defaults = ltc3589_reg_defaults, .num_reg_defaults = ARRAY_SIZE(ltc3589_reg_defaults), - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .cache_type = REGCACHE_RBTREE, }; diff --git a/drivers/regulator/ltc3676.c b/drivers/regulator/ltc3676.c index 9dec1609ff666c..71fd0f2a4b76e6 100644 --- a/drivers/regulator/ltc3676.c +++ b/drivers/regulator/ltc3676.c @@ -321,7 +321,8 @@ static const struct regmap_config ltc3676_regmap_config = { .readable_reg = ltc3676_readable_reg, .volatile_reg = ltc3676_volatile_reg, .max_register = LTC3676_CLIRQ, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .cache_type = REGCACHE_RBTREE, }; diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 379505a53722fd..6ea9bf9377cb01 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -315,9 +315,12 @@ typedef void (*regmap_unlock)(void *); * masks are used. * @zero_flag_mask: If set, read_flag_mask and write_flag_mask are used even * if they are both empty. - * @use_single_rw: If set, converts the bulk read and write operations into - * a series of single read and write operations. This is useful - * for device that does not support bulk read and write. + * @use_single_read: If set, converts the bulk read operation into a series of + * single read operations. This is useful for a device that + * does not support bulk read. + * @use_single_write: If set, converts the bulk write operation into a series of + * single write operations. This is useful for a device that + * does not support bulk write. * @can_multi_write: If set, the device supports the multi write mode of bulk * write operations, if clear multi write requests will be * split into individual write operations @@ -380,7 +383,8 @@ struct regmap_config { unsigned long write_flag_mask; bool zero_flag_mask; - bool use_single_rw; + bool use_single_read; + bool use_single_write; bool can_multi_write; enum regmap_endian reg_format_endian; diff --git a/sound/hda/hdac_regmap.c b/sound/hda/hdac_regmap.c index 419e285e0226d6..996dbc8502244a 100644 --- a/sound/hda/hdac_regmap.c +++ b/sound/hda/hdac_regmap.c @@ -359,7 +359,8 @@ static const struct regmap_config hda_regmap_cfg = { .cache_type = REGCACHE_RBTREE, .reg_read = hda_reg_read, .reg_write = hda_reg_write, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; /** diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c index 668cd3754209d9..e9b7f72d880b9e 100644 --- a/sound/soc/codecs/cs35l33.c +++ b/sound/soc/codecs/cs35l33.c @@ -857,7 +857,8 @@ static const struct regmap_config cs35l33_regmap = { .readable_reg = cs35l33_readable_register, .writeable_reg = cs35l33_writeable_register, .cache_type = REGCACHE_RBTREE, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static int __maybe_unused cs35l33_runtime_resume(struct device *dev) diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index bd6226bde45f67..9f4a59871cee72 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -1105,7 +1105,8 @@ static struct regmap_config cs35l35_regmap = { .readable_reg = cs35l35_readable_register, .precious_reg = cs35l35_precious_register, .cache_type = REGCACHE_RBTREE, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static irqreturn_t cs35l35_irq(int irq, void *data) diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index 80dc4219715482..3f7b255587e6aa 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -2362,7 +2362,9 @@ static const struct regmap_config cs43130_regmap = { .precious_reg = cs43130_precious_register, .volatile_reg = cs43130_volatile_register, .cache_type = REGCACHE_RBTREE, - .use_single_rw = true, /* needed for regcache_sync */ + /* needed for regcache_sync */ + .use_single_read = true, + .use_single_write = true, }; static u16 const cs43130_dc_threshold[CS43130_DC_THRESHOLD] = { diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index e9fc2fd97d2f4f..4b5827dc23aac3 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -824,7 +824,8 @@ const struct regmap_config es8328_regmap_config = { .val_bits = 8, .max_register = ES8328_REG_MAX, .cache_type = REGCACHE_RBTREE, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; EXPORT_SYMBOL_GPL(es8328_regmap_config); diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c index c4452efc79700a..c2c8a68cec97e0 100644 --- a/sound/soc/codecs/rt1305.c +++ b/sound/soc/codecs/rt1305.c @@ -963,7 +963,8 @@ static const struct regmap_config rt1305_regmap = { .num_reg_defaults = ARRAY_SIZE(rt1305_reg), .ranges = rt1305_ranges, .num_ranges = ARRAY_SIZE(rt1305_ranges), - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; #if defined(CONFIG_OF) diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 32fe76c3134ab4..a67de68b6da6c6 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -1201,7 +1201,8 @@ static const struct regmap_config rt5514_regmap = { .cache_type = REGCACHE_RBTREE, .reg_defaults = rt5514_reg, .num_reg_defaults = ARRAY_SIZE(rt5514_reg), - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static const struct i2c_device_id rt5514_i2c_id[] = { diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index 3dc795f444ce9b..36a9f1c56c8ddd 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -1313,7 +1313,8 @@ static const struct snd_soc_component_driver soc_component_dev_rt5616 = { static const struct regmap_config rt5616_regmap = { .reg_bits = 8, .val_bits = 16, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .max_register = RT5616_DEVICE_ID + 1 + (ARRAY_SIZE(rt5616_ranges) * RT5616_PR_SPACING), .volatile_reg = rt5616_volatile_register, diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 27770143ae8f22..fc530481a6e476 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2704,7 +2704,8 @@ static const struct snd_soc_component_driver soc_component_dev_rt5640 = { static const struct regmap_config rt5640_regmap = { .reg_bits = 8, .val_bits = 16, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .max_register = RT5640_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5640_ranges) * RT5640_PR_SPACING), diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 1dc70f452c1b95..be674688dc4061 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3559,7 +3559,8 @@ static const struct snd_soc_component_driver soc_component_dev_rt5645 = { static const struct regmap_config rt5645_regmap = { .reg_bits = 8, .val_bits = 16, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .max_register = RT5645_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5645_ranges) * RT5645_PR_SPACING), .volatile_reg = rt5645_volatile_register, @@ -3575,7 +3576,8 @@ static const struct regmap_config rt5645_regmap = { static const struct regmap_config rt5650_regmap = { .reg_bits = 8, .val_bits = 16, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .max_register = RT5645_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5645_ranges) * RT5645_PR_SPACING), .volatile_reg = rt5645_volatile_register, @@ -3592,7 +3594,8 @@ static const struct regmap_config temp_regmap = { .name="nocache", .reg_bits = 8, .val_bits = 16, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .max_register = RT5645_VENDOR_ID2 + 1, .cache_type = REGCACHE_NONE, }; diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index b613103d801b51..b7ba64350a07cc 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -2123,7 +2123,8 @@ static const struct regmap_config rt5651_regmap = { .num_reg_defaults = ARRAY_SIZE(rt5651_reg), .ranges = rt5651_ranges, .num_ranges = ARRAY_SIZE(rt5651_ranges), - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; #if defined(CONFIG_OF) diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index 20a755137e637c..27f7445b243200 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -1217,7 +1217,8 @@ static const struct snd_soc_component_driver soc_component_dev_rt5660 = { static const struct regmap_config rt5660_regmap = { .reg_bits = 8, .val_bits = 16, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .max_register = RT5660_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5660_ranges) * RT5660_PR_SPACING), diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 2444fad7c2dfec..7eb2cbd39d6e09 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -3257,7 +3257,8 @@ static const struct snd_soc_component_driver soc_component_dev_rt5663 = { static const struct regmap_config rt5663_v2_regmap = { .reg_bits = 16, .val_bits = 16, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .max_register = 0x07fa, .volatile_reg = rt5663_v2_volatile_register, .readable_reg = rt5663_v2_readable_register, @@ -3269,7 +3270,8 @@ static const struct regmap_config rt5663_v2_regmap = { static const struct regmap_config rt5663_regmap = { .reg_bits = 16, .val_bits = 16, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .max_register = 0x03f3, .volatile_reg = rt5663_volatile_register, .readable_reg = rt5663_readable_register, @@ -3282,7 +3284,8 @@ static const struct regmap_config temp_regmap = { .name = "nocache", .reg_bits = 16, .val_bits = 16, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .max_register = 0x03f3, .cache_type = REGCACHE_NONE, }; diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 6ba99f5ed3f42e..f2ad3a4c3b7f76 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4633,7 +4633,8 @@ static const struct regmap_config rt5665_regmap = { .cache_type = REGCACHE_RBTREE, .reg_defaults = rt5665_reg, .num_reg_defaults = ARRAY_SIZE(rt5665_reg), - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static const struct i2c_device_id rt5665_i2c_id[] = { diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index 85ba04d6e7aef4..230a21c93b6bad 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -2375,7 +2375,8 @@ static const struct regmap_config rt5668_regmap = { .cache_type = REGCACHE_RBTREE, .reg_defaults = rt5668_reg, .num_reg_defaults = ARRAY_SIZE(rt5668_reg), - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static const struct i2c_device_id rt5668_i2c_id[] = { diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 455fe7cff700bd..453328c988c0cf 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2814,7 +2814,8 @@ static const struct snd_soc_component_driver soc_component_dev_rt5670 = { static const struct regmap_config rt5670_regmap = { .reg_bits = 8, .val_bits = 16, - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, .max_register = RT5670_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5670_ranges) * RT5670_PR_SPACING), .volatile_reg = rt5670_volatile_register, diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 340f90497d072a..34cfaf8f6f3452 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2441,7 +2441,8 @@ static const struct regmap_config rt5682_regmap = { .cache_type = REGCACHE_RBTREE, .reg_defaults = rt5682_reg, .num_reg_defaults = ARRAY_SIZE(rt5682_reg), - .use_single_rw = true, + .use_single_read = true, + .use_single_write = true, }; static const struct i2c_device_id rt5682_i2c_id[] = { From 5d5424ac57d4743ce1c881ac85ba53fdf48ba22f Mon Sep 17 00:00:00 2001 From: Ricardo Biehl Pasquali Date: Fri, 7 Sep 2018 16:58:54 -0300 Subject: [PATCH 0218/1995] ALSA: pcm: Update hardware pointer before start capture This ensures the transfer loop won't waste a run to read the few frames (if any) between start and hw_ptr update. It will wait for the next interrupt with wait_for_avail(). Signed-off-by: Ricardo Biehl Pasquali Signed-off-by: Takashi Iwai (cherry picked from commit 64b6acf60b665fffd419c23886a1cbeeb253cfb4) --- sound/core/pcm_lib.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 7f71c2449af5ec..40013b26f67196 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2172,6 +2172,10 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, if (err < 0) goto _end_unlock; + runtime->twake = runtime->control->avail_min ? : 1; + if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) + snd_pcm_update_hw_ptr(substream); + if (!is_playback && runtime->status->state == SNDRV_PCM_STATE_PREPARED) { if (size >= runtime->start_threshold) { @@ -2185,10 +2189,8 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, } } - runtime->twake = runtime->control->avail_min ? : 1; - if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) - snd_pcm_update_hw_ptr(substream); avail = snd_pcm_avail(substream); + while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; snd_pcm_uframes_t cont; From 2527d122ecb3910a12fc953da7499865b092cd39 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 28 Sep 2018 17:38:59 +0800 Subject: [PATCH 0219/1995] ALSA: hda: Fix mismatch for register mask and value in ext controller. E.g. for snd_hdac_ext_bus_link_power_up(), we should set mask to be AZX_MLCTL_SPA(it was 0), and AZX_MLCTL_SPA as value to power up it, here correct it and several similar mismatches. Signed-off-by: Keyon Jie Signed-off-by: Takashi Iwai (cherry picked from commit c32bf867cb6721d6ea04044d33f19c8bd81280c1) --- sound/hda/ext/hdac_ext_controller.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index 5bc4a1d587d4f1..60cb00fd0c6936 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c @@ -48,9 +48,11 @@ void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *bus, bool enable) } if (enable) - snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_GPROCEN); + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, + AZX_PPCTL_GPROCEN, AZX_PPCTL_GPROCEN); else - snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_GPROCEN, 0); + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, + AZX_PPCTL_GPROCEN, 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable); @@ -68,9 +70,11 @@ void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *bus, bool enable) } if (enable) - snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_PIE); + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, + AZX_PPCTL_PIE, AZX_PPCTL_PIE); else - snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_PIE, 0); + snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, + AZX_PPCTL_PIE, 0); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable); @@ -194,7 +198,8 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable) */ int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link) { - snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA); + snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, + AZX_MLCTL_SPA, AZX_MLCTL_SPA); return check_hdac_link_power_active(link, true); } @@ -222,8 +227,8 @@ int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus) int ret; list_for_each_entry(hlink, &bus->hlink_list, list) { - snd_hdac_updatel(hlink->ml_addr, - AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA); + snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, + AZX_MLCTL_SPA, AZX_MLCTL_SPA); ret = check_hdac_link_power_active(hlink, true); if (ret < 0) return ret; @@ -243,7 +248,8 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus) int ret; list_for_each_entry(hlink, &bus->hlink_list, list) { - snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_MLCTL_SPA, 0); + snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, + AZX_MLCTL_SPA, 0); ret = check_hdac_link_power_active(hlink, false); if (ret < 0) return ret; From c80bd80c0d7e6e7f312d8b0e7d610ceaa086f75a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 13 Sep 2018 08:20:43 +0200 Subject: [PATCH 0220/1995] ALSA: rawmidi: A lightweight function to discard pending bytes For discarding the pending bytes on rawmidi, we process with a loop of snd_rawmidi_transmit() which is just a waste of CPU power. Implement a lightweight API function to discard the pending bytes and the proceed the ring buffer instantly, and use it instead of open codes. Signed-off-by: Takashi Iwai (cherry picked from commit 6aea5702e27ebc85747d6e4943a0c378e1752be0) --- include/sound/rawmidi.h | 1 + sound/core/rawmidi.c | 22 ++++++++++++++++++++++ sound/core/seq/seq_virmidi.c | 4 +--- sound/usb/midi.c | 3 +-- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index 6665cb29e1a238..3b5a061132b676 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -171,6 +171,7 @@ int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count); int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count); +int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream); /* main midi functions */ diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 08d5662039e381..ee601d7f092694 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1236,6 +1236,28 @@ int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, } EXPORT_SYMBOL(snd_rawmidi_transmit); +/** + * snd_rawmidi_proceed - Discard the all pending bytes and proceed + * @substream: rawmidi substream + * + * Return: the number of discarded bytes + */ +int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream) +{ + struct snd_rawmidi_runtime *runtime = substream->runtime; + unsigned long flags; + int count = 0; + + spin_lock_irqsave(&runtime->lock, flags); + if (runtime->avail < runtime->buffer_size) { + count = runtime->buffer_size - runtime->avail; + __snd_rawmidi_transmit_ack(substream, count); + } + spin_unlock_irqrestore(&runtime->lock, flags); + return count; +} +EXPORT_SYMBOL(snd_rawmidi_proceed); + static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream, const unsigned char __user *userbuf, const unsigned char *kernelbuf, diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index cb988efd1ed0d6..e5a40795914a66 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -149,9 +149,7 @@ static void snd_vmidi_output_work(struct work_struct *work) /* discard the outputs in dispatch mode unless subscribed */ if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH && !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) { - char buf[32]; - while (snd_rawmidi_transmit(substream, buf, sizeof(buf)) > 0) - ; /* ignored */ + snd_rawmidi_proceed(substream); return; } diff --git a/sound/usb/midi.c b/sound/usb/midi.c index dcfc546d81b924..b737f0ec77d090 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -1175,8 +1175,7 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, if (port->ep->umidi->disconnected) { /* gobble up remaining bytes to prevent wait in * snd_rawmidi_drain_output */ - while (!snd_rawmidi_transmit_empty(substream)) - snd_rawmidi_transmit_ack(substream, 1); + snd_rawmidi_proceed(substream); return; } tasklet_schedule(&port->ep->tasklet); From e326ae8548e133e54bd8e645c4bc0f4028d2fee2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 4 Oct 2018 19:54:51 +0200 Subject: [PATCH 0221/1995] ALSA: memalloc: Add fall-through annotation As a preparatory patch for the upcoming -Wimplicit-fallthrough compiler checks, add the "fall through" annotation in snd_dma_alloc_pages(). Note that this seems necessary to be put exactly before the next label, so it's outside the ifdef block. Signed-off-by: Takashi Iwai (cherry picked from commit 3c4cfa7bf6075be035cff3cac0986395f6fca32b) --- sound/core/memalloc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index aa266907ec9ba9..59a4adc286ed77 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -203,6 +203,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, */ dmab->dev.type = SNDRV_DMA_TYPE_DEV; #endif /* CONFIG_GENERIC_ALLOCATOR */ + /* fall through */ case SNDRV_DMA_TYPE_DEV: case SNDRV_DMA_TYPE_DEV_UC: snd_malloc_dev_pages(dmab, size); From 6b03a077ffe43991cc8b8c4cb11d6c70656f7e46 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sat, 3 Nov 2018 22:21:22 +0100 Subject: [PATCH 0222/1995] ASoC: Intel: mrfld: fix uninitialized variable access Randconfig testing revealed a very old bug, with gcc-8: sound/soc/intel/atom/sst/sst_loader.c: In function 'sst_load_fw': sound/soc/intel/atom/sst/sst_loader.c:357:5: error: 'fw' may be used uninitialized in this function [-Werror=maybe-uninitialized] if (fw == NULL) { ^ sound/soc/intel/atom/sst/sst_loader.c:354:25: note: 'fw' was declared here const struct firmware *fw; We must check the return code of request_firmware() before we look at the pointer result that may be uninitialized when the function fails. Fixes: 9012c9544eea ("ASoC: Intel: mrfld - Add DSP load and management") Signed-off-by: Arnd Bergmann Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 1539c7f23f256120f89f8b9ec53160790bce9ed2) --- sound/soc/intel/atom/sst/sst_loader.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c index 27413ebae9566e..b8c456753f015f 100644 --- a/sound/soc/intel/atom/sst/sst_loader.c +++ b/sound/soc/intel/atom/sst/sst_loader.c @@ -354,14 +354,14 @@ static int sst_request_fw(struct intel_sst_drv *sst) const struct firmware *fw; retval = request_firmware(&fw, sst->firmware_name, sst->dev); - if (fw == NULL) { - dev_err(sst->dev, "fw is returning as null\n"); - return -EINVAL; - } if (retval) { dev_err(sst->dev, "request fw failed %d\n", retval); return retval; } + if (fw == NULL) { + dev_err(sst->dev, "fw is returning as null\n"); + return -EINVAL; + } mutex_lock(&sst->sst_lock); retval = sst_cache_and_parse_fw(sst, fw); mutex_unlock(&sst->sst_lock); From f575459445e08949c6be877a0cda883bcf15bdc7 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 4 Nov 2018 07:55:29 -0500 Subject: [PATCH 0223/1995] ASoC: nau8825: remove unnecessary unlikely() WARN_ON() already contains an unlikely(), so it's not necessary to use unlikely. Signed-off-by: Yangtao Li Signed-off-by: Mark Brown (cherry picked from commit 0b6277e6343e192aaa7d452ab933281eb0d420dc) --- sound/soc/codecs/nau8825.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index b9fed99d8b5ed3..7bbcbf5f05c887 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -424,10 +424,8 @@ static u32 nau8825_xtalk_sidetone(u32 sig_org, u32 sig_cros) { u32 gain, sidetone; - if (unlikely(sig_org == 0) || unlikely(sig_cros == 0)) { - WARN_ON(1); + if (WARN_ON(sig_org == 0 || sig_cros == 0)) return 0; - } sig_org = nau8825_intlog10_dec3(sig_org); sig_cros = nau8825_intlog10_dec3(sig_cros); From e4abd31b88f5cb4dc76e7432ca10a9c8350aea19 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 27 Oct 2018 15:34:44 +0200 Subject: [PATCH 0224/1995] ASoC: codecs: constify snd_soc_dai_ops structures The snd_soc_dai_ops structures are only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structures const as well. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Mark Brown (cherry picked from commit 704a9fc20b87f2929732cab0a1a04f28d4093085) --- sound/soc/codecs/ak4458.c | 2 +- sound/soc/codecs/ak5558.c | 2 +- sound/soc/codecs/hdac_hda.c | 2 +- sound/soc/codecs/tas6424.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index 299ada4dfaa009..70d4c89bd6fc38 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -456,7 +456,7 @@ static int ak4458_startup(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_dai_ops ak4458_dai_ops = { +static const struct snd_soc_dai_ops ak4458_dai_ops = { .startup = ak4458_startup, .hw_params = ak4458_hw_params, .set_fmt = ak4458_set_dai_fmt, diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index 448bb90c9c8e0a..60f1f12c81ea78 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -246,7 +246,7 @@ static int ak5558_startup(struct snd_pcm_substream *substream, &ak5558_rate_constraints); } -static struct snd_soc_dai_ops ak5558_dai_ops = { +static const struct snd_soc_dai_ops ak5558_dai_ops = { .startup = ak5558_startup, .hw_params = ak5558_hw_params, diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 2aaa83028e55f2..ffecdaaa8cf2bb 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -46,7 +46,7 @@ static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, struct snd_soc_dai *dai); -static struct snd_soc_dai_ops hdac_hda_dai_ops = { +static const struct snd_soc_dai_ops hdac_hda_dai_ops = { .startup = hdac_hda_dai_open, .shutdown = hdac_hda_dai_close, .prepare = hdac_hda_dai_prepare, diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c index 0d6145549a98d6..2eaff1f31ade5f 100644 --- a/sound/soc/codecs/tas6424.c +++ b/sound/soc/codecs/tas6424.c @@ -377,7 +377,7 @@ static struct snd_soc_component_driver soc_codec_dev_tas6424 = { .non_legacy_dai_naming = 1, }; -static struct snd_soc_dai_ops tas6424_speaker_dai_ops = { +static const struct snd_soc_dai_ops tas6424_speaker_dai_ops = { .hw_params = tas6424_hw_params, .set_fmt = tas6424_set_dai_fmt, .set_tdm_slot = tas6424_set_dai_tdm_slot, From 02af69de497696eeb1e355eca1ec390aa8cddab1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 31 Oct 2018 15:22:25 +0100 Subject: [PATCH 0225/1995] ASoC: intel: cht_bsw_max98090_ti: Add quirk for boards using pmc_plt_clk_0 Some boards such as the Swanky model Chromebooks use pmc_plt_clk_0 for the mclk instead of pmc_plt_clk_3. This commit adds a DMI based quirk for this. This fixing audio no longer working on these devices after commit 648e921888ad ("clk: x86: Stop marking clocks as CLK_IS_CRITICAL") that commit fixes us unnecessary keeping unused clocks on, but in case of the Swanky that was breaking audio support since we were not using the right clock in the cht_bsw_max98090_ti machine driver. Cc: stable@vger.kernel.org Fixes: 648e921888ad ("clk: x86: Stop marking clocks as CLK_IS_CRITICAL") Reported-and-tested-by: Dean Wallace Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit a182ecd3809c8d5a2da80c520f3602e301c5317e) --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 32 ++++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index db6976f4ddaa28..9d9f6e41d81c07 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -19,6 +19,7 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include #include #include #include @@ -35,6 +36,8 @@ #define CHT_PLAT_CLK_3_HZ 19200000 #define CHT_CODEC_DAI "HiFi" +#define QUIRK_PMC_PLT_CLK_0 0x01 + struct cht_mc_private { struct clk *mclk; struct snd_soc_jack jack; @@ -385,11 +388,29 @@ static struct snd_soc_card snd_soc_card_cht = { .num_controls = ARRAY_SIZE(cht_mc_controls), }; +static const struct dmi_system_id cht_max98090_quirk_table[] = { + { + /* Swanky model Chromebook (Toshiba Chromebook 2) */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Swanky"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, + {} +}; + static int snd_cht_mc_probe(struct platform_device *pdev) { + const struct dmi_system_id *dmi_id; struct device *dev = &pdev->dev; int ret_val = 0; struct cht_mc_private *drv; + const char *mclk_name; + int quirks = 0; + + dmi_id = dmi_first_match(cht_max98090_quirk_table); + if (dmi_id) + quirks = (unsigned long)dmi_id->driver_data; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); if (!drv) @@ -411,11 +432,16 @@ static int snd_cht_mc_probe(struct platform_device *pdev) snd_soc_card_cht.dev = &pdev->dev; snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); - drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + if (quirks & QUIRK_PMC_PLT_CLK_0) + mclk_name = "pmc_plt_clk_0"; + else + mclk_name = "pmc_plt_clk_3"; + + drv->mclk = devm_clk_get(&pdev->dev, mclk_name); if (IS_ERR(drv->mclk)) { dev_err(&pdev->dev, - "Failed to get MCLK from pmc_plt_clk_3: %ld\n", - PTR_ERR(drv->mclk)); + "Failed to get MCLK from %s: %ld\n", + mclk_name, PTR_ERR(drv->mclk)); return PTR_ERR(drv->mclk); } From fb32f41d152d9572bdab2f5c601405576f8eefee Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 1 Nov 2018 16:34:48 -0500 Subject: [PATCH 0226/1995] ASoC: acpi: define common interface for machine driver configuration The machine drivers may need information provided by the platform driver. Currently the information is passed using pdata specific to each plaform driver. This prevents other drivers, such as SOF, from reusing machine drivers directly. Add a new structure which contains the required fields. This proposal requires a bit more work on the platform side but this generic interface helps reuse code directly. Reviewed-by: Andy Shevchenko Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 8679284b37e9e2d529d60d1acc4133af4aa5dd34) --- include/sound/soc-acpi.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index e45b2330d16a45..5154c6359609fc 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -37,6 +37,19 @@ snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], struct snd_soc_acpi_mach * snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines); +/** + * snd_soc_acpi_mach_params: interface for machine driver configuration + * + * @acpi_ipc_irq_index: used for BYT-CR detection + * @platform: string used for HDaudio codec support + * @codec_mask: used for HDAudio support + */ +struct snd_soc_acpi_mach_params { + u32 acpi_ipc_irq_index; + const char *platform; + u32 codec_mask; +}; + /** * snd_soc_acpi_mach: ACPI-based machine descriptor. Most of the fields are * related to the hardware, except for the firmware and topology file names. @@ -68,6 +81,7 @@ struct snd_soc_acpi_mach { struct snd_soc_acpi_mach * (*machine_quirk)(void *arg); const void *quirk_data; void *pdata; + struct snd_soc_acpi_mach_params mach_params; const char *sof_fw_filename; const char *sof_tplg_filename; const char *asoc_plat_name; From 485454ebb42bf5c7b55795adadab8cf077630a1a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 1 Nov 2018 16:34:49 -0500 Subject: [PATCH 0227/1995] ASoC: Intel: use standard interface for Hdaudio machine driver Don't rely on internal Skylake-specific data structures, use generic interface to let other drivers use the same machine driver as is, e.g. SOF to support HDaudio codecs and HDMI outputs. Tested on LeafHill CRB board, no regression seen with this change. Reviewed-by: Andy Shevchenko Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 842bb5135f1016151235413726e4956210a79664) --- sound/soc/intel/boards/skl_hda_dsp_generic.c | 20 ++++++++++---------- sound/soc/intel/skylake/skl.c | 10 +++------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index b415dd4c85f5ac..b6f287fa950533 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -12,8 +12,8 @@ #include #include #include +#include #include "../../codecs/hdac_hdmi.h" -#include "../skylake/skl.h" #include "skl_hda_dsp_common.h" static const struct snd_soc_dapm_widget skl_hda_widgets[] = { @@ -101,17 +101,17 @@ static struct snd_soc_card hda_soc_card = { #define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2) #define IDISP_CODEC_MASK 0x4 -static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) +static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params) { struct snd_soc_card *card = &hda_soc_card; struct snd_soc_dai_link *dai_link; u32 codec_count, codec_mask; int i, num_links, num_route; - codec_mask = pdata->codec_mask; + codec_mask = mach_params->codec_mask; codec_count = hweight_long(codec_mask); - if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) { + if (codec_count == 1 && codec_mask & IDISP_CODEC_MASK) { num_links = IDISP_DAI_COUNT; num_route = IDISP_ROUTE_COUNT; } else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) { @@ -127,14 +127,14 @@ static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) card->num_dapm_routes = num_route; for_each_card_prelinks(card, i, dai_link) - dai_link->platform_name = pdata->platform; + dai_link->platform_name = mach_params->platform; return 0; } static int skl_hda_audio_probe(struct platform_device *pdev) { - struct skl_machine_pdata *pdata; + struct snd_soc_acpi_mach *mach; struct skl_hda_private *ctx; int ret; @@ -146,11 +146,11 @@ static int skl_hda_audio_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - pdata = dev_get_drvdata(&pdev->dev); - if (!pdata) + mach = dev_get_drvdata(&pdev->dev); + if (!mach) return -EINVAL; - ret = skl_hda_fill_card_info(pdata); + ret = skl_hda_fill_card_info(&mach->mach_params); if (ret < 0) { dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n"); return ret; @@ -158,7 +158,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev) ctx->pcm_count = hda_soc_card.num_links; ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */ - ctx->platform_name = pdata->platform; + ctx->platform_name = mach->mach_params.platform; hda_soc_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&hda_soc_card, ctx); diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 29225623b4b40d..ebab04b51bc126 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -525,7 +525,6 @@ static int skl_machine_device_register(struct skl *skl) { struct snd_soc_acpi_mach *mach = skl->mach; struct hdac_bus *bus = skl_to_bus(skl); - struct skl_machine_pdata *pdata; struct platform_device *pdev; int ret; @@ -542,12 +541,9 @@ static int skl_machine_device_register(struct skl *skl) return -EIO; } - if (mach->pdata) { - pdata = (struct skl_machine_pdata *)mach->pdata; - pdata->platform = dev_name(bus->dev); - pdata->codec_mask = bus->codec_mask; - dev_set_drvdata(&pdev->dev, mach->pdata); - } + mach->mach_params.platform = dev_name(bus->dev); + mach->mach_params.codec_mask = bus->codec_mask; + dev_set_drvdata(&pdev->dev, mach); skl->i2s_dev = pdev; From f2ed9a0c20e7d48082830ad36f9343e9a5bfd736 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 1 Nov 2018 16:34:50 -0500 Subject: [PATCH 0228/1995] ASoC: Intel: use standard interface for Atom machine drivers Don't rely on internal Atom/SST-specific data structures, use generic interface to let other drivers use the same machine drivers as is, e.g. SOF to support BYT-CR devices Tested-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 3ee1cd4f81e15f51638db80fb9f1371b3bdf05ba) --- sound/soc/intel/atom/sst/sst_acpi.c | 4 ++++ sound/soc/intel/boards/bytcr_rt5640.c | 6 +----- sound/soc/intel/boards/bytcr_rt5651.c | 6 +----- sound/soc/intel/boards/cht_bsw_rt5645.c | 6 +----- 4 files changed, 7 insertions(+), 15 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index c90b04cc071dc2..ac542535b9d53f 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -341,6 +341,10 @@ static int sst_acpi_probe(struct platform_device *pdev) byt_rvp_platform_data.res_info = &bytcr_res_info; } + /* update machine parameters */ + mach->mach_params.acpi_ipc_irq_index = + pdata->res_info->acpi_ipc_irq_index; + plat_dev = platform_device_register_data(dev, pdata->platform, -1, NULL, 0); if (IS_ERR(plat_dev)) { diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 8587bd3d1cc17d..09591144ea7d2e 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -1152,10 +1151,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) * (will be overridden if DMI quirk is detected) */ if (is_valleyview()) { - struct sst_platform_info *p_info = mach->pdata; - const struct sst_res_info *res_info = p_info->res_info; - - if (res_info->acpi_ipc_irq_index == 0) + if (mach->mach_params.acpi_ipc_irq_index == 0) is_bytcr = true; } diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 8dffeecda55b88..4c9508da860258 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -920,10 +919,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) * (will be overridden if DMI quirk is detected) */ if (x86_match_cpu(baytrail_cpu_ids)) { - struct sst_platform_info *p_info = mach->pdata; - const struct sst_res_info *res_info = p_info->res_info; - - if (res_info->acpi_ipc_irq_index == 0) + if (mach->mach_params.acpi_ipc_irq_index == 0) is_bytcr = true; } diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index f5a5ea6a093c71..250a356a0cbf08 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -585,10 +584,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) * (will be overridden if DMI quirk is detected) */ if (is_valleyview()) { - struct sst_platform_info *p_info = mach->pdata; - const struct sst_res_info *res_info = p_info->res_info; - - if (res_info->acpi_ipc_irq_index == 0) + if (mach->mach_params.acpi_ipc_irq_index == 0) is_bytcr = true; } From 8d4f2e53bb5320c8c4a1b0fff38f584f1e8367bb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 1 Nov 2018 16:34:51 -0500 Subject: [PATCH 0229/1995] ASoC: Intel: boards: fix Skylake typo s/skylaye/skylake Reviewed-by: Andy Shevchenko Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 48bf41a2be51ef3f67b60f85bf75cecfb57884ba) --- sound/soc/intel/boards/kbl_da7219_max98927.c | 6 +++--- sound/soc/intel/boards/kbl_rt5663_max98927.c | 4 ++-- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 4 ++-- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 3fa1c3ca6d376f..3bc78e3a91ee5f 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -441,7 +441,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream) } -static struct snd_soc_ops skylaye_refcap_ops = { +static struct snd_soc_ops skylake_refcap_ops = { .startup = kabylake_refcap_startup, }; @@ -525,7 +525,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { .dpcm_capture = 1, .nonatomic = 1, .dynamic = 1, - .ops = &skylaye_refcap_ops, + .ops = &skylake_refcap_ops, }, [KBL_DPCM_AUDIO_DMIC_CP] = { .name = "Kbl Audio DMIC cap", @@ -736,7 +736,7 @@ static struct snd_soc_dai_link kabylake_max98927_dais[] = { .dpcm_capture = 1, .nonatomic = 1, .dynamic = 1, - .ops = &skylaye_refcap_ops, + .ops = &skylake_refcap_ops, }, [KBL_DPCM_AUDIO_DMIC_CP] = { .name = "Kbl Audio DMIC cap", diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index 99e1320c485ff2..6ea969c0a5fb8c 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -586,7 +586,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream) &constraints_16000); } -static struct snd_soc_ops skylaye_refcap_ops = { +static struct snd_soc_ops skylake_refcap_ops = { .startup = kabylake_refcap_startup, }; @@ -655,7 +655,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { .dpcm_capture = 1, .nonatomic = 1, .dynamic = 1, - .ops = &skylaye_refcap_ops, + .ops = &skylake_refcap_ops, }, [KBL_DPCM_AUDIO_DMIC_CP] = { .name = "Kbl Audio DMIC cap", diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index d31482b8c9bbb0..552958ce736d1e 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -400,7 +400,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream) &constraints_16000); } -static const struct snd_soc_ops skylaye_refcap_ops = { +static const struct snd_soc_ops skylake_refcap_ops = { .startup = skylake_refcap_startup, }; @@ -447,7 +447,7 @@ static struct snd_soc_dai_link skylake_dais[] = { .dpcm_capture = 1, .nonatomic = 1, .dynamic = 1, - .ops = &skylaye_refcap_ops, + .ops = &skylake_refcap_ops, }, [SKL_DPCM_AUDIO_DMIC_CP] = { .name = "Skl Audio DMIC cap", diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index e877bb60beb10b..f985b30a1d0eaa 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -449,7 +449,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream) &constraints_16000); } -static const struct snd_soc_ops skylaye_refcap_ops = { +static const struct snd_soc_ops skylake_refcap_ops = { .startup = skylake_refcap_startup, }; @@ -496,7 +496,7 @@ static struct snd_soc_dai_link skylake_dais[] = { .dpcm_capture = 1, .nonatomic = 1, .dynamic = 1, - .ops = &skylaye_refcap_ops, + .ops = &skylake_refcap_ops, }, [SKL_DPCM_AUDIO_DMIC_CP] = { .name = "Skl Audio DMIC cap", From 8fdfa0a4bfb8518f1cdd45102884fbeccd31e652 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 1 Nov 2018 16:34:52 -0500 Subject: [PATCH 0230/1995] ASoC: Intel: remove GFP_ATOMIC, use GFP_KERNEL GFP_ATOMIC is not required on any Intel drivers, use GFP_KERNEL instead. A first cleanup was merged in April but missed a number occurrences and new ones were added by copy/paste inertia. While we are at it, make checkpatch happy with a sizeof(*msg) Reviewed-by: Andy Shevchenko Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 972b0d456e645ea8fd3fdc70f95f0e41c27c0870) --- sound/soc/intel/atom/sst/sst_pvt.c | 4 ++-- sound/soc/intel/boards/cht_bsw_rt5672.c | 2 +- sound/soc/intel/boards/glk_rt5682_max98357a.c | 2 +- sound/soc/intel/boards/kbl_da7219_max98927.c | 2 +- sound/soc/intel/boards/skl_hda_dsp_generic.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c index af93244b48686f..00a37a09dc9b0f 100644 --- a/sound/soc/intel/atom/sst/sst_pvt.c +++ b/sound/soc/intel/atom/sst/sst_pvt.c @@ -166,11 +166,11 @@ int sst_create_ipc_msg(struct ipc_post **arg, bool large) { struct ipc_post *msg; - msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC); + msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (!msg) return -ENOMEM; if (large) { - msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC); + msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL); if (!msg->mailbox_data) { kfree(msg); return -ENOMEM; diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 51f0d45d6f8f9d..9de64f447e7bed 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -403,7 +403,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) const char *i2c_name; int i; - drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); + drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); if (!drv) return -ENOMEM; diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index c4b94e2617c59b..c74c4f17316fe8 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -603,7 +603,7 @@ static int geminilake_audio_probe(struct platform_device *pdev) { struct glk_card_private *ctx; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 3bc78e3a91ee5f..58eb0fe69978bd 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -935,7 +935,7 @@ static int kabylake_audio_probe(struct platform_device *pdev) { struct kbl_codec_private *ctx; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index b6f287fa950533..15c502d6774d08 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -140,7 +140,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s: entry\n", __func__); - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; From 2e700996a5f28713daff55f1344e4b3eab38d36e Mon Sep 17 00:00:00 2001 From: Bard liao Date: Thu, 1 Nov 2018 16:34:53 -0500 Subject: [PATCH 0231/1995] ASoC: Intel: common: add SOF information for APL RVP Add firmware/topology information for APL RVP Reviewed-by: Andy Shevchenko Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 97bb91ae2f3325fd06ea2c28fb8b5b4e023b4b5d) --- sound/soc/intel/common/soc-acpi-intel-bxt-match.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c index f39386e540d322..2756fa4ab55201 100644 --- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c @@ -19,6 +19,9 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .id = "INT343A", .drv_name = "bxt_alc298s_i2s", .fw_filename = "intel/dsp_fw_bxtn.bin", + .sof_fw_filename = "intel/sof-apl.ri", + .sof_tplg_filename = "intel/sof-apl-rt298.tplg", + .asoc_plat_name = "0000:00:0e.0", }, { .id = "DLGS7219", From 2279f900f8e6a11d56d71a7210714ff189c74e91 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 1 Nov 2018 16:34:54 -0500 Subject: [PATCH 0232/1995] ASoC: Intel: common: add quirk for APL RVP boards For some reason the RVP/LeafHill SSDT exposes an INT34C3 ID which is used on other boards to point to the TDF8532 amplifier. Yay BIOS. Add a DMI-quirk to ignore this ID and check for other valid machine driver descriptors. Reviewed-by: Andy Shevchenko Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 935ff8007f5efd24e995d26ebf875ee2c787465e) --- .../intel/common/soc-acpi-intel-bxt-match.c | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c index 2756fa4ab55201..61dedc103b1966 100644 --- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c @@ -6,9 +6,41 @@ * */ +#include #include #include +enum { + APL_RVP, +}; + +static const struct dmi_system_id apl_table[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."), + DMI_MATCH(DMI_BOARD_NAME, "Apollolake RVP1A"), + }, + .driver_data = (void *)(APL_RVP), + }, + {} +}; + +static struct snd_soc_acpi_mach *apl_quirk(void *arg) +{ + struct snd_soc_acpi_mach *mach = arg; + const struct dmi_system_id *dmi_id; + unsigned long apl_machine_id; + + dmi_id = dmi_first_match(apl_table); + if (dmi_id) { + apl_machine_id = (unsigned long)dmi_id->driver_data; + if (apl_machine_id == APL_RVP) + return NULL; + } + + return mach; +} + static struct snd_soc_acpi_codecs bxt_codecs = { .num_codecs = 1, .codecs = {"MX98357A"} @@ -50,6 +82,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { { .id = "INT34C3", .drv_name = "bxt_tdf8532", + .machine_quirk = apl_quirk, .sof_fw_filename = "intel/sof-apl.ri", .sof_tplg_filename = "intel/sof-apl-tdf8532.tplg", .asoc_plat_name = "0000:00:0e.0", From 928f4c60de584004677356c7a7f9adf8008139e8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 9 Nov 2018 14:00:38 -0600 Subject: [PATCH 0233/1995] ASoC: Intel" bytcr_rt5640: revert SOF-specific changes Change in pdata structure Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bytcr_rt5640.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 2d24317bf3a5f7..98db6e6d3384db 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -1154,13 +1153,8 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) * (will be overridden if DMI quirk is detected) */ if (is_valleyview()) { -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) /* FIXME: bytcr not supported yet */ - struct sst_platform_info *p_info = mach->pdata; - const struct sst_res_info *res_info = p_info->res_info; - - if (res_info->acpi_ipc_irq_index == 0) + if (mach->mach_params.acpi_ipc_irq_index == 0) is_bytcr = true; -#endif } if (is_bytcr) { From 4edef6ed7162c09aab73a68fe02e87c11468f9c1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 9 Nov 2018 14:01:42 -0600 Subject: [PATCH 0234/1995] ASoC: Intel: cht_bsw_rt5645: revert SOF-specific changes Change in pdata structure Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/cht_bsw_rt5645.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 710a5a11215b52..be693d02a20fe8 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -593,13 +592,8 @@ static int snd_cht_mc_probe(struct platform_device *pdev) * (will be overridden if DMI quirk is detected) */ if (is_valleyview()) { -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) /* FIXME: bytcr not supported yet */ - struct sst_platform_info *p_info = mach->pdata; - const struct sst_res_info *res_info = p_info->res_info; - - if (res_info->acpi_ipc_irq_index == 0) + if (mach->mach_params.acpi_ipc_irq_index == 0) is_bytcr = true; -#endif } if (is_bytcr) { From 2a65aad9770b519a6a2ba776a393140a9927bf4d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 9 Nov 2018 14:02:46 -0600 Subject: [PATCH 0235/1995] ASoC: Intel: skl-generic: revert SOF-specific changes Change in pdata structure Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/skl_hda_dsp_generic.c | 27 ++++++++------------ 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 399d1b03595959..15c502d6774d08 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -12,9 +12,8 @@ #include #include #include -#include +#include #include "../../codecs/hdac_hdmi.h" -#include "../skylake/skl.h" #include "skl_hda_dsp_common.h" static const struct snd_soc_dapm_widget skl_hda_widgets[] = { @@ -102,14 +101,14 @@ static struct snd_soc_card hda_soc_card = { #define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2) #define IDISP_CODEC_MASK 0x4 -static int skl_hda_fill_card_info(const char *platform, - unsigned long codec_mask) +static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params) { struct snd_soc_card *card = &hda_soc_card; struct snd_soc_dai_link *dai_link; - u32 codec_count; + u32 codec_count, codec_mask; int i, num_links, num_route; + codec_mask = mach_params->codec_mask; codec_count = hweight_long(codec_mask); if (codec_count == 1 && codec_mask & IDISP_CODEC_MASK) { @@ -128,34 +127,30 @@ static int skl_hda_fill_card_info(const char *platform, card->num_dapm_routes = num_route; for_each_card_prelinks(card, i, dai_link) - dai_link->platform_name = platform; + dai_link->platform_name = mach_params->platform; return 0; } static int skl_hda_audio_probe(struct platform_device *pdev) { + struct snd_soc_acpi_mach *mach; struct skl_hda_private *ctx; int ret; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) - struct snd_sof_pdata *pdata = dev_get_platdata(&pdev->dev); -#else - struct skl_machine_pdata *pdata = dev_get_drvdata(&pdev->dev); -#endif - dev_dbg(&pdev->dev, "%s: entry\n", __func__); - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - if (!pdata) + mach = dev_get_drvdata(&pdev->dev); + if (!mach) return -EINVAL; - ret = skl_hda_fill_card_info(pdata->platform, pdata->codec_mask); + ret = skl_hda_fill_card_info(&mach->mach_params); if (ret < 0) { dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n"); return ret; @@ -163,7 +158,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev) ctx->pcm_count = hda_soc_card.num_links; ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */ - ctx->platform_name = pdata->platform; + ctx->platform_name = mach->mach_params.platform; hda_soc_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&hda_soc_card, ctx); From e2910c74cf603b6216d93ae7aa94b9315d146b34 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 9 Nov 2018 14:30:32 -0600 Subject: [PATCH 0236/1995] ASoC: SOF: remove codec_mask from sof dev Use ACPI-defined machine driver instead Signed-off-by: Pierre-Louis Bossart --- include/sound/sof.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index 06f5d9d015b046..206b4f8f1a8a98 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -60,9 +60,6 @@ struct snd_sof_pdata { unsigned int gpio; unsigned int active; - /* hda codec */ - unsigned long codec_mask; - /* machine */ struct platform_device *pdev_mach; union { From b8ea5c2d3c819c69e3614ff2dd2589b7bbee04e9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 9 Nov 2018 14:40:24 -0600 Subject: [PATCH 0237/1995] ASoC: SOF: Intel: hda: pass codec_mask with new pdata structure No change in functionality, just pass the value with a different structure. FIXME: explicit cast used to work-around limitation that SOF pdata declare the machine structure as const - even when we do assign fields dynamically. Either we keep it this way and use casts, or we fix the SOF structure to /* machine */ struct platform_device *pdev_mach; union { struct snd_soc_acpi_mach *machine; struct snd_sof_machine *sof_machine; }; Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index d7311f480635b3..1579b8070a434c 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -434,6 +434,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) struct hdac_bus *bus = sof_to_bus(sdev); struct pci_dev *pci = sdev->pci; struct hdac_ext_link *hlink = NULL; + struct snd_soc_acpi_mach_params *mach_params; int ret = 0; device_disable_async_suspend(bus->dev); @@ -467,7 +468,9 @@ static int hda_init_caps(struct snd_sof_dev *sdev) dev_info(bus->dev, "no hda codecs found!\n"); /* used by hda machine driver to create dai links */ - sdev->pdata->codec_mask = bus->codec_mask; + mach_params = (struct snd_soc_acpi_mach_params *) + &sdev->pdata->machine->mach_params; + mach_params->codec_mask = bus->codec_mask; /* create codec instances */ hda_codec_probe_bus(sdev); From b06850849f36eb4a8984899da77f4406cf1d5c5e Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 8 Nov 2018 21:50:23 +0000 Subject: [PATCH 0238/1995] ASoC: SOF: ABI: Split ABI headers and update to latest FW ABI. Copy FW IPC headers to include/sound/sof/. Copy FW userspace ABI headers to include/uapi/sound/sof/. Fix various include guards and comments for kernel. Signed-off-by: Liam Girdwood --- include/sound/sof.h | 1 - include/sound/sof/control.h | 125 +++ include/sound/sof/dai-intel.h | 161 +++ include/sound/sof/dai.h | 75 ++ include/sound/sof/header.h | 177 ++++ include/sound/sof/info.h | 112 ++ include/sound/sof/pm.h | 47 + include/sound/sof/stream.h | 140 +++ include/sound/sof/topology.h | 242 +++++ include/sound/sof/trace.h | 46 + include/sound/sof/xtensa.h | 41 + include/uapi/sound/sof-abi.h | 50 - include/uapi/sound/sof-ipc.h | 991 ------------------ include/uapi/sound/sof/abi.h | 63 ++ include/uapi/sound/{sof-eq.h => sof/eq.h} | 46 +- include/uapi/sound/{sof-fw.h => sof/fw.h} | 6 +- include/uapi/sound/sof/header.h | 27 + include/uapi/sound/sof/manifest.h | 188 ++++ .../sound/{sof-topology.h => sof/tokens.h} | 0 include/uapi/sound/{sof-tone.h => sof/tone.h} | 17 +- include/uapi/sound/sof/trace.h | 93 ++ sound/soc/sof/compressed.c | 1 - sound/soc/sof/control.c | 3 - sound/soc/sof/debug.c | 1 - sound/soc/sof/hw-spi.c | 2 +- sound/soc/sof/intel/bdw.c | 3 + sound/soc/sof/intel/byt.c | 3 +- sound/soc/sof/intel/hda-dsp.c | 2 +- sound/soc/sof/intel/hda.c | 1 + sound/soc/sof/intel/hsw.c | 2 + sound/soc/sof/ipc.c | 1 - sound/soc/sof/loader.c | 2 +- sound/soc/sof/ops.c | 1 - sound/soc/sof/ops.h | 1 - sound/soc/sof/pcm.c | 1 - sound/soc/sof/sof-priv.h | 12 +- sound/soc/sof/topology.c | 8 +- sound/soc/sof/trace.c | 2 - sound/soc/sof/xtensa/core.c | 1 + 39 files changed, 1599 insertions(+), 1096 deletions(-) create mode 100644 include/sound/sof/control.h create mode 100644 include/sound/sof/dai-intel.h create mode 100644 include/sound/sof/dai.h create mode 100644 include/sound/sof/header.h create mode 100644 include/sound/sof/info.h create mode 100644 include/sound/sof/pm.h create mode 100644 include/sound/sof/stream.h create mode 100644 include/sound/sof/topology.h create mode 100644 include/sound/sof/trace.h create mode 100644 include/sound/sof/xtensa.h delete mode 100644 include/uapi/sound/sof-abi.h delete mode 100644 include/uapi/sound/sof-ipc.h create mode 100644 include/uapi/sound/sof/abi.h rename include/uapi/sound/{sof-eq.h => sof/eq.h} (91%) rename include/uapi/sound/{sof-fw.h => sof/fw.h} (95%) create mode 100644 include/uapi/sound/sof/header.h create mode 100644 include/uapi/sound/sof/manifest.h rename include/uapi/sound/{sof-topology.h => sof/tokens.h} (100%) rename include/uapi/sound/{sof-tone.h => sof/tone.h} (62%) create mode 100644 include/uapi/sound/sof/trace.h diff --git a/include/sound/sof.h b/include/sound/sof.h index 06f5d9d015b046..4cd89661b55c1c 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -19,7 +19,6 @@ #include #include #include -#include struct snd_sof_dsp_ops; diff --git a/include/sound/sof/control.h b/include/sound/sof/control.h new file mode 100644 index 00000000000000..7c839ae73b8f33 --- /dev/null +++ b/include/sound/sof/control.h @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_CONTROL_H__ +#define __INCLUDE_SOUND_SOF_CONTROL_H__ + +#include +#include + +/* + * Component Mixers and Controls + */ + +/* channel positions - uses same values as ALSA */ +enum sof_ipc_chmap { + SOF_CHMAP_UNKNOWN = 0, + SOF_CHMAP_NA, /**< N/A, silent */ + SOF_CHMAP_MONO, /**< mono stream */ + SOF_CHMAP_FL, /**< front left */ + SOF_CHMAP_FR, /**< front right */ + SOF_CHMAP_RL, /**< rear left */ + SOF_CHMAP_RR, /**< rear right */ + SOF_CHMAP_FC, /**< front centre */ + SOF_CHMAP_LFE, /**< LFE */ + SOF_CHMAP_SL, /**< side left */ + SOF_CHMAP_SR, /**< side right */ + SOF_CHMAP_RC, /**< rear centre */ + SOF_CHMAP_FLC, /**< front left centre */ + SOF_CHMAP_FRC, /**< front right centre */ + SOF_CHMAP_RLC, /**< rear left centre */ + SOF_CHMAP_RRC, /**< rear right centre */ + SOF_CHMAP_FLW, /**< front left wide */ + SOF_CHMAP_FRW, /**< front right wide */ + SOF_CHMAP_FLH, /**< front left high */ + SOF_CHMAP_FCH, /**< front centre high */ + SOF_CHMAP_FRH, /**< front right high */ + SOF_CHMAP_TC, /**< top centre */ + SOF_CHMAP_TFL, /**< top front left */ + SOF_CHMAP_TFR, /**< top front right */ + SOF_CHMAP_TFC, /**< top front centre */ + SOF_CHMAP_TRL, /**< top rear left */ + SOF_CHMAP_TRR, /**< top rear right */ + SOF_CHMAP_TRC, /**< top rear centre */ + SOF_CHMAP_TFLC, /**< top front left centre */ + SOF_CHMAP_TFRC, /**< top front right centre */ + SOF_CHMAP_TSL, /**< top side left */ + SOF_CHMAP_TSR, /**< top side right */ + SOF_CHMAP_LLFE, /**< left LFE */ + SOF_CHMAP_RLFE, /**< right LFE */ + SOF_CHMAP_BC, /**< bottom centre */ + SOF_CHMAP_BLC, /**< bottom left centre */ + SOF_CHMAP_BRC, /**< bottom right centre */ + SOF_CHMAP_LAST = SOF_CHMAP_BRC, +}; + +/* control data type and direction */ +enum sof_ipc_ctrl_type { + /* per channel data - uses struct sof_ipc_ctrl_value_chan */ + SOF_CTRL_TYPE_VALUE_CHAN_GET = 0, + SOF_CTRL_TYPE_VALUE_CHAN_SET, + /* component data - uses struct sof_ipc_ctrl_value_comp */ + SOF_CTRL_TYPE_VALUE_COMP_GET, + SOF_CTRL_TYPE_VALUE_COMP_SET, + /* bespoke data - struct struct sof_abi_hdr */ + SOF_CTRL_TYPE_DATA_GET, + SOF_CTRL_TYPE_DATA_SET, +}; + +/* control command type */ +enum sof_ipc_ctrl_cmd { + SOF_CTRL_CMD_VOLUME = 0, /**< maps to ALSA volume style controls */ + SOF_CTRL_CMD_ENUM, /**< maps to ALSA enum style controls */ + SOF_CTRL_CMD_SWITCH, /**< maps to ALSA switch style controls */ + SOF_CTRL_CMD_BINARY, /**< maps to ALSA binary style controls */ +}; + +/* generic channel mapped value data */ +struct sof_ipc_ctrl_value_chan { + uint32_t channel; /**< channel map - enum sof_ipc_chmap */ + uint32_t value; +} __packed; + +/* generic component mapped value data */ +struct sof_ipc_ctrl_value_comp { + uint32_t index; /**< component source/sink/control index in control */ + union { + uint32_t uvalue; + int32_t svalue; + }; +} __packed; + +/* generic control data */ +struct sof_ipc_ctrl_data { + struct sof_ipc_reply rhdr; + uint32_t comp_id; + + /* control access and data type */ + uint32_t type; /**< enum sof_ipc_ctrl_type */ + uint32_t cmd; /**< enum sof_ipc_ctrl_cmd */ + uint32_t index; /**< control index for comps > 1 control */ + + /* control data - can either be appended or DMAed from host */ + struct sof_ipc_host_buffer buffer; + uint32_t num_elems; /**< in array elems or bytes */ + + /* reserved for future use */ + uint32_t reserved[8]; + + /* control data - add new types if needed */ + union { + /* channel values can be used by volume type controls */ + struct sof_ipc_ctrl_value_chan chanv[0]; + /* component values used by routing controls like mux, mixer */ + struct sof_ipc_ctrl_value_comp compv[0]; + /* data can be used by binary controls */ + struct sof_abi_hdr data[0]; + }; +} __packed; + +#endif diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h new file mode 100644 index 00000000000000..3b960216eedb59 --- /dev/null +++ b/include/sound/sof/dai-intel.h @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_DAI_INTEL_H__ +#define __INCLUDE_SOUND_SOF_DAI_INTEL_H__ + +#include + + /* ssc1: TINTE */ +#define SOF_DAI_INTEL_SSP_QUIRK_TINTE (1 << 0) + /* ssc1: PINTE */ +#define SOF_DAI_INTEL_SSP_QUIRK_PINTE (1 << 1) + /* ssc2: SMTATF */ +#define SOF_DAI_INTEL_SSP_QUIRK_SMTATF (1 << 2) + /* ssc2: MMRATF */ +#define SOF_DAI_INTEL_SSP_QUIRK_MMRATF (1 << 3) + /* ssc2: PSPSTWFDFD */ +#define SOF_DAI_INTEL_SSP_QUIRK_PSPSTWFDFD (1 << 4) + /* ssc2: PSPSRWFDFD */ +#define SOF_DAI_INTEL_SSP_QUIRK_PSPSRWFDFD (1 << 5) + /* here is the possibility to define others aux macros */ + +#define SOF_DAI_INTEL_SSP_FRAME_PULSE_WIDTH_MAX 38 +#define SOF_DAI_INTEL_SSP_SLOT_PADDING_MAX 31 + +/* SSP clocks control settings + * + * Macros for clks_control field in sof_ipc_dai_ssp_params struct. + */ + +/* mclk 0 disable */ +#define SOF_DAI_INTEL_SSP_MCLK_0_DISABLE BIT(0) +/* mclk 1 disable */ +#define SOF_DAI_INTEL_SSP_MCLK_1_DISABLE BIT(1) +/* mclk keep active */ +#define SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_KA BIT(2) +/* bclk keep active */ +#define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_KA BIT(3) +/* fs keep active */ +#define SOF_DAI_INTEL_SSP_CLKCTRL_FS_KA BIT(4) +/* bclk idle */ +#define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_IDLE_HIGH BIT(5) + +/* SSP Configuration Request - SOF_IPC_DAI_SSP_CONFIG */ +struct sof_ipc_dai_ssp_params { + uint16_t reserved1; + uint16_t mclk_id; + + uint32_t mclk_rate; /* mclk frequency in Hz */ + uint32_t fsync_rate; /* fsync frequency in Hz */ + uint32_t bclk_rate; /* bclk frequency in Hz */ + + /* TDM */ + uint32_t tdm_slots; + uint32_t rx_slots; + uint32_t tx_slots; + + /* data */ + uint32_t sample_valid_bits; + uint16_t tdm_slot_width; + uint16_t reserved2; /* alignment */ + + /* MCLK */ + uint32_t mclk_direction; + + uint16_t frame_pulse_width; + uint16_t tdm_per_slot_padding_flag; + uint32_t clks_control; + uint32_t quirks; +} __packed; + +/* HDA Configuration Request - SOF_IPC_DAI_HDA_CONFIG */ +struct sof_ipc_dai_hda_params { + struct sof_ipc_hdr hdr; + /* TODO */ +} __packed; + +/* DMIC Configuration Request - SOF_IPC_DAI_DMIC_CONFIG */ + +/* This struct is defined per 2ch PDM controller available in the platform. + * Normally it is sufficient to set the used microphone specific enables to 1 + * and keep other parameters as zero. The customizations are: + * + * 1. If a device mixes different microphones types with different polarity + * and/or the absolute polarity matters the PCM signal from a microphone + * can be inverted with the controls. + * + * 2. If the microphones in a stereo pair do not appear in captured stream + * in desired order due to board schematics choises they can be swapped with + * the clk_edge parameter. + * + * 3. If PDM bit errors are seen in capture (poor quality) the skew parameter + * that delays the sampling time of data by half cycles of DMIC source clock + * can be tried for improvement. However there is no guarantee for this to fix + * data integrity problems. + */ +struct sof_ipc_dai_dmic_pdm_ctrl { + uint16_t id; /**< PDM controller ID */ + + uint16_t enable_mic_a; /**< Use A (left) channel mic (0 or 1)*/ + uint16_t enable_mic_b; /**< Use B (right) channel mic (0 or 1)*/ + + uint16_t polarity_mic_a; /**< Optionally invert mic A signal (0 or 1) */ + uint16_t polarity_mic_b; /**< Optionally invert mic B signal (0 or 1) */ + + uint16_t clk_edge; /**< Optionally swap data clock edge (0 or 1) */ + uint16_t skew; /**< Adjust PDM data sampling vs. clock (0..15) */ + + uint16_t reserved[3]; /**< Make sure the total size is 4 bytes aligned */ +} __packed; + +/* This struct contains the global settings for all 2ch PDM controllers. The + * version number used in configuration data is checked vs. version used by + * device driver src/drivers/dmic.c need to match. It is incremented from + * initial value 1 if updates done for the to driver would alter the operation + * of the microhone. + * + * Note: The microphone clock (pdmclk_min, pdmclk_max, duty_min, duty_max) + * parameters need to be set as defined in microphone data sheet. E.g. clock + * range 1.0 - 3.2 MHz is usually supported microphones. Some microphones are + * multi-mode capable and there may be denied mic clock frequencies between + * the modes. In such case set the clock range limits of the desired mode to + * avoid the driver to set clock to an illegal rate. + * + * The duty cycle could be set to 48-52% if not known. Generally these + * parameters can be altered within data sheet specified limits to match + * required audio application performance power. + * + * The microphone clock needs to be usually about 50-80 times the used audio + * sample rate. With highest sample rates above 48 kHz this can relaxed + * somewhat. + */ +struct sof_ipc_dai_dmic_params { + uint32_t driver_ipc_version; /**< Version (1..N) */ + + uint32_t pdmclk_min; /**< Minimum microphone clock in Hz (100000..N) */ + uint32_t pdmclk_max; /**< Maximum microphone clock in Hz (min...N) */ + + uint32_t fifo_fs_a; /**< FIFO A sample rate in Hz (8000..96000) */ + uint32_t fifo_fs_b; /**< FIFO B sample rate in Hz (8000..96000) */ + uint16_t fifo_bits_a; /**< FIFO A word length (16 or 32) */ + uint16_t fifo_bits_b; /**< FIFO B word length (16 or 32) */ + + uint16_t duty_min; /**< Min. mic clock duty cycle in % (20..80) */ + uint16_t duty_max; /**< Max. mic clock duty cycle in % (min..80) */ + + uint32_t num_pdm_active; /**< Number of active pdm controllers */ + + /* reserved for future use */ + uint32_t reserved[8]; + + /**< variable number of pdm controller config */ + struct sof_ipc_dai_dmic_pdm_ctrl pdm[0]; +} __packed; + +#endif diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h new file mode 100644 index 00000000000000..025a5cba682e30 --- /dev/null +++ b/include/sound/sof/dai.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_DAI_H__ +#define __INCLUDE_SOUND_SOF_DAI_H__ + +#include +#include + +/* + * DAI Configuration. + * + * Each different DAI type will have it's own structure and IPC cmd. + */ + +#define SOF_DAI_FMT_I2S 1 /**< I2S mode */ +#define SOF_DAI_FMT_RIGHT_J 2 /**< Right Justified mode */ +#define SOF_DAI_FMT_LEFT_J 3 /**< Left Justified mode */ +#define SOF_DAI_FMT_DSP_A 4 /**< L data MSB after FRM LRC */ +#define SOF_DAI_FMT_DSP_B 5 /**< L data MSB during FRM LRC */ +#define SOF_DAI_FMT_PDM 6 /**< Pulse density modulation */ + +#define SOF_DAI_FMT_CONT (1 << 4) /**< continuous clock */ +#define SOF_DAI_FMT_GATED (0 << 4) /**< clock is gated */ + +#define SOF_DAI_FMT_NB_NF (0 << 8) /**< normal bit clock + frame */ +#define SOF_DAI_FMT_NB_IF (2 << 8) /**< normal BCLK + inv FRM */ +#define SOF_DAI_FMT_IB_NF (3 << 8) /**< invert BCLK + nor FRM */ +#define SOF_DAI_FMT_IB_IF (4 << 8) /**< invert BCLK + FRM */ + +#define SOF_DAI_FMT_CBM_CFM (0 << 12) /**< codec clk & FRM master */ +#define SOF_DAI_FMT_CBS_CFM (2 << 12) /**< codec clk slave & FRM master */ +#define SOF_DAI_FMT_CBM_CFS (3 << 12) /**< codec clk master & frame slave */ +#define SOF_DAI_FMT_CBS_CFS (4 << 12) /**< codec clk & FRM slave */ + +#define SOF_DAI_FMT_FORMAT_MASK 0x000f +#define SOF_DAI_FMT_CLOCK_MASK 0x00f0 +#define SOF_DAI_FMT_INV_MASK 0x0f00 +#define SOF_DAI_FMT_MASTER_MASK 0xf000 + +/** \brief Types of DAI */ +enum sof_ipc_dai_type { + SOF_DAI_INTEL_NONE = 0, /**< None */ + SOF_DAI_INTEL_SSP, /**< Intel SSP */ + SOF_DAI_INTEL_DMIC, /**< Intel DMIC */ + SOF_DAI_INTEL_HDA, /**< Intel HD/A */ +}; + +/* general purpose DAI configuration */ +struct sof_ipc_dai_config { + struct sof_ipc_hdr hdr; + uint32_t type; /**< DAI type - enum sof_ipc_dai_type */ + uint32_t dai_index; /**< index of this type dai */ + + /* physical protocol and clocking */ + uint16_t format; /**< SOF_DAI_FMT_ */ + uint16_t reserved16; /**< alignment */ + + /* reserved for future use */ + uint32_t reserved[8]; + + /* HW specific data */ + union { + struct sof_ipc_dai_ssp_params ssp; + struct sof_ipc_dai_dmic_params dmic; + struct sof_ipc_dai_hda_params hda; + }; +} __packed; + +#endif diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h new file mode 100644 index 00000000000000..7b506877b7dec3 --- /dev/null +++ b/include/sound/sof/header.h @@ -0,0 +1,177 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_HEADER_H__ +#define __INCLUDE_SOUND_SOF_HEADER_H__ + +#include + +/** \addtogroup sof_uapi uAPI + * SOF uAPI specification. + * @{ + */ + +/* + * IPC messages have a prefixed 32 bit identifier made up as follows :- + * + * 0xGCCCNNNN where + * G is global cmd type (4 bits) + * C is command type (12 bits) + * I is the ID number (16 bits) - monotonic and overflows + * + * This is sent at the start of the IPM message in the mailbox. Messages should + * not be sent in the doorbell (special exceptions for firmware . + */ + +/* Global Message - Generic */ +#define SOF_GLB_TYPE_SHIFT 28 +#define SOF_GLB_TYPE_MASK (0xf << SOF_GLB_TYPE_SHIFT) +#define SOF_GLB_TYPE(x) ((x) << SOF_GLB_TYPE_SHIFT) + +/* Command Message - Generic */ +#define SOF_CMD_TYPE_SHIFT 16 +#define SOF_CMD_TYPE_MASK (0xfff << SOF_CMD_TYPE_SHIFT) +#define SOF_CMD_TYPE(x) ((x) << SOF_CMD_TYPE_SHIFT) + +/* Global Message Types */ +#define SOF_IPC_GLB_REPLY SOF_GLB_TYPE(0x1U) +#define SOF_IPC_GLB_COMPOUND SOF_GLB_TYPE(0x2U) +#define SOF_IPC_GLB_TPLG_MSG SOF_GLB_TYPE(0x3U) +#define SOF_IPC_GLB_PM_MSG SOF_GLB_TYPE(0x4U) +#define SOF_IPC_GLB_COMP_MSG SOF_GLB_TYPE(0x5U) +#define SOF_IPC_GLB_STREAM_MSG SOF_GLB_TYPE(0x6U) +#define SOF_IPC_FW_READY SOF_GLB_TYPE(0x7U) +#define SOF_IPC_GLB_DAI_MSG SOF_GLB_TYPE(0x8U) +#define SOF_IPC_GLB_TRACE_MSG SOF_GLB_TYPE(0x9U) + +/* + * DSP Command Message Types + */ + +/* topology */ +#define SOF_IPC_TPLG_COMP_NEW SOF_CMD_TYPE(0x001) +#define SOF_IPC_TPLG_COMP_FREE SOF_CMD_TYPE(0x002) +#define SOF_IPC_TPLG_COMP_CONNECT SOF_CMD_TYPE(0x003) +#define SOF_IPC_TPLG_PIPE_NEW SOF_CMD_TYPE(0x010) +#define SOF_IPC_TPLG_PIPE_FREE SOF_CMD_TYPE(0x011) +#define SOF_IPC_TPLG_PIPE_CONNECT SOF_CMD_TYPE(0x012) +#define SOF_IPC_TPLG_PIPE_COMPLETE SOF_CMD_TYPE(0x013) +#define SOF_IPC_TPLG_BUFFER_NEW SOF_CMD_TYPE(0x020) +#define SOF_IPC_TPLG_BUFFER_FREE SOF_CMD_TYPE(0x021) + +/* PM */ +#define SOF_IPC_PM_CTX_SAVE SOF_CMD_TYPE(0x001) +#define SOF_IPC_PM_CTX_RESTORE SOF_CMD_TYPE(0x002) +#define SOF_IPC_PM_CTX_SIZE SOF_CMD_TYPE(0x003) +#define SOF_IPC_PM_CLK_SET SOF_CMD_TYPE(0x004) +#define SOF_IPC_PM_CLK_GET SOF_CMD_TYPE(0x005) +#define SOF_IPC_PM_CLK_REQ SOF_CMD_TYPE(0x006) +#define SOF_IPC_PM_CORE_ENABLE SOF_CMD_TYPE(0x007) + +/* component runtime config - multiple different types */ +#define SOF_IPC_COMP_SET_VALUE SOF_CMD_TYPE(0x001) +#define SOF_IPC_COMP_GET_VALUE SOF_CMD_TYPE(0x002) +#define SOF_IPC_COMP_SET_DATA SOF_CMD_TYPE(0x003) +#define SOF_IPC_COMP_GET_DATA SOF_CMD_TYPE(0x004) + +/* DAI messages */ +#define SOF_IPC_DAI_CONFIG SOF_CMD_TYPE(0x001) +#define SOF_IPC_DAI_LOOPBACK SOF_CMD_TYPE(0x002) + +/* stream */ +#define SOF_IPC_STREAM_PCM_PARAMS SOF_CMD_TYPE(0x001) +#define SOF_IPC_STREAM_PCM_PARAMS_REPLY SOF_CMD_TYPE(0x002) +#define SOF_IPC_STREAM_PCM_FREE SOF_CMD_TYPE(0x003) +#define SOF_IPC_STREAM_TRIG_START SOF_CMD_TYPE(0x004) +#define SOF_IPC_STREAM_TRIG_STOP SOF_CMD_TYPE(0x005) +#define SOF_IPC_STREAM_TRIG_PAUSE SOF_CMD_TYPE(0x006) +#define SOF_IPC_STREAM_TRIG_RELEASE SOF_CMD_TYPE(0x007) +#define SOF_IPC_STREAM_TRIG_DRAIN SOF_CMD_TYPE(0x008) +#define SOF_IPC_STREAM_TRIG_XRUN SOF_CMD_TYPE(0x009) +#define SOF_IPC_STREAM_POSITION SOF_CMD_TYPE(0x00a) +#define SOF_IPC_STREAM_VORBIS_PARAMS SOF_CMD_TYPE(0x010) +#define SOF_IPC_STREAM_VORBIS_FREE SOF_CMD_TYPE(0x011) + +/* trace and debug */ +#define SOF_IPC_TRACE_DMA_PARAMS SOF_CMD_TYPE(0x001) +#define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002) + +/* Get message component id */ +#define SOF_IPC_MESSAGE_ID(x) ((x) & 0xffff) + +/* maximum message size for mailbox Tx/Rx */ +#define SOF_IPC_MSG_MAX_SIZE 384 + +/* + * SOF panic codes + */ +#define SOF_IPC_PANIC_MAGIC 0x0dead000 +#define SOF_IPC_PANIC_MAGIC_MASK 0x0ffff000 +#define SOF_IPC_PANIC_CODE_MASK 0x00000fff +#define SOF_IPC_PANIC_MEM (SOF_IPC_PANIC_MAGIC | 0x0) +#define SOF_IPC_PANIC_WORK (SOF_IPC_PANIC_MAGIC | 0x1) +#define SOF_IPC_PANIC_IPC (SOF_IPC_PANIC_MAGIC | 0x2) +#define SOF_IPC_PANIC_ARCH (SOF_IPC_PANIC_MAGIC | 0x3) +#define SOF_IPC_PANIC_PLATFORM (SOF_IPC_PANIC_MAGIC | 0x4) +#define SOF_IPC_PANIC_TASK (SOF_IPC_PANIC_MAGIC | 0x5) +#define SOF_IPC_PANIC_EXCEPTION (SOF_IPC_PANIC_MAGIC | 0x6) +#define SOF_IPC_PANIC_DEADLOCK (SOF_IPC_PANIC_MAGIC | 0x7) +#define SOF_IPC_PANIC_STACK (SOF_IPC_PANIC_MAGIC | 0x8) +#define SOF_IPC_PANIC_IDLE (SOF_IPC_PANIC_MAGIC | 0x9) +#define SOF_IPC_PANIC_WFI (SOF_IPC_PANIC_MAGIC | 0xa) + +/* + * SOF memory capabilities, add new ones at the end + */ +#define SOF_MEM_CAPS_RAM (1 << 0) +#define SOF_MEM_CAPS_ROM (1 << 1) +#define SOF_MEM_CAPS_EXT (1 << 2) /**< external */ +#define SOF_MEM_CAPS_LP (1 << 3) /**< low power */ +#define SOF_MEM_CAPS_HP (1 << 4) /**< high performance */ +#define SOF_MEM_CAPS_DMA (1 << 5) /**< DMA'able */ +#define SOF_MEM_CAPS_CACHE (1 << 6) /**< cacheable */ +#define SOF_MEM_CAPS_EXEC (1 << 7) /**< executable */ + +/* + * Command Header - Header for all IPC. Identifies IPC message. + * The size can be greater than the structure size and that means there is + * extended bespoke data beyond the end of the structure including variable + * arrays. + */ + +struct sof_ipc_hdr { + uint32_t cmd; /**< SOF_IPC_GLB_ + cmd */ + uint32_t size; /**< size of structure */ +} __packed; + +/* + * Generic reply message. Some commands override this with their own reply + * types that must include this at start. + */ +struct sof_ipc_reply { + struct sof_ipc_hdr hdr; + int32_t error; /**< negative error numbers */ +} __packed; + +/* + * Compound commands - SOF_IPC_GLB_COMPOUND. + * + * Compound commands are sent to the DSP as a single IPC operation. The + * commands are split into blocks and each block has a header. This header + * identifies the command type and the number of commands before the next + * header. + */ + +struct sof_ipc_compound_hdr { + struct sof_ipc_hdr hdr; + uint32_t count; /**< count of 0 means end of compound sequence */ +} __packed; + +/** @}*/ + +#endif diff --git a/include/sound/sof/info.h b/include/sound/sof/info.h new file mode 100644 index 00000000000000..e7c16ac90fa62c --- /dev/null +++ b/include/sound/sof/info.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_INFO_H__ +#define __INCLUDE_SOUND_SOF_INFO_H__ + +#include +#include + +/* + * Firmware boot and version + */ + +#define SOF_IPC_MAX_ELEMS 16 + +/* extended data types that can be appended onto end of sof_ipc_fw_ready */ +enum sof_ipc_ext_data { + SOF_IPC_EXT_DMA_BUFFER = 0, + SOF_IPC_EXT_WINDOW, +}; + +/* FW version - SOF_IPC_GLB_VERSION */ +struct sof_ipc_fw_version { + uint16_t major; + uint16_t minor; + uint16_t micro; + uint16_t build; + uint8_t date[12]; + uint8_t time[10]; + uint8_t tag[6]; + uint32_t abi_version; + + /* reserved for future use */ + uint32_t reserved[4]; +} __packed; + +/* FW ready Message - sent by firmware when boot has completed */ +struct sof_ipc_fw_ready { + struct sof_ipc_hdr hdr; + uint32_t dspbox_offset; /* dsp initiated IPC mailbox */ + uint32_t hostbox_offset; /* host initiated IPC mailbox */ + uint32_t dspbox_size; + uint32_t hostbox_size; + struct sof_ipc_fw_version version; + + /* Miscellaneous debug flags showing build/debug features enabled */ + union { + uint64_t reserved; + uint64_t build:1; + uint64_t locks:1; + uint64_t locks_verbose:1; + } debug; + + /* reserved for future use */ + uint32_t reserved[4]; +} __packed; + +/* + * Extended Firmware data. All optional, depends on platform/arch. + */ +enum sof_ipc_region { + SOF_IPC_REGION_DOWNBOX = 0, + SOF_IPC_REGION_UPBOX, + SOF_IPC_REGION_TRACE, + SOF_IPC_REGION_DEBUG, + SOF_IPC_REGION_STREAM, + SOF_IPC_REGION_REGS, + SOF_IPC_REGION_EXCEPTION, +}; + +struct sof_ipc_ext_data_hdr { + struct sof_ipc_hdr hdr; + uint32_t type; /**< SOF_IPC_EXT_ */ +} __packed; + +struct sof_ipc_dma_buffer_elem { + uint32_t type; /**< SOF_IPC_REGION_ */ + uint32_t id; /**< platform specific - used to map to host memory */ + struct sof_ipc_host_buffer buffer; +} __packed; + +/* extended data DMA buffers for IPC, trace and debug */ +struct sof_ipc_dma_buffer_data { + struct sof_ipc_ext_data_hdr ext_hdr; + uint32_t num_buffers; + + /* host files in buffer[n].buffer */ + struct sof_ipc_dma_buffer_elem buffer[]; +} __packed; + +struct sof_ipc_window_elem { + uint32_t type; /**< SOF_IPC_REGION_ */ + uint32_t id; /**< platform specific - used to map to host memory */ + uint32_t flags; /**< R, W, RW, etc - to define */ + uint32_t size; /**< size of region in bytes */ + /* offset in window region as windows can be partitioned */ + uint32_t offset; +} __packed; + +/* extended data memory windows for IPC, trace and debug */ +struct sof_ipc_window { + struct sof_ipc_ext_data_hdr ext_hdr; + uint32_t num_windows; + struct sof_ipc_window_elem window[]; +} __packed; + +#endif diff --git a/include/sound/sof/pm.h b/include/sound/sof/pm.h new file mode 100644 index 00000000000000..76a0529338999a --- /dev/null +++ b/include/sound/sof/pm.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_PM_H__ +#define __INCLUDE_SOUND_SOF_PM_H__ + +#include + +/* + * PM + */ + +/* PM context element */ +struct sof_ipc_pm_ctx_elem { + uint32_t type; + uint32_t size; + uint64_t addr; +} __packed; + +/* + * PM context - SOF_IPC_PM_CTX_SAVE, SOF_IPC_PM_CTX_RESTORE, + * SOF_IPC_PM_CTX_SIZE + */ +struct sof_ipc_pm_ctx { + struct sof_ipc_hdr hdr; + struct sof_ipc_host_buffer buffer; + uint32_t num_elems; + uint32_t size; + + /* reserved for future use */ + uint32_t reserved[8]; + + struct sof_ipc_pm_ctx_elem elems[]; +} __packed; + +/* enable or disable cores - SOF_IPC_PM_CORE_ENABLE */ +struct sof_ipc_pm_core_config { + struct sof_ipc_hdr hdr; + uint32_t enable_mask; +} __packed; + +#endif diff --git a/include/sound/sof/stream.h b/include/sound/sof/stream.h new file mode 100644 index 00000000000000..ce43e1bfdb83ed --- /dev/null +++ b/include/sound/sof/stream.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_STREAM_H__ +#define __INCLUDE_SOUND_SOF_STREAM_H__ + +#include + +/* + * Stream configuration. + */ + +#define SOF_IPC_MAX_CHANNELS 8 + +/* common sample rates for use in masks */ +#define SOF_RATE_8000 (1 << 0) /**< 8000Hz */ +#define SOF_RATE_11025 (1 << 1) /**< 11025Hz */ +#define SOF_RATE_12000 (1 << 2) /**< 12000Hz */ +#define SOF_RATE_16000 (1 << 3) /**< 16000Hz */ +#define SOF_RATE_22050 (1 << 4) /**< 22050Hz */ +#define SOF_RATE_24000 (1 << 5) /**< 24000Hz */ +#define SOF_RATE_32000 (1 << 6) /**< 32000Hz */ +#define SOF_RATE_44100 (1 << 7) /**< 44100Hz */ +#define SOF_RATE_48000 (1 << 8) /**< 48000Hz */ +#define SOF_RATE_64000 (1 << 9) /**< 64000Hz */ +#define SOF_RATE_88200 (1 << 10) /**< 88200Hz */ +#define SOF_RATE_96000 (1 << 11) /**< 96000Hz */ +#define SOF_RATE_176400 (1 << 12) /**< 176400Hz */ +#define SOF_RATE_192000 (1 << 13) /**< 192000Hz */ + +/* continuous and non-standard rates for flexibility */ +#define SOF_RATE_CONTINUOUS (1 << 30) /**< range */ +#define SOF_RATE_KNOT (1 << 31) /**< non-continuous */ + +/* stream PCM frame format */ +enum sof_ipc_frame { + SOF_IPC_FRAME_S16_LE = 0, + SOF_IPC_FRAME_S24_4LE, + SOF_IPC_FRAME_S32_LE, + SOF_IPC_FRAME_FLOAT, + /* other formats here */ +}; + +/* stream buffer format */ +enum sof_ipc_buffer_format { + SOF_IPC_BUFFER_INTERLEAVED, + SOF_IPC_BUFFER_NONINTERLEAVED, + /* other formats here */ +}; + +/* stream direction */ +enum sof_ipc_stream_direction { + SOF_IPC_STREAM_PLAYBACK = 0, + SOF_IPC_STREAM_CAPTURE, +}; + +/* stream ring info */ +struct sof_ipc_host_buffer { + uint32_t phy_addr; + uint32_t pages; + uint32_t size; + uint32_t offset; +} __packed; + +struct sof_ipc_stream_params { + struct sof_ipc_host_buffer buffer; + uint32_t direction; /**< enum sof_ipc_stream_directio */ + uint32_t frame_fmt; /**< enum sof_ipc_frame */ + uint32_t buffer_fmt; /**< enum sof_ipc_buffer_format */ + uint32_t rate; + uint16_t stream_tag; + uint16_t channels; + uint16_t sample_valid_bytes; + uint16_t sample_container_bytes; + + /* for notifying host period has completed - 0 means no period IRQ */ + uint32_t host_period_bytes; + + uint16_t chmap[SOF_IPC_MAX_CHANNELS]; /**< channel map - SOF_CHMAP_ */ +} __packed; + +/* PCM params info - SOF_IPC_STREAM_PCM_PARAMS */ +struct sof_ipc_pcm_params { + struct sof_ipc_hdr hdr; + uint32_t comp_id; + struct sof_ipc_stream_params params; +} __packed; + +/* PCM params info reply - SOF_IPC_STREAM_PCM_PARAMS_REPLY */ +struct sof_ipc_pcm_params_reply { + struct sof_ipc_reply rhdr; + uint32_t comp_id; + uint32_t posn_offset; +} __packed; + +/* free stream - SOF_IPC_STREAM_PCM_PARAMS */ +struct sof_ipc_stream { + struct sof_ipc_hdr hdr; + uint32_t comp_id; +} __packed; + +/* flags indicating which time stamps are in sync with each other */ +#define SOF_TIME_HOST_SYNC (1 << 0) +#define SOF_TIME_DAI_SYNC (1 << 1) +#define SOF_TIME_WALL_SYNC (1 << 2) +#define SOF_TIME_STAMP_SYNC (1 << 3) + +/* flags indicating which time stamps are valid */ +#define SOF_TIME_HOST_VALID (1 << 8) +#define SOF_TIME_DAI_VALID (1 << 9) +#define SOF_TIME_WALL_VALID (1 << 10) +#define SOF_TIME_STAMP_VALID (1 << 11) + +/* flags indicating time stamps are 64bit else 3use low 32bit */ +#define SOF_TIME_HOST_64 (1 << 16) +#define SOF_TIME_DAI_64 (1 << 17) +#define SOF_TIME_WALL_64 (1 << 18) +#define SOF_TIME_STAMP_64 (1 << 19) + +struct sof_ipc_stream_posn { + struct sof_ipc_reply rhdr; + uint32_t comp_id; /**< host component ID */ + uint32_t flags; /**< SOF_TIME_ */ + uint32_t wallclock_hz; /**< frequency of wallclock in Hz */ + uint32_t timestamp_ns; /**< resolution of timestamp in ns */ + uint64_t host_posn; /**< host DMA position in bytes */ + uint64_t dai_posn; /**< DAI DMA position in bytes */ + uint64_t comp_posn; /**< comp position in bytes */ + uint64_t wallclock; /**< audio wall clock */ + uint64_t timestamp; /**< system time stamp */ + uint32_t xrun_comp_id; /**< comp ID of XRUN component */ + int32_t xrun_size; /**< XRUN size in bytes */ +} __packed; + +#endif diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h new file mode 100644 index 00000000000000..166ead19bf6d15 --- /dev/null +++ b/include/sound/sof/topology.h @@ -0,0 +1,242 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_TOPOLOGY_H__ +#define __INCLUDE_SOUND_SOF_TOPOLOGY_H__ + +#include + +/* + * Component + */ + +/* types of component */ +enum sof_comp_type { + SOF_COMP_NONE = 0, + SOF_COMP_HOST, + SOF_COMP_DAI, + SOF_COMP_SG_HOST, /**< scatter gather variant */ + SOF_COMP_SG_DAI, /**< scatter gather variant */ + SOF_COMP_VOLUME, + SOF_COMP_MIXER, + SOF_COMP_MUX, + SOF_COMP_SRC, + SOF_COMP_SPLITTER, + SOF_COMP_TONE, + SOF_COMP_SWITCH, + SOF_COMP_BUFFER, + SOF_COMP_EQ_IIR, + SOF_COMP_EQ_FIR, + SOF_COMP_FILEREAD, /**< host test based file IO */ + SOF_COMP_FILEWRITE, /**< host test based file IO */ +}; + +/* XRUN action for component */ +#define SOF_XRUN_STOP 1 /**< stop stream */ +#define SOF_XRUN_UNDER_ZERO 2 /**< send 0s to sink */ +#define SOF_XRUN_OVER_NULL 4 /**< send data to NULL */ + +/* create new generic component - SOF_IPC_TPLG_COMP_NEW */ +struct sof_ipc_comp { + struct sof_ipc_hdr hdr; + uint32_t id; + enum sof_comp_type type; + uint32_t pipeline_id; + + /* reserved for future use */ + uint32_t reserved[2]; +} __packed; + +/* + * Component Buffers + */ + +/* create new component buffer - SOF_IPC_TPLG_BUFFER_NEW */ +struct sof_ipc_buffer { + struct sof_ipc_comp comp; + uint32_t size; /**< buffer size in bytes */ + uint32_t caps; /**< SOF_MEM_CAPS_ */ +} __packed; + +/* generic component config data - must always be after struct sof_ipc_comp */ +struct sof_ipc_comp_config { + uint32_t periods_sink; /**< 0 means variable */ + uint32_t periods_source; /**< 0 means variable */ + uint32_t preload_count; /**< how many periods to preload */ + uint32_t frame_fmt; /**< SOF_IPC_FRAME_ */ + uint32_t xrun_action; + + /* reserved for future use */ + uint32_t reserved[2]; +} __packed; + +/* generic host component */ +struct sof_ipc_comp_host { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + uint32_t direction; /**< SOF_IPC_STREAM_ */ + uint32_t no_irq; /**< don't send periodic IRQ to host/DSP */ + uint32_t dmac_config; /**< DMA engine specific */ +} __packed; + +/* generic DAI component */ +struct sof_ipc_comp_dai { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + uint32_t direction; /**< SOF_IPC_STREAM_ */ + uint32_t dai_index; /**< index of this type dai */ + uint32_t type; /**< DAI type - SOF_DAI_ */ + uint32_t dmac_config; /**< DMA engine specific */ +} __packed; + +/* generic mixer component */ +struct sof_ipc_comp_mixer { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; +} __packed; + +/* volume ramping types */ +enum sof_volume_ramp { + SOF_VOLUME_LINEAR = 0, + SOF_VOLUME_LOG, + SOF_VOLUME_LINEAR_ZC, + SOF_VOLUME_LOG_ZC, +}; + +/* generic volume component */ +struct sof_ipc_comp_volume { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + uint32_t channels; + uint32_t min_value; + uint32_t max_value; + uint32_t ramp; /**< SOF_VOLUME_ */ + uint32_t initial_ramp; /**< ramp space in ms */ +} __packed; + +/* generic SRC component */ +struct sof_ipc_comp_src { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + /* either source or sink rate must be non zero */ + uint32_t source_rate; /**< source rate or 0 for variable */ + uint32_t sink_rate; /**< sink rate or 0 for variable */ + uint32_t rate_mask; /**< SOF_RATE_ supported rates */ +} __packed; + +/* generic MUX component */ +struct sof_ipc_comp_mux { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; +} __packed; + +/* generic tone generator component */ +struct sof_ipc_comp_tone { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + int32_t sample_rate; + int32_t frequency; + int32_t amplitude; + int32_t freq_mult; + int32_t ampl_mult; + int32_t length; + int32_t period; + int32_t repeats; + int32_t ramp_step; +} __packed; + +/** \brief Types of EFFECT */ +enum sof_ipc_effect_type { + SOF_EFFECT_NONE = 0, /**< None */ + SOF_EFFECT_INTEL_EQFIR, /**< Intel FIR */ + SOF_EFFECT_INTEL_EQIIR, /**< Intel IIR */ +}; + +/* general purpose EFFECT configuration */ +struct sof_ipc_comp_effect { + uint32_t type; /** sof_ipc_effect_type */ +} __packed; + +/* FIR equalizer component */ +struct sof_ipc_comp_eq_fir { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + uint32_t size; + + /* reserved for future use */ + uint32_t reserved[8]; + + unsigned char data[0]; +} __packed; + +/* IIR equalizer component */ +struct sof_ipc_comp_eq_iir { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + uint32_t size; + + /* reserved for future use */ + uint32_t reserved[8]; + + unsigned char data[0]; +} __packed; + +/* frees components, buffers and pipelines + * SOF_IPC_TPLG_COMP_FREE, SOF_IPC_TPLG_PIPE_FREE, SOF_IPC_TPLG_BUFFER_FREE + */ +struct sof_ipc_free { + struct sof_ipc_hdr hdr; + uint32_t id; +} __packed; + +struct sof_ipc_comp_reply { + struct sof_ipc_reply rhdr; + uint32_t id; + uint32_t offset; +} __packed; + +/* + * Pipeline + */ + +/* new pipeline - SOF_IPC_TPLG_PIPE_NEW */ +struct sof_ipc_pipe_new { + struct sof_ipc_hdr hdr; + uint32_t comp_id; /**< component id for pipeline */ + uint32_t pipeline_id; /**< pipeline id */ + uint32_t sched_id; /**< sheduling component id */ + uint32_t core; /**< core we run on */ + uint32_t deadline; /**< execution completion deadline in us*/ + uint32_t priority; /**< priority level 0 (low) to 10 (max) */ + uint32_t period_mips; /**< worst case instruction count per period */ + uint32_t frames_per_sched;/**< output frames of pipeline, 0 is variable */ + uint32_t xrun_limit_usecs; /**< report xruns greater than limit */ + + /* non zero if timer scheduled, otherwise DAI DMA irq scheduled */ + uint32_t timer_delay; +} __packed; + +/* pipeline construction complete - SOF_IPC_TPLG_PIPE_COMPLETE */ +struct sof_ipc_pipe_ready { + struct sof_ipc_hdr hdr; + uint32_t comp_id; +} __packed; + +struct sof_ipc_pipe_free { + struct sof_ipc_hdr hdr; + uint32_t comp_id; +} __packed; + +/* connect two components in pipeline - SOF_IPC_TPLG_COMP_CONNECT */ +struct sof_ipc_pipe_comp_connect { + struct sof_ipc_hdr hdr; + uint32_t source_id; + uint32_t sink_id; +} __packed; + +#endif diff --git a/include/sound/sof/trace.h b/include/sound/sof/trace.h new file mode 100644 index 00000000000000..7493059d6ef0be --- /dev/null +++ b/include/sound/sof/trace.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_TRACE_H__ +#define __INCLUDE_SOUND_SOF_TRACE_H__ + +#include +#include + +/* + * DMA for Trace + */ + +#define SOF_TRACE_FILENAME_SIZE 32 + +/* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS */ +struct sof_ipc_dma_trace_params { + struct sof_ipc_hdr hdr; + struct sof_ipc_host_buffer buffer; + uint32_t stream_tag; +} __packed; + +/* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS */ +struct sof_ipc_dma_trace_posn { + struct sof_ipc_reply rhdr; + uint32_t host_offset; /* Offset of DMA host buffer */ + uint32_t overflow; /* overflow bytes if any */ + uint32_t messages; /* total trace messages */ +} __packed; + +/* + * Commom debug + */ + +/* panic info include filename and line number */ +struct sof_ipc_panic_info { + char filename[SOF_TRACE_FILENAME_SIZE]; + uint32_t linenum; +} __packed; + +#endif diff --git a/include/sound/sof/xtensa.h b/include/sound/sof/xtensa.h new file mode 100644 index 00000000000000..e7c36a5c667d2d --- /dev/null +++ b/include/sound/sof/xtensa.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_XTENSA_H__ +#define __INCLUDE_SOUND_SOF_XTENSA_H__ + +/* + * Architecture specific debug + */ + +/* Xtensa Firmware Oops data */ +struct sof_ipc_dsp_oops_xtensa { + uint32_t exccause; + uint32_t excvaddr; + uint32_t ps; + uint32_t epc1; + uint32_t epc2; + uint32_t epc3; + uint32_t epc4; + uint32_t epc5; + uint32_t epc6; + uint32_t epc7; + uint32_t eps2; + uint32_t eps3; + uint32_t eps4; + uint32_t eps5; + uint32_t eps6; + uint32_t eps7; + uint32_t depc; + uint32_t intenable; + uint32_t interrupt; + uint32_t sar; + uint32_t stack; +} __packed; + +#endif diff --git a/include/uapi/sound/sof-abi.h b/include/uapi/sound/sof-abi.h deleted file mode 100644 index 88c61f8c2a4a7a..00000000000000 --- a/include/uapi/sound/sof-abi.h +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - */ - -#ifndef __INCLUDE_UAPI_ABI_H__ -#define __INCLUDE_UAPI_ABI_H__ - -#define SOF_ABI_VER(major, minor, micro) \ - (((major) << 8) | ((minor) << 4) | (micro)) -#define SOF_ABI_VERSION_MAJOR(version) (((version) >> 8) & 0xff) -#define SOF_ABI_VERSION_MINOR(version) (((version) >> 4) & 0xf) -#define SOF_ABI_VERSION_MICRO(version) ((version) & 0xf) -#define SOF_ABI_VERSION_INCOMPATIBLE(sof_ver, client_ver) \ - (SOF_ABI_VERSION_MAJOR((sof_ver)) != \ - SOF_ABI_VERSION_MAJOR((client_ver)) || \ - ( \ - SOF_ABI_VERSION_MAJOR((sof_ver)) == \ - SOF_ABI_VERSION_MAJOR((client_ver)) && \ - SOF_ABI_VERSION_MINOR((sof_ver)) != \ - SOF_ABI_VERSION_MINOR((client_ver)) \ - ) \ - ) - -#define SOF_ABI_MAJOR 1 -#define SOF_ABI_MINOR 0 -#define SOF_ABI_MICRO 0 - -#define SOF_ABI_VERSION SOF_ABI_VER(SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_MICRO) - -#define SOF_ABI_MAGIC 0x00464F53 /* "SOF\0" */ - -/* - * Header for all non IPC ABI data. Identifies data type, size and ABI. - * Used by any bespoke component data structures or binary blobs. - */ - -struct sof_abi_hdr { - uint32_t magic; /* 'S', 'O', 'F', '\0' */ - uint32_t type; /* component specific type */ - uint32_t size; /* size in bytes of data excluding this struct */ - uint32_t abi; /* SOF ABI version */ - uint32_t comp_abi; /* component specific ABI version */ - char data[0]; -} __attribute__((packed)); - -#endif diff --git a/include/uapi/sound/sof-ipc.h b/include/uapi/sound/sof-ipc.h deleted file mode 100644 index 5b042079ea9595..00000000000000 --- a/include/uapi/sound/sof-ipc.h +++ /dev/null @@ -1,991 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ - -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood - * Keyon Jie - */ - -#ifndef __INCLUDE_UAPI_SOF_IPC_H__ -#define __INCLUDE_UAPI_SOF_IPC_H__ - -#include - -/* - * IPC messages have a prefixed 32 bit identifier made up as follows :- - * - * 0xGCCCNNNN where - * G is global cmd type (4 bits) - * C is command type (12 bits) - * I is the ID number (16 bits) - monotonic and overflows - * - * This is sent at the start of the IPM message in the mailbox. Messages should - * not be sent in the doorbell (special exceptions for firmware . - */ - -/* Global Message - Generic */ -#define SOF_GLB_TYPE_SHIFT 28 -#define SOF_GLB_TYPE_MASK (0xf << SOF_GLB_TYPE_SHIFT) -#define SOF_GLB_TYPE(x) ((x) << SOF_GLB_TYPE_SHIFT) - -/* Command Message - Generic */ -#define SOF_CMD_TYPE_SHIFT 16 -#define SOF_CMD_TYPE_MASK (0xfff << SOF_CMD_TYPE_SHIFT) -#define SOF_CMD_TYPE(x) ((x) << SOF_CMD_TYPE_SHIFT) - -/* Global Message Types */ -#define SOF_IPC_GLB_REPLY SOF_GLB_TYPE(0x1U) -#define SOF_IPC_GLB_COMPOUND SOF_GLB_TYPE(0x2U) -#define SOF_IPC_GLB_TPLG_MSG SOF_GLB_TYPE(0x3U) -#define SOF_IPC_GLB_PM_MSG SOF_GLB_TYPE(0x4U) -#define SOF_IPC_GLB_COMP_MSG SOF_GLB_TYPE(0x5U) -#define SOF_IPC_GLB_STREAM_MSG SOF_GLB_TYPE(0x6U) -#define SOF_IPC_FW_READY SOF_GLB_TYPE(0x7U) -#define SOF_IPC_GLB_DAI_MSG SOF_GLB_TYPE(0x8U) -#define SOF_IPC_GLB_TRACE_MSG SOF_GLB_TYPE(0x9U) - -/* - * DSP Command Message Types - */ - -/* topology */ -#define SOF_IPC_TPLG_COMP_NEW SOF_CMD_TYPE(0x001) -#define SOF_IPC_TPLG_COMP_FREE SOF_CMD_TYPE(0x002) -#define SOF_IPC_TPLG_COMP_CONNECT SOF_CMD_TYPE(0x003) -#define SOF_IPC_TPLG_PIPE_NEW SOF_CMD_TYPE(0x010) -#define SOF_IPC_TPLG_PIPE_FREE SOF_CMD_TYPE(0x011) -#define SOF_IPC_TPLG_PIPE_CONNECT SOF_CMD_TYPE(0x012) -#define SOF_IPC_TPLG_PIPE_COMPLETE SOF_CMD_TYPE(0x013) -#define SOF_IPC_TPLG_BUFFER_NEW SOF_CMD_TYPE(0x020) -#define SOF_IPC_TPLG_BUFFER_FREE SOF_CMD_TYPE(0x021) - -/* PM */ -#define SOF_IPC_PM_CTX_SAVE SOF_CMD_TYPE(0x001) -#define SOF_IPC_PM_CTX_RESTORE SOF_CMD_TYPE(0x002) -#define SOF_IPC_PM_CTX_SIZE SOF_CMD_TYPE(0x003) -#define SOF_IPC_PM_CLK_SET SOF_CMD_TYPE(0x004) -#define SOF_IPC_PM_CLK_GET SOF_CMD_TYPE(0x005) -#define SOF_IPC_PM_CLK_REQ SOF_CMD_TYPE(0x006) -#define SOF_IPC_PM_CORE_ENABLE SOF_CMD_TYPE(0x007) - -/* component runtime config - multiple different types */ -#define SOF_IPC_COMP_SET_VALUE SOF_CMD_TYPE(0x001) -#define SOF_IPC_COMP_GET_VALUE SOF_CMD_TYPE(0x002) -#define SOF_IPC_COMP_SET_DATA SOF_CMD_TYPE(0x003) -#define SOF_IPC_COMP_GET_DATA SOF_CMD_TYPE(0x004) - -/* DAI messages */ -#define SOF_IPC_DAI_CONFIG SOF_CMD_TYPE(0x001) -#define SOF_IPC_DAI_LOOPBACK SOF_CMD_TYPE(0x002) - -/* stream */ -#define SOF_IPC_STREAM_PCM_PARAMS SOF_CMD_TYPE(0x001) -#define SOF_IPC_STREAM_PCM_PARAMS_REPLY SOF_CMD_TYPE(0x002) -#define SOF_IPC_STREAM_PCM_FREE SOF_CMD_TYPE(0x003) -#define SOF_IPC_STREAM_TRIG_START SOF_CMD_TYPE(0x004) -#define SOF_IPC_STREAM_TRIG_STOP SOF_CMD_TYPE(0x005) -#define SOF_IPC_STREAM_TRIG_PAUSE SOF_CMD_TYPE(0x006) -#define SOF_IPC_STREAM_TRIG_RELEASE SOF_CMD_TYPE(0x007) -#define SOF_IPC_STREAM_TRIG_DRAIN SOF_CMD_TYPE(0x008) -#define SOF_IPC_STREAM_TRIG_XRUN SOF_CMD_TYPE(0x009) -#define SOF_IPC_STREAM_POSITION SOF_CMD_TYPE(0x00a) -#define SOF_IPC_STREAM_VORBIS_PARAMS SOF_CMD_TYPE(0x010) -#define SOF_IPC_STREAM_VORBIS_FREE SOF_CMD_TYPE(0x011) - -/* trace and debug */ -#define SOF_IPC_TRACE_DMA_PARAMS SOF_CMD_TYPE(0x001) -#define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002) - -/* Get message component id */ -#define SOF_IPC_MESSAGE_ID(x) ((x) & 0xffff) - -/* maximum message size for mailbox Tx/Rx */ -#define SOF_IPC_MSG_MAX_SIZE 384 - -/* - * SOF panic codes - */ -#define SOF_IPC_PANIC_MAGIC 0x0dead000 -#define SOF_IPC_PANIC_MAGIC_MASK 0x0ffff000 -#define SOF_IPC_PANIC_CODE_MASK 0x00000fff -#define SOF_IPC_PANIC_MEM (SOF_IPC_PANIC_MAGIC | 0x0) -#define SOF_IPC_PANIC_WORK (SOF_IPC_PANIC_MAGIC | 0x1) -#define SOF_IPC_PANIC_IPC (SOF_IPC_PANIC_MAGIC | 0x2) -#define SOF_IPC_PANIC_ARCH (SOF_IPC_PANIC_MAGIC | 0x3) -#define SOF_IPC_PANIC_PLATFORM (SOF_IPC_PANIC_MAGIC | 0x4) -#define SOF_IPC_PANIC_TASK (SOF_IPC_PANIC_MAGIC | 0x5) -#define SOF_IPC_PANIC_EXCEPTION (SOF_IPC_PANIC_MAGIC | 0x6) -#define SOF_IPC_PANIC_DEADLOCK (SOF_IPC_PANIC_MAGIC | 0x7) -#define SOF_IPC_PANIC_STACK (SOF_IPC_PANIC_MAGIC | 0x8) -#define SOF_IPC_PANIC_IDLE (SOF_IPC_PANIC_MAGIC | 0x9) -#define SOF_IPC_PANIC_WFI (SOF_IPC_PANIC_MAGIC | 0xa) - -/* - * SOF memory capabilities, add new ones at the end - */ -#define SOF_MEM_CAPS_RAM (1 << 0) -#define SOF_MEM_CAPS_ROM (1 << 1) -#define SOF_MEM_CAPS_EXT (1 << 2) /* external */ -#define SOF_MEM_CAPS_LP (1 << 3) /* low power */ -#define SOF_MEM_CAPS_HP (1 << 4) /* high performance */ -#define SOF_MEM_CAPS_DMA (1 << 5) /* DMA'able */ -#define SOF_MEM_CAPS_CACHE (1 << 6) /* cacheable */ -#define SOF_MEM_CAPS_EXEC (1 << 7) /* executable */ - -/* - * Command Header - Header for all IPC. Identifies IPC message. - * The size can be greater than the structure size and that means there is - * extended bespoke data beyond the end of the structure including variable - * arrays. - */ - -struct sof_ipc_hdr { - uint32_t cmd; /* SOF_IPC_GLB_ + cmd */ - uint32_t size; /* size of structure */ -} __attribute__((packed)); - -/* - * Generic reply message. Some commands override this with their own reply - * types that must include this at start. - */ -struct sof_ipc_reply { - struct sof_ipc_hdr hdr; - int32_t error; /* negative error numbers */ -} __attribute__((packed)); - -/* - * Compound commands - SOF_IPC_GLB_COMPOUND. - * - * Compound commands are sent to the DSP as a single IPC operation. The - * commands are split into blocks and each block has a header. This header - * identifies the command type and the number of commands before the next - * header. - */ - -struct sof_ipc_compound_hdr { - struct sof_ipc_hdr hdr; - uint32_t count; /* count of 0 means end of compound sequence */ -} __attribute__((packed)); - -/* - * DAI Configuration. - * - * Each different DAI type will have it's own structure and IPC cmd. - */ - -#define SOF_DAI_FMT_I2S 1 /* I2S mode */ -#define SOF_DAI_FMT_RIGHT_J 2 /* Right Justified mode */ -#define SOF_DAI_FMT_LEFT_J 3 /* Left Justified mode */ -#define SOF_DAI_FMT_DSP_A 4 /* L data MSB after FRM LRC */ -#define SOF_DAI_FMT_DSP_B 5 /* L data MSB during FRM LRC */ -#define SOF_DAI_FMT_PDM 6 /* Pulse density modulation */ - -#define SOF_DAI_FMT_CONT (1 << 4) /* continuous clock */ -#define SOF_DAI_FMT_GATED (0 << 4) /* clock is gated */ - -#define SOF_DAI_FMT_NB_NF (0 << 8) /* normal bit clock + frame */ -#define SOF_DAI_FMT_NB_IF (2 << 8) /* normal BCLK + inv FRM */ -#define SOF_DAI_FMT_IB_NF (3 << 8) /* invert BCLK + nor FRM */ -#define SOF_DAI_FMT_IB_IF (4 << 8) /* invert BCLK + FRM */ - -#define SOF_DAI_FMT_CBM_CFM (0 << 12) /* codec clk & FRM master */ -#define SOF_DAI_FMT_CBS_CFM (2 << 12) /* codec clk slave & FRM master */ -#define SOF_DAI_FMT_CBM_CFS (3 << 12) /* codec clk master & frame slave */ -#define SOF_DAI_FMT_CBS_CFS (4 << 12) /* codec clk & FRM slave */ - -#define SOF_DAI_FMT_FORMAT_MASK 0x000f -#define SOF_DAI_FMT_CLOCK_MASK 0x00f0 -#define SOF_DAI_FMT_INV_MASK 0x0f00 -#define SOF_DAI_FMT_MASTER_MASK 0xf000 - - /* ssc1: TINTE */ -#define SOF_DAI_INTEL_SSP_QUIRK_TINTE (1 << 0) - /* ssc1: PINTE */ -#define SOF_DAI_INTEL_SSP_QUIRK_PINTE (1 << 1) - /* ssc2: SMTATF */ -#define SOF_DAI_INTEL_SSP_QUIRK_SMTATF (1 << 2) - /* ssc2: MMRATF */ -#define SOF_DAI_INTEL_SSP_QUIRK_MMRATF (1 << 3) - /* ssc2: PSPSTWFDFD */ -#define SOF_DAI_INTEL_SSP_QUIRK_PSPSTWFDFD (1 << 4) - /* ssc2: PSPSRWFDFD */ -#define SOF_DAI_INTEL_SSP_QUIRK_PSPSRWFDFD (1 << 5) - /* here is the possibility to define others aux macros */ - -#define SOF_DAI_INTEL_SSP_FRAME_PULSE_WIDTH_MAX 38 -#define SOF_DAI_INTEL_SSP_SLOT_PADDING_MAX 31 - -/* SSP clocks control settings - * - * Macros for clks_control field in sof_ipc_dai_ssp_params struct. - */ - -/* mclk 0 disable */ -#define SOF_DAI_INTEL_SSP_MCLK_0_DISABLE BIT(0) -/* mclk 1 disable */ -#define SOF_DAI_INTEL_SSP_MCLK_1_DISABLE BIT(1) -/* mclk keep active */ -#define SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_KA BIT(2) -/* bclk keep active */ -#define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_KA BIT(3) -/* fs keep active */ -#define SOF_DAI_INTEL_SSP_CLKCTRL_FS_KA BIT(4) -/* bclk idle */ -#define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_IDLE_HIGH BIT(5) - -/** \brief Types of DAI */ -enum sof_ipc_dai_type { - SOF_DAI_INTEL_NONE = 0, /**< None */ - SOF_DAI_INTEL_SSP, /**< Intel SSP */ - SOF_DAI_INTEL_DMIC, /**< Intel DMIC */ - SOF_DAI_INTEL_HDA, /**< Intel HD/A */ -}; - -/* SSP Configuration Request - SOF_IPC_DAI_SSP_CONFIG */ -struct sof_ipc_dai_ssp_params { - uint16_t mode; // FIXME: do we need this? - uint16_t mclk_id; - - uint32_t mclk_rate; /* mclk frequency in Hz */ - uint32_t fsync_rate; /* fsync frequency in Hz */ - uint32_t bclk_rate; /* bclk frequency in Hz */ - - /* TDM */ - uint32_t tdm_slots; - uint32_t rx_slots; - uint32_t tx_slots; - - /* data */ - uint32_t sample_valid_bits; - uint16_t tdm_slot_width; - uint16_t reserved2; /* alignment */ - - /* MCLK */ - uint32_t mclk_direction; - - uint16_t frame_pulse_width; - uint16_t tdm_per_slot_padding_flag; - uint32_t clks_control; - uint32_t quirks; // FIXME: is 32 bits enough ? - /* private data, e.g. for quirks */ - //uint32_t pdata[10]; // FIXME: would really need ~16 u32 -} __attribute__((packed)); - -/* HDA Configuration Request - SOF_IPC_DAI_HDA_CONFIG */ -struct sof_ipc_dai_hda_params { - struct sof_ipc_hdr hdr; - /* TODO */ -} __attribute__((packed)); - -/* DMIC Configuration Request - SOF_IPC_DAI_DMIC_CONFIG */ - -/* This struct is defined per 2ch PDM controller available in the platform. - * Normally it is sufficient to set the used microphone specific enables to 1 - * and keep other parameters as zero. The customizations are: - * - * 1. If a device mixes different microphones types with different polarity - * and/or the absolute polarity matters the PCM signal from a microphone - * can be inverted with the controls. - * - * 2. If the microphones in a stereo pair do not appear in captured stream - * in desired order due to board schematics choises they can be swapped with - * the clk_edge parameter. - * - * 3. If PDM bit errors are seen in capture (poor quality) the skew parameter - * that delays the sampling time of data by half cycles of DMIC source clock - * can be tried for improvement. However there is no guarantee for this to fix - * data integrity problems. - */ -struct sof_ipc_dai_dmic_pdm_ctrl { - uint16_t id; /* PDM controller ID */ - uint16_t enable_mic_a; /* Use A (left) channel mic (0 or 1)*/ - uint16_t enable_mic_b; /* Use B (right) channel mic (0 or 1)*/ - uint16_t polarity_mic_a; /* Optionally invert mic A signal (0 or 1) */ - uint16_t polarity_mic_b; /* Optionally invert mic B signal (0 or 1) */ - uint16_t clk_edge; /* Optionally swap data clock edge (0 or 1) */ - uint16_t skew; /* Adjust PDM data sampling vs. clock (0..15) */ - uint16_t pad; /* Make sure the total size is 4 bytes aligned */ -} __attribute__((packed)); - -/* This struct contains the global settings for all 2ch PDM controllers. The - * version number used in configuration data is checked vs. version used by - * device driver src/drivers/dmic.c need to match. It is incremented from - * initial value 1 if updates done for the to driver would alter the operation - * of the microhone. - * - * Note: The microphone clock (pdmclk_min, pdmclk_max, duty_min, duty_max) - * parameters need to be set as defined in microphone data sheet. E.g. clock - * range 1.0 - 3.2 MHz is usually supported microphones. Some microphones are - * multi-mode capable and there may be denied mic clock frequencies between - * the modes. In such case set the clock range limits of the desired mode to - * avoid the driver to set clock to an illegal rate. - * - * The duty cycle could be set to 48-52% if not known. Generally these - * parameters can be altered within data sheet specified limits to match - * required audio application performance power. - * - * The microphone clock needs to be usually about 50-80 times the used audio - * sample rate. With highest sample rates above 48 kHz this can relaxed - * somewhat. - */ -struct sof_ipc_dai_dmic_params { - uint32_t driver_ipc_version; /* Version (1..N) */ - uint32_t pdmclk_min; /* Minimum microphone clock in Hz (100000..N) */ - uint32_t pdmclk_max; /* Maximum microphone clock in Hz (min...N) */ - uint32_t fifo_fs_a; /* FIFO A sample rate in Hz (8000..96000) */ - uint32_t fifo_fs_b; /* FIFO B sample rate in Hz (8000..96000) */ - uint16_t fifo_bits_a; /* FIFO A word length (16 or 32) */ - uint16_t fifo_bits_b; /* FIFO B word length (16 or 32) */ - uint16_t duty_min; /* Min. mic clock duty cycle in % (20..80) */ - uint16_t duty_max; /* Max. mic clock duty cycle in % (min..80) */ - uint32_t num_pdm_active; /* Number of active pdm controllers */ - /* variable number of pdm controller config */ - struct sof_ipc_dai_dmic_pdm_ctrl pdm[0]; -} __attribute__((packed)); - -/* general purpose DAI configuration */ -struct sof_ipc_dai_config { - struct sof_ipc_hdr hdr; - enum sof_ipc_dai_type type; - uint32_t dai_index; /* index of this type dai */ - - /* physical protocol and clocking */ - uint16_t format; /* SOF_DAI_FMT_ */ - uint16_t reserved; /* alignment */ - - /* HW specific data */ - union { - struct sof_ipc_dai_ssp_params ssp; - struct sof_ipc_dai_hda_params hda; - struct sof_ipc_dai_dmic_params dmic; - }; -}; - -/* - * Stream configuration. - */ - -#define SOF_IPC_MAX_CHANNELS 8 - -/* channel positions - uses same values as ALSA */ -enum sof_ipc_chmap { - SOF_CHMAP_UNKNOWN = 0, - SOF_CHMAP_NA, /* N/A, silent */ - SOF_CHMAP_MONO, /* mono stream */ - SOF_CHMAP_FL, /* front left */ - SOF_CHMAP_FR, /* front right */ - SOF_CHMAP_RL, /* rear left */ - SOF_CHMAP_RR, /* rear right */ - SOF_CHMAP_FC, /* front centre */ - SOF_CHMAP_LFE, /* LFE */ - SOF_CHMAP_SL, /* side left */ - SOF_CHMAP_SR, /* side right */ - SOF_CHMAP_RC, /* rear centre */ - SOF_CHMAP_FLC, /* front left centre */ - SOF_CHMAP_FRC, /* front right centre */ - SOF_CHMAP_RLC, /* rear left centre */ - SOF_CHMAP_RRC, /* rear right centre */ - SOF_CHMAP_FLW, /* front left wide */ - SOF_CHMAP_FRW, /* front right wide */ - SOF_CHMAP_FLH, /* front left high */ - SOF_CHMAP_FCH, /* front centre high */ - SOF_CHMAP_FRH, /* front right high */ - SOF_CHMAP_TC, /* top centre */ - SOF_CHMAP_TFL, /* top front left */ - SOF_CHMAP_TFR, /* top front right */ - SOF_CHMAP_TFC, /* top front centre */ - SOF_CHMAP_TRL, /* top rear left */ - SOF_CHMAP_TRR, /* top rear right */ - SOF_CHMAP_TRC, /* top rear centre */ - SOF_CHMAP_TFLC, /* top front left centre */ - SOF_CHMAP_TFRC, /* top front right centre */ - SOF_CHMAP_TSL, /* top side left */ - SOF_CHMAP_TSR, /* top side right */ - SOF_CHMAP_LLFE, /* left LFE */ - SOF_CHMAP_RLFE, /* right LFE */ - SOF_CHMAP_BC, /* bottom centre */ - SOF_CHMAP_BLC, /* bottom left centre */ - SOF_CHMAP_BRC, /* bottom right centre */ - SOF_CHMAP_LAST = SOF_CHMAP_BRC, -}; - -/* common sample rates for use in masks */ -#define SOF_RATE_8000 (1 << 0) /* 8000Hz */ -#define SOF_RATE_11025 (1 << 1) /* 11025Hz */ -#define SOF_RATE_12000 (1 << 2) /* 12000Hz */ -#define SOF_RATE_16000 (1 << 3) /* 16000Hz */ -#define SOF_RATE_22050 (1 << 4) /* 22050Hz */ -#define SOF_RATE_24000 (1 << 5) /* 24000Hz */ -#define SOF_RATE_32000 (1 << 6) /* 32000Hz */ -#define SOF_RATE_44100 (1 << 7) /* 44100Hz */ -#define SOF_RATE_48000 (1 << 8) /* 48000Hz */ -#define SOF_RATE_64000 (1 << 9) /* 64000Hz */ -#define SOF_RATE_88200 (1 << 10) /* 88200Hz */ -#define SOF_RATE_96000 (1 << 11) /* 96000Hz */ -#define SOF_RATE_176400 (1 << 12) /* 176400Hz */ -#define SOF_RATE_192000 (1 << 13) /* 192000Hz */ - -/* continuous and non-standard rates for flexibility */ -#define SOF_RATE_CONTINUOUS (1 << 30) /* range */ -#define SOF_RATE_KNOT (1 << 31) /* non-continuous */ - -/* stream PCM frame format */ -enum sof_ipc_frame { - SOF_IPC_FRAME_S16_LE = 0, - SOF_IPC_FRAME_S24_4LE, - SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_FLOAT, - /* other formats here */ -}; - -/* stream buffer format */ -enum sof_ipc_buffer_format { - SOF_IPC_BUFFER_INTERLEAVED, - SOF_IPC_BUFFER_NONINTERLEAVED, - /* other formats here */ -}; - -/* stream direction */ -enum sof_ipc_stream_direction { - SOF_IPC_STREAM_PLAYBACK = 0, - SOF_IPC_STREAM_CAPTURE, -}; - -/* stream ring info */ -struct sof_ipc_host_buffer { - uint32_t phy_addr; - uint32_t pages; - uint32_t size; - uint32_t offset; -} __attribute__((packed)); - -struct sof_ipc_stream_params { - struct sof_ipc_host_buffer buffer; - enum sof_ipc_stream_direction direction; - enum sof_ipc_frame frame_fmt; - enum sof_ipc_buffer_format buffer_fmt; - uint32_t stream_tag; - uint32_t rate; - uint32_t channels; - uint32_t sample_valid_bytes; - uint32_t sample_container_bytes; - /* for notifying host period has completed - 0 means no period IRQ */ - uint32_t host_period_bytes; - enum sof_ipc_chmap chmap[SOF_IPC_MAX_CHANNELS]; /* channel map */ -} __attribute__((packed)); - -/* PCM params info - SOF_IPC_STREAM_PCM_PARAMS */ -struct sof_ipc_pcm_params { - struct sof_ipc_hdr hdr; - uint32_t comp_id; - struct sof_ipc_stream_params params; -} __attribute__((packed)); - -/* PCM params info reply - SOF_IPC_STREAM_PCM_PARAMS_REPLY */ -struct sof_ipc_pcm_params_reply { - struct sof_ipc_reply rhdr; - uint32_t comp_id; - uint32_t posn_offset; -} __attribute__((packed)); - -/* compressed vorbis params - SOF_IPC_STREAM_VORBIS_PARAMS */ -struct sof_ipc_vorbis_params { - struct sof_ipc_hdr hdr; - uint32_t comp_id; - struct sof_ipc_stream_params params; - /* TODO */ -} __attribute__((packed)); - -/* free stream - SOF_IPC_STREAM_PCM_PARAMS */ -struct sof_ipc_stream { - struct sof_ipc_hdr hdr; - uint32_t comp_id; -} __attribute__((packed)); - -/* flags indicating which time stamps are in sync with each other */ -#define SOF_TIME_HOST_SYNC (1 << 0) -#define SOF_TIME_DAI_SYNC (1 << 1) -#define SOF_TIME_WALL_SYNC (1 << 2) -#define SOF_TIME_STAMP_SYNC (1 << 3) - -/* flags indicating which time stamps are valid */ -#define SOF_TIME_HOST_VALID (1 << 8) -#define SOF_TIME_DAI_VALID (1 << 9) -#define SOF_TIME_WALL_VALID (1 << 10) -#define SOF_TIME_STAMP_VALID (1 << 11) - -/* flags indicating time stamps are 64bit else 3use low 32bit */ -#define SOF_TIME_HOST_64 (1 << 16) -#define SOF_TIME_DAI_64 (1 << 17) -#define SOF_TIME_WALL_64 (1 << 18) -#define SOF_TIME_STAMP_64 (1 << 19) - -struct sof_ipc_stream_posn { - struct sof_ipc_reply rhdr; - uint32_t comp_id; /* host component ID */ - uint32_t flags; /* SOF_TIME_ */ - uint32_t wallclock_hz; /* frequency of wallclock in Hz */ - uint32_t timestamp_ns; /* resolution of timestamp in ns */ - uint64_t host_posn; /* host DMA position in bytes */ - uint64_t dai_posn; /* DAI DMA position in bytes */ - uint64_t comp_posn; /* comp position in bytes */ - uint64_t wallclock; /* audio wall clock */ - uint64_t timestamp; /* system time stamp */ - uint32_t xrun_comp_id; /* comp ID of XRUN component */ - int32_t xrun_size; /* XRUN size in bytes */ -} __attribute__((packed)); - -/* - * Component Mixers and Controls - */ - -/* control data type and direction */ -enum sof_ipc_ctrl_type { - /* per channel data - uses struct sof_ipc_ctrl_value_chan */ - SOF_CTRL_TYPE_VALUE_CHAN_GET = 0, - SOF_CTRL_TYPE_VALUE_CHAN_SET, - /* component data - uses struct sof_ipc_ctrl_value_comp */ - SOF_CTRL_TYPE_VALUE_COMP_GET, - SOF_CTRL_TYPE_VALUE_COMP_SET, - /* bespoke data - struct struct sof_abi_hdr */ - SOF_CTRL_TYPE_DATA_GET, - SOF_CTRL_TYPE_DATA_SET, -}; - -/* control command type */ -enum sof_ipc_ctrl_cmd { - SOF_CTRL_CMD_VOLUME = 0, /* maps to ALSA volume style controls */ - SOF_CTRL_CMD_ENUM, /* maps to ALSA enum style controls */ - SOF_CTRL_CMD_SWITCH, /* maps to ALSA switch style controls */ - SOF_CTRL_CMD_BINARY, /* maps to ALSA binary style controls */ -}; - -/* generic channel mapped value data */ -struct sof_ipc_ctrl_value_chan { - enum sof_ipc_chmap channel; - uint32_t value; -} __attribute__((packed)); - -/* generic component mapped value data */ -struct sof_ipc_ctrl_value_comp { - uint32_t index; /* component source/sink/control index in control */ - union { - uint32_t uvalue; - int32_t svalue; - }; -} __attribute__((packed)); - -/* generic control data */ -struct sof_ipc_ctrl_data { - struct sof_ipc_reply rhdr; - uint32_t comp_id; - - /* control access and data type */ - enum sof_ipc_ctrl_type type; - enum sof_ipc_ctrl_cmd cmd; - uint32_t index; /* control index for comps > 1 control */ - - /* control data - can either be appended or DMAed from host */ - struct sof_ipc_host_buffer buffer; - uint32_t num_elems; /* in array elems or bytes */ - - /* control data - add new types if needed */ - union { - /* channel values can be used by volume type controls */ - struct sof_ipc_ctrl_value_chan chanv[0]; - /* component values used by routing controls like mux, mixer */ - struct sof_ipc_ctrl_value_comp compv[0]; - /* data can be used by binary controls */ - struct sof_abi_hdr data[0]; - }; -} __attribute__((packed)); - -/* - * Component - */ - -/* types of component */ -enum sof_comp_type { - SOF_COMP_NONE = 0, - SOF_COMP_HOST, - SOF_COMP_DAI, - SOF_COMP_SG_HOST, /* scatter gather variant */ - SOF_COMP_SG_DAI, /* scatter gather variant */ - SOF_COMP_VOLUME, - SOF_COMP_MIXER, - SOF_COMP_MUX, - SOF_COMP_SRC, - SOF_COMP_SPLITTER, - SOF_COMP_TONE, - SOF_COMP_SWITCH, - SOF_COMP_BUFFER, - SOF_COMP_EQ_IIR, - SOF_COMP_EQ_FIR, - SOF_COMP_FILEREAD, /* host test based file IO */ - SOF_COMP_FILEWRITE, /* host test based file IO */ -}; - -/* XRUN action for component */ -#define SOF_XRUN_STOP 1 /* stop stream */ -#define SOF_XRUN_UNDER_ZERO 2 /* send 0s to sink */ -#define SOF_XRUN_OVER_NULL 4 /* send data to NULL */ - -/* create new generic component - SOF_IPC_TPLG_COMP_NEW */ -struct sof_ipc_comp { - struct sof_ipc_hdr hdr; - uint32_t id; - enum sof_comp_type type; - uint32_t pipeline_id; -} __attribute__((packed)); - -/* - * Component Buffers - */ - -/* create new component buffer - SOF_IPC_TPLG_BUFFER_NEW */ -struct sof_ipc_buffer { - struct sof_ipc_comp comp; - uint32_t size; /* buffer size in bytes */ - uint32_t caps; /* SOF_MEM_CAPS_ */ -} __attribute__((packed)); - -/* generic component config data - must always be after struct sof_ipc_comp */ -struct sof_ipc_comp_config { - uint32_t periods_sink; /* 0 means variable */ - uint32_t periods_source; /* 0 means variable */ - uint32_t preload_count; /* how many periods to preload */ - enum sof_ipc_frame frame_fmt; - uint32_t xrun_action; -} __attribute__((packed)); - -/* generic host component */ -struct sof_ipc_comp_host { - struct sof_ipc_comp comp; - struct sof_ipc_comp_config config; - enum sof_ipc_stream_direction direction; - uint32_t no_irq; /* don't send periodic IRQ to host/DSP */ - uint32_t dmac_config; /* DMA engine specific */ -} __attribute__((packed)); - -/* generic DAI component */ -struct sof_ipc_comp_dai { - struct sof_ipc_comp comp; - struct sof_ipc_comp_config config; - enum sof_ipc_stream_direction direction; - uint32_t dai_index; /* index of this type dai */ - enum sof_ipc_dai_type type; - uint32_t dmac_config; /* DMA engine specific */ -} __attribute__((packed)); - -/* generic mixer component */ -struct sof_ipc_comp_mixer { - struct sof_ipc_comp comp; - struct sof_ipc_comp_config config; -} __attribute__((packed)); - -/* volume ramping types */ -enum sof_volume_ramp { - SOF_VOLUME_LINEAR = 0, - SOF_VOLUME_LOG, - SOF_VOLUME_LINEAR_ZC, - SOF_VOLUME_LOG_ZC, -}; - -/* generic volume component */ -struct sof_ipc_comp_volume { - struct sof_ipc_comp comp; - struct sof_ipc_comp_config config; - uint32_t channels; - uint32_t min_value; - uint32_t max_value; - enum sof_volume_ramp ramp; - uint32_t initial_ramp; /* ramp space in ms */ -} __attribute__((packed)); - -/* generic SRC component */ -struct sof_ipc_comp_src { - struct sof_ipc_comp comp; - struct sof_ipc_comp_config config; - /* either source or sink rate must be non zero */ - uint32_t source_rate; /* source rate or 0 for variable */ - uint32_t sink_rate; /* sink rate or 0 for variable */ - uint32_t rate_mask; /* SOF_RATE_ supported rates */ -} __attribute__((packed)); - -/* generic MUX component */ -struct sof_ipc_comp_mux { - struct sof_ipc_comp comp; - struct sof_ipc_comp_config config; -} __attribute__((packed)); - -/* generic tone generator component */ -struct sof_ipc_comp_tone { - struct sof_ipc_comp comp; - struct sof_ipc_comp_config config; - int32_t sample_rate; - int32_t frequency; - int32_t amplitude; - int32_t freq_mult; - int32_t ampl_mult; - int32_t length; - int32_t period; - int32_t repeats; - int32_t ramp_step; -} __attribute__((packed)); - -/* FIR equalizer component */ -struct sof_ipc_comp_eq_fir { - struct sof_ipc_comp comp; - struct sof_ipc_comp_config config; - uint32_t size; - unsigned char data[0]; -} __attribute__((packed)); - -/* IIR equalizer component */ -struct sof_ipc_comp_eq_iir { - struct sof_ipc_comp comp; - struct sof_ipc_comp_config config; - uint32_t size; - unsigned char data[0]; -} __attribute__((packed)); - -/** \brief Types of EFFECT */ -enum sof_ipc_effect_type { - SOF_EFFECT_NONE = 0, /**< None */ - SOF_EFFECT_INTEL_EQFIR, /**< Intel FIR */ - SOF_EFFECT_INTEL_EQIIR, /**< Intel IIR */ -}; - -/* general purpose EFFECT configuration */ -struct sof_ipc_comp_effect { - enum sof_ipc_effect_type type; -} __attribute__((packed)); - -/* frees components, buffers and pipelines - * SOF_IPC_TPLG_COMP_FREE, SOF_IPC_TPLG_PIPE_FREE, SOF_IPC_TPLG_BUFFER_FREE - */ -struct sof_ipc_free { - struct sof_ipc_hdr hdr; - uint32_t id; -} __attribute__((packed)); - -struct sof_ipc_comp_reply { - struct sof_ipc_reply rhdr; - uint32_t id; - uint32_t offset; -} __attribute__((packed)); - -/* - * Pipeline - */ - -/* new pipeline - SOF_IPC_TPLG_PIPE_NEW */ -struct sof_ipc_pipe_new { - struct sof_ipc_hdr hdr; - uint32_t comp_id; /* component id for pipeline */ - uint32_t pipeline_id; /* pipeline id */ - uint32_t sched_id; /* sheduling component id */ - uint32_t core; /* core we run on */ - uint32_t deadline; /* execution completion deadline in us*/ - uint32_t priority; /* priority level 0 (low) to 10 (max) */ - uint32_t mips; /* worst case instruction count per period */ - uint32_t frames_per_sched;/* output frames of pipeline, 0 is variable */ - uint32_t xrun_limit_usecs; /* report xruns greater than limit */ - - /* non zero if timer scheduled, otherwise DAI DMA irq scheduled */ - uint32_t timer_delay; -} __attribute__((packed)); - -/* pipeline construction complete - SOF_IPC_TPLG_PIPE_COMPLETE */ -struct sof_ipc_pipe_ready { - struct sof_ipc_hdr hdr; - uint32_t comp_id; -} __attribute__((packed)); - -struct sof_ipc_pipe_free { - struct sof_ipc_hdr hdr; - uint32_t comp_id; -} __attribute__((packed)); - -/* connect two components in pipeline - SOF_IPC_TPLG_COMP_CONNECT */ -struct sof_ipc_pipe_comp_connect { - struct sof_ipc_hdr hdr; - uint32_t source_id; - uint32_t sink_id; -} __attribute__((packed)); - -/* - * PM - */ - -/* PM context element */ -struct sof_ipc_pm_ctx_elem { - uint32_t type; - uint32_t size; - uint64_t addr; -} __attribute__((packed)); - -/* - * PM context - SOF_IPC_PM_CTX_SAVE, SOF_IPC_PM_CTX_RESTORE, - * SOF_IPC_PM_CTX_SIZE - */ -struct sof_ipc_pm_ctx { - struct sof_ipc_hdr hdr; - struct sof_ipc_host_buffer buffer; - uint32_t num_elems; - uint32_t size; - struct sof_ipc_pm_ctx_elem elems[]; -}; - -/* enable or disable cores - SOF_IPC_PM_CORE_ENABLE */ -struct sof_ipc_pm_core_config { - struct sof_ipc_hdr hdr; - uint32_t enable_mask; -}; - -/* - * Firmware boot and version - */ - -#define SOF_IPC_MAX_ELEMS 16 - -/* extended data types that can be appended onto end of sof_ipc_fw_ready */ -enum sof_ipc_ext_data { - SOF_IPC_EXT_DMA_BUFFER = 0, - SOF_IPC_EXT_WINDOW, -}; - -/* FW version - SOF_IPC_GLB_VERSION */ -struct sof_ipc_fw_version { - uint16_t major; - uint16_t minor; - uint16_t build; - uint8_t date[12]; - uint8_t time[10]; - uint8_t tag[6]; - uint16_t abi_version; - /* Make sure the total size is 4 bytes aligned */ -} __attribute__((packed)); - -/* FW ready Message - sent by firmware when boot has completed */ -struct sof_ipc_fw_ready { - struct sof_ipc_hdr hdr; - uint32_t dspbox_offset; /* dsp initiated IPC mailbox */ - uint32_t hostbox_offset; /* host initiated IPC mailbox */ - uint32_t dspbox_size; - uint32_t hostbox_size; - struct sof_ipc_fw_version version; -} __attribute__((packed)); - -/* - * Extended Firmware data. All optional, depends on platform/arch. - */ - -enum sof_ipc_region { - SOF_IPC_REGION_DOWNBOX = 0, - SOF_IPC_REGION_UPBOX, - SOF_IPC_REGION_TRACE, - SOF_IPC_REGION_DEBUG, - SOF_IPC_REGION_STREAM, - SOF_IPC_REGION_REGS, - SOF_IPC_REGION_EXCEPTION, -}; - -struct sof_ipc_ext_data_hdr { - struct sof_ipc_hdr hdr; - enum sof_ipc_ext_data type; /* SOF_IPC_EXT_ */ -}; - -struct sof_ipc_dma_buffer_elem { - enum sof_ipc_region type; - uint32_t id; /* platform specific - used to map to host memory */ - struct sof_ipc_host_buffer buffer; -}; - -/* extended data DMA buffers for IPC, trace and debug */ -struct sof_ipc_dma_buffer_data { - struct sof_ipc_ext_data_hdr ext_hdr; - uint32_t num_buffers; - /* host files in buffer[n].buffer */ - struct sof_ipc_dma_buffer_elem buffer[]; -} __attribute__((packed)); - -struct sof_ipc_window_elem { - enum sof_ipc_region type; - uint32_t id; /* platform specific - used to map to host memory */ - uint32_t flags; /* R, W, RW, etc - to define */ - uint32_t size; /* size of region in bytes */ - /* offset in window region as windows can be partitioned */ - uint32_t offset; -}; - -/* extended data memory windows for IPC, trace and debug */ -struct sof_ipc_window { - struct sof_ipc_ext_data_hdr ext_hdr; - uint32_t num_windows; - struct sof_ipc_window_elem window[]; -} __attribute__((packed)); - -/* - * DMA for Trace - */ - -/* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS */ -struct sof_ipc_dma_trace_params { - struct sof_ipc_hdr hdr; - struct sof_ipc_host_buffer buffer; - uint32_t stream_tag; -} __attribute__((packed)); - -/* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS */ -struct sof_ipc_dma_trace_posn { - struct sof_ipc_reply rhdr; - uint32_t host_offset; /* Offset of DMA host buffer */ - uint32_t overflow; /* overflow bytes if any */ - uint32_t messages; /* total trace messages */ -} __attribute__((packed)); - -/* - * Architecture specific debug - */ - -/* Xtensa Firmware Oops data */ -struct sof_ipc_dsp_oops_xtensa { - uint32_t exccause; - uint32_t excvaddr; - uint32_t ps; - uint32_t epc1; - uint32_t epc2; - uint32_t epc3; - uint32_t epc4; - uint32_t epc5; - uint32_t epc6; - uint32_t epc7; - uint32_t eps2; - uint32_t eps3; - uint32_t eps4; - uint32_t eps5; - uint32_t eps6; - uint32_t eps7; - uint32_t depc; - uint32_t intenable; - uint32_t interrupt; - uint32_t sar; - uint32_t stack; -} __attribute__((packed)); - -/* - * Commom debug - */ - -/* panic info include filename and line number */ -struct sof_ipc_panic_info { - char filename[32]; - uint32_t linenum; -} __attribute__((packed)); - -#endif diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h new file mode 100644 index 00000000000000..48bd898d953ed4 --- /dev/null +++ b/include/uapi/sound/sof/abi.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +/** + * SOF ABI versioning is based on Semantic Versioning where we have a given + * MAJOR.MINOR.PATCH version number. See https://semver.org/ + * + * Rules for incrementing or changing version :- + * + * 1) Increment MAJOR version if you make incompatible API changes. MINOR and + * PATCH should be reset to 0. + * + * 2) Increment MINOR version if you add backwards compatible features or + * changes. PATCH should be reset to 0. + * + * 3) Increment PATCH version if you add backwards compatible bug fixes. + */ + +#ifndef __INCLUDE_UAPI_SOUND_SOF_ABI_H__ +#define __INCLUDE_UAPI_SOUND_SOF_ABI_H__ + +/* SOF ABI version major, minor and patch numbers */ +#define SOF_ABI_MAJOR 2 +#define SOF_ABI_MINOR 0 +#define SOF_ABI_PATCH 0 + +/* SOF ABI version number. Format within 32bit word is MMmmmppp */ +#define SOF_ABI_MAJOR_SHIFT 24 +#define SOF_ABI_MAJOR_MASK 0xff +#define SOF_ABI_MINOR_SHIFT 12 +#define SOF_ABI_MINOR_MASK 0xfff +#define SOF_ABI_PATCH_SHIFT 0 +#define SOF_ABI_PATCH_MASK 0xfff + +#define SOF_ABI_VER(major, minor, patch) \ + (((major) << SOF_ABI_MAJOR_SHIFT) | \ + ((minor) << SOF_ABI_MINOR_SHIFT) | \ + ((patch) << SOF_ABI_PATCH_SHIFT)) + +#define SOF_ABI_VERSION_MAJOR(version) \ + (((version) >> SOF_ABI_MAJOR_SHIFT) & SOF_ABI_MAJOR_MASK) +#define SOF_ABI_VERSION_MINOR(version) \ + (((version) >> SOF_ABI_MINOR_SHIFT) & SOF_ABI_MINOR_MASK) +#define SOF_ABI_VERSION_PATCH(version) \ + (((version) >> SOF_ABI_PATCH_SHIFT) & SOF_ABI_PATCH_MASK) + +#define SOF_ABI_VERSION_INCOMPATIBLE(sof_ver, client_ver) \ + (SOF_ABI_VERSION_MAJOR((sof_ver)) != \ + SOF_ABI_VERSION_MAJOR((client_ver)) \ + ) + +#define SOF_ABI_VERSION SOF_ABI_VER(SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH) + +/* SOF ABI magic number "SOF\0". */ +#define SOF_ABI_MAGIC 0x00464F53 + +#endif + diff --git a/include/uapi/sound/sof-eq.h b/include/uapi/sound/sof/eq.h similarity index 91% rename from include/uapi/sound/sof-eq.h rename to include/uapi/sound/sof/eq.h index bd82fea5206ed0..9567d4abea703f 100644 --- a/include/uapi/sound/sof-eq.h +++ b/include/uapi/sound/sof/eq.h @@ -4,26 +4,21 @@ * redistributing this file, you may do so under either license. * * Copyright(c) 2018 Intel Corporation. All rights reserved. - * - * Author: Seppo Ingalsuo */ -#ifndef EQ_H -#define EQ_H +#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_EQ_H__ +#define __INCLUDE_UAPI_SOUND_SOF_USER_EQ_H__ /* FIR EQ type */ -/* Component will reject non-matching configuration. The version number need - * to be incremented with any ABI changes in function fir_cmd(). - */ -#define SOF_EQ_FIR_ABI_VERSION 1 - #define SOF_EQ_FIR_IDX_SWITCH 0 #define SOF_EQ_FIR_MAX_SIZE 4096 /* Max size allowed for coef data in bytes */ #define SOF_EQ_FIR_MAX_LENGTH 192 /* Max length for individual filter */ +#define SOF_EQ_FIR_MAX_RESPONSES 8 /* A blob can define max 8 FIR EQs */ + /* * eq_fir_configuration data structure contains this information * uint32_t size @@ -59,14 +54,22 @@ struct sof_eq_fir_config { uint32_t size; uint16_t channels_in_config; uint16_t number_of_responses; + + /* reserved */ + uint32_t reserved[4]; + int16_t data[]; -}; +} __packed; struct sof_eq_fir_coef_data { int16_t length; /* Number of FIR taps */ int16_t out_shift; /* Amount of right shifts at output */ + + /* reserved */ + uint32_t reserved[4]; + int16_t coef[]; /* FIR coefficients */ -}; +} __packed; /* In the struct above there's two words (length, shift) before the actual * FIR coefficients. This information is used in parsing of the config blob. @@ -75,11 +78,6 @@ struct sof_eq_fir_coef_data { /* IIR EQ type */ -/* Component will reject non-matching configuration. The version number need - * to be incremented with any ABI changes in function fir_cmd(). - */ -#define SOF_EQ_IIR_ABI_VERSION 1 - #define SOF_EQ_IIR_IDX_SWITCH 0 #define SOF_EQ_IIR_MAX_SIZE 1024 /* Max size allowed for coef data in bytes */ @@ -125,14 +123,22 @@ struct sof_eq_iir_config { uint32_t size; uint32_t channels_in_config; uint32_t number_of_responses; + + /* reserved */ + uint32_t reserved[4]; + int32_t data[]; /* eq_assign[channels], eq 0, eq 1, ... */ -}; +} __packed; struct sof_eq_iir_header_df2t { uint32_t num_sections; uint32_t num_sections_in_series; + + /* reserved */ + uint32_t reserved[4]; + int32_t biquads[]; /* Repeated biquad coefficients */ -}; +} __packed; struct sof_eq_iir_biquad_df2t { int32_t a2; /* Q2.30 */ @@ -142,7 +148,7 @@ struct sof_eq_iir_biquad_df2t { int32_t b0; /* Q2.30 */ int32_t output_shift; /* Number of right shifts */ int32_t output_gain; /* Q2.14 */ -}; +} __packed; /* A full 22th order equalizer with 11 biquads cover octave bands 1-11 in * in the 0 - 20 kHz bandwidth. @@ -155,4 +161,4 @@ struct sof_eq_iir_biquad_df2t { /* The number of int32_t words in sof_eq_iir_biquad_df2t */ #define SOF_EQ_IIR_NBIQUAD_DF2T 7 -#endif /* EQ_H */ +#endif diff --git a/include/uapi/sound/sof-fw.h b/include/uapi/sound/sof/fw.h similarity index 95% rename from include/uapi/sound/sof-fw.h rename to include/uapi/sound/sof/fw.h index e55ea88ee69607..c82e094f865b9f 100644 --- a/include/uapi/sound/sof-fw.h +++ b/include/uapi/sound/sof/fw.h @@ -37,7 +37,7 @@ struct snd_sof_blk_hdr { enum snd_sof_fw_blk_type type; uint32_t size; /* bytes minus this header */ uint32_t offset; /* offset from base */ -} __attribute__((packed)); +} __packed; /* * Firmware file is made up of 1 .. N different modules types. The module @@ -52,7 +52,7 @@ struct snd_sof_mod_hdr { enum snd_sof_fw_mod_type type; uint32_t size; /* bytes minus this header */ uint32_t num_blocks; /* number of blocks */ -} __attribute__((packed)); +} __packed; /* * Firmware file header. @@ -62,6 +62,6 @@ struct snd_sof_fw_header { uint32_t file_size; /* size of file minus this header */ uint32_t num_modules; /* number of modules */ uint32_t abi; /* version of header format */ -} __attribute__((packed)); +} __packed; #endif diff --git a/include/uapi/sound/sof/header.h b/include/uapi/sound/sof/header.h new file mode 100644 index 00000000000000..e69daec521fb93 --- /dev/null +++ b/include/uapi/sound/sof/header.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_HEADER_H__ +#define __INCLUDE_UAPI_SOUND_SOF_USER_HEADER_H__ + +/* + * Header for all non IPC ABI data. + * + * Identifies data type, size and ABI. + * Used by any bespoke component data structures or binary blobs. + */ +struct sof_abi_hdr { + uint32_t magic; /**< 'S', 'O', 'F', '\0' */ + uint32_t type; /**< component specific type */ + uint32_t size; /**< size in bytes of data excl. this struct */ + uint32_t abi; /**< SOF ABI version */ + uint32_t reserved[4]; /**< reserved for future use */ + uint32_t data[0]; /**< Component data - opaque to core */ +} __packed; + +#endif diff --git a/include/uapi/sound/sof/manifest.h b/include/uapi/sound/sof/manifest.h new file mode 100644 index 00000000000000..c130518961c83b --- /dev/null +++ b/include/uapi/sound/sof/manifest.h @@ -0,0 +1,188 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_MANIFEST_H__ +#define __INCLUDE_UAPI_SOUND_SOF_USER_MANIFEST_H__ + +/* start offset for base FW module */ +#define SOF_MAN_ELF_TEXT_OFFSET 0x2000 + +/* FW Extended Manifest Header id = $AE1 */ +#define SOF_MAN_EXT_HEADER_MAGIC 0x31454124 + +/* module type load type */ +#define SOF_MAN_MOD_TYPE_BUILTIN 0 +#define SOF_MAN_MOD_TYPE_MODULE 1 + +struct sof_man_module_type { + uint32_t load_type:4; /* SOF_MAN_MOD_TYPE_ */ + uint32_t auto_start:1; + uint32_t domain_ll:1; + uint32_t domain_dp:1; + uint32_t rsvd_:25; +}; + +/* segment flags.type */ +#define SOF_MAN_SEGMENT_TEXT 0 +#define SOF_MAN_SEGMENT_RODATA 1 +#define SOF_MAN_SEGMENT_DATA 1 +#define SOF_MAN_SEGMENT_BSS 2 +#define SOF_MAN_SEGMENT_EMPTY 15 + +union sof_man_segment_flags { + uint32_t ul; + struct { + uint32_t contents:1; + uint32_t alloc:1; + uint32_t load:1; + uint32_t readonly:1; + uint32_t code:1; + uint32_t data:1; + uint32_t _rsvd0:2; + uint32_t type:4; /* MAN_SEGMENT_ */ + uint32_t _rsvd1:4; + uint32_t length:16; /* of segment in pages */ + } r; +} __packed; + +/* + * Module segment descriptor. Used by ROM - Immutable. + */ +struct sof_man_segment_desc { + union sof_man_segment_flags flags; + uint32_t v_base_addr; + uint32_t file_offset; +} __packed; + +/* + * The firmware binary can be split into several modules. + */ + +#define SOF_MAN_MOD_ID_LEN 4 +#define SOF_MAN_MOD_NAME_LEN 8 +#define SOF_MAN_MOD_SHA256_LEN 32 +#define SOF_MAN_MOD_ID {'$', 'A', 'M', 'E'} + +/* + * Each module has an entry in the FW header. Used by ROM - Immutable. + */ +struct sof_man_module { + uint8_t struct_id[SOF_MAN_MOD_ID_LEN]; /* SOF_MAN_MOD_ID */ + uint8_t name[SOF_MAN_MOD_NAME_LEN]; + uint8_t uuid[16]; + struct sof_man_module_type type; + uint8_t hash[SOF_MAN_MOD_SHA256_LEN]; + uint32_t entry_point; + uint16_t cfg_offset; + uint16_t cfg_count; + uint32_t affinity_mask; + uint16_t instance_max_count; /* max number of instances */ + uint16_t instance_bss_size; /* instance (pages) */ + struct sof_man_segment_desc segment[3]; +} __packed; + +/* + * Each module has a configuration in the FW header. Used by ROM - Immutable. + */ +struct sof_man_mod_config { + uint32_t par[4]; /* module parameters */ + uint32_t is_pages; /* actual size of instance .bss (pages) */ + uint32_t cps; /* cycles per second */ + uint32_t ibs; /* input buffer size (bytes) */ + uint32_t obs; /* output buffer size (bytes) */ + uint32_t module_flags; /* flags, reserved for future use */ + uint32_t cpc; /* cycles per single run */ + uint32_t obls; /* output block size, reserved for future use */ +} __packed; + +/* + * FW Manifest Header + */ + +#define SOF_MAN_FW_HDR_FW_NAME_LEN 8 +#define SOF_MAN_FW_HDR_ID {'$', 'A', 'M', '1'} +#define SOF_MAN_FW_HDR_NAME "ADSPFW" +#define SOF_MAN_FW_HDR_FLAGS 0x0 +#define SOF_MAN_FW_HDR_FEATURES 0xff + +/* + * The firmware has a standard header that is checked by the ROM on firmware + * loading. preload_page_count is used by DMA code loader and is entire + * image size on CNL. i.e. CNL: total size of the binary’s .text and .rodata + * Used by ROM - Immutable. + */ +struct sof_man_fw_header { + uint8_t header_id[4]; + uint32_t header_len; + uint8_t name[SOF_MAN_FW_HDR_FW_NAME_LEN]; + /* number of pages of preloaded image loaded by driver */ + uint32_t preload_page_count; + uint32_t fw_image_flags; + uint32_t feature_mask; + uint16_t major_version; + uint16_t minor_version; + uint16_t hotfix_version; + uint16_t build_version; + uint32_t num_module_entries; + uint32_t hw_buf_base_addr; + uint32_t hw_buf_length; + /* target address for binary loading as offset in IMR - must be == base offset */ + uint32_t load_offset; +} __packed; + +/* + * Firmware manifest descriptor. This can contain N modules and N module + * configs. Used by ROM - Immutable. + */ +struct sof_man_fw_desc { + struct sof_man_fw_header header; + + /* Warning - hack for module arrays. For some unknown reason the we + * have a variable size array of struct man_module followed by a + * variable size array of struct mod_config. These should have been + * merged into a variable array of a parent structure. We have to hack + * around this in many places.... + * + * struct sof_man_module man_module[]; + * struct sof_man_mod_config mod_config[]; + */ + +} __packed; + +/* + * Component Descriptor. Used by ROM - Immutable. + */ +struct sof_man_component_desc { + uint32_t reserved[2]; /* all 0 */ + uint32_t version; + uint8_t hash[SOF_MAN_MOD_SHA256_LEN]; + uint32_t base_offset; + uint32_t limit_offset; + uint32_t attributes[4]; +} __packed; + +/* + * Audio DSP extended metadata. Used by ROM - Immutable. + */ +struct sof_man_adsp_meta_file_ext { + uint32_t ext_type; /* always 17 for ADSP extension */ + uint32_t ext_len; + uint32_t imr_type; + uint8_t reserved[16]; /* all 0 */ + struct sof_man_component_desc comp_desc[1]; +} __packed; + +/* + * Module Manifest for rimage module metadata. Not used by ROM. + */ +struct sof_man_module_manifest { + struct sof_man_module module; + uint32_t text_size; +} __packed; + +#endif diff --git a/include/uapi/sound/sof-topology.h b/include/uapi/sound/sof/tokens.h similarity index 100% rename from include/uapi/sound/sof-topology.h rename to include/uapi/sound/sof/tokens.h diff --git a/include/uapi/sound/sof-tone.h b/include/uapi/sound/sof/tone.h similarity index 62% rename from include/uapi/sound/sof-tone.h rename to include/uapi/sound/sof/tone.h index ce258cd7ef70ec..2a5503aa94e40c 100644 --- a/include/uapi/sound/sof-tone.h +++ b/include/uapi/sound/sof/tone.h @@ -1,14 +1,13 @@ /* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ /* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - * Author: Seppo Ingalsuo - */ +* This file is provided under a dual BSD/GPLv2 license. When using or +* redistributing this file, you may do so under either license. +* +* Copyright(c) 2018 Intel Corporation. All rights reserved. +*/ -#ifndef TONE_H -#define TONE_H +#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_TONE_H__ +#define __INCLUDE_UAPI_SOUND_SOF_USER_TONE_H__ /* Component will reject non-matching configuration. The version number need * to be incremented with any ABI changes in function fir_cmd(). @@ -24,4 +23,4 @@ #define SOF_TONE_IDX_REPEATS 6 #define SOF_TONE_IDX_LIN_RAMP_STEP 7 -#endif /* TONE_ABI_H */ +#endif diff --git a/include/uapi/sound/sof/trace.h b/include/uapi/sound/sof/trace.h new file mode 100644 index 00000000000000..606add4d951f91 --- /dev/null +++ b/include/uapi/sound/sof/trace.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_TRACE_H__ +#define __INCLUDE_UAPI_SOUND_SOF_USER_TRACE_H__ + +/* + * Host system time. + * + * This property is used by the driver to pass down information about + * current system time. It is expressed in us. + * FW translates timestamps (in log entries, probe pockets) to this time + * domain. + * + * (cavs: SystemTime). + */ +struct system_time { + uint32_t val_l; /* Lower dword of current host time value */ + uint32_t val_u; /* Upper dword of current host time value */ +} __packed; + +/* trace event classes - high 8 bits*/ +#define TRACE_CLASS_IRQ (1 << 24) +#define TRACE_CLASS_IPC (2 << 24) +#define TRACE_CLASS_PIPE (3 << 24) +#define TRACE_CLASS_HOST (4 << 24) +#define TRACE_CLASS_DAI (5 << 24) +#define TRACE_CLASS_DMA (6 << 24) +#define TRACE_CLASS_SSP (7 << 24) +#define TRACE_CLASS_COMP (8 << 24) +#define TRACE_CLASS_WAIT (9 << 24) +#define TRACE_CLASS_LOCK (10 << 24) +#define TRACE_CLASS_MEM (11 << 24) +#define TRACE_CLASS_MIXER (12 << 24) +#define TRACE_CLASS_BUFFER (13 << 24) +#define TRACE_CLASS_VOLUME (14 << 24) +#define TRACE_CLASS_SWITCH (15 << 24) +#define TRACE_CLASS_MUX (16 << 24) +#define TRACE_CLASS_SRC (17 << 24) +#define TRACE_CLASS_TONE (18 << 24) +#define TRACE_CLASS_EQ_FIR (19 << 24) +#define TRACE_CLASS_EQ_IIR (20 << 24) +#define TRACE_CLASS_SA (21 << 24) +#define TRACE_CLASS_DMIC (22 << 24) +#define TRACE_CLASS_POWER (23 << 24) +#define TRACE_CLASS_IDC (24 << 24) +#define TRACE_CLASS_CPU (25 << 24) + +#define LOG_ENABLE 1 /* Enable logging */ +#define LOG_DISABLE 0 /* Disable logging */ + +#define LOG_LEVEL_CRITICAL 1 /* (FDK fatal) */ +#define LOG_LEVEL_VERBOSE 2 + +/* + * Layout of a log fifo. + */ +struct log_buffer_layout { + uint32_t read_ptr; /*read pointer */ + uint32_t write_ptr; /* write pointer */ + uint32_t buffer[0]; /* buffer */ +} __packed; + +/* + * Log buffer status reported by FW. + */ +struct log_buffer_status { + uint32_t core_id; /* ID of core that logged to other half */ +} __packed; + +#define TRACE_ID_LENGTH 12 + +/* + * Log entry header. + * + * The header is followed by an array of arguments (uint32_t[]). + * Number of arguments is specified by the params_num field of log_entry + */ +struct log_entry_header { + uint32_t id_0 : TRACE_ID_LENGTH; /* e.g. Pipeline ID */ + uint32_t id_1 : TRACE_ID_LENGTH; /* e.g. Component ID */ + uint32_t core_id : 8; /* Reporting core's id */ + + uint64_t timestamp; /* Timestamp (in dsp ticks) */ + uint32_t log_entry_address; /* Address of log entry in ELF */ +} __packed; + +#endif diff --git a/sound/soc/sof/compressed.c b/sound/soc/sof/compressed.c index e747293fe4fac2..7cc35dda0979cc 100644 --- a/sound/soc/sof/compressed.c +++ b/sound/soc/sof/compressed.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "sof-priv.h" #define DRV_NAME "sof-audio" diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 7b72361c3baee1..e08f7e007d293b 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "sof-priv.h" static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size) @@ -327,7 +326,6 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, /* set the ABI header values */ cdata->data->magic = SOF_ABI_MAGIC; cdata->data->abi = SOF_ABI_VERSION; - cdata->data->comp_abi = SOF_ABI_VERSION; /* notify DSP of mixer updates */ snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_DATA, @@ -386,7 +384,6 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, /* set the ABI header values */ cdata->data->magic = SOF_ABI_MAGIC; cdata->data->abi = SOF_ABI_VERSION; - cdata->data->comp_abi = SOF_ABI_VERSION; /* get all the component data from DSP */ ret = snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 793d6ac3cf0fe5..f1a95902279fb5 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -21,7 +21,6 @@ #include #include #include -#include #include "sof-priv.h" #include "ops.h" diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index 75b8ff857dc7ce..637ca57a9c76c8 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include "sof-priv.h" #include "ops.h" diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 0a0892afaffd77..ff20528951a5da 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -24,6 +24,9 @@ #include #include +#include +#include + #include "../sof-priv.h" #include "../ops.h" #include "shim.h" diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 292eed4eeead43..67d7ba513bdc85 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -22,7 +22,8 @@ #include #include #include -#include +#include +#include #include "../sof-priv.h" #include "../ops.h" diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 8311c1bb455075..4d7028ff7a9c09 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -31,7 +31,7 @@ #include #include #include -#include + #include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 5451ba0cfc72dc..7e1e6e8c63804b 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "../sof-priv.h" #include "../ops.h" diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 2299686db32c50..b7e475ab99abaf 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -25,6 +25,8 @@ #include #include +#include +#include #include "../sof-priv.h" #include "../ops.h" #include "shim.h" diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 4ee63ce4dd2b11..fa95209ce64715 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -30,7 +30,6 @@ #include #include #include -#include #include "sof-priv.h" #include "ops.h" diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 3bbbd3c0e0398b..f1a5bb6d08437a 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include "sof-priv.h" #include "ops.h" diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index 48ea9ac32620b5..37b114356d312b 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "ops.h" #include "sof-priv.h" diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 78bca5ad419f2d..1912994a1c94cb 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -16,7 +16,6 @@ #include #include #include -#include #include "sof-priv.h" /* init */ diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index f873c9bffac6b1..b60ef603121718 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -25,7 +25,6 @@ #include #include #include -#include #include "sof-priv.h" #include "ops.h" diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index a4e6624d317088..531fed526c5a2f 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -19,8 +19,16 @@ #include #include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 51d7294b974654..9af530bb45dc9a 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -22,8 +22,7 @@ #include #include #include -#include -#include +#include #include "sof-priv.h" #define COMP_ID_UNASSIGNED 0xffffffff @@ -329,7 +328,6 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, cdata->data->size = control->priv.size; cdata->data->magic = SOF_ABI_MAGIC; cdata->data->abi = SOF_ABI_VERSION; - cdata->data->comp_abi = SOF_ABI_VERSION; } return 0; @@ -428,7 +426,7 @@ static const struct sof_topology_token sched_tokens[] = { {SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, offsetof(struct sof_ipc_pipe_new, priority), 0}, {SOF_TKN_SCHED_MIPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_pipe_new, mips), 0}, + offsetof(struct sof_ipc_pipe_new, period_mips), 0}, {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, offsetof(struct sof_ipc_pipe_new, core), 0}, {SOF_TKN_SCHED_FRAMES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -1120,7 +1118,7 @@ static int sof_widget_load_pipeline(struct snd_soc_component *scomp, dev_dbg(sdev->dev, "pipeline %s: deadline %d pri %d mips %d core %d frames %d\n", swidget->widget->name, pipeline->deadline, pipeline->priority, - pipeline->mips, pipeline->core, pipeline->frames_per_sched); + pipeline->period_mips, pipeline->core, pipeline->frames_per_sched); swidget->private = (void *)pipeline; diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 5aeb6ea3c58b2b..5db0aaca3bf0fb 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -21,8 +21,6 @@ #include #include #include -#include -#include #include "sof-priv.h" #include "ops.h" diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c index 5ca9185f5afdf5..330146fe70f3e3 100644 --- a/sound/soc/sof/xtensa/core.c +++ b/sound/soc/sof/xtensa/core.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "../sof-priv.h" #include "../ops.h" From 165b34de9fdfdb80bc75352fa11ae362c0ba17f6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 12 Nov 2018 11:41:58 -0600 Subject: [PATCH 0239/1995] ASoC: Intel: bxt_pcm512x: fix compilation issues Kbuild report errors when modules are enabled. Move structure definitions and use IS_ENABLED. Fixes: 7ce1ad60ae5a ('ASoC: Intel: bxt_pcm512x: make HDMI optional') Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bxt_pcm512x.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/boards/bxt_pcm512x.c b/sound/soc/intel/boards/bxt_pcm512x.c index 728a53876374ce..ae6a5feded18e9 100644 --- a/sound/soc/intel/boards/bxt_pcm512x.c +++ b/sound/soc/intel/boards/bxt_pcm512x.c @@ -32,7 +32,11 @@ #include "../../codecs/pcm512x.h" #include "../atom/sst-atom-controls.h" -#ifdef CONFIG_SND_SOC_HDAC_HDMI +struct bxt_card_private { + struct list_head hdmi_pcm_list; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) static struct snd_soc_jack broxton_hdmi[3]; struct bxt_hdmi_pcm { @@ -99,10 +103,6 @@ static int bxt_card_late_probe(struct snd_soc_card *card) } #endif -struct bxt_card_private { - struct list_head hdmi_pcm_list; -}; - static const struct snd_soc_dapm_widget dapm_widgets[] = { SND_SOC_DAPM_SPK("Ext Spk", NULL), }; @@ -192,7 +192,7 @@ static struct snd_soc_dai_link dailink[] = { .dpcm_playback = 1, .dpcm_capture = 1, }, -#ifdef CONFIG_SND_SOC_HDAC_HDMI +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) { .name = "iDisp1", .id = 1, From 1c35bbc9fc86f03464d160ef64a08cbf318b5693 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Sat, 10 Nov 2018 11:52:38 +0800 Subject: [PATCH 0240/1995] [DEBUG][CI]travis: modify check patch script The checkpatch script seems to be broken with the Travis CI ENV variable. Use some git parse to generate the commit. Signed-off-by: Pan Xiuli --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 410da51203c6c6..f6803541df8691 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,10 @@ jobs: include: - if: type = pull_request name: checkpatch - script: scripts/checkpatch.pl --strict --codespell -g $TRAVIS_COMMIT_RANGE + script: + - SHA_PR=`git log --oneline -1 | sed -rn "s/.*Merge (.*) into.*/\1/p"` + - SHA_MAIN=`git log --oneline -1 | sed -rn "s/.*Merge .* into (.*)/\1/p"` + - scripts/checkpatch.pl --strict --codespell -g $SHA_MAIN..$SHA_PR - name: "BUILD SOF Kernel x86_64" script: - export ARCH=x86_64 From ddf853b87b701ccf347e4245e23d3ab40e457301 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 13 Nov 2018 14:30:49 -0800 Subject: [PATCH 0241/1995] ASoC: SOF: dmic: fix size of pdm config array A variable length pdm config array introduces issues with insufficient memory allocated for dai_config in struct snd_sof_dai. So fix the array size to 2 to suuport max of 2 PDM controllers for now. Will need to be revisited later for platforms that can support more than 2 controllers. Signed-off-by: Ranjani Sridharan --- include/sound/sof/dai-intel.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h index 3b960216eedb59..529933e177d4b1 100644 --- a/include/sound/sof/dai-intel.h +++ b/include/sound/sof/dai-intel.h @@ -46,6 +46,12 @@ /* bclk idle */ #define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_IDLE_HIGH BIT(5) +/* + * Max number of DMIC PDM controllers supported + * Needs to be re-visited for platforms with > 2 controllers. + */ +#define SOF_DAI_INTEL_DMIC_MAX_PDM 2 + /* SSP Configuration Request - SOF_IPC_DAI_SSP_CONFIG */ struct sof_ipc_dai_ssp_params { uint16_t reserved1; @@ -154,8 +160,8 @@ struct sof_ipc_dai_dmic_params { /* reserved for future use */ uint32_t reserved[8]; - /**< variable number of pdm controller config */ - struct sof_ipc_dai_dmic_pdm_ctrl pdm[0]; + /**< pdm controller config */ + struct sof_ipc_dai_dmic_pdm_ctrl pdm[SOF_DAI_INTEL_DMIC_MAX_PDM]; } __packed; #endif From 8deecf64ed03a0c0232d932451bfde1a42eb2b60 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 12 Nov 2018 11:54:51 -0600 Subject: [PATCH 0242/1995] ASoC: SOF: ipc: fix use of 'complete' Use ipc_complete to make it non-ambiguous and move to u32 to avoid checkpatch warning on boolean usage in structures https://lkml.org/lkml/2017/11/21/384 Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/ipc.c | 6 +++--- sound/soc/sof/sof-priv.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index fa95209ce64715..8850e0605c26e2 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -218,7 +218,7 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, int ret; /* wait for DSP IPC completion */ - ret = wait_event_timeout(msg->waitq, msg->complete, + ret = wait_event_timeout(msg->waitq, msg->ipc_complete, msecs_to_jiffies(IPC_TIMEOUT_MSECS)); spin_lock_irqsave(&sdev->ipc_lock, flags); @@ -275,7 +275,7 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, msg->header = header; msg->msg_size = msg_bytes; msg->reply_size = reply_bytes; - msg->complete = false; + msg->ipc_complete = false; /* attach any data */ if (msg_bytes) @@ -347,7 +347,7 @@ static struct snd_sof_ipc_msg *sof_ipc_reply_find_msg(struct snd_sof_ipc *ipc, static void sof_ipc_tx_msg_reply_complete(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg) { - msg->complete = true; + msg->ipc_complete = true; wake_up(&msg->waitq); } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 531fed526c5a2f..0eefe9e7961e08 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -229,7 +229,7 @@ struct snd_sof_ipc_msg { size_t reply_size; wait_queue_head_t waitq; - bool complete; + u32 ipc_complete; }; /* PCM stream, mapped to FW component */ From 326e446f3b1d5d625074784246287d773ffee810 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 12 Nov 2018 11:57:52 -0600 Subject: [PATCH 0243/1995] ASoC: SOF: remove boolean use in structures Make checkpatch happy https://lkml.org/lkml/2017/11/21/384 Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.h | 2 +- sound/soc/sof/ipc.c | 2 +- sound/soc/sof/sof-priv.h | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index cfe88ecd44778c..a1a525376d760f 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -371,7 +371,7 @@ struct sof_intel_hda_dev { struct hdac_ext_stream *dtrace_stream; /* if position update IPC needed */ - bool no_ipc_position; + u32 no_ipc_position; int irq; diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 8850e0605c26e2..02ca677ad22ed2 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -54,7 +54,7 @@ struct snd_sof_ipc { /* TX message work and status */ wait_queue_head_t wait_txq; struct work_struct tx_kwork; - bool msg_pending; + u32 msg_pending; /* Rx Message work and status */ struct work_struct rx_kwork; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 0eefe9e7961e08..d5f386e81eef46 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -317,7 +317,7 @@ struct snd_sof_dev { /* DSP firmware boot */ wait_queue_head_t boot_wait; - bool boot_complete; + u32 boot_complete; /* DSP HW differentiation */ struct snd_sof_pdata *pdata; @@ -377,12 +377,12 @@ struct snd_sof_dev { int dma_trace_pages; wait_queue_head_t trace_sleep; u32 host_offset; - bool dtrace_is_enabled; - bool dtrace_error; + u32 dtrace_is_enabled; + u32 dtrace_error; /* PM */ - bool restore_kcontrols; /* restore kcontrols upon resume */ - bool first_boot; + u32 restore_kcontrols; /* restore kcontrols upon resume */ + u32 first_boot; void *private; /* core does not touch this */ }; From 3c1f6928bfd8b74f0ac14e1c4a7b7f46ffaa332f Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 9 Nov 2018 10:21:10 +0800 Subject: [PATCH 0244/1995] ASoC: SOF: debug: change runtime PM get/put to correct usuage When doing debugFS entry read, we should make sure it won't enter suspend during the reading, and the reading won't interact the runtime PM(e.g. if the idle timeout is expired when should enter runtime suspend ASSP) neither. Here change to use get_noresume() to make sure not resuming ADSP for debugFS reading, and put_sync_autosuspend() to ensure we can enter runtime suspend after reading finished if needed. Signed-off-by: Keyon Jie --- sound/soc/sof/debug.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index f1a95902279fb5..fa25be01a09657 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -36,7 +36,7 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, { struct snd_sof_dfsentry_io *dfse = file->private_data; struct snd_sof_dev *sdev = dfse->sdev; - int size, err; + int size; u32 *buf; loff_t pos = *ppos; size_t ret; @@ -58,20 +58,18 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, return -ENOMEM; /* copy from DSP MMIO */ - err = pm_runtime_get_sync(sdev->dev); - if (err < 0) { - dev_err(sdev->dev, "error: debugFS failed to resume %d\n", - err); - kfree(buf); - return err; - } + pm_runtime_get_noresume(sdev->dev); memcpy_fromio(buf, dfse->buf + pos, size); - ret = pm_runtime_put(sdev->dev); + /* + * TODO: revisit to check if we need mark_last_busy, or if we + * should change to use xxx_put_sync[_suspend](). + */ + ret = pm_runtime_put_sync_autosuspend(sdev->dev); if (ret < 0) - dev_err(sdev->dev, "error: debugFS failed to idle %zd\n", - ret); + dev_warn(sdev->dev, "warn: debugFS failed to autosuspend %zd\n", + ret); /* copy to userspace */ ret = copy_to_user(buffer, buf, count); From b34040b7e34836f386aa4b8b0b760e83c0df6da4 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 14 Nov 2018 13:33:05 +0800 Subject: [PATCH 0245/1995] ASoC: SOF: trace: fix a put stream failed issue We clear hstream->opened in hda_dsp_stream_put_cstream(), the redundant clear before that is leading to *_put_cstream() fail and error like 'tag 1 not opened!' reported. Here remove this extra clear to fix the issue. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-trace.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c index 3d36db3b1aa22e..8e01fb3677810c 100644 --- a/sound/soc/sof/intel/hda-trace.c +++ b/sound/soc/sof/intel/hda-trace.c @@ -76,7 +76,6 @@ int hda_dsp_trace_release(struct snd_sof_dev *sdev) if (sdev->hda->dtrace_stream) { hstream = &sdev->hda->dtrace_stream->hstream; - hstream->opened = false; hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_CAPTURE, hstream->stream_tag); From 21947cd7724218af2b5f248dbd05f0620039003c Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 7 Nov 2018 15:00:35 +0800 Subject: [PATCH 0246/1995] ASoC: SOF: trace: only init wait_queue one time Today we init trace wait_queue at each resume, snd_sof_init_trace_ipc(), which will clear the wait_queue entry that is waiting for trace update at suspend, that will lead to sof-logger infinitely waiting for logger tools like sof-logger so no trace updating or refreshing though we are back to resume and playback. Here move this wait_queue initialization to snd_sof_init_trace() which is called at first boot only, keep waiting trace update during S0->S3->S0, and fix logger tools no update issues. Signed-off-by: Keyon Jie --- sound/soc/sof/trace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 5db0aaca3bf0fb..0769f44db2a803 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -160,7 +160,6 @@ int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) params.buffer.offset = 0; params.buffer.pages = sdev->dma_trace_pages; - init_waitqueue_head(&sdev->trace_sleep); sdev->host_offset = 0; ret = snd_sof_dma_trace_init(sdev, ¶ms.stream_tag); @@ -233,6 +232,8 @@ int snd_sof_init_trace(struct snd_sof_dev *sdev) goto table_err; } + init_waitqueue_head(&sdev->trace_sleep); + ret = snd_sof_init_trace_ipc(sdev); if (ret < 0) goto table_err; From 0dabbb86f32e01c301e6f2b1344a567ffe574990 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 15 Nov 2018 09:55:46 -0800 Subject: [PATCH 0247/1995] ASoC: SOF: check if sdev->hda is not null check if sdev->hda is not null before initializing chip. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 63d2d0a3a6e62c..8ef9484ee0068d 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -731,7 +731,10 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); struct pci_dev *pci = sdev->pci; - const struct sof_intel_dsp_desc *chip = sdev->hda->desc; + const struct sof_intel_dsp_desc *chip = NULL; + + if (sdev->hda) + chip = sdev->hda->desc; if (sdev->hda && (!IS_ERR(sdev->hda->dmic_dev))) platform_device_unregister(sdev->hda->dmic_dev); From 441b4b0374200744131f8c03fb225a2be42d88f1 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Sun, 11 Nov 2018 05:18:46 +0800 Subject: [PATCH 0248/1995] ASoC: Intel: hdac_hdmi: add Icelake support Add Icelake device id. Also, Icelake's pin2port mapping table is complicated. So we use a mapping table to do the pin2port mapping. Signed-off-by: Bard liao Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 019033c854a20e10f691f6cc0e897df8817d9521) --- sound/soc/codecs/hdac_hdmi.c | 63 ++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 4e9854889a9570..fac39732651551 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -121,8 +121,16 @@ struct hdac_hdmi_dai_port_map { struct hdac_hdmi_cvt *cvt; }; +/* + * pin to port mapping table where the value indicate the pin number and + * the index indicate the port number with 1 base. + */ +static const int icl_pin2port_map[] = {0x4, 0x6, 0x8, 0xa, 0xb}; + struct hdac_hdmi_drv_data { unsigned int vendor_nid; + const int *port_map; /* pin to port mapping table */ + int port_num; }; struct hdac_hdmi_priv { @@ -1329,11 +1337,12 @@ static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid) return 0; } -#define INTEL_VENDOR_NID 0x08 -#define INTEL_GLK_VENDOR_NID 0x0b +#define INTEL_VENDOR_NID_0x2 0x02 +#define INTEL_VENDOR_NID_0x8 0x08 +#define INTEL_VENDOR_NID_0xb 0x0b #define INTEL_GET_VENDOR_VERB 0xf81 #define INTEL_SET_VENDOR_VERB 0x781 -#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ +#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ #define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdev) @@ -1538,7 +1547,26 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev, static int hdac_hdmi_pin2port(void *aptr, int pin) { - return pin - 4; /* map NID 0x05 -> port #1 */ + struct hdac_device *hdev = aptr; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); + const int *map = hdmi->drv_data->port_map; + int i; + + if (!hdmi->drv_data->port_num) + return pin - 4; /* map NID 0x05 -> port #1 */ + + /* + * looking for the pin number in the mapping table and return + * the index which indicate the port number + */ + for (i = 0; i < hdmi->drv_data->port_num; i++) { + if (pin == map[i]) + return i + 1; + } + + /* return -1 if pin number exceeds our expectation */ + dev_err(&hdev->dev, "Can't find the port for pin %d\n", pin); + return -1; } static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) @@ -1549,9 +1577,18 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) struct hdac_hdmi_port *hport = NULL; struct snd_soc_component *component = hdmi->component; int i; - - /* Don't know how this mapping is derived */ - hda_nid_t pin_nid = port + 0x04; + hda_nid_t pin_nid; + + if (!hdmi->drv_data->port_num) { + /* for legacy platforms */ + pin_nid = port + 0x04; + } else if (port < hdmi->drv_data->port_num) { + /* get pin number from the pin2port mapping table */ + pin_nid = hdmi->drv_data->port_map[port - 1]; + } else { + dev_err(&hdev->dev, "Can't find the pin for port %d\n", port); + return; + } dev_dbg(&hdev->dev, "%s: for pin:%d port=%d\n", __func__, pin_nid, pipe); @@ -1973,12 +2010,18 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx) return port->eld.info.spk_alloc; } +static struct hdac_hdmi_drv_data intel_icl_drv_data = { + .vendor_nid = INTEL_VENDOR_NID_0x2, + .port_map = icl_pin2port_map, + .port_num = ARRAY_SIZE(icl_pin2port_map), +}; + static struct hdac_hdmi_drv_data intel_glk_drv_data = { - .vendor_nid = INTEL_GLK_VENDOR_NID, + .vendor_nid = INTEL_VENDOR_NID_0xb, }; static struct hdac_hdmi_drv_data intel_drv_data = { - .vendor_nid = INTEL_VENDOR_NID, + .vendor_nid = INTEL_VENDOR_NID_0x8, }; static int hdac_hdmi_dev_probe(struct hdac_device *hdev) @@ -2259,6 +2302,8 @@ static const struct hda_device_id hdmi_list[] = { &intel_glk_drv_data), HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI", &intel_glk_drv_data), + HDA_CODEC_EXT_ENTRY(0x8086280f, 0x100000, "Icelake HDMI", + &intel_icl_drv_data), {} }; From 07d75676454ca89af6fd2eb148cd3cfb1b44dd76 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 9 Nov 2018 13:39:23 -0600 Subject: [PATCH 0249/1995] ASoC: Intel: Power down links before turning off display audio power On certain platforms, Display HDMI HDA codec was not going to sleep state after the use when links are powered down after turning off the display power. As per the HW recommendation, links are powered down before turning off the display power to ensure that the codec goes to sleep state. This patch was updated from an earlier version submitted upstream [1] which conflicted with the changes merged for HDaudio codec support with the Intel DSP. [1] https://patchwork.kernel.org/patch/10540213/ Signed-off-by: Sriram Periyasamy Signed-off-by: Sanyog Kale Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 4c10473d6ddf12ec124c9ff71a5d23bb5388478b) --- sound/soc/codecs/hdac_hdmi.c | 11 +++++------ sound/soc/intel/skylake/skl.c | 12 ++++++------ 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index fac39732651551..db709eeb019c78 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2230,11 +2230,6 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) */ snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - err = snd_hdac_display_power(bus, false); - if (err < 0) { - dev_err(dev, "Cannot turn on display power on i915\n"); - return err; - } hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev)); if (!hlink) { @@ -2244,7 +2239,11 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) snd_hdac_ext_bus_link_put(bus, hlink); - return 0; + err = snd_hdac_display_power(bus, false); + if (err < 0) + dev_err(dev, "Cannot turn off display power on i915\n"); + + return err; } static int hdac_hdmi_runtime_resume(struct device *dev) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index ebab04b51bc126..ac0b4ff21acc50 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -811,6 +811,12 @@ static void skl_probe_work(struct work_struct *work) } } + /* + * we are done probing so decrement link counts + */ + list_for_each_entry(hlink, &bus->hlink_list, list) + snd_hdac_ext_bus_link_put(bus, hlink); + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { err = snd_hdac_display_power(bus, false); if (err < 0) { @@ -820,12 +826,6 @@ static void skl_probe_work(struct work_struct *work) } } - /* - * we are done probing so decrement link counts - */ - list_for_each_entry(hlink, &bus->hlink_list, list) - snd_hdac_ext_bus_link_put(bus, hlink); - /* configure PM */ pm_runtime_put_noidle(bus->dev); pm_runtime_allow(bus->dev); From 59557d64515fc067e376d7aaa5316a8379ad9562 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 14 Nov 2018 17:06:13 +0800 Subject: [PATCH 0250/1995] ASoC: dapm: Recalculate audio map forcely when card instantiated Audio map are possible in wrong state before card->instantiated has been set to true. Imaging the following examples: time 1: at the beginning in:-1 in:-1 in:-1 in:-1 out:-1 out:-1 out:-1 out:-1 SIGGEN A B Spk time 2: after someone called snd_soc_dapm_new_widgets() (e.g. create_fill_widget_route_map() in sound/soc/codecs/hdac_hdmi.c) in:1 in:0 in:0 in:0 out:0 out:0 out:0 out:1 SIGGEN A B Spk time 3: routes added in:1 in:0 in:0 in:0 out:0 out:0 out:0 out:1 SIGGEN -----> A -----> B ---> Spk In the end, the path should be powered on but it did not. At time 3, "in" of SIGGEN and "out" of Spk did not propagate to their neighbors because snd_soc_dapm_add_path() will not invalidate the paths if the card has not instantiated (i.e. card->instantiated is false). To correct the state of audio map, recalculate the whole map forcely. Signed-off-by: Tzung-Bi Shih Signed-off-by: Mark Brown (cherry picked from commit 882eab6c28d23a970ae73b7eb831b169a672d456) --- sound/soc/soc-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6ddcf12bc030db..b29d0f65611eb5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2131,6 +2131,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } card->instantiated = 1; + dapm_mark_endpoints_dirty(card); snd_soc_dapm_sync(&card->dapm); mutex_unlock(&card->mutex); mutex_unlock(&client_mutex); From 40740c12700768ad2e17fc3a7175dfd5912380a8 Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Thu, 15 Nov 2018 12:13:34 +0800 Subject: [PATCH 0251/1995] ASoC: rt5663: Add regulator support Add regulator support to turn on cpvdd and avdd in probe. If a regulator is not given from device tree, a dummy regulator will be used. Signed-off-by: Cheng-Yi Chiang Signed-off-by: Mark Brown (cherry picked from commit e81a2a6d12e85fbd7b19e96ad72b82a3cc8a6b2d) --- sound/soc/codecs/rt5663.c | 68 +++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 7eb2cbd39d6e09..29c059ed06821d 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,9 @@ #define RT5663_DEVICE_ID_2 0x6451 #define RT5663_DEVICE_ID_1 0x6406 +#define RT5663_POWER_ON_DELAY_MS 300 +#define RT5663_SUPPLY_CURRENT_UA 500000 + enum { CODEC_VER_1, CODEC_VER_0, @@ -48,6 +52,11 @@ struct impedance_mapping_table { unsigned int dc_offset_r_manual_mic; }; +static const char *const rt5663_supply_names[] = { + "avdd", + "cpvdd", +}; + struct rt5663_priv { struct snd_soc_component *component; struct rt5663_platform_data pdata; @@ -56,6 +65,7 @@ struct rt5663_priv { struct snd_soc_jack *hs_jack; struct timer_list btn_check_timer; struct impedance_mapping_table *imp_table; + struct regulator_bulk_data supplies[ARRAY_SIZE(rt5663_supply_names)]; int codec_ver; int sysclk; @@ -3483,7 +3493,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, { struct rt5663_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5663_priv *rt5663; - int ret; + int ret, i; unsigned int val; struct regmap *regmap; @@ -3500,6 +3510,37 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, else rt5663_parse_dp(rt5663, &i2c->dev); + for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++) + rt5663->supplies[i].supply = rt5663_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, + ARRAY_SIZE(rt5663->supplies), + rt5663->supplies); + if (ret) { + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + /* Set load for regulator. */ + for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++) { + ret = regulator_set_load(rt5663->supplies[i].consumer, + RT5663_SUPPLY_CURRENT_UA); + if (ret) { + dev_err(&i2c->dev, + "Failed to set regulator %s, ret: %d\n", + rt5663->supplies[i].supply, ret); + } + } + + ret = regulator_bulk_enable(ARRAY_SIZE(rt5663->supplies), + rt5663->supplies); + + if (ret) { + dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + msleep(RT5663_POWER_ON_DELAY_MS); + regmap = devm_regmap_init_i2c(i2c, &temp_regmap); if (IS_ERR(regmap)) { ret = PTR_ERR(regmap); @@ -3530,7 +3571,8 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, dev_err(&i2c->dev, "Device with ID register %#x is not rt5663\n", val); - return -ENODEV; + ret = -ENODEV; + goto err_enable; } if (IS_ERR(rt5663->regmap)) { @@ -3635,20 +3677,30 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, ret = request_irq(i2c->irq, rt5663_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "rt5663", rt5663); - if (ret) + if (ret) { dev_err(&i2c->dev, "%s Failed to reguest IRQ: %d\n", __func__, ret); + goto err_enable; + } } ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5663, rt5663_dai, ARRAY_SIZE(rt5663_dai)); - if (ret) { - if (i2c->irq) - free_irq(i2c->irq, rt5663); - } + if (ret) + goto err_irq; + return 0; + +err_irq: + if (i2c->irq) + free_irq(i2c->irq, rt5663); + +err_enable: + dev_err(&i2c->dev, + "%s: Disable regulator after probe error\n", __func__); + regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies); return ret; } @@ -3659,6 +3711,8 @@ static int rt5663_i2c_remove(struct i2c_client *i2c) if (i2c->irq) free_irq(i2c->irq, rt5663); + regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies); + return 0; } From fed5195ff9bda5b8ad9d6602d6fd6d7e77cd72de Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 12 Nov 2018 16:03:19 -0600 Subject: [PATCH 0252/1995] ASoC: SOF: Intel: hda: fix error handling in probe The GPROCEN bit is only set when there is no error path, so don't clear it on all errors. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 8ef9484ee0068d..9253168e76597f 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -721,9 +721,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) free_streams: hda_dsp_stream_free(sdev); err: - /* disable DSP */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, - SOF_HDA_PPCTL_GPROCEN, 0); return ret; } From 17f982b7d3e83736e325b45d8e7c3c794fd61f21 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 12 Nov 2018 16:10:33 -0600 Subject: [PATCH 0253/1995] ASoC: SOF: Intel: hda: fix sof_hda_bus_init This function returns zero always, change return type to void Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-bus.c | 7 ++----- sound/soc/sof/intel/hda.h | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index 759f1e61a0309c..e7fd07f1f80d5b 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -75,10 +75,9 @@ static const struct hdac_io_ops io_ops = { /* * This can be used for both with/without hda link support. - * Returns 0 if successful, or a negative error code. */ -int sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, - const struct hdac_ext_bus_ops *ext_ops) +void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, + const struct hdac_ext_bus_ops *ext_ops) { static int idx; @@ -103,6 +102,4 @@ int sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, mutex_init(&bus->lock); bus->cmd_dma_state = true; - - return 0; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index a1a525376d760f..f31c1b02eb394e 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -504,8 +504,8 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset); /* * HDA bus operations. */ -int sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, - const struct hdac_ext_bus_ops *ext_ops); +void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, + const struct hdac_ext_bus_ops *ext_ops); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* From 07eaaf4c40e1b8c8bd0cf37c1e914e6cf0d97b43 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 12 Nov 2018 16:20:44 -0600 Subject: [PATCH 0254/1995] ASoC: SOF: Intel: hda: unmap on hda_init error Add new goto to handle possible errors and unmap bar Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 9253168e76597f..eda53d7e00d8ea 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -563,9 +563,10 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) #endif /* set up HDA base */ + bus = sof_to_bus(sdev); ret = hda_init(sdev); if (ret < 0) - return ret; + goto hdac_bus_unmap; /* DSP base */ sdev->bar[HDA_DSP_BAR] = pci_ioremap_bar(pci, HDA_DSP_BAR); @@ -619,7 +620,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) sdev->ipc_irq = sdev->hda->irq; } - bus = sof_to_bus(sdev); dev_dbg(sdev->dev, "using HDA IRQ %d\n", sdev->hda->irq); ret = request_threaded_irq(sdev->hda->irq, hda_dsp_stream_interrupt, hda_dsp_stream_threaded_handler, @@ -720,6 +720,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) pci_free_irq_vectors(pci); free_streams: hda_dsp_stream_free(sdev); +hdac_bus_unmap: + iounmap(bus->remap_addr); err: return ret; } From 3421fef13d8488b8d732e75d3709c158f0469521 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 12 Nov 2018 16:22:21 -0600 Subject: [PATCH 0255/1995] ASoC: SOF: Intel: hda: handle error on DSP BAR remap Jump to correct goto instead of just returning -ENXIO Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index eda53d7e00d8ea..22932eb2f25915 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -572,7 +572,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) sdev->bar[HDA_DSP_BAR] = pci_ioremap_bar(pci, HDA_DSP_BAR); if (!sdev->bar[HDA_DSP_BAR]) { dev_err(&pci->dev, "error: ioremap error\n"); - return -ENXIO; + ret = -ENXIO; + goto hdac_bus_unmap; } sdev->mmio_bar = HDA_DSP_BAR; From 72ec64bff2d0068478d9f963c84f4d7d11bb4965 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 12 Nov 2018 16:36:47 -0600 Subject: [PATCH 0256/1995] ASoC: SOF: Intel: hda: free streams on error The comments make no sense, the streams are not freed on error. Fix. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 22932eb2f25915..74791786943184 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -597,7 +597,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) * not all errors are due to memory issues, but trying * to free everything does not harm */ - goto err; + goto free_streams; } /* From ae0c35f70f82e0d427dc5e992fa682526ec4af97 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 12 Nov 2018 16:40:42 -0600 Subject: [PATCH 0257/1995] ASoC: SOF: hda: Intel: free dsp bar mapping Add label (not currently used) which is always reached with free_streams Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 74791786943184..cc232e176d2d8a 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -721,6 +721,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) pci_free_irq_vectors(pci); free_streams: hda_dsp_stream_free(sdev); +/* dsp_unmap: not currently used */ + iounmap(sdev->bar[HDA_DSP_BAR]); hdac_bus_unmap: iounmap(bus->remap_addr); err: From d838241c6768a9c52d20d9586e012d19f16036d4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 12 Nov 2018 16:49:37 -0600 Subject: [PATCH 0258/1995] ASoC: SOF: hda: be consistent and free hda->irq instead of pci->irq Follow Keyon'd recommendation Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index cc232e176d2d8a..ddb803dc074fb6 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -758,7 +758,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) SOF_HDA_PPCTL_GPROCEN, 0); free_irq(sdev->ipc_irq, sdev); - free_irq(sdev->pci->irq, bus); + free_irq(sdev->hda->irq, bus); pci_free_irq_vectors(pci); hda_dsp_stream_free(sdev); From 893e7e85d46fdce8ec5be6fed0d50b41bccd2711 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 12 Nov 2018 16:51:28 -0600 Subject: [PATCH 0259/1995] ASoC: SOF: Intel: hda: unmap on remove Follow same pattern as for error handling on probe Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index ddb803dc074fb6..d4ffdb2a76629d 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -762,6 +762,10 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) pci_free_irq_vectors(pci); hda_dsp_stream_free(sdev); + + iounmap(sdev->bar[HDA_DSP_BAR]); + iounmap(bus->remap_addr); + return 0; } From 1abb9e733e735ad2ac8ae7f8062e7e12d56d3e29 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 12 Nov 2018 16:01:38 -0600 Subject: [PATCH 0260/1995] ASoC: SOF: Intel: clean-up i915 support Add missing exit and get/put helpers. It's assumed that the device will not be active on exit - so we don't need to decrease the refcount. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-codec.c | 49 +++++++++++++++++++++++++++++++-- sound/soc/sof/intel/hda-dsp.c | 4 +-- sound/soc/sof/intel/hda.c | 13 +++++---- sound/soc/sof/intel/hda.h | 8 +++++- 4 files changed, 62 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index fbf64635b309e6..9701aac357b3ea 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -112,6 +112,34 @@ int hda_codec_probe_bus(struct snd_sof_dev *sdev) } EXPORT_SYMBOL(hda_codec_probe_bus); +int hda_codec_i915_get(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int ret; + + dev_dbg(bus->dev, "Turning i915 HDAC power on\n"); + ret = snd_hdac_display_power(bus, true); + if (ret < 0) + dev_err(bus->dev, "i915 HDAC power on failed %d\n", ret); + + return ret; +} +EXPORT_SYMBOL(hda_codec_i915_get); + +int hda_codec_i915_put(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int ret; + + dev_dbg(bus->dev, "Turning i915 HDAC power off\n"); + ret = snd_hdac_display_power(bus, false); + if (ret < 0) + dev_err(bus->dev, "i915 HDAC power off failed %d\n", ret); + + return ret; +} +EXPORT_SYMBOL(hda_codec_i915_put); + int hda_codec_i915_init(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); @@ -122,12 +150,27 @@ int hda_codec_i915_init(struct snd_sof_dev *sdev) if (ret < 0) return ret; - ret = snd_hdac_display_power(bus, true); - if (ret < 0) - dev_err(bus->dev, "i915 HDAC power on failed %d\n", ret); + ret = hda_codec_i915_get(sdev); return ret; } EXPORT_SYMBOL(hda_codec_i915_init); +int hda_codec_i915_exit(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int ret; + + /* + * we don't need to decrease the refcount with + * hda_codec_i915_put() on exit since the device cannot be + * active + */ + + ret = snd_hdac_i915_exit(bus); + + return ret; +} +EXPORT_SYMBOL(hda_codec_i915_exit); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 4d7028ff7a9c09..9e1874f3f4d268 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -380,7 +380,7 @@ int hda_dsp_resume(struct snd_sof_dev *sdev) /* turn display power on */ if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, true); + ret = hda_codec_i915_get(sdev); if (ret < 0) { dev_err(bus->dev, "Cannot turn on display power on i915 after resume\n"); return ret; @@ -417,7 +417,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state) /* turn display power off */ if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, false); + ret = hda_codec_i915_put(sdev); if (ret < 0) { dev_err(bus->dev, "Cannot turn OFF display power on i915 during suspend\n"); return ret; diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index d4ffdb2a76629d..1c2f8c08dc2555 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -459,8 +459,11 @@ static int hda_init_caps(struct snd_sof_dev *sdev) ret = hda_dsp_ctrl_init_chip(sdev, true); if (ret < 0) { dev_err(bus->dev, "Init chip failed with ret: %d\n", ret); - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - snd_hdac_display_power(bus, false); + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { + ret = hda_codec_i915_put(sdev); + if (ret < 0) + return ret; + } return ret; } @@ -477,11 +480,9 @@ static int hda_init_caps(struct snd_sof_dev *sdev) hda_codec_probe_bus(sdev); if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, false); - if (ret < 0) { - dev_err(bus->dev, "Cannot turn off display power on i915\n"); + ret = hda_codec_i915_put(sdev); + if (ret < 0) return ret; - } } /* diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index f31c1b02eb394e..875af5e287dfc9 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -512,9 +512,15 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, * HDA Codec operations. */ int hda_codec_probe_bus(struct snd_sof_dev *sdev); + +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) +int hda_codec_i915_get(struct snd_sof_dev *sdev); +int hda_codec_i915_put(struct snd_sof_dev *sdev); int hda_codec_i915_init(struct snd_sof_dev *sdev); -#endif +int hda_codec_i915_exit(struct snd_sof_dev *sdev); +#endif /* CONFIG_SND_SOC_HDAC_HDMI */ +#endif /* CONFIG_SND_SOC_SOF_HDA */ /* * Trace Control. */ From e5d6e446a64a365657756b1188a8d099465dcc74 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 12 Nov 2018 17:26:56 -0600 Subject: [PATCH 0261/1995] ASoC: SOF: Intel: hda: add i915_exit Start dealing with resource free to enable module load/unload FIXME: is this necessary or is this handled by the _suspend cases? Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 1c2f8c08dc2555..a951de0edb4daf 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -767,6 +767,9 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) iounmap(sdev->bar[HDA_DSP_BAR]); iounmap(bus->remap_addr); + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + hda_codec_i915_exit(sdev); + return 0; } From 64ab02cc65a7d245047646cebe3fd8d0c9cb880a Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Thu, 1 Nov 2018 10:36:41 +0800 Subject: [PATCH 0262/1995] ASoC: acpi: fix: continue searching when machine is ignored The machine_quirk may return NULL which means the acpi entries should be skipped and search for next matched entry is needed, here add return check here and continue for NULL case. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart --- sound/soc/soc-acpi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c index b8e72b52db30ea..4fb29f0e561ef3 100644 --- a/sound/soc/soc-acpi.c +++ b/sound/soc/soc-acpi.c @@ -10,11 +10,17 @@ struct snd_soc_acpi_mach * snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines) { struct snd_soc_acpi_mach *mach; + struct snd_soc_acpi_mach *mach_alt; for (mach = machines; mach->id[0]; mach++) { if (acpi_dev_present(mach->id, NULL, -1)) { - if (mach->machine_quirk) - mach = mach->machine_quirk(mach); + if (mach->machine_quirk) { + mach_alt = mach->machine_quirk(mach); + if (!mach_alt) + continue; /* not full match, ignore */ + mach = mach_alt; + } + return mach; } } From 089ceeab16871755e57f4aefe48e9f179f8ae0e3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 14 Nov 2018 13:49:54 -0600 Subject: [PATCH 0263/1995] ASoC: Intel: fix interface for Chromebook machine drivers The changes for HDaudio overlooked the fact that the machine drivers used for Chromebooks rely on the dmic number information passed as pdata. Add dmic_num field to standard interface and use standard interface instead of SKL-specific one. Also clean-up pdata definition to remove fields that are no longer used. Fixes: 842bb5135f10 ('ASoC: Intel: use standard interface for Hdaudio machine driver') Signed-off-by: Pierre-Louis Bossart --- include/sound/soc-acpi.h | 1 + sound/soc/intel/boards/kbl_rt5663_max98927.c | 10 +++++----- sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c | 10 +++++----- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 10 +++++----- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 10 +++++----- sound/soc/intel/skylake/skl.c | 2 +- sound/soc/intel/skylake/skl.h | 3 --- 7 files changed, 22 insertions(+), 24 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 5154c6359609fc..266e64e3c24c4f 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -48,6 +48,7 @@ struct snd_soc_acpi_mach_params { u32 acpi_ipc_irq_index; const char *platform; u32 codec_mask; + u32 dmic_num; }; /** diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index 6ea969c0a5fb8c..c2a96940f9f296 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -25,9 +25,9 @@ #include #include #include +#include #include "../../codecs/rt5663.h" #include "../../codecs/hdac_hdmi.h" -#include "../skylake/skl.h" #include #include #include @@ -969,7 +969,7 @@ static struct snd_soc_card kabylake_audio_card_rt5663 = { static int kabylake_audio_probe(struct platform_device *pdev) { struct kbl_rt5663_private *ctx; - struct skl_machine_pdata *pdata; + struct snd_soc_acpi_mach *mach; int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); @@ -984,9 +984,9 @@ static int kabylake_audio_probe(struct platform_device *pdev) kabylake_audio_card->dev = &pdev->dev; snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - pdata = dev_get_drvdata(&pdev->dev); - if (pdata) - dmic_constraints = pdata->dmic_num == 2 ? + mach = dev_get_drvdata(&pdev->dev); + if (mach) + dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk"); diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index a737c915d46a83..d7df307b406f7a 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -26,10 +26,10 @@ #include #include #include +#include #include "../../codecs/rt5514.h" #include "../../codecs/rt5663.h" #include "../../codecs/hdac_hdmi.h" -#include "../skylake/skl.h" #define KBL_REALTEK_CODEC_DAI "rt5663-aif" #define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1" @@ -648,7 +648,7 @@ static struct snd_soc_card kabylake_audio_card = { static int kabylake_audio_probe(struct platform_device *pdev) { struct kbl_codec_private *ctx; - struct skl_machine_pdata *pdata; + struct snd_soc_acpi_mach *mach; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -659,9 +659,9 @@ static int kabylake_audio_probe(struct platform_device *pdev) kabylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&kabylake_audio_card, ctx); - pdata = dev_get_drvdata(&pdev->dev); - if (pdata) - dmic_constraints = pdata->dmic_num == 2 ? + mach = dev_get_drvdata(&pdev->dev); + if (mach) + dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card); diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 552958ce736d1e..931890f9aa742c 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -21,9 +21,9 @@ #include #include #include +#include #include "../../codecs/nau8825.h" #include "../../codecs/hdac_hdmi.h" -#include "../skylake/skl.h" #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" #define SKL_MAXIM_CODEC_DAI "HiFi" @@ -641,7 +641,7 @@ static struct snd_soc_card skylake_audio_card = { static int skylake_audio_probe(struct platform_device *pdev) { struct skl_nau8825_private *ctx; - struct skl_machine_pdata *pdata; + struct snd_soc_acpi_mach *mach; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -652,9 +652,9 @@ static int skylake_audio_probe(struct platform_device *pdev) skylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - pdata = dev_get_drvdata(&pdev->dev); - if (pdata) - dmic_constraints = pdata->dmic_num == 2 ? + mach = dev_get_drvdata(&pdev->dev); + if (mach) + dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index f985b30a1d0eaa..657c650766fc71 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -23,11 +23,11 @@ #include #include #include +#include #include #include #include "../../codecs/nau8825.h" #include "../../codecs/hdac_hdmi.h" -#include "../skylake/skl.h" #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" #define SKL_SSM_CODEC_DAI "ssm4567-hifi" @@ -694,7 +694,7 @@ static struct snd_soc_card skylake_audio_card = { static int skylake_audio_probe(struct platform_device *pdev) { struct skl_nau88125_private *ctx; - struct skl_machine_pdata *pdata; + struct snd_soc_acpi_mach *mach; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -705,9 +705,9 @@ static int skylake_audio_probe(struct platform_device *pdev) skylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - pdata = dev_get_drvdata(&pdev->dev); - if (pdata) - dmic_constraints = pdata->dmic_num == 2 ? + mach = dev_get_drvdata(&pdev->dev); + if (mach) + dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index ac0b4ff21acc50..c05618c6392f9a 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -515,7 +515,7 @@ static int skl_find_machine(struct skl *skl, void *driver_data) if (pdata) { skl->use_tplg_pcm = pdata->use_tplg_pcm; - pdata->dmic_num = skl_get_dmic_geo(skl); + mach->mach_params.dmic_num = skl_get_dmic_geo(skl); } return 0; diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 9a9688dcf26010..85f8bb6687dcbd 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -119,10 +119,7 @@ struct skl_dma_params { }; struct skl_machine_pdata { - u32 dmic_num; bool use_tplg_pcm; /* use dais and dai links from topology */ - const char *platform; - unsigned long codec_mask; }; struct skl_dsp_ops { From c029da6bf5cfdb2fb006545ac4981899faa7df41 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 14 Nov 2018 14:00:58 -0600 Subject: [PATCH 0264/1995] ASoC: Intel: use platform_data for machine drivers For some reason we have different mechanisms for passing data to machine drivers. Use the solution used by Atom/SST and SOF instead of using drv_data as done by Skylake. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/kbl_rt5663_max98927.c | 2 +- sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c | 2 +- sound/soc/intel/boards/skl_hda_dsp_generic.c | 2 +- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 2 +- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 2 +- sound/soc/intel/skylake/skl.c | 13 ++++++++++--- 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index c2a96940f9f296..d71475200b08aa 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -984,7 +984,7 @@ static int kabylake_audio_probe(struct platform_device *pdev) kabylake_audio_card->dev = &pdev->dev; snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - mach = dev_get_drvdata(&pdev->dev); + mach = (&pdev->dev)->platform_data; if (mach) dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index d7df307b406f7a..7044d8c2b18737 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -659,7 +659,7 @@ static int kabylake_audio_probe(struct platform_device *pdev) kabylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&kabylake_audio_card, ctx); - mach = dev_get_drvdata(&pdev->dev); + mach = (&pdev->dev)->platform_data; if (mach) dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 15c502d6774d08..b9a21e64ead2ec 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -146,7 +146,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - mach = dev_get_drvdata(&pdev->dev); + mach = (&pdev->dev)->platform_data; if (!mach) return -EINVAL; diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 931890f9aa742c..0922106bd323d7 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -652,7 +652,7 @@ static int skylake_audio_probe(struct platform_device *pdev) skylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - mach = dev_get_drvdata(&pdev->dev); + mach = (&pdev->dev)->platform_data; if (mach) dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 657c650766fc71..8433c521d39f21 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -705,7 +705,7 @@ static int skylake_audio_probe(struct platform_device *pdev) skylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - mach = dev_get_drvdata(&pdev->dev); + mach = (&pdev->dev)->platform_data; if (mach) dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index c05618c6392f9a..00a754a8e2163c 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -534,6 +534,16 @@ static int skl_machine_device_register(struct skl *skl) return -EIO; } + mach->mach_params.platform = dev_name(bus->dev); + mach->mach_params.codec_mask = bus->codec_mask; + + ret = platform_device_add_data(pdev, (const void *)mach, sizeof(*mach)); + if (ret) { + dev_err(bus->dev, "failed to add machine device platform data\n"); + platform_device_put(pdev); + return ret; + } + ret = platform_device_add(pdev); if (ret) { dev_err(bus->dev, "failed to add machine device\n"); @@ -541,9 +551,6 @@ static int skl_machine_device_register(struct skl *skl) return -EIO; } - mach->mach_params.platform = dev_name(bus->dev); - mach->mach_params.codec_mask = bus->codec_mask; - dev_set_drvdata(&pdev->dev, mach); skl->i2s_dev = pdev; From 12df398ac2e66c55ac2e958517d6d2106a7b0666 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 13 Nov 2018 13:48:51 -0600 Subject: [PATCH 0265/1995] ASoC: SOF: core: pass correct machine into to machine driver Wrong pointer. Oops. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index fa8ea61d3fe296..f92279c688e688 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -335,8 +335,8 @@ static int sof_probe(struct platform_device *pdev) plat_data->machine->new_mach_data(plat_data); } else { drv_name = plat_data->machine->drv_name; - mach = (const void *)plat_data; - size = sizeof(*plat_data); + mach = (const void *)plat_data->machine; + size = sizeof(*plat_data->machine); /* register machine driver, pass machine info as pdata */ plat_data->pdev_mach = From 6017ab9fbd1f0c9e6e42ddb05b9cdbf8dac9eefa Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 13 Nov 2018 13:50:19 -0600 Subject: [PATCH 0266/1995] ASoC: SOF: Intel: hda: log codec mask It's useful information to check if iDisp is detected Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index a951de0edb4daf..192289fb734b4f 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -470,6 +470,8 @@ static int hda_init_caps(struct snd_sof_dev *sdev) /* codec detection */ if (!bus->codec_mask) dev_info(bus->dev, "no hda codecs found!\n"); + else + dev_info(bus->dev, "hda codecs found, mask %lx!\n", bus->codec_mask); /* used by hda machine driver to create dai links */ mach_params = (struct snd_soc_acpi_mach_params *) From af2dbec88bd12cd4aec78a48d71f3b526ad4dbd6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 13 Nov 2018 18:02:57 -0600 Subject: [PATCH 0267/1995] ASoC: SOF: pci: respin HDaudio/nocodec selections Only fallback to nocodec if HDaudio is not selected. This avoids having to tweak default configs to enable HDAudio. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-pci-dev.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index a652bc2f424896..0381d5198e5895 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -222,21 +222,31 @@ static int sof_pci_probe(struct pci_dev *pci, #else /* find machine */ mach = snd_soc_acpi_find_machine(desc->machines); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) if (!mach) { + dev_warn(dev, "No matching ASoC machine driver found - falling back to HDA codec\n"); + mach = snd_soc_acpi_intel_hda_machines; + mach->sof_fw_filename = desc->nocodec_fw_filename; + + /* + * TODO: we need to find a way to check if codecs are actually + * present + */ + } +#endif /* CONFIG_SND_SOC_SOF_HDA */ + #if IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) + if (!mach) { /* fallback to nocodec mode */ dev_warn(dev, "No matching ASoC machine driver found - using nocodec\n"); mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); if (ret < 0) goto release_regions; -#else - dev_warn(dev, "No matching ASoC machine driver found - falling back to HDA codec\n"); - mach = snd_soc_acpi_intel_hda_machines; - mach->sof_fw_filename = desc->nocodec_fw_filename; -#endif } -#endif +#endif /* CONFIG_SND_SOC_SOF_NOCODEC */ + +#endif /* CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE */ mach->pdata = ops; From 68cc156d4ff7ff512d76e66107ae35ed5445ff44 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 17 Nov 2018 10:19:05 -0600 Subject: [PATCH 0268/1995] ASoC: SOF: hda: better split between HDA and non-HDA platforms Most inits can be conditionally included. the bus->reg_lock spinlock is required in all cases. TODO: remove the static variable (unclear why it's needed) Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-bus.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index e7fd07f1f80d5b..de158dd7d0cf58 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -86,20 +86,22 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, bus->io_ops = &io_ops; INIT_LIST_HEAD(&bus->stream_list); - INIT_LIST_HEAD(&bus->codec_list); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - bus->ops = &bus_ops; - INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); -#endif - spin_lock_init(&bus->reg_lock); - mutex_init(&bus->cmd_mutex); bus->irq = -1; - bus->ext_ops = ext_ops; - INIT_LIST_HEAD(&bus->hlink_list); bus->idx = idx++; + spin_lock_init(&bus->reg_lock); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + INIT_LIST_HEAD(&bus->codec_list); + INIT_LIST_HEAD(&bus->hlink_list); + + mutex_init(&bus->cmd_mutex); mutex_init(&bus->lock); + bus->ops = &bus_ops; + INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); bus->cmd_dma_state = true; +#endif + } From 5cde05535aec7d4abc7165cac6c663d67002d906 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 17 Nov 2018 10:22:19 -0600 Subject: [PATCH 0269/1995] ASoC: SOF: intel: hda-stream: remove warnings when SOF_HDA is not defined Make bus and hlink variables conditionally declared Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-dsp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 9e1874f3f4d268..c4585a0d85a3fe 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -259,7 +259,9 @@ int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, static int hda_suspend(struct snd_sof_dev *sdev, int state) { const struct sof_intel_dsp_desc *chip = sdev->hda->desc; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_bus *bus = sof_to_bus(sdev); +#endif int ret = 0; #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) @@ -302,8 +304,10 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state) static int hda_resume(struct snd_sof_dev *sdev) { const struct sof_intel_dsp_desc *chip = sdev->hda->desc; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_ext_link *hlink = NULL; +#endif int ret; /* From 13b4fafeae0f0a4afd62b7385f1b7e3f24a3aaa5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 17 Nov 2018 10:25:09 -0600 Subject: [PATCH 0270/1995] ASoC: SOF: intel: remove DRSM support This code isn't tested, let's remove it and re-add later if needed Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-stream.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 49725fcd5590ed..566a2f1f54becc 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -555,14 +555,6 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) SOF_HDA_SPIB_MAXFIFO; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_DRSM) - /* FIXME: Remove? HDAC doesn't use DRSM so has no drsm_addr */ - /* do we support DRSM */ - if (sdev->bar[HDA_DSP_DRSM_BAR]) - stream->drsm_addr = sdev->bar[HDA_DSP_DRSM_BAR] + - SOF_HDA_DRSM_BASE + SOF_HDA_DRSM_INTERVAL * i; -#endif - hstream = &stream->hstream; hstream->bus = bus; hstream->sd_int_sta_mask = 1 << i; @@ -613,14 +605,6 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) SOF_HDA_SPIB_MAXFIFO; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_DRSM) - /* FIXME: Remove? HDAC doesn't use DRSM so has no drsm_addr */ - /* do we support DRSM */ - if (sdev->bar[HDA_DSP_DRSM_BAR]) - stream->drsm_addr = sdev->bar[HDA_DSP_DRSM_BAR] + - SOF_HDA_DRSM_BASE + SOF_HDA_DRSM_INTERVAL * i; -#endif - hstream = &stream->hstream; hstream->bus = bus; hstream->sd_int_sta_mask = 1 << i; From 018945c83c42c1dad66b23b1a357c5961ee7e4e5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 17 Nov 2018 10:28:53 -0600 Subject: [PATCH 0271/1995] ASoC: SOF: Intel: fix CORB/RIRB usage/release Make rb conditional on SOF_HDA and add missing free on release. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-stream.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 566a2f1f54becc..880c7425c13172 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -522,6 +522,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) return -ENOMEM; } +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* mem alloc for the CORB/RIRB ringbuffers */ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, PAGE_SIZE, &bus->rb); @@ -529,6 +530,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) dev_err(sdev->dev, "error: RB alloc failed\n"); return -ENOMEM; } +#endif /* create capture streams */ for (i = 0; i < num_capture; i++) { @@ -643,6 +645,12 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev) if (bus->posbuf.area) snd_dma_free_pages(&bus->posbuf); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* free position buffer */ + if (bus->rb.area) + snd_dma_free_pages(&bus->rb); +#endif + list_for_each_entry_safe(s, _s, &bus->stream_list, list) { /* TODO: decouple */ From 7f4d6574690581337a1bc48af9071967132ed3b5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 17 Nov 2018 10:58:39 -0600 Subject: [PATCH 0272/1995] ASoC: SOF: intel: better handling of i915 code Use static inlines to make code simpler. i915 is only enabled/used when both SOF_HDA and SOC_HDAC_HDMI are used. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-codec.c | 4 ++++ sound/soc/sof/intel/hda-dsp.c | 20 ++++++++------------ sound/soc/sof/intel/hda.c | 30 ++++++++++++------------------ sound/soc/sof/intel/hda.h | 16 +++++++++++++--- 4 files changed, 37 insertions(+), 33 deletions(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 9701aac357b3ea..cc4a537d0e8a6f 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -112,6 +112,8 @@ int hda_codec_probe_bus(struct snd_sof_dev *sdev) } EXPORT_SYMBOL(hda_codec_probe_bus); +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) + int hda_codec_i915_get(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); @@ -173,4 +175,6 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev) } EXPORT_SYMBOL(hda_codec_i915_exit); +#endif /* CONFIG_SND_SOC_HDAC_HDMI */ + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index c4585a0d85a3fe..413e76a46b300b 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -383,12 +383,10 @@ int hda_dsp_resume(struct snd_sof_dev *sdev) int ret; /* turn display power on */ - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = hda_codec_i915_get(sdev); - if (ret < 0) { - dev_err(bus->dev, "Cannot turn on display power on i915 after resume\n"); - return ret; - } + ret = hda_codec_i915_get(sdev); + if (ret < 0) { + dev_err(bus->dev, "Cannot turn on display power on i915 after resume\n"); + return ret; } /* init hda controller and power dsp up */ @@ -420,12 +418,10 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state) } /* turn display power off */ - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = hda_codec_i915_put(sdev); - if (ret < 0) { - dev_err(bus->dev, "Cannot turn OFF display power on i915 during suspend\n"); - return ret; - } + ret = hda_codec_i915_put(sdev); + if (ret < 0) { + dev_err(bus->dev, "Cannot turn OFF display power on i915 during suspend\n"); + return ret; } return 0; diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 192289fb734b4f..e0ba5c75f3a8f0 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -437,6 +437,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) struct hdac_ext_link *hlink = NULL; struct snd_soc_acpi_mach_params *mach_params; int ret = 0; + int err; device_disable_async_suspend(bus->dev); @@ -448,22 +449,18 @@ static int hda_init_caps(struct snd_sof_dev *sdev) snd_hdac_ext_bus_get_ml_capabilities(bus); /* init i915 and HDMI codecs */ - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = hda_codec_i915_init(sdev); - if (ret < 0) { - dev_err(&pci->dev, "no HDMI audio devices found\n"); - return ret; - } + ret = hda_codec_i915_init(sdev); + if (ret < 0) { + dev_err(&pci->dev, "no HDMI audio devices found\n"); + return ret; } ret = hda_dsp_ctrl_init_chip(sdev, true); if (ret < 0) { dev_err(bus->dev, "Init chip failed with ret: %d\n", ret); - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = hda_codec_i915_put(sdev); - if (ret < 0) - return ret; - } + err = hda_codec_i915_put(sdev); + if (err < 0) + return err; return ret; } @@ -481,11 +478,9 @@ static int hda_init_caps(struct snd_sof_dev *sdev) /* create codec instances */ hda_codec_probe_bus(sdev); - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = hda_codec_i915_put(sdev); - if (ret < 0) - return ret; - } + ret = hda_codec_i915_put(sdev); + if (ret < 0) + return ret; /* * we are done probing so decrement link counts @@ -769,8 +764,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) iounmap(sdev->bar[HDA_DSP_BAR]); iounmap(bus->remap_addr); - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - hda_codec_i915_exit(sdev); + hda_codec_i915_exit(sdev); return 0; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 875af5e287dfc9..6cf4d84a88a396 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -513,14 +513,24 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, */ int hda_codec_probe_bus(struct snd_sof_dev *sdev); -#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) +#endif /* CONFIG_SND_SOC_SOF_HDA */ + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) && IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) + int hda_codec_i915_get(struct snd_sof_dev *sdev); int hda_codec_i915_put(struct snd_sof_dev *sdev); int hda_codec_i915_init(struct snd_sof_dev *sdev); int hda_codec_i915_exit(struct snd_sof_dev *sdev); -#endif /* CONFIG_SND_SOC_HDAC_HDMI */ -#endif /* CONFIG_SND_SOC_SOF_HDA */ +#else + +static inline int hda_codec_i915_get(struct snd_sof_dev *sdev) { return 0; } +static inline int hda_codec_i915_put(struct snd_sof_dev *sdev) { return 0; } +static inline int hda_codec_i915_init(struct snd_sof_dev *sdev) { return 0; } +static inline int hda_codec_i915_exit(struct snd_sof_dev *sdev) { return 0; } + +#endif /* CONFIG_SND_SOC_SOF_HDA && CONFIG_SND_SOC_HDAC_HDMI */ + /* * Trace Control. */ From 1d20a694c3c207f69845e1cc20694c9446ebf611 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 17 Nov 2018 11:04:39 -0600 Subject: [PATCH 0273/1995] ASoC: SOF: intel: remove compilation warning when SOF_HDA is not defined -Wunused-variable should be an error Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-ctrl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 3414e50bf4fb7e..1f6cd07f8c756a 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -138,7 +138,9 @@ void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable) */ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_bus *bus = sof_to_bus(sdev); +#endif u32 val; /* enable/disable audio dsp clock gating */ From 38a7c34efe5f90b260605ff07ae3c6e784d704d5 Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Wed, 14 Nov 2018 17:41:04 -0800 Subject: [PATCH 0274/1995] Move mfld_new_mach_data inside BAYTRAIL block mfld_new_mach_data is only used by bautrail and clang won't build broadwell with it being left unused Signed-off-by: Curtis Malainey --- sound/soc/sof/sof-acpi-dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index dc44c5c1146f88..f77bd078f78947 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -115,7 +115,6 @@ static struct sof_dev_desc sof_acpi_cherrytrail_desc = { .nocodec_fw_filename = "intel/sof-cht.ri", .nocodec_tplg_filename = "intel/sof-cht-nocodec.tplg" }; -#endif static struct platform_device * mfld_new_mach_data(struct snd_sof_pdata *sof_pdata) @@ -133,6 +132,7 @@ static struct platform_device * &pmach, sizeof(pmach)); return pdev; } +#endif static const struct dev_pm_ops sof_acpi_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) From 6a976e12db4c89759e28a38dc3450d4742ae53c3 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 13 Nov 2018 15:18:23 +0800 Subject: [PATCH 0275/1995] ASoC: SOF: add spin_lock to protect stream allocation function According to hda framework, stream should be protected by reg_lock Signed-off-by: Rander Wang --- sound/soc/sof/intel/hda-stream.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 880c7425c13172..5d530305eda60f 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -170,6 +170,8 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction) struct hdac_ext_stream *stream = NULL; struct hdac_stream *s; + spin_lock_irq(&bus->reg_lock); + /* get an unused stream */ list_for_each_entry(s, &bus->stream_list, list) { if (s->direction == direction && !s->opened) { @@ -179,6 +181,8 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction) } } + spin_unlock_irq(&bus->reg_lock); + /* stream found ? */ if (!stream) dev_err(sdev->dev, "error: no free %s streams\n", @@ -194,15 +198,20 @@ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int tag) struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_stream *s; + spin_lock_irq(&bus->reg_lock); + /* find used stream */ list_for_each_entry(s, &bus->stream_list, list) { if (s->direction == direction && s->opened && s->stream_tag == tag) { s->opened = false; + spin_unlock_irq(&bus->reg_lock); return 0; } } + spin_unlock_irq(&bus->reg_lock); + dev_dbg(sdev->dev, "tag %d not opened!\n", tag); return -ENODEV; } From b846ee5671e8ed1f0fdf9a1bb3403209d1a9d86c Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 21 Nov 2018 17:39:04 +0800 Subject: [PATCH 0276/1995] ASoC: SOF: HDA: initialize period_bytes at prepare for Code Loader and Trace For Code Loader and DMA Trace, we don't have hw_params() stage, but do the related settings at prepare(), we should set period_bytes of them to be 0 to make BDL setting up works, here add this explicit initialization for both of them. Without this initialization, the first_boot works fine, but Code Loader or DMA Trace may failed after suspend/resume, as the stream might be used by other streams with different period_bytes setting before suspend. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-loader.c | 1 + sound/soc/sof/intel/hda-trace.c | 1 + 2 files changed, 2 insertions(+) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 5b2da821b5c245..bfa258bee44c2e 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -63,6 +63,7 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, goto error; } + hstream->period_bytes = 0;/* initialize period_bytes */ hstream->format_val = format; hstream->bufsize = size; diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c index 8e01fb3677810c..ca539589ebe306 100644 --- a/sound/soc/sof/intel/hda-trace.c +++ b/sound/soc/sof/intel/hda-trace.c @@ -41,6 +41,7 @@ static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev) struct snd_dma_buffer *dmab = &sdev->dmatb; int ret; + hstream->period_bytes = 0;/* initialize period_bytes */ hstream->bufsize = sdev->dmatb.bytes; ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL); From 4a3aa5f384a054194b0e564231cec97da609b9cb Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Thu, 22 Nov 2018 09:56:44 +0100 Subject: [PATCH 0277/1995] ASoC: SOF: ipc: change reply for pm_ipc Use generic reply for sof_ipc_pm_ctx. Signed-off-by: Tomasz Lauda --- sound/soc/sof/pm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index a235b6ccf48436..81b7050394ca75 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -187,6 +187,7 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev) static int sof_send_pm_ipc(struct snd_sof_dev *sdev, int cmd) { struct sof_ipc_pm_ctx pm_ctx; + struct sof_ipc_reply reply; memset(&pm_ctx, 0, sizeof(pm_ctx)); @@ -196,7 +197,7 @@ static int sof_send_pm_ipc(struct snd_sof_dev *sdev, int cmd) /* send ctx save ipc to dsp */ return sof_ipc_tx_message(sdev->ipc, pm_ctx.hdr.cmd, &pm_ctx, - sizeof(pm_ctx), &pm_ctx, sizeof(pm_ctx)); + sizeof(pm_ctx), &reply, sizeof(reply)); } static void sof_suspend_streams(struct snd_sof_dev *sdev) From 00d6c81e3eb9f569f386aa5c88c2b8c44667af83 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 18 Nov 2018 17:31:11 -0600 Subject: [PATCH 0278/1995] ASoC: SOF: intel: move SPI up This shouldn't be here anyways Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/Kconfig | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index d41d60b037426e..50e03bfa8648d9 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -1,14 +1,3 @@ -config SND_SOC_SOF_INTEL - tristate "SOF support for Intel audio DSPs" - depends on SND_SOC_SOF - depends on SND_DMA_SGBUF - select SND_SOC_INTEL_MACH - select SND_SOC_SOF_XTENSA - help - This adds support for Sound Open Firmware for Intel(R) platforms. - Say Y if you have such a device. - If unsure select "N". - config SND_SOC_SOF_SPIDSP tristate "SOF support over the SPI bus" depends on SND_SOC_SOF @@ -20,6 +9,17 @@ config SND_SOC_SOF_SPIDSP Say Y if you have such a device. If unsure select "N". +config SND_SOC_SOF_INTEL + tristate "SOF support for Intel audio DSPs" + depends on SND_SOC_SOF + depends on SND_DMA_SGBUF + select SND_SOC_INTEL_MACH + select SND_SOC_SOF_XTENSA + help + This adds support for Sound Open Firmware for Intel(R) platforms. + Say Y if you have such a device. + If unsure select "N". + if SND_SOC_SOF_INTEL config SND_SOC_SOF_BAYTRAIL From feb14f170e824d3cfcb24132de61357e51a27a34 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 18 Nov 2018 18:26:34 -0600 Subject: [PATCH 0279/1995] ASoC: SOF: Intel: make SOF_SOC_HDA optional, fix Kconfig Make sure we can build without any code related to HDaudio links and codecs. Also make sure that when we do, the same option is used for SND_SOC_SOF_HDA and for HDAC_HDA due to code dependencies. Compiled-tested only for now. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/Kconfig | 32 ++++++++++++++++++++++++++------ sound/soc/sof/intel/hda-codec.c | 19 ++++++++++++++++++- sound/soc/sof/intel/hda.c | 4 +++- 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 50e03bfa8648d9..87e4eb507abdaf 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -111,17 +111,37 @@ config SND_SOC_SOF_HDA_COMMON tristate select SND_SOC_SOF_PCI select SND_SOC_ACPI_INTEL_MATCH + select SND_SOC_SOF_HDA_LINK_BASELINE -config SND_SOC_SOF_HDA - tristate "SOF support for HDA Links(HDA/HDMI)" - depends on SND_SOC_SOF_HDA_COMMON - select SND_HDA_EXT_CORE - select SND_SOC_HDAC_HDA - select SND_SOC_HDAC_HDMI +if SND_SOC_SOF_HDA_COMMON + +config SND_SOC_SOF_HDA_LINK + bool "SOF support for HDA Links(HDA/HDMI)" help This adds support for HDA links(HDA/HDMI) with Sound Open Firmware for Intel(R) platforms. Say Y if you want to enble HDA links with SOF. If unsure select "N". +if SND_SOC_SOF_HDA_LINK +config SND_SOC_SOF_HDA_AUDIO_CODEC + bool "SOF support for HDAudio codecs" + help + This adds support for HDAudio codecs with Sound Open Firmware + for Intel(R) platforms. + Say Y if you want to enble HDAudio codecs with SOF. + If unsure select "N". +endif ## SND_SOC_SOF_HDA_LINK + +endif ## SND_SOC_SOF_HDA_COMMON + +config SND_SOC_SOF_HDA_LINK_BASELINE + tristate + select SND_SOC_SOF_HDA if SND_SOC_SOF_HDA_LINK + +config SND_SOC_SOF_HDA + tristate + select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK + select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC + endif ## SND_SOC_SOF_INTEL diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index cc4a537d0e8a6f..9040293c38f018 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -23,13 +23,15 @@ #include #include #include - +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) #include "../../codecs/hdac_hda.h" +#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ #include "../sof-priv.h" #include "../ops.h" #include "hda.h" +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) #define IDISP_VID_INTEL 0x80860000 /* load the legacy HDA codec driver */ @@ -47,12 +49,16 @@ static void hda_codec_load_module(struct hda_codec *codec) static void hda_codec_load_module(struct hda_codec *codec) {} #endif +#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ + /* probe individual codec */ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) { struct hda_bus *hbus = sof_to_hbus(sdev); struct hdac_device *hdev; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) struct hdac_hda_priv *hda_priv; +#endif u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) | (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; u32 resp = -1; @@ -67,6 +73,7 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) dev_dbg(sdev->dev, "HDA codec #%d probed OK: response: %x\n", address, resp); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) hda_priv = devm_kzalloc(&hbus->pci->dev, sizeof(*hda_priv), GFP_KERNEL); if (!hda_priv) @@ -86,6 +93,16 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) } return 0; +#else + hdev = devm_kzalloc(&hbus->pci->dev, sizeof(*hdev), + GFP_KERNEL); + if (!hdev) + return -ENOMEM; + + ret = snd_hdac_ext_bus_device_init(&hbus->core, address, hdev); + + return ret; +#endif } /* Codec initialization */ diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index e0ba5c75f3a8f0..d90134cf3b36e8 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -36,7 +36,9 @@ #include "../sof-priv.h" #include "../ops.h" #include "hda.h" +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) #include "../../codecs/hdac_hda.h" +#endif /* platform specific devices */ #include "shim.h" @@ -397,7 +399,7 @@ static int hda_init(struct snd_sof_dev *sdev) bus = sof_to_bus(sdev); /* HDA bus init */ -#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDA) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) ext_ops = snd_soc_hdac_hda_get_ops(); #endif sof_hda_bus_init(bus, &pci->dev, ext_ops); From aff80d74c2461371e75e0bbdb1f384f66f1c8e57 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 19 Nov 2018 15:31:15 -0600 Subject: [PATCH 0280/1995] ASoC: intel: boards: clarify Kconfigs for SOF Only include boards with HDMI support if SOF has enabled HDA_LINK support. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 08166bf048ec51..72b170640e162d 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -222,7 +222,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH endif ## SND_SOC_INTEL_SKYLAKE -if SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_APOLLOLAKE +if SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_APOLLOLAKE && SND_SOC_SOF_HDA_LINK config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH tristate "Broxton with DA7219 and MAX98357A in I2S Mode" @@ -251,6 +251,10 @@ config SND_SOC_INTEL_BXT_RT298_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +endif + +if SND_SOC_SOF_APOLLOLAKE + config SND_SOC_INTEL_BXT_PCM512x_MACH tristate "Broxton with TI PCM512x codec" depends on MFD_INTEL_LPSS && I2C && ACPI @@ -271,6 +275,10 @@ config SND_SOC_INTEL_BXT_WM8804_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +endif + +if SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_APOLLOLAKE + config SND_SOC_INTEL_BXT_TDF8532_MACH tristate "ASoC Audio driver for BXT with TDF8532 in I2S mode" depends on X86 && ACPI && I2C @@ -341,7 +349,7 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH endif ## SND_SOC_INTEL_SKYLAKE -if SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_HDA +if SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_HDA_AUDIO_CODEC config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH tristate "SKL/KBL/BXT/APL with HDA Codecs" @@ -355,7 +363,7 @@ config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH endif ## SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_HDA -if SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_GEMINILAKE +if SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_GEMINILAKE && SND_SOC_SOF_HDA_LINK config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH tristate "GLK with RT5682 and MAX98357A in I2S Mode" @@ -373,7 +381,7 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH endif ## SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_GEMINILAKE -if SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_CANNONLAKE +if SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_CANNONLAKE && SND_SOC_SOF_HDA_LINK config SND_SOC_INTEL_CNL_RT274_MACH tristate "Cannonlake with RT274 I2S mode" From 0b6b84837aee618b857a5afa1b41455ce413ec02 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Mon, 26 Nov 2018 12:41:01 +0200 Subject: [PATCH 0281/1995] ASoC: SOF: IPC: DMIC: Add wake_up_time and min_clock_on_time parameters This patch adds the two parameters into DMIC configuration IPC. The parameters will control DMIC HW muting in capture start and ensure in capture stop that the clock has been kept active sufficient long time. The implementation of these features is done later. The reserved[] vector is reduced by the amount of added words. Also the MINOR version number is incremented in abi.h. Signed-off-by: Seppo Ingalsuo --- include/sound/sof/dai-intel.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h index 529933e177d4b1..cc83ebbbe66455 100644 --- a/include/sound/sof/dai-intel.h +++ b/include/sound/sof/dai-intel.h @@ -140,6 +140,14 @@ struct sof_ipc_dai_dmic_pdm_ctrl { * The microphone clock needs to be usually about 50-80 times the used audio * sample rate. With highest sample rates above 48 kHz this can relaxed * somewhat. + * + * The parameter wake_up_time describes how long time the microphone needs + * for the data line to produce valid output from mic clock start. The driver + * will mute the captured audio for the given time. The min_clock_on_time + * parameter is used to prevent too short clock bursts to happen. The driver + * will keep the clock active after capture stop if this time is not yet + * met. The unit for both is microseconds (us). Exceed of 100 ms will be + * treated as an error. */ struct sof_ipc_dai_dmic_params { uint32_t driver_ipc_version; /**< Version (1..N) */ @@ -157,8 +165,11 @@ struct sof_ipc_dai_dmic_params { uint32_t num_pdm_active; /**< Number of active pdm controllers */ + uint32_t wake_up_time; /**< Time from clock start to data (us) */ + uint32_t min_clock_on_time; /**< Min. time that clk is kept on (us) */ + /* reserved for future use */ - uint32_t reserved[8]; + uint32_t reserved[6]; /**< pdm controller config */ struct sof_ipc_dai_dmic_pdm_ctrl pdm[SOF_DAI_INTEL_DMIC_MAX_PDM]; From 550526962a79b08651f09227f8a90096d63ed129 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 26 Nov 2018 14:33:43 -0600 Subject: [PATCH 0282/1995] ASoC: Intel: boards: remove CNL-rt274 this may be revisited, e.g. for SoundWire support, but for now let's reduce the differences with upstream. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 16 -- sound/soc/intel/boards/Makefile | 2 - sound/soc/intel/boards/cnl_rt274.c | 348 ----------------------------- 3 files changed, 366 deletions(-) delete mode 100644 sound/soc/intel/boards/cnl_rt274.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 72b170640e162d..99aaefbf4330a4 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -381,20 +381,4 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH endif ## SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_GEMINILAKE -if SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_CANNONLAKE && SND_SOC_SOF_HDA_LINK - -config SND_SOC_INTEL_CNL_RT274_MACH - tristate "Cannonlake with RT274 I2S mode" - depends on MFD_INTEL_LPSS && I2C && ACPI - select SND_SOC_RT274 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC machine driver for Cannonlake platform - with RT274 I2S audio codec. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -endif ## SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_CANNONLAKE - endif ## SND_SOC_INTEL_MACH diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 93a1e132c73bb3..f6a5513368bf93 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -27,7 +27,6 @@ snd-soc-skl_rt286-objs := skl_rt286.o snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o -snd-soc-cnl-rt274-objs := cnl_rt274.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o @@ -57,4 +56,3 @@ obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o -obj-$(CONFIG_SND_SOC_INTEL_CNL_RT274_MACH) += snd-soc-cnl-rt274.o diff --git a/sound/soc/intel/boards/cnl_rt274.c b/sound/soc/intel/boards/cnl_rt274.c deleted file mode 100644 index 0689c63304ea46..00000000000000 --- a/sound/soc/intel/boards/cnl_rt274.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * cnl_rt274.c - ASOC Machine driver for CNL - * - * Copyright (C) 2016 Intel Corp - * Author: Guneshwor Singh - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../codecs/rt274.h" - -#define CNL_FREQ_OUT 24000000 -#define CNL_BE_FIXUP_RATE 48000 -#define RT274_CODEC_DAI "rt274-aif1" - -static int cnl_rt274_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - int ret = 0; - int ratio = 100; - - struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, - RT274_CODEC_DAI); - if (!codec_dai) - return -EINVAL; - - /* Codec needs clock for Jack detection and button press */ - ret = snd_soc_dai_set_sysclk(codec_dai, RT274_SCLK_S_PLL2, - CNL_FREQ_OUT, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(codec_dai->dev, "set codec sysclk failed: %d\n", ret); - return ret; - } - - if (SND_SOC_DAPM_EVENT_ON(event)) { - snd_soc_dai_set_bclk_ratio(codec_dai, ratio); - - ret = snd_soc_dai_set_pll(codec_dai, 0, RT274_PLL2_S_BCLK, - CNL_BE_FIXUP_RATE * ratio, - CNL_FREQ_OUT); - if (ret) { - dev_err(codec_dai->dev, - "failed to enable PLL2: %d\n", ret); - return ret; - } - } - - return ret; -} - -static struct snd_soc_jack cnl_headset; - -/* Headset jack detection DAPM pins */ -static struct snd_soc_jack_pin cnl_headset_pins[] = { - { - .pin = "Mic Jack", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, -}; - -static const struct snd_kcontrol_new cnl_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Mic Jack"), -}; - -static const struct snd_soc_dapm_widget cnl_rt274_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Mic Jack", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - cnl_rt274_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) -static int cnl_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *channels = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - channels->min = channels->max = 2; - - return 0; -} -#endif - -static const struct snd_soc_dapm_route cnl_map[] = { - {"Headphone Jack", NULL, "HPO Pin"}, - {"MIC", NULL, "Mic Jack"}, - {"DMic", NULL, "SoC DMIC"}, - {"DMIC01 Rx", NULL, "Capture"}, - {"dmic01_hifi", NULL, "DMIC01 Rx"}, - - /* ssp2 path */ - {"Dummy Playback", NULL, "ssp2 Tx"}, - {"ssp2 Tx", NULL, "ssp2_out"}, - - {"ssp2 Rx", NULL, "Dummy Capture"}, - {"ssp2_in", NULL, "ssp2 Rx"}, - - /* ssp1 path */ - {"Dummy Playback", NULL, "ssp1 Tx"}, - {"ssp1 Tx", NULL, "ssp1_out"}, - - {"AIF1 Playback", NULL, "ssp0 Tx"}, - {"ssp0 Tx", NULL, "codec1_out"}, - {"ssp0 Tx", NULL, "codec0_out"}, - - {"ssp0 Rx", NULL, "AIF1 Capture"}, - {"codec0_in", NULL, "ssp0 Rx"}, - - {"Headphone Jack", NULL, "Platform Clock"}, - {"MIC", NULL, "Platform Clock"}, -}; - -static int cnl_rt274_init(struct snd_soc_pcm_runtime *runtime) -{ - int ret; - struct snd_soc_component *component = runtime->codec_dai->component; - struct snd_soc_card *card = runtime->card; - struct snd_soc_dai *codec_dai = runtime->codec_dai; - - ret = snd_soc_card_jack_new(runtime->card, "Headset", - SND_JACK_HEADSET, &cnl_headset, - cnl_headset_pins, - ARRAY_SIZE(cnl_headset_pins)); - - if (ret) - return ret; - - snd_soc_component_set_jack(component, &cnl_headset, NULL); - - /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); - if (ret < 0) { - dev_err(runtime->dev, "can't set codec pcm format %d\n", ret); - return ret; - } - - card->dapm.idle_bias_off = true; - - return 0; -} - -static int cnl_be_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); - - rate->min = CNL_BE_FIXUP_RATE; - rate->max = CNL_BE_FIXUP_RATE; - channels->min = 2; - channels->max = 2; - snd_mask_none(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT)); - snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), - (unsigned int __force)SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL_FPGA) -static const char pname[] = "0000:02:18.0"; -static const char cname[] = "rt274.0-001c"; -#else -#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) -static const char pname[] = "sof-audio"; -#else -static const char pname[] = "0000:00:1f.3"; -#endif -static const char cname[] = "i2c-INT34C2:00"; -#endif - -static struct snd_soc_dai_link cnl_rt274_msic_dailink[] = { -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) - /* Trace Buffer DAI links */ - { - .name = "CNL Trace Buffer0", - .stream_name = "Core 0 Trace Buffer", - .cpu_dai_name = "TraceBuffer0 Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = pname, - .capture_only = true, - .ignore_suspend = 1, - }, - { - .name = "CNL Trace Buffer1", - .stream_name = "Core 1 Trace Buffer", - .cpu_dai_name = "TraceBuffer1 Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = pname, - .capture_only = true, - .ignore_suspend = 1, - }, - { - .name = "CNL Trace Buffer2", - .stream_name = "Core 2 Trace Buffer", - .cpu_dai_name = "TraceBuffer2 Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = pname, - .capture_only = true, - .ignore_suspend = 1, - }, - { - .name = "CNL Trace Buffer3", - .stream_name = "Core 3 Trace Buffer", - .cpu_dai_name = "TraceBuffer3 Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = pname, - .capture_only = true, - .ignore_suspend = 1, - }, - /* Probe DAI-links */ - { - .name = "CNL Compress Probe playback", - .stream_name = "Probe Playback", - .cpu_dai_name = "Compress Probe0 Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = pname, - .init = NULL, - .ignore_suspend = 1, - .nonatomic = 1, - }, - { - .name = "CNL Compress Probe capture", - .stream_name = "Probe Capture", - .cpu_dai_name = "Compress Probe1 Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = pname, - .init = NULL, - .ignore_suspend = 1, - .nonatomic = 1, - }, -#endif - /* back ends */ - { - .name = "SSP0-Codec", - .id = 1, - .cpu_dai_name = "SSP0 Pin", - .codec_name = cname, - .codec_dai_name = "rt274-aif1", - .be_hw_params_fixup = cnl_be_fixup, - .ignore_suspend = 1, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .dpcm_playback = 1, - .dpcm_capture = 1, - .init = cnl_rt274_init, - }, -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) - { - .name = "dmic01", - .id = 2, - .cpu_dai_name = "DMIC01 Pin", - .codec_name = "dmic-codec", - .codec_dai_name = "dmic-hifi", - .ignore_suspend = 1, - .no_pcm = 1, - .dpcm_capture = 1, - .be_hw_params_fixup = cnl_dmic_fixup, - }, -#endif -}; - -static int -cnl_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) -{ - link->platform_name = pname; - link->nonatomic = 1; - - return 0; -} - -/* SoC card */ -static struct snd_soc_card snd_soc_card_cnl = { - .name = "cnl-audio", - .dai_link = cnl_rt274_msic_dailink, - .num_links = ARRAY_SIZE(cnl_rt274_msic_dailink), - .dapm_widgets = cnl_rt274_widgets, - .num_dapm_widgets = ARRAY_SIZE(cnl_rt274_widgets), - .dapm_routes = cnl_map, - .num_dapm_routes = ARRAY_SIZE(cnl_map), - .controls = cnl_controls, - .num_controls = ARRAY_SIZE(cnl_controls), - .add_dai_link = cnl_add_dai_link, - .fully_routed = true, -}; - -static int snd_cnl_rt274_mc_probe(struct platform_device *pdev) -{ - snd_soc_card_cnl.dev = &pdev->dev; - return devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cnl); -} - -static struct platform_driver snd_cnl_rt274_driver = { - .driver = { - .name = "cnl_rt274", - .pm = &snd_soc_pm_ops, - }, - .probe = snd_cnl_rt274_mc_probe, -}; - -module_platform_driver(snd_cnl_rt274_driver); - -MODULE_AUTHOR("Guneshwor Singh "); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:cnl_rt274"); From 1d63887361ec0a3c4b33ebd671791fbda513dff7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 26 Nov 2018 14:31:35 -0600 Subject: [PATCH 0283/1995] ASoC: Intel: boards: remove BXT-TDF8532 support This may be revisited but for now let's reduce the differences with upstream Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 14 -- sound/soc/intel/boards/Makefile | 2 - sound/soc/intel/boards/bxt_tdf8532.c | 265 --------------------------- 3 files changed, 281 deletions(-) delete mode 100644 sound/soc/intel/boards/bxt_tdf8532.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 99aaefbf4330a4..76b3da471cd1e0 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -277,20 +277,6 @@ config SND_SOC_INTEL_BXT_WM8804_MACH endif -if SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_APOLLOLAKE - -config SND_SOC_INTEL_BXT_TDF8532_MACH - tristate "ASoC Audio driver for BXT with TDF8532 in I2S mode" - depends on X86 && ACPI && I2C - select SND_SOC_TDF8532 - select SND_SOC_COMPRESS - help - This adds support for ASoC machine driver for Broxton IVI GP MRB platform - Say Y if you have such a device. - If unsure select "N". - -endif ## SND_SOC_INTEL_SKYLAKE || SND_SOC_SOF_APOLLOLAKE - if SND_SOC_INTEL_SKYLAKE config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index f6a5513368bf93..5b797efc305ae5 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -8,7 +8,6 @@ snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o snd-soc-sst-bxt-rt298-objs := bxt_rt298.o snd-soc-sst-bxt-pcm512x-objs := bxt_pcm512x.o snd-soc-sst-bxt-wm8804-objs := bxt_wm8804.o -snd-soc-sst_bxt_tdf8532-objs := bxt_tdf8532.o snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o @@ -35,7 +34,6 @@ obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_ obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o obj-$(CONFIG_SND_SOC_INTEL_BXT_PCM512x_MACH) += snd-soc-sst-bxt-pcm512x.o obj-$(CONFIG_SND_SOC_INTEL_BXT_WM8804_MACH) += snd-soc-sst-bxt-wm8804.o -obj-$(CONFIG_SND_SOC_INTEL_BXT_TDF8532_MACH) += snd-soc-sst_bxt_tdf8532.o obj-$(CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH) += snd-soc-sst-glk-rt5682_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.o diff --git a/sound/soc/intel/boards/bxt_tdf8532.c b/sound/soc/intel/boards/bxt_tdf8532.c deleted file mode 100644 index 336205309e2c8b..00000000000000 --- a/sound/soc/intel/boards/bxt_tdf8532.c +++ /dev/null @@ -1,265 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel Broxton-P I2S Machine Driver for IVI reference platform - * Copyright (c) 2017, Intel Corporation. - */ - -#include -#include -#include -#include -#include -#include - -static const struct snd_kcontrol_new broxton_tdf8532_controls[] = { - SOC_DAPM_PIN_SWITCH("Speaker"), -}; - -static const struct snd_soc_dapm_widget broxton_tdf8532_widgets[] = { - SND_SOC_DAPM_SPK("Speaker", NULL), - SND_SOC_DAPM_MIC("DiranaCp", NULL), - SND_SOC_DAPM_HP("DiranaPb", NULL), - SND_SOC_DAPM_MIC("HdmiIn", NULL), - SND_SOC_DAPM_MIC("TestPinCp", NULL), - SND_SOC_DAPM_HP("TestPinPb", NULL), - SND_SOC_DAPM_MIC("BtHfpDl", NULL), - SND_SOC_DAPM_HP("BtHfpUl", NULL), - SND_SOC_DAPM_MIC("ModemDl", NULL), - SND_SOC_DAPM_HP("ModemUl", NULL), -}; - -static const struct snd_soc_dapm_route broxton_tdf8532_map[] = { - /* Speaker BE connections */ - { "Speaker", NULL, "ssp4 Tx"}, - { "ssp4 Tx", NULL, "codec0_out"}, - - { "dirana_in", NULL, "ssp2 Rx"}, - { "ssp2 Rx", NULL, "DiranaCp"}, - - { "dirana_aux_in", NULL, "ssp2 Rx"}, - { "ssp2 Rx", NULL, "DiranaCp"}, - - { "dirana_tuner_in", NULL, "ssp2 Rx"}, - { "ssp2 Rx", NULL, "DiranaCp"}, - - { "DiranaPb", NULL, "ssp2 Tx"}, - { "ssp2 Tx", NULL, "dirana_out"}, - - { "hdmi_ssp1_in", NULL, "ssp1 Rx"}, - { "ssp1 Rx", NULL, "HdmiIn"}, - - { "TestPin_ssp5_in", NULL, "ssp5 Rx"}, - { "ssp5 Rx", NULL, "TestPinCp"}, - - { "TestPinPb", NULL, "ssp5 Tx"}, - { "ssp5 Tx", NULL, "TestPin_ssp5_out"}, - - { "BtHfp_ssp0_in", NULL, "ssp0 Rx"}, - { "ssp0 Rx", NULL, "BtHfpDl"}, - - { "BtHfpUl", NULL, "ssp0 Tx"}, - { "ssp0 Tx", NULL, "BtHfp_ssp0_out"}, - - { "Modem_ssp3_in", NULL, "ssp3 Rx"}, - { "ssp3 Rx", NULL, "ModemDl"}, - - { "ModemUl", NULL, "ssp3 Tx"}, - { "ssp3 Tx", NULL, "Modem_ssp3_out"}, -}; - -static int bxt_tdf8532_ssp2_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* set SSP to 32 bit */ - snd_mask_none(fmt); - snd_mask_set(fmt, SNDRV_PCM_FORMAT_S32_LE); - - return 0; -} - -/* broxton digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link broxton_tdf8532_dais[] = { - /* Probe DAI links*/ - { - .name = "Bxt Compress Probe playback", - .stream_name = "Probe Playback", - .cpu_dai_name = "Compress Probe0 Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = "0000:00:0e.0", - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - }, - { - .name = "Bxt Compress Probe capture", - .stream_name = "Probe Capture", - .cpu_dai_name = "Compress Probe1 Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = "0000:00:0e.0", - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - }, - /* Trace Buffer DAI links */ - { - .name = "Bxt Trace Buffer0", - .stream_name = "Core 0 Trace Buffer", - .cpu_dai_name = "TraceBuffer0 Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = "0000:00:0e.0", - .capture_only = true, - .ignore_suspend = 1, - .dynamic = 1, - }, - { - .name = "Bxt Trace Buffer1", - .stream_name = "Core 1 Trace Buffer", - .cpu_dai_name = "TraceBuffer1 Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = "0000:00:0e.0", - .capture_only = true, - .ignore_suspend = 1, - .dynamic = 1, - }, - /* Back End DAI links */ - { - /* SSP0 - BT */ - .name = "SSP0-Codec", - .id = 0, - .cpu_dai_name = "SSP0 Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = "0000:00:0e.0", - .ignore_suspend = 1, - .dpcm_capture = 1, - .dpcm_playback = 1, - .no_pcm = 1, - }, - { - /* SSP1 - HDMI-In */ - .name = "SSP1-Codec", - .id = 1, - .cpu_dai_name = "SSP1 Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = "0000:00:0e.0", - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - }, - { - /* SSP2 - Dirana */ - .name = "SSP2-Codec", - .id = 2, - .cpu_dai_name = "SSP2 Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = "0000:00:0e.0", - .ignore_suspend = 1, - .dpcm_capture = 1, - .dpcm_playback = 1, - .no_pcm = 1, - .be_hw_params_fixup = bxt_tdf8532_ssp2_fixup, - }, - { - /* SSP3 - Modem */ - .name = "SSP3-Codec", - .id = 3, - .cpu_dai_name = "SSP3 Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = "0000:00:0e.0", - .ignore_suspend = 1, - .dpcm_capture = 1, - .dpcm_playback = 1, - .no_pcm = 1, - }, - { - /* SSP4 - Amplifier */ - .name = "SSP4-Codec", - .id = 4, - .cpu_dai_name = "SSP4 Pin", - .codec_name = "i2c-INT34C3:00", - .codec_dai_name = "tdf8532-hifi", - .platform_name = "0000:00:0e.0", - .ignore_suspend = 1, - .dpcm_playback = 1, - .no_pcm = 1, - }, - { - /* SSP5 - TestPin */ - .name = "SSP5-Codec", - .id = 5, - .cpu_dai_name = "SSP5 Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .platform_name = "0000:00:0e.0", - .ignore_suspend = 1, - .dpcm_capture = 1, - .dpcm_playback = 1, - .no_pcm = 1, - }, -}; - -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) -static int bxt_add_dai_link(struct snd_soc_card *card, - struct snd_soc_dai_link *link) -{ - link->platform_name = "0000:00:0e.0"; - link->nonatomic = 1; - return 0; -} -#endif - -/* broxton audio machine driver for TDF8532 */ -static struct snd_soc_card broxton_tdf8532 = { - .name = "broxton_tdf8532", - .dai_link = broxton_tdf8532_dais, - .num_links = ARRAY_SIZE(broxton_tdf8532_dais), - .controls = broxton_tdf8532_controls, - .num_controls = ARRAY_SIZE(broxton_tdf8532_controls), - .dapm_widgets = broxton_tdf8532_widgets, - .num_dapm_widgets = ARRAY_SIZE(broxton_tdf8532_widgets), - .dapm_routes = broxton_tdf8532_map, - .num_dapm_routes = ARRAY_SIZE(broxton_tdf8532_map), - .fully_routed = true, -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) - .add_dai_link = bxt_add_dai_link, -#endif -}; - -static int broxton_tdf8532_audio_probe(struct platform_device *pdev) -{ - dev_info(&pdev->dev, "%s registering %s\n", __func__, pdev->name); - broxton_tdf8532.dev = &pdev->dev; - return snd_soc_register_card(&broxton_tdf8532); -} - -static int broxton_tdf8532_audio_remove(struct platform_device *pdev) -{ - snd_soc_unregister_card(&broxton_tdf8532); - return 0; -} - -static struct platform_driver broxton_tdf8532_audio = { - .probe = broxton_tdf8532_audio_probe, - .remove = broxton_tdf8532_audio_remove, - .driver = { - .name = "bxt_tdf8532", - .pm = &snd_soc_pm_ops, - }, -}; - -module_platform_driver(broxton_tdf8532_audio) - -/* Module information */ -MODULE_DESCRIPTION("Intel SST Audio for Broxton GP MRB"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:gpmrb_machine"); -MODULE_ALIAS("platform:bxt_tdf8532"); From 79976723c8cef8aac1b0c0ebe9d5df35958fcd63 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 26 Nov 2018 14:28:49 -0600 Subject: [PATCH 0284/1995] ASoC: codecs: remove TDF8532 support This may be revisited later for for now it's simpler to remove. Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/Kconfig | 5 - sound/soc/codecs/Makefile | 2 - sound/soc/codecs/tdf8532.c | 377 ------------------------------------- sound/soc/codecs/tdf8532.h | 92 --------- 4 files changed, 476 deletions(-) delete mode 100644 sound/soc/codecs/tdf8532.c delete mode 100644 sound/soc/codecs/tdf8532.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a228f33633ef5a..bf0b949eb7e82a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -164,7 +164,6 @@ config SND_SOC_ALL_CODECS select SND_SOC_TAS5720 if I2C select SND_SOC_TAS6424 if I2C select SND_SOC_TDA7419 if I2C - select SND_SOC_TDF8532 if I2C select SND_SOC_TFA9879 if I2C select SND_SOC_TLV320AIC23_I2C if I2C select SND_SOC_TLV320AIC23_SPI if SPI_MASTER @@ -994,10 +993,6 @@ config SND_SOC_TDA7419 depends on I2C select REGMAP_I2C -config SND_SOC_TDF8532 - tristate - depends on I2C - config SND_SOC_TFA9879 tristate "NXP Semiconductors TFA9879 amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 3680e19672d7e0..3046b33ca9d308 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -175,7 +175,6 @@ snd-soc-tas571x-objs := tas571x.o snd-soc-tas5720-objs := tas5720.o snd-soc-tas6424-objs := tas6424.o snd-soc-tda7419-objs := tda7419.o -snd-soc-tdf8532-objs := tdf8532.o snd-soc-tfa9879-objs := tfa9879.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o @@ -436,7 +435,6 @@ obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o obj-$(CONFIG_SND_SOC_TAS6424) += snd-soc-tas6424.o obj-$(CONFIG_SND_SOC_TDA7419) += snd-soc-tda7419.o -obj-$(CONFIG_SND_SOC_TDF8532) += snd-soc-tdf8532.o obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o diff --git a/sound/soc/codecs/tdf8532.c b/sound/soc/codecs/tdf8532.c deleted file mode 100644 index d8ae9ff441c8d9..00000000000000 --- a/sound/soc/codecs/tdf8532.c +++ /dev/null @@ -1,377 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Codec driver for NXP Semiconductors - TDF8532 - * Copyright (c) 2017, Intel Corporation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "tdf8532.h" - -static int __tdf8532_build_pkt(struct tdf8532_priv *dev_data, - va_list valist, u8 *payload) -{ - int param; - u8 len; - u8 *cmd_payload; - const u8 cmd_offset = 3; - - payload[HEADER_TYPE] = MSG_TYPE_STX; - payload[HEADER_PKTID] = dev_data->pkt_id; - - cmd_payload = &payload[cmd_offset]; - - param = va_arg(valist, int); - len = 0; - - while (param != END) { - cmd_payload[len] = param; - - len++; - - param = va_arg(valist, int); - } - - payload[HEADER_LEN] = len; - - return len + cmd_offset; -} - -static int __tdf8532_single_write(struct tdf8532_priv *dev_data, - int dummy, ...) -{ - va_list valist; - int ret; - u8 len; - u8 payload[255]; - - va_start(valist, dummy); - - len = __tdf8532_build_pkt(dev_data, valist, payload); - - va_end(valist); - - print_hex_dump_debug("tdf8532-codec: Tx:", DUMP_PREFIX_NONE, 32, 1, - payload, len, false); - ret = i2c_master_send(dev_data->i2c, payload, len); - - dev_data->pkt_id++; - - if (ret < 0) { - dev_err(&dev_data->i2c->dev, - "i2c send packet returned: %d\n", ret); - - return ret; - } - - return 0; -} - -static u8 tdf8532_read_wait_ack(struct tdf8532_priv *dev_data, - unsigned long timeout) -{ - u8 ack_repl[HEADER_SIZE] = {0, 0, 0}; - unsigned long timeout_point = jiffies + timeout; - int ret; - - usleep_range(10000, 20000); - do { - ret = i2c_master_recv(dev_data->i2c, ack_repl, HEADER_SIZE); - if (ret < 0) - goto out; - } while (time_before(jiffies, timeout_point) && - ack_repl[0] != MSG_TYPE_ACK); - - if (ack_repl[0] != MSG_TYPE_ACK) - return -ETIME; - else - return ack_repl[2]; - -out: - return ret; -} - -static int tdf8532_single_read(struct tdf8532_priv *dev_data, - char **repl_buff) -{ - int ret; - int len; - - struct device *dev = &dev_data->i2c->dev; - - ret = tdf8532_read_wait_ack(dev_data, msecs_to_jiffies(ACK_TIMEOUT)); - - if (ret < 0) { - dev_err(dev, - "Error waiting for ACK reply: %d\n", ret); - goto out; - } - - len = ret + HEADER_SIZE; - - *repl_buff = kzalloc(len, GFP_KERNEL); - if (*repl_buff == NULL) { - ret = -ENOMEM; - goto out; - } - - ret = i2c_master_recv(dev_data->i2c, *repl_buff, len); - - print_hex_dump_debug("tdf8532-codec: Rx:", DUMP_PREFIX_NONE, 32, 1, - *repl_buff, len, false); - - if (ret < 0 || ret != len) { - dev_err(dev, - "i2c recv packet returned: %d (expected: %d)\n", - ret, len); - - ret = -EINVAL; - goto out_free; - } - - return len; - -out_free: - kfree(*repl_buff); - *repl_buff = NULL; -out: - return ret; -} - -static int tdf8532_get_state(struct tdf8532_priv *dev_data, - struct get_dev_status_repl **status_repl) -{ - char *repl_buff = NULL; - int ret = 0; - - ret = tdf8532_amp_write(dev_data, GET_DEV_STATUS); - if (ret < 0) - goto out; - - ret = tdf8532_single_read(dev_data, &repl_buff); - if (ret < 0) - goto out; - - *status_repl = (struct get_dev_status_repl *)repl_buff; - -out: - return ret; -} - -static int tdf8532_wait_state(struct tdf8532_priv *dev_data, u8 req_state, - unsigned long timeout) -{ - unsigned long timeout_point = jiffies + msecs_to_jiffies(timeout); - struct device *dev = &dev_data->i2c->dev; - struct get_dev_status_repl *status_repl = NULL; - u8 cur_state = STATE_NONE; - int ret; - - do { - ret = tdf8532_get_state(dev_data, &status_repl); - if (ret < 0) - goto out; - cur_state = status_repl->state; - print_hex_dump_debug("tdf8532-codec: wait_state: ", - DUMP_PREFIX_NONE, 32, 1, status_repl, - 6, false); - - kfree(status_repl); - status_repl = NULL; - } while (time_before(jiffies, timeout_point) && cur_state != req_state); - - if (cur_state == req_state) - return 0; - -out: - ret = -ETIME; - - dev_err(dev, "tdf8532-codec: state: %u, req_state: %u, ret: %d\n", - cur_state, req_state, ret); - return ret; -} - -static int tdf8532_start_play(struct tdf8532_priv *tdf8532) -{ - int ret; - - ret = tdf8532_amp_write(tdf8532, SET_CLK_STATE, CLK_CONNECT); - if (ret < 0) - return ret; - - ret = tdf8532_amp_write(tdf8532, SET_CHNL_ENABLE, - CHNL_MASK(tdf8532->channels)); - - if (ret >= 0) - ret = tdf8532_wait_state(tdf8532, STATE_PLAY, ACK_TIMEOUT); - - return ret; -} - -static int tdf8532_stop_play(struct tdf8532_priv *tdf8532) -{ - int ret; - - ret = tdf8532_amp_write(tdf8532, SET_CHNL_DISABLE, - CHNL_MASK(tdf8532->channels)); - if (ret < 0) - goto out; - - ret = tdf8532_wait_state(tdf8532, STATE_STBY, ACK_TIMEOUT); - - /* Refer to TDF8532 manual: - * If the wait_state result is ok, we should send CLK_DISCONNECT - * command to force codec from STANDBY(2) to IDLE(1). - * If the wait_state result is timeout, the codec state should be - * at Clockfail(7), we still should send CLK_DISCONNECT command - * force the codec from Clockfail(7) to Idle(1). - */ - - ret = tdf8532_amp_write(tdf8532, SET_CLK_STATE, CLK_DISCONNECT); - if (ret < 0) - goto out; - - ret = tdf8532_wait_state(tdf8532, STATE_IDLE, ACK_TIMEOUT); - -out: - return ret; -} - -static int tdf8532_dai_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct snd_soc_component *component = dai->component; - struct tdf8532_priv *tdf8532 = snd_soc_component_get_drvdata(component); - int ret = 0; - - dev_dbg(component->dev, "%s: cmd = %d\n", __func__, cmd); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: - ret = tdf8532_start_play(tdf8532); - break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - ret = tdf8532_stop_play(tdf8532); - break; - } - - return ret; -} - -static int tdf8532_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_component *component = dai->component; - struct tdf8532_priv *tdf8532 = snd_soc_component_get_drvdata(component); - - dev_dbg(component->dev, "%s\n", __func__); - - if (mute) - return tdf8532_amp_write(tdf8532, SET_CHNL_MUTE, - CHNL_MASK(CHNL_MAX)); - else - return tdf8532_amp_write(tdf8532, SET_CHNL_UNMUTE, - CHNL_MASK(CHNL_MAX)); -} - -static const struct snd_soc_dai_ops tdf8532_dai_ops = { - .trigger = tdf8532_dai_trigger, - .digital_mute = tdf8532_mute, -}; - -static const struct snd_soc_component_driver soc_component_tdf8532; - -static struct snd_soc_dai_driver tdf8532_dai[] = { - { - .name = "tdf8532-hifi", - .playback = { - .stream_name = "Playback", - .channels_min = 4, - .channels_max = 4, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .ops = &tdf8532_dai_ops, - } -}; - -static int tdf8532_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - int ret; - struct tdf8532_priv *dev_data; - struct device *dev = &i2c->dev; - - dev_dbg(&i2c->dev, "%s\n", __func__); - - dev_data = devm_kzalloc(dev, sizeof(struct tdf8532_priv), GFP_KERNEL); - - if (!dev_data) { - ret = -ENOMEM; - goto out; - } - - dev_data->i2c = i2c; - dev_data->pkt_id = 0; - dev_data->channels = 4; - - i2c_set_clientdata(i2c, dev_data); - - ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_tdf8532, - tdf8532_dai, ARRAY_SIZE(tdf8532_dai)); - if (ret != 0) { - dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); - goto out; - } - -out: - return ret; -} - -static int tdf8532_i2c_remove(struct i2c_client *i2c) -{ - return 0; -} - -static const struct i2c_device_id tdf8532_i2c_id[] = { - { "tdf8532", 0 }, - { } -}; - -MODULE_DEVICE_TABLE(i2c, tdf8532_i2c_id); - -#if CONFIG_ACPI -static const struct acpi_device_id tdf8532_acpi_match[] = { - {"INT34C3", 0}, - {}, -}; - -MODULE_DEVICE_TABLE(acpi, tdf8532_acpi_match); -#endif - -static struct i2c_driver tdf8532_i2c_driver = { - .driver = { - .name = "tdf8532-codec", - .owner = THIS_MODULE, - .acpi_match_table = ACPI_PTR(tdf8532_acpi_match), - }, - .probe = tdf8532_i2c_probe, - .remove = tdf8532_i2c_remove, - .id_table = tdf8532_i2c_id, -}; - -module_i2c_driver(tdf8532_i2c_driver); - -MODULE_DESCRIPTION("ASoC NXP Semiconductors TDF8532 driver"); -MODULE_AUTHOR("Steffen Wagner "); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/tdf8532.h b/sound/soc/codecs/tdf8532.h deleted file mode 100644 index 8818252dcda6fa..00000000000000 --- a/sound/soc/codecs/tdf8532.h +++ /dev/null @@ -1,92 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * tdf8532.h - Codec driver for NXP Semiconductors - * Copyright (c) 2017, Intel Corporation. - */ - -#ifndef __TDF8532_H_ -#define __TDF8532_H_ - -#define ACK_TIMEOUT 300 - -#define CHNL_MAX 5 - -#define AMP_MOD 0x80 -#define END -1 - -#define MSG_TYPE_STX 0x02 -#define MSG_TYPE_NAK 0x15 -#define MSG_TYPE_ACK 0x6 - -#define HEADER_SIZE 3 -#define HEADER_TYPE 0 -#define HEADER_PKTID 1 -#define HEADER_LEN 2 - -/* Set commands */ -#define SET_CLK_STATE 0x1A -#define CLK_DISCONNECT 0x00 -#define CLK_CONNECT 0x01 - -#define SET_CHNL_ENABLE 0x26 -#define SET_CHNL_DISABLE 0x27 - -#define SET_CHNL_MUTE 0x42 -#define SET_CHNL_UNMUTE 0x43 - -struct header_repl { - u8 msg_type; - u8 pkt_id; - u8 len; -} __packed; - -#define GET_IDENT 0xE0 - -struct get_ident_repl { - struct header_repl header; - u8 module_id; - u8 cmd_id; - u8 type_name; - u8 hw_major; - u8 hw_minor; - u8 sw_major; - u8 sw_minor; - u8 sw_sub; -} __packed; - -#define GET_ERROR 0xE2 - -struct get_error_repl { - struct header_repl header; - u8 module_id; - u8 cmd_id; - u8 last_cmd_id; - u8 error; - u8 status; -} __packed; - -#define GET_DEV_STATUS 0x80 - -enum dev_state {STATE_BOOT, STATE_IDLE, STATE_STBY, STATE_LDAG, STATE_PLAY, - STATE_PROT, STATE_SDWN, STATE_CLFA, STATE_NONE }; - -struct get_dev_status_repl { - struct header_repl header; - u8 module_id; - u8 cmd_id; - u8 state; -} __packed; - -/* Helpers */ -#define CHNL_MASK(channels) (u8)((0x00FF << (channels)) >> 8) - -#define tdf8532_amp_write(dev_data, ...)\ - __tdf8532_single_write(dev_data, 0, AMP_MOD, __VA_ARGS__, END) - -struct tdf8532_priv { - struct i2c_client *i2c; - u8 channels; - u8 pkt_id; -}; - -#endif From da09ccb75f179bb095bdc3edbd3e88f4b4f4f97f Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Fri, 16 Nov 2018 17:28:56 +0800 Subject: [PATCH 0285/1995] ASoC: rt5663: Fix error handling of regulator_set_load The default implementation of regulator_set_load returns REGULATOR_MODE_NORMAL, which is positive. [This was a bug which is being fixed but the change is valid anyway -- bronie] rt5663_i2c_probe should only do error handling when return value of regulator_set_load is negative. In this case, rt5663_i2c_probe should return error. Also, consolidate err_irq into err_enable. Fix the missing goto for temporary regmap and rt5663->regmap. Signed-off-by: Cheng-Yi Chiang Signed-off-by: Mark Brown (cherry picked from commit 746dca0aebd4d77adccb76c500a60028a900dabb) --- sound/soc/codecs/rt5663.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 29c059ed06821d..da664701570808 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -3525,10 +3525,11 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++) { ret = regulator_set_load(rt5663->supplies[i].consumer, RT5663_SUPPLY_CURRENT_UA); - if (ret) { + if (ret < 0) { dev_err(&i2c->dev, - "Failed to set regulator %s, ret: %d\n", + "Failed to set regulator load on %s, ret: %d\n", rt5663->supplies[i].supply, ret); + return ret; } } @@ -3546,7 +3547,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, ret = PTR_ERR(regmap); dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n", ret); - return ret; + goto err_enable; } ret = regmap_read(regmap, RT5663_VENDOR_ID_2, &val); @@ -3579,7 +3580,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, ret = PTR_ERR(rt5663->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); - return ret; + goto err_enable; } /* reset and calibrate */ @@ -3689,17 +3690,19 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, rt5663_dai, ARRAY_SIZE(rt5663_dai)); if (ret) - goto err_irq; + goto err_enable; return 0; -err_irq: + + /* + * Error after enabling regulators should goto err_enable + * to disable regulators. + */ +err_enable: if (i2c->irq) free_irq(i2c->irq, rt5663); -err_enable: - dev_err(&i2c->dev, - "%s: Disable regulator after probe error\n", __func__); regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies); return ret; } From 4dcbc9d1870b29a6fe363a2681d20c0b1a17afba Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 18 Nov 2018 16:38:09 -0600 Subject: [PATCH 0286/1995] ASoC: Intel: Skylake: fix Kconfigs, make HDaudio codec optional The Skylake driver currently has a set of problems supporting load/unload modules. We need to make the HDaudio codec support optional to help narrow down the issues. Support for HDaudio codecs also leads to a Kconfig issue. We want the hdac_hda codec to be compilable independently of Skylake (e.g. with ALL_CODECS) but when Skylake is selected as built-in the hdac_hda codec needs to use the same option due a a code dependency Solve both problems by adding a user-selectable boolean Kconfig, select HDAC_HDA as needed and make the HDaudio codec support in the Skylake driver optional. Tests on a Chell Chromebook device without HDaudio show no regression for speaker and HDMI playback. This is submitted as an RFC to allow for comments and more validation. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 8c4e7c2ee8096b5ca8214418f287b3878d578cc0) --- sound/soc/intel/Kconfig | 26 +++++++++++++++++++++++--- sound/soc/intel/boards/Kconfig | 24 ++++++++++++++---------- sound/soc/intel/skylake/skl.c | 20 ++++++++++++++++++-- 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 0caa1f4eb94d7d..18e71770368550 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -101,22 +101,42 @@ config SND_SST_ATOM_HIFI2_PLATFORM_ACPI codec, then enable this option by saying Y or m. This is a recommended option -config SND_SOC_INTEL_SKYLAKE_SSP_CLK - tristate - config SND_SOC_INTEL_SKYLAKE tristate "SKL/BXT/KBL/GLK/CNL... Platforms" depends on PCI && ACPI + select SND_SOC_INTEL_SKYLAKE_COMMON + help + If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/ + GeminiLake or CannonLake platform with the DSP enabled in the BIOS + then enable this option by saying Y or m. + +if SND_SOC_INTEL_SKYLAKE + +config SND_SOC_INTEL_SKYLAKE_SSP_CLK + tristate + +config SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC + bool "HDAudio codec support" + help + If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/ + GeminiLake or CannonLake platform with an HDaudio codec + then enable this option by saying Y + +config SND_SOC_INTEL_SKYLAKE_COMMON + tristate select SND_HDA_EXT_CORE select SND_HDA_DSP_LOADER select SND_SOC_TOPOLOGY select SND_SOC_INTEL_SST + select SND_SOC_HDAC_HDA if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC select SND_SOC_ACPI_INTEL_MATCH help If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/ GeminiLake or CannonLake platform with the DSP enabled in the BIOS then enable this option by saying Y or m. +endif ## SND_SOC_INTEL_SKYLAKE + config SND_SOC_ACPI_INTEL_MATCH tristate select SND_SOC_ACPI if ACPI diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 73ca1350aa3124..b177db2a0dbb2a 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -293,16 +293,6 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH Say Y if you have such a device. If unsure select "N". -config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH - tristate "SKL/KBL/BXT/APL with HDA Codecs" - select SND_SOC_HDAC_HDMI - select SND_SOC_HDAC_HDA - help - This adds support for ASoC machine driver for Intel platforms - SKL/KBL/BXT/APL with iDisp, HDA audio codecs. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH tristate "GLK with RT5682 and MAX98357A in I2S Mode" depends on MFD_INTEL_LPSS && I2C && ACPI @@ -319,4 +309,18 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH endif ## SND_SOC_INTEL_SKYLAKE +if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC + +config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH + tristate "SKL/KBL/BXT/APL with HDA Codecs" + select SND_SOC_HDAC_HDMI + # SND_SOC_HDAC_HDA is already selected + help + This adds support for ASoC machine driver for Intel platforms + SKL/KBL/BXT/APL with iDisp, HDA audio codecs. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + +endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC + endif ## SND_SOC_INTEL_MACH diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index ac0b4ff21acc50..901ef590276236 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -37,7 +37,9 @@ #include "skl.h" #include "skl-sst-dsp.h" #include "skl-sst-ipc.h" +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) #include "../../../soc/codecs/hdac_hda.h" +#endif /* * initialize the PCI registers @@ -654,6 +656,8 @@ static void skl_clock_device_unregister(struct skl *skl) platform_device_unregister(skl->clk_dev); } +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) + #define IDISP_INTEL_VENDOR_ID 0x80860000 /* @@ -672,6 +676,8 @@ static void load_codec_module(struct hda_codec *codec) #endif } +#endif /* CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC */ + /* * Probe the given codec address */ @@ -681,9 +687,11 @@ static int probe_codec(struct hdac_bus *bus, int addr) (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; unsigned int res = -1; struct skl *skl = bus_to_skl(bus); +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) struct hdac_hda_priv *hda_codec; - struct hdac_device *hdev; int err; +#endif + struct hdac_device *hdev; mutex_lock(&bus->cmd_mutex); snd_hdac_bus_send_cmd(bus, cmd); @@ -693,6 +701,7 @@ static int probe_codec(struct hdac_bus *bus, int addr) return -EIO; dev_dbg(bus->dev, "codec #%d probed OK: %x\n", addr, res); +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) hda_codec = devm_kzalloc(&skl->pci->dev, sizeof(*hda_codec), GFP_KERNEL); if (!hda_codec) @@ -711,6 +720,13 @@ static int probe_codec(struct hdac_bus *bus, int addr) load_codec_module(&hda_codec->codec); } return 0; +#else + hdev = devm_kzalloc(&skl->pci->dev, sizeof(*hdev), GFP_KERNEL); + if (!hdev) + return -ENOMEM; + + return snd_hdac_ext_bus_device_init(bus, addr, hdev); +#endif /* CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC */ } /* Codec initialization */ @@ -866,7 +882,7 @@ static int skl_create(struct pci_dev *pci, hbus = skl_to_hbus(skl); bus = skl_to_bus(skl); -#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDA) +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) ext_ops = snd_soc_hdac_hda_get_ops(); #endif snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, ext_ops); From aa3488f18aaf8104bc8a4ea54f1f45938f8b5cf2 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 16 Nov 2018 18:47:04 -0600 Subject: [PATCH 0287/1995] ASoC: acpi: fix: continue searching when machine is ignored The machine_quirk may return NULL which means the acpi entries should be skipped and search for next matched entry is needed, here add return check here and continue for NULL case. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit a3e620f8422832afd832ad5e20aa97d0c72bada8) --- sound/soc/soc-acpi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c index b8e72b52db30ea..4fb29f0e561ef3 100644 --- a/sound/soc/soc-acpi.c +++ b/sound/soc/soc-acpi.c @@ -10,11 +10,17 @@ struct snd_soc_acpi_mach * snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines) { struct snd_soc_acpi_mach *mach; + struct snd_soc_acpi_mach *mach_alt; for (mach = machines; mach->id[0]; mach++) { if (acpi_dev_present(mach->id, NULL, -1)) { - if (mach->machine_quirk) - mach = mach->machine_quirk(mach); + if (mach->machine_quirk) { + mach_alt = mach->machine_quirk(mach); + if (!mach_alt) + continue; /* not full match, ignore */ + mach = mach_alt; + } + return mach; } } From 045129406d1e5bd880de6a839fa7f862dcf60fd3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 16 Nov 2018 18:47:05 -0600 Subject: [PATCH 0288/1995] ASoC: Intel: fix interface for Chromebook machine drivers The changes for HDaudio overlooked the fact that the machine drivers used for Chromebooks rely on the dmic number information passed as pdata. Add dmic_num field to standard interface and use standard interface instead of SKL-specific one. Also clean-up pdata definition to remove fields that are no longer used. Fixes: 842bb5135f10 ('ASoC: Intel: use standard interface for Hdaudio machine driver') Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit b92826fa8c5a423edf6c9e385b5d433c61375cc8) --- include/sound/soc-acpi.h | 1 + sound/soc/intel/boards/kbl_rt5663_max98927.c | 10 +++++----- sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c | 10 +++++----- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 10 +++++----- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 10 +++++----- sound/soc/intel/skylake/skl.c | 2 +- sound/soc/intel/skylake/skl.h | 3 --- 7 files changed, 22 insertions(+), 24 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 5154c6359609fc..266e64e3c24c4f 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -48,6 +48,7 @@ struct snd_soc_acpi_mach_params { u32 acpi_ipc_irq_index; const char *platform; u32 codec_mask; + u32 dmic_num; }; /** diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index 6ea969c0a5fb8c..c2a96940f9f296 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -25,9 +25,9 @@ #include #include #include +#include #include "../../codecs/rt5663.h" #include "../../codecs/hdac_hdmi.h" -#include "../skylake/skl.h" #include #include #include @@ -969,7 +969,7 @@ static struct snd_soc_card kabylake_audio_card_rt5663 = { static int kabylake_audio_probe(struct platform_device *pdev) { struct kbl_rt5663_private *ctx; - struct skl_machine_pdata *pdata; + struct snd_soc_acpi_mach *mach; int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); @@ -984,9 +984,9 @@ static int kabylake_audio_probe(struct platform_device *pdev) kabylake_audio_card->dev = &pdev->dev; snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - pdata = dev_get_drvdata(&pdev->dev); - if (pdata) - dmic_constraints = pdata->dmic_num == 2 ? + mach = dev_get_drvdata(&pdev->dev); + if (mach) + dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk"); diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index a737c915d46a83..d7df307b406f7a 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -26,10 +26,10 @@ #include #include #include +#include #include "../../codecs/rt5514.h" #include "../../codecs/rt5663.h" #include "../../codecs/hdac_hdmi.h" -#include "../skylake/skl.h" #define KBL_REALTEK_CODEC_DAI "rt5663-aif" #define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1" @@ -648,7 +648,7 @@ static struct snd_soc_card kabylake_audio_card = { static int kabylake_audio_probe(struct platform_device *pdev) { struct kbl_codec_private *ctx; - struct skl_machine_pdata *pdata; + struct snd_soc_acpi_mach *mach; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -659,9 +659,9 @@ static int kabylake_audio_probe(struct platform_device *pdev) kabylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&kabylake_audio_card, ctx); - pdata = dev_get_drvdata(&pdev->dev); - if (pdata) - dmic_constraints = pdata->dmic_num == 2 ? + mach = dev_get_drvdata(&pdev->dev); + if (mach) + dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card); diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 552958ce736d1e..931890f9aa742c 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -21,9 +21,9 @@ #include #include #include +#include #include "../../codecs/nau8825.h" #include "../../codecs/hdac_hdmi.h" -#include "../skylake/skl.h" #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" #define SKL_MAXIM_CODEC_DAI "HiFi" @@ -641,7 +641,7 @@ static struct snd_soc_card skylake_audio_card = { static int skylake_audio_probe(struct platform_device *pdev) { struct skl_nau8825_private *ctx; - struct skl_machine_pdata *pdata; + struct snd_soc_acpi_mach *mach; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -652,9 +652,9 @@ static int skylake_audio_probe(struct platform_device *pdev) skylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - pdata = dev_get_drvdata(&pdev->dev); - if (pdata) - dmic_constraints = pdata->dmic_num == 2 ? + mach = dev_get_drvdata(&pdev->dev); + if (mach) + dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index f985b30a1d0eaa..657c650766fc71 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -23,11 +23,11 @@ #include #include #include +#include #include #include #include "../../codecs/nau8825.h" #include "../../codecs/hdac_hdmi.h" -#include "../skylake/skl.h" #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" #define SKL_SSM_CODEC_DAI "ssm4567-hifi" @@ -694,7 +694,7 @@ static struct snd_soc_card skylake_audio_card = { static int skylake_audio_probe(struct platform_device *pdev) { struct skl_nau88125_private *ctx; - struct skl_machine_pdata *pdata; + struct snd_soc_acpi_mach *mach; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -705,9 +705,9 @@ static int skylake_audio_probe(struct platform_device *pdev) skylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - pdata = dev_get_drvdata(&pdev->dev); - if (pdata) - dmic_constraints = pdata->dmic_num == 2 ? + mach = dev_get_drvdata(&pdev->dev); + if (mach) + dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 901ef590276236..b9e41fa284a729 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -517,7 +517,7 @@ static int skl_find_machine(struct skl *skl, void *driver_data) if (pdata) { skl->use_tplg_pcm = pdata->use_tplg_pcm; - pdata->dmic_num = skl_get_dmic_geo(skl); + mach->mach_params.dmic_num = skl_get_dmic_geo(skl); } return 0; diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 8d48cd7c56c835..85f8bb6687dcbd 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -119,10 +119,7 @@ struct skl_dma_params { }; struct skl_machine_pdata { - u32 dmic_num; bool use_tplg_pcm; /* use dais and dai links from topology */ - const char *platform; - u32 codec_mask; }; struct skl_dsp_ops { From 7205007668ccaeb0c472fec04deadbb2a555085e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 16 Nov 2018 18:47:06 -0600 Subject: [PATCH 0289/1995] ASoC: Intel: use platform_data for machine drivers For some reason we have different mechanisms for passing data to machine drivers. Use the solution used by Atom/SST and SOF instead of using drv_data as done by Skylake. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 5a619b9e8883a0f9691964d001b8480df44df5b9) --- sound/soc/intel/boards/kbl_rt5663_max98927.c | 2 +- sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c | 2 +- sound/soc/intel/boards/skl_hda_dsp_generic.c | 2 +- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 2 +- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 2 +- sound/soc/intel/skylake/skl.c | 13 ++++++++++--- 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index c2a96940f9f296..d71475200b08aa 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -984,7 +984,7 @@ static int kabylake_audio_probe(struct platform_device *pdev) kabylake_audio_card->dev = &pdev->dev; snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - mach = dev_get_drvdata(&pdev->dev); + mach = (&pdev->dev)->platform_data; if (mach) dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index d7df307b406f7a..7044d8c2b18737 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -659,7 +659,7 @@ static int kabylake_audio_probe(struct platform_device *pdev) kabylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&kabylake_audio_card, ctx); - mach = dev_get_drvdata(&pdev->dev); + mach = (&pdev->dev)->platform_data; if (mach) dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 15c502d6774d08..b9a21e64ead2ec 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -146,7 +146,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - mach = dev_get_drvdata(&pdev->dev); + mach = (&pdev->dev)->platform_data; if (!mach) return -EINVAL; diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 931890f9aa742c..0922106bd323d7 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -652,7 +652,7 @@ static int skylake_audio_probe(struct platform_device *pdev) skylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - mach = dev_get_drvdata(&pdev->dev); + mach = (&pdev->dev)->platform_data; if (mach) dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 657c650766fc71..8433c521d39f21 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -705,7 +705,7 @@ static int skylake_audio_probe(struct platform_device *pdev) skylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - mach = dev_get_drvdata(&pdev->dev); + mach = (&pdev->dev)->platform_data; if (mach) dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index b9e41fa284a729..3f0ac13129829e 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -536,6 +536,16 @@ static int skl_machine_device_register(struct skl *skl) return -EIO; } + mach->mach_params.platform = dev_name(bus->dev); + mach->mach_params.codec_mask = bus->codec_mask; + + ret = platform_device_add_data(pdev, (const void *)mach, sizeof(*mach)); + if (ret) { + dev_err(bus->dev, "failed to add machine device platform data\n"); + platform_device_put(pdev); + return ret; + } + ret = platform_device_add(pdev); if (ret) { dev_err(bus->dev, "failed to add machine device\n"); @@ -543,9 +553,6 @@ static int skl_machine_device_register(struct skl *skl) return -EIO; } - mach->mach_params.platform = dev_name(bus->dev); - mach->mach_params.codec_mask = bus->codec_mask; - dev_set_drvdata(&pdev->dev, mach); skl->i2s_dev = pdev; From e396b1b010b6f9bcdf1ef37048633460722e5795 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 22 Nov 2018 00:55:09 +0000 Subject: [PATCH 0290/1995] ASoC: soc-core: add snd_soc_of_parse_node_prefix() Current ASoC has snd_soc_of_parse_audio_prefix() to get codec_conf settings from DT which is used to avoid DAI naming conflict when CPU/Codec matching. Currently, it is parsing from "top node", but, we want to parse from "each sub node" if sound card had multi cpus/codecs. This patch adds new snd_soc_of_parse_node_prefix() to allow parsing settings from selected node. It is keeping existing snd_soc_of_parse_audio_prefix() by using macro. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 3b7103562c03cffb1a351f8c235b3bba2acd9e9b) --- include/sound/soc.h | 6 +++++- sound/soc/soc-core.c | 11 +++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 70c10a8f3e90a7..369f68179ebcbb 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1477,10 +1477,14 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, unsigned int *rx_mask, unsigned int *slots, unsigned int *slot_width); -void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, +void snd_soc_of_parse_node_prefix(struct device_node *np, struct snd_soc_codec_conf *codec_conf, struct device_node *of_node, const char *propname); +#define snd_soc_of_parse_audio_prefix(card, conf, node, name) \ + snd_soc_of_parse_node_prefix((card)->dev->of_node, \ + (conf), (node), (name)) + int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname); unsigned int snd_soc_of_parse_daifmt(struct device_node *np, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b29d0f65611eb5..b0db59e6339d97 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3485,12 +3485,11 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); -void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, - struct snd_soc_codec_conf *codec_conf, - struct device_node *of_node, - const char *propname) +void snd_soc_of_parse_node_prefix(struct device_node *np, + struct snd_soc_codec_conf *codec_conf, + struct device_node *of_node, + const char *propname) { - struct device_node *np = card->dev->of_node; const char *str; int ret; @@ -3503,7 +3502,7 @@ void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, codec_conf->of_node = of_node; codec_conf->name_prefix = str; } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_node_prefix); int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname) From b0dc82f7825596664d657a6607b9c89314efcfbf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Nov 2018 01:21:22 +0000 Subject: [PATCH 0291/1995] ASoC: soc.h: makes snd_soc_of_parse_audio_prefix() inline commit 3b7103562c03c ("ASoC: soc-core: add snd_soc_of_parse_node_prefix()") maked snd_soc_of_parse_audio_prefix() as #define. But it'd be better to make this a static inline rather than a #define. It helps with error messages and type safety. This patch makes it inline. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 2708bccf9c6f142c3ef5a27f15d34febe751ce4c) --- include/sound/soc.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 369f68179ebcbb..48fbaf7f3fe014 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1481,9 +1481,15 @@ void snd_soc_of_parse_node_prefix(struct device_node *np, struct snd_soc_codec_conf *codec_conf, struct device_node *of_node, const char *propname); -#define snd_soc_of_parse_audio_prefix(card, conf, node, name) \ - snd_soc_of_parse_node_prefix((card)->dev->of_node, \ - (conf), (node), (name)) +static inline +void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, + struct snd_soc_codec_conf *codec_conf, + struct device_node *of_node, + const char *propname) +{ + snd_soc_of_parse_node_prefix(card->dev->of_node, + codec_conf, of_node, propname); +} int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname); From 4ccf38672989bfeb91ac4243734c5ed3c971e8c1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 26 Nov 2018 18:17:12 -0600 Subject: [PATCH 0292/1995] Revert "ASoC: Intel: boards: bxt_da7219_max: remove dependency on dmic-codec" This reverts commit 80a535e23fc52f792555979ff6d1592806d5f68e. This is no longer needed since we actually make use of dmic-codec in the SOF code Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 78131be2f7a7cb..6f052fc8d1e25a 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -488,8 +488,8 @@ static struct snd_soc_dai_link broxton_dais[] = { .name = "dmic01", .id = 2, .cpu_dai_name = "DMIC01 Pin", - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", .platform_name = "0000:00:0e.0", .ignore_suspend = 1, .be_hw_params_fixup = broxton_dmic_fixup, From 48e4bb27705713597dd20cc9a14ee731326517b5 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Tue, 27 Nov 2018 11:39:38 +0800 Subject: [PATCH 0293/1995] ASoC: SOF: hda-ipc: mask busy interrupt earlier to align with done interrupt It's better we handle interrupt in this sequence: mask interrupt ==> handle message ==> unmask interrupt For new message from DSP, let's align this with reply from DSP, mask busy interrupt before handling messages. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-ipc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index e025da964ef59e..cec2fe8dc21fea 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -194,6 +194,11 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n", msg, msg_ext); + /* mask BUSY interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCCTL, + HDA_DSP_REG_HIPCCTL_BUSY, 0); + /* handle messages from DSP */ if ((hipct & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { /* this is a PANIC message !! */ @@ -203,11 +208,6 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) snd_sof_ipc_msgs_rx(sdev); } - /* mask BUSY interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - HDA_DSP_REG_HIPCCTL, - HDA_DSP_REG_HIPCCTL_BUSY, 0); - ret = IRQ_HANDLED; } From b50619398c7befa3bc19266c352d0bf4cc51d948 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 23 Nov 2018 15:59:06 +0800 Subject: [PATCH 0294/1995] ASoC: SOF: hda-ipc: fix IPC handled wrong issue When IPC interrupt arrived, we need to check HDA_DSP_REG_HIPCCTL to make sure we can tell the message initiator(new or reply from DSP), otherwise, we may treat new message as reply one by mistake, and see error message reported as "error: rx list empty but received ...". Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-ipc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index cec2fe8dc21fea..d17723ba243e02 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -135,7 +135,7 @@ int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev, irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; - u32 hipci, hipcie, hipct, hipcte, msg = 0, msg_ext = 0; + u32 hipci, hipcie, hipct, hipcte, hipcctl, msg = 0, msg_ext = 0; irqreturn_t ret = IRQ_NONE; int reply = -EINVAL; @@ -147,9 +147,11 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE); hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT); + hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL); /* is this a reply message from the DSP */ - if (hipcie & HDA_DSP_REG_HIPCIE_DONE) { + if (hipcie & HDA_DSP_REG_HIPCIE_DONE && + hipcctl & HDA_DSP_REG_HIPCCTL_DONE) { hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI); @@ -183,7 +185,8 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) } /* is this a new message from DSP */ - if (hipct & HDA_DSP_REG_HIPCT_BUSY) { + if (hipct & HDA_DSP_REG_HIPCT_BUSY && + hipcctl & HDA_DSP_REG_HIPCCTL_BUSY) { hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCTE); From f585396251b7ffc8afda804f30c75dee12a4e689 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 27 Nov 2018 09:29:29 +0100 Subject: [PATCH 0295/1995] sof: switch SPI over to using the common ACPI machine struct struct snd_soc_acpi_mach is commonly used by all platforms, including those, not using ACPI. It should be renamed in the future. For now switch the SPI driver to also use it. Signed-off-by: Guennadi Liakhovetski --- include/sound/sof.h | 19 ++--------------- sound/soc/sof/intel/hda-loader.c | 9 +------- sound/soc/sof/loader.c | 9 +------- sound/soc/sof/pcm.c | 20 +++--------------- sound/soc/sof/sof-spi-dev.c | 36 ++++++++++++++++++++++++-------- 5 files changed, 34 insertions(+), 59 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index 1074712742bec6..fea176e35551f9 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -32,15 +32,6 @@ enum sof_device_type { /* * SOF Platform data. */ -struct snd_sof_machine { - const u8 id[ACPI_ID_LEN]; - const char *drv_name; - const char *sof_fw_filename; - const char *sof_tplg_filename; - const char *asoc_plat_name; - const struct snd_sof_dsp_ops *ops; -}; - struct snd_sof_pdata { u32 id; /* PCI/ACPI ID */ const struct firmware *fw; @@ -61,10 +52,7 @@ struct snd_sof_pdata { /* machine */ struct platform_device *pdev_mach; - union { - const struct snd_soc_acpi_mach *machine; - const struct snd_sof_machine *sof_machine; - }; + const struct snd_soc_acpi_mach *machine; }; /* @@ -73,10 +61,7 @@ struct snd_sof_pdata { */ struct sof_dev_desc { /* list of machines using this configuration */ - union { - struct snd_soc_acpi_mach *machines; - struct snd_sof_machine *sof_machines; - }; + struct snd_soc_acpi_mach *machines; /* Platform resource indexes in BAR / ACPI resources. */ /* Must set to -1 if not used - add new items to end */ diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index bfa258bee44c2e..38460376e53b97 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -306,14 +306,7 @@ int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, bool first_boot) /* set code loading condition to true */ sdev->code_loading = 1; - - switch (plat_data->type) { - case SOF_DEVICE_SPI: - fw_filename = plat_data->sof_machine->sof_fw_filename; - break; - default: - fw_filename = plat_data->machine->sof_fw_filename; - } + fw_filename = plat_data->machine->sof_fw_filename; return request_firmware(&plat_data->fw, fw_filename, sdev->dev); } diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index f1a5bb6d08437a..770a0eb2ac97a0 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -217,14 +217,7 @@ int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev, /* set code loading condition to true */ sdev->code_loading = 1; - - switch (plat_data->type) { - case SOF_DEVICE_SPI: - fw_filename = plat_data->sof_machine->sof_fw_filename; - break; - default: - fw_filename = plat_data->machine->sof_fw_filename; - } + fw_filename = plat_data->machine->sof_fw_filename; ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev); diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index b60ef603121718..66887d9a088a44 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -690,14 +690,7 @@ static int sof_pcm_probe(struct snd_soc_component *component) /* load the default topology */ sdev->component = component; - - switch (plat_data->type) { - case SOF_DEVICE_SPI: - tplg_filename = plat_data->sof_machine->sof_tplg_filename; - break; - default: - tplg_filename = plat_data->machine->sof_tplg_filename; - } + tplg_filename = plat_data->machine->sof_tplg_filename; ret = snd_sof_load_topology(sdev, tplg_filename); if (ret < 0) { @@ -732,15 +725,8 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) struct snd_sof_pdata *plat_data = sdev->pdata; const char *plat_name, *drv_name; - switch (plat_data->type) { - case SOF_DEVICE_SPI: - plat_name = plat_data->sof_machine->asoc_plat_name; - drv_name = plat_data->sof_machine->drv_name; - break; - default: - plat_name = plat_data->machine->asoc_plat_name; - drv_name = plat_data->machine->drv_name; - } + plat_name = plat_data->machine->asoc_plat_name; + drv_name = plat_data->machine->drv_name; dev_dbg(sdev->dev, "using platform alias %s\n", plat_name); diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index 4445a91a732683..dd7ab7f5775424 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -21,7 +21,7 @@ #include "sof-priv.h" #include "hw-spi.h" -static const struct dev_pm_ops sof_spi_pm = { +static const struct dev_pm_ops spi_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, NULL) @@ -29,19 +29,18 @@ static const struct dev_pm_ops sof_spi_pm = { }; /* FIXME: replace with some meaningful values */ -static struct snd_sof_machine sof_spi_machines[] = { +static struct snd_soc_acpi_mach spi_machines[] = { { .id = "INT343A", .drv_name = "bxt_alc298s_i2s", .sof_fw_filename = "intel/sof-spi.ri", .sof_tplg_filename = "intel/sof-spi.tplg", .asoc_plat_name = "0000:00:0e.0", - .ops = &snd_sof_spi_ops, }, }; static const struct sof_dev_desc spi_desc = { - .sof_machines = sof_spi_machines, + .machines = spi_machines, .nocodec_fw_filename = "intel/sof-spi.ri", .nocodec_tplg_filename = "intel/sof-spi.tplg", .resindex_lpe_base = -1, @@ -51,12 +50,27 @@ static const struct sof_dev_desc spi_desc = { .resindex_dma_base = -1, }; +static const struct sof_ops_table spi_mach_ops[] = { + {&spi_desc, &snd_sof_spi_ops}, +}; + +static struct snd_sof_dsp_ops *spi_get_ops(const struct sof_dev_desc *d) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(spi_mach_ops); i++) + if (d == spi_mach_ops[i].desc) + return spi_mach_ops[i].ops; + + /* not found */ + return NULL; +} + static int sof_spi_probe(struct spi_device *spi) { struct device *dev = &spi->dev; const struct sof_dev_desc *desc = of_device_get_match_data(dev); - struct snd_sof_machine *machines; - struct snd_sof_machine *mach; + struct snd_soc_acpi_mach *machines, *mach; struct snd_sof_pdata *sof_pdata; struct sof_platform_priv *priv; const char *tplg, *fw; @@ -66,7 +80,7 @@ static int sof_spi_probe(struct spi_device *spi) if (!dev->of_node || !desc) return -ENODEV; - machines = desc->sof_machines; + machines = desc->machines; if (!machines) return -ENODEV; @@ -119,12 +133,16 @@ static int sof_spi_probe(struct spi_device *spi) */ mach->sof_fw_filename = desc->nocodec_fw_filename; mach->sof_tplg_filename = desc->nocodec_tplg_filename; - mach->ops = machines[0].ops; mach->asoc_plat_name = "sof-platform"; + mach->pdata = spi_get_ops(desc); + if (!mach->pdata) { + dev_err(dev, "No matching SPI descriptor ops\n"); + return -ENODEV; + } sof_pdata->id = -1; sof_pdata->name = dev_name(&spi->dev); - sof_pdata->sof_machine = mach; + sof_pdata->machine = mach; sof_pdata->desc = desc; priv->sof_pdata = sof_pdata; sof_pdata->dev = dev; From 4fd5f872f2fe443c53ef48a42350fb9a56a3e125 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 27 Nov 2018 14:46:50 -0600 Subject: [PATCH 0296/1995] ASoC: SOF: fix SPDX license for include files Spurious parenthesis makes checkpatch.pl angry with 4.19+ Signed-off-by: Pierre-Louis Bossart --- include/sound/sof/control.h | 2 +- include/sound/sof/dai-intel.h | 2 +- include/sound/sof/dai.h | 2 +- include/sound/sof/header.h | 2 +- include/sound/sof/info.h | 2 +- include/sound/sof/pm.h | 2 +- include/sound/sof/stream.h | 2 +- include/sound/sof/topology.h | 2 +- include/sound/sof/trace.h | 2 +- include/sound/sof/xtensa.h | 2 +- include/uapi/sound/sof/abi.h | 2 +- include/uapi/sound/sof/eq.h | 2 +- include/uapi/sound/sof/fw.h | 2 +- include/uapi/sound/sof/header.h | 2 +- include/uapi/sound/sof/manifest.h | 2 +- include/uapi/sound/sof/tokens.h | 2 +- include/uapi/sound/sof/tone.h | 2 +- include/uapi/sound/sof/trace.h | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/include/sound/sof/control.h b/include/sound/sof/control.h index 7c839ae73b8f33..e2f6696d953aac 100644 --- a/include/sound/sof/control.h +++ b/include/sound/sof/control.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h index cc83ebbbe66455..71f9b34d624427 100644 --- a/include/sound/sof/dai-intel.h +++ b/include/sound/sof/dai-intel.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 025a5cba682e30..5ebf9648d3fa4e 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index 7b506877b7dec3..1a66cdb9353741 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. diff --git a/include/sound/sof/info.h b/include/sound/sof/info.h index e7c16ac90fa62c..aa99e12e3bc97c 100644 --- a/include/sound/sof/info.h +++ b/include/sound/sof/info.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. diff --git a/include/sound/sof/pm.h b/include/sound/sof/pm.h index 76a0529338999a..5f725fdd3e161d 100644 --- a/include/sound/sof/pm.h +++ b/include/sound/sof/pm.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. diff --git a/include/sound/sof/stream.h b/include/sound/sof/stream.h index ce43e1bfdb83ed..31dd8a56de9ddc 100644 --- a/include/sound/sof/stream.h +++ b/include/sound/sof/stream.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h index 166ead19bf6d15..b63cc41deb20a9 100644 --- a/include/sound/sof/topology.h +++ b/include/sound/sof/topology.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. diff --git a/include/sound/sof/trace.h b/include/sound/sof/trace.h index 7493059d6ef0be..1fba59798bb070 100644 --- a/include/sound/sof/trace.h +++ b/include/sound/sof/trace.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. diff --git a/include/sound/sof/xtensa.h b/include/sound/sof/xtensa.h index e7c36a5c667d2d..07f46385ea5f0d 100644 --- a/include/sound/sof/xtensa.h +++ b/include/sound/sof/xtensa.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index 48bd898d953ed4..dbc80cde3ed6e2 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. diff --git a/include/uapi/sound/sof/eq.h b/include/uapi/sound/sof/eq.h index 9567d4abea703f..71a159502d069d 100644 --- a/include/uapi/sound/sof/eq.h +++ b/include/uapi/sound/sof/eq.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. diff --git a/include/uapi/sound/sof/fw.h b/include/uapi/sound/sof/fw.h index c82e094f865b9f..37dd159c955b01 100644 --- a/include/uapi/sound/sof/fw.h +++ b/include/uapi/sound/sof/fw.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. diff --git a/include/uapi/sound/sof/header.h b/include/uapi/sound/sof/header.h index e69daec521fb93..7868990b0d6f34 100644 --- a/include/uapi/sound/sof/header.h +++ b/include/uapi/sound/sof/header.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. diff --git a/include/uapi/sound/sof/manifest.h b/include/uapi/sound/sof/manifest.h index c130518961c83b..2009ee30fad022 100644 --- a/include/uapi/sound/sof/manifest.h +++ b/include/uapi/sound/sof/manifest.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 0db5253a37bf35..98c2257e8e8286 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. diff --git a/include/uapi/sound/sof/tone.h b/include/uapi/sound/sof/tone.h index 2a5503aa94e40c..ec792ccdf51260 100644 --- a/include/uapi/sound/sof/tone.h +++ b/include/uapi/sound/sof/tone.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. diff --git a/include/uapi/sound/sof/trace.h b/include/uapi/sound/sof/trace.h index 606add4d951f91..dadedd199a68aa 100644 --- a/include/uapi/sound/sof/trace.h +++ b/include/uapi/sound/sof/trace.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note)) OR BSD-3-Clause) */ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. From fa06c6decfeca2fe53d2e85fe9c5c922ea1b2ea4 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 23 Nov 2018 22:38:41 +0800 Subject: [PATCH 0297/1995] ASoC: SOF: Intel: add balanced code of snd_hdac_ext_bus_device_init snd_hdac_ext_bus_device_init is called in hda_codec_probe, it will initialize and register the HDA extended codec. We should call snd_hdac_ext_bus_device_remove to unregister the HDA extended codec. Also, snd_hdac_link_free_all() and snd_hdac_ext_bus_exit() are required for remove. Otherwise, We will fail in rmmod/modprobe cycle. Signed-off-by: Bard liao --- sound/soc/sof/intel/hda.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index d90134cf3b36e8..ee8b9a0c9a74be 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -738,6 +738,11 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) if (sdev->hda) chip = sdev->hda->desc; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* codec removal, invoke bus_device_remove */ + snd_hdac_ext_bus_device_remove(bus); +#endif + if (sdev->hda && (!IS_ERR(sdev->hda->dmic_dev))) platform_device_unregister(sdev->hda->dmic_dev); @@ -762,10 +767,16 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) pci_free_irq_vectors(pci); hda_dsp_stream_free(sdev); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + snd_hdac_link_free_all(bus); +#endif iounmap(sdev->bar[HDA_DSP_BAR]); iounmap(bus->remap_addr); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + snd_hdac_ext_bus_exit(bus); +#endif hda_codec_i915_exit(sdev); return 0; From 405e866b031eafee80e454ae375f537a8ddf4978 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 28 Nov 2018 13:08:46 -0600 Subject: [PATCH 0298/1995] ASoC: SOF: fix sparse issues Come on, people. Use sparse! this simple tools finds all kinds of issues with memory spaces, missing headers, endianness... make SUBDIRS=sound/soc/sof C=2 3 remaining issues filed on github (fw_version, BDL as __le32 (x2) ) Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/control.c | 6 ++++-- sound/soc/sof/hw-spi.c | 2 +- sound/soc/sof/intel/hda-bus.c | 2 ++ sound/soc/sof/sof-spi-dev.c | 2 +- sound/soc/sof/topology.c | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index e08f7e007d293b..9328c078f4bd42 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -278,7 +278,8 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct snd_ctl_tlv header; - struct snd_ctl_tlv *tlvd = (struct snd_ctl_tlv *)binary_data; + struct snd_ctl_tlv __user *tlvd = + (struct snd_ctl_tlv __user *)binary_data; int ret; int err; int max_length = SOF_IPC_MSG_MAX_SIZE - @@ -350,7 +351,8 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct snd_ctl_tlv header; - struct snd_ctl_tlv *tlvd = (struct snd_ctl_tlv *)binary_data; + struct snd_ctl_tlv __user *tlvd = + (struct snd_ctl_tlv __user *)binary_data; int max_length = SOF_IPC_MSG_MAX_SIZE - sizeof(const struct sof_ipc_ctrl_data) - sizeof(const struct sof_abi_hdr); diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index 637ca57a9c76c8..75066bd79c4825 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -277,7 +277,7 @@ static int spi_cmd_done(struct snd_sof_dev *sof_dev __maybe_unused, int dir __ma } /* SPI SOF ops */ -struct snd_sof_dsp_ops snd_sof_spi_ops = { +static struct snd_sof_dsp_ops snd_sof_spi_ops = { /* device init */ .probe = spi_sof_probe, .remove = spi_sof_remove, diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index de158dd7d0cf58..f515144b0a6bf5 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -10,6 +10,8 @@ */ #include +#include "../sof-priv.h" +#include "hda.h" #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index dd7ab7f5775424..ca6cf8b08e3354 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -177,7 +177,7 @@ static int sof_spi_remove(struct spi_device *spi) return 0; } -const struct of_device_id sof_of_match[] = { +static const struct of_device_id sof_of_match[] = { { .compatible = "sof,spi-sue-creek", .data = &spi_desc }, { } }; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 9af530bb45dc9a..59c9d76bc2899f 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -325,7 +325,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, if (le32_to_cpu(control->priv.size) > 0) { memcpy(cdata->data->data, control->priv.data, le32_to_cpu(control->priv.size)); - cdata->data->size = control->priv.size; + cdata->data->size = le32_to_cpu(control->priv.size); cdata->data->magic = SOF_ABI_MAGIC; cdata->data->abi = SOF_ABI_VERSION; } From 96290688124823d46a6a34b46482e0ca88108307 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 28 Nov 2018 15:27:27 -0600 Subject: [PATCH 0299/1995] ASoC: SOF: ACPI: remove new_mach_data usage No one seems to recall why we need to have a specific flow for Baytrail and Cherrytrail which actually looks completely identical to the default one. Also remove references to HDAudio that were added sometime between August and October, this makes no sense for ACPI devices. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 23 ++++++++------------- sound/soc/sof/sof-acpi-dev.c | 40 +++++++----------------------------- 2 files changed, 16 insertions(+), 47 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index f92279c688e688..8161fd2dbad947 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -329,20 +329,15 @@ static int sof_probe(struct platform_device *pdev) goto comp_err; } - /* do we need to generate any machine plat data ? */ - if (plat_data->machine->new_mach_data) { - plat_data->pdev_mach = - plat_data->machine->new_mach_data(plat_data); - } else { - drv_name = plat_data->machine->drv_name; - mach = (const void *)plat_data->machine; - size = sizeof(*plat_data->machine); - - /* register machine driver, pass machine info as pdata */ - plat_data->pdev_mach = - platform_device_register_data(sdev->dev, - drv_name, -1, mach, size); - } + drv_name = plat_data->machine->drv_name; + mach = (const void *)plat_data->machine; + size = sizeof(*plat_data->machine); + + /* register machine driver, pass machine info as pdata */ + plat_data->pdev_mach = + platform_device_register_data(sdev->dev, drv_name, + -1, mach, size); + if (IS_ERR(plat_data->pdev_mach)) { ret = PTR_ERR(plat_data->pdev_mach); goto comp_err; diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index f77bd078f78947..1a77eefe6afa3c 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -116,22 +116,6 @@ static struct sof_dev_desc sof_acpi_cherrytrail_desc = { .nocodec_tplg_filename = "intel/sof-cht-nocodec.tplg" }; -static struct platform_device * - mfld_new_mach_data(struct snd_sof_pdata *sof_pdata) -{ - struct snd_soc_acpi_mach pmach; - struct device *dev = sof_pdata->dev; - const struct snd_soc_acpi_mach *mach = sof_pdata->machine; - struct platform_device *pdev = NULL; - - memset(&pmach, 0, sizeof(pmach)); - memcpy((void *)pmach.id, mach->id, ACPI_ID_LEN); - pmach.drv_name = mach->drv_name; - - pdev = platform_device_register_data(dev, mach->drv_name, -1, - &pmach, sizeof(pmach)); - return pdev; -} #endif static const struct dev_pm_ops sof_acpi_pm = { @@ -149,22 +133,18 @@ static const struct sof_ops_table mach_ops[] = { {&sof_acpi_broadwell_desc, &sof_bdw_ops}, #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - {&sof_acpi_baytrail_desc, &sof_byt_ops, mfld_new_mach_data}, - {&sof_acpi_baytrailcr_desc, &sof_byt_ops, mfld_new_mach_data}, - {&sof_acpi_cherrytrail_desc, &sof_cht_ops, mfld_new_mach_data}, + {&sof_acpi_baytrail_desc, &sof_byt_ops}, + {&sof_acpi_baytrailcr_desc, &sof_byt_ops}, + {&sof_acpi_cherrytrail_desc, &sof_cht_ops}, #endif }; -static struct snd_sof_dsp_ops * - sof_acpi_get_ops(const struct sof_dev_desc *d, - struct platform_device *(**new_mach_data) - (struct snd_sof_pdata *)) +static struct snd_sof_dsp_ops *sof_acpi_get_ops(const struct sof_dev_desc *d) { int i; for (i = 0; i < ARRAY_SIZE(mach_ops); i++) { if (d == mach_ops[i].desc) { - *new_mach_data = mach_ops[i].new_data; return mach_ops[i].ops; } } @@ -182,7 +162,6 @@ static int sof_acpi_probe(struct platform_device *pdev) struct snd_sof_pdata *sof_pdata; struct sof_platform_priv *priv; struct snd_sof_dsp_ops *ops; - struct platform_device *(*new_mach_data)(struct snd_sof_pdata *pdata); int ret = 0; dev_dbg(&pdev->dev, "ACPI DSP detected"); @@ -206,8 +185,7 @@ static int sof_acpi_probe(struct platform_device *pdev) #endif /* get ops for platform */ - new_mach_data = NULL; - ops = sof_acpi_get_ops(desc, &new_mach_data); + ops = sof_acpi_get_ops(desc); if (!ops) { dev_err(dev, "error: no matching ACPI descriptor ops\n"); return -ENODEV; @@ -232,17 +210,13 @@ static int sof_acpi_probe(struct platform_device *pdev) if (ret < 0) return ret; #else - dev_warn(dev, "No matching ASoC machine driver found - falling back to HDA codec\n"); - mach = snd_soc_acpi_intel_hda_machines; - mach->sof_fw_filename = desc->nocodec_fw_filename; + dev_err(dev, "No matching ASoC machine driver found - aborting probe\n"); + return -ENODEV; #endif } #endif mach->pdata = ops; - mach->new_mach_data = (struct platform_device * - (*)(void *pdata)) new_mach_data; - sof_pdata->machine = mach; /* * FIXME, this can't work for baytrail cr: From 341b4fb3b49d4faff6c480f5de3c8c81bd83ae93 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 28 Nov 2018 15:42:47 -0600 Subject: [PATCH 0300/1995] ASoC: SOF: add helper to retrieve .ops Now that there is no ACPI-specific code for .ops, use a common helper Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/ops.h | 15 +++++++++++++++ sound/soc/sof/sof-acpi-dev.c | 19 +++---------------- sound/soc/sof/sof-pci-dev.c | 18 +++--------------- sound/soc/sof/sof-spi-dev.c | 15 ++------------- 4 files changed, 23 insertions(+), 44 deletions(-) diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 1912994a1c94cb..708363a111d01f 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -312,6 +312,21 @@ snd_sof_pcm_platform_pointer(struct snd_sof_dev *sdev, return 0; } +static inline struct snd_sof_dsp_ops +*sof_get_ops(const struct sof_dev_desc *d, + const struct sof_ops_table mach_ops[], int asize) +{ + int i; + + for (i = 0; i < asize; i++) { + if (d == mach_ops[i].desc) + return mach_ops[i].ops; + } + + /* not found */ + return NULL; +} + int snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 mask, u32 value); diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 1a77eefe6afa3c..4430460a7c0150 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -22,6 +22,7 @@ #include #include #include "sof-priv.h" +#include "ops.h" /* platform specific devices */ #include "intel/shim.h" @@ -125,7 +126,7 @@ static const struct dev_pm_ops sof_acpi_pm = { .suspend_late = snd_sof_suspend_late, }; -static const struct sof_ops_table mach_ops[] = { +static const struct sof_ops_table acpi_mach_ops[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL) {&sof_acpi_haswell_desc, &sof_hsw_ops}, #endif @@ -139,20 +140,6 @@ static const struct sof_ops_table mach_ops[] = { #endif }; -static struct snd_sof_dsp_ops *sof_acpi_get_ops(const struct sof_dev_desc *d) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(mach_ops); i++) { - if (d == mach_ops[i].desc) { - return mach_ops[i].ops; - } - } - - /* not found */ - return NULL; -} - static int sof_acpi_probe(struct platform_device *pdev) { const struct acpi_device_id *id; @@ -185,7 +172,7 @@ static int sof_acpi_probe(struct platform_device *pdev) #endif /* get ops for platform */ - ops = sof_acpi_get_ops(desc); + ops = sof_get_ops(desc, acpi_mach_ops, ARRAY_SIZE(acpi_mach_ops)); if (!ops) { dev_err(dev, "error: no matching ACPI descriptor ops\n"); return -ENODEV; diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 0381d5198e5895..cdf10a9161783c 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -20,6 +20,7 @@ #include #include #include "sof-priv.h" +#include "ops.h" /* platform specific devices */ #include "intel/shim.h" @@ -136,7 +137,7 @@ static const struct dev_pm_ops sof_pci_pm = { }; -static const struct sof_ops_table mach_ops[] = { +static const struct sof_ops_table pci_mach_ops[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) {&bxt_desc, &sof_apl_ops}, #endif @@ -160,19 +161,6 @@ static const struct sof_ops_table mach_ops[] = { #endif }; -static struct snd_sof_dsp_ops *sof_pci_get_ops(const struct sof_dev_desc *d) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(mach_ops); i++) { - if (d == mach_ops[i].desc) - return mach_ops[i].ops; - } - - /* not found */ - return NULL; -} - static int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -188,7 +176,7 @@ static int sof_pci_probe(struct pci_dev *pci, dev_dbg(&pci->dev, "PCI DSP detected"); /* get ops for platform */ - ops = sof_pci_get_ops(desc); + ops = sof_get_ops(desc, pci_mach_ops, ARRAY_SIZE(pci_mach_ops)); if (!ops) { dev_err(dev, "error: no matching PCI descriptor ops\n"); return -ENODEV; diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index ca6cf8b08e3354..a09e0f8e57e51e 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -20,6 +20,7 @@ #include #include "sof-priv.h" #include "hw-spi.h" +#include "ops.h" static const struct dev_pm_ops spi_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) @@ -54,18 +55,6 @@ static const struct sof_ops_table spi_mach_ops[] = { {&spi_desc, &snd_sof_spi_ops}, }; -static struct snd_sof_dsp_ops *spi_get_ops(const struct sof_dev_desc *d) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(spi_mach_ops); i++) - if (d == spi_mach_ops[i].desc) - return spi_mach_ops[i].ops; - - /* not found */ - return NULL; -} - static int sof_spi_probe(struct spi_device *spi) { struct device *dev = &spi->dev; @@ -134,7 +123,7 @@ static int sof_spi_probe(struct spi_device *spi) mach->sof_fw_filename = desc->nocodec_fw_filename; mach->sof_tplg_filename = desc->nocodec_tplg_filename; mach->asoc_plat_name = "sof-platform"; - mach->pdata = spi_get_ops(desc); + mach->pdata = sof_get_ops(desc, spi_mach_ops, ARRAY_SIZE(spi_mach_ops)); if (!mach->pdata) { dev_err(dev, "No matching SPI descriptor ops\n"); return -ENODEV; From e6de672361d7023b16c46e31cc2a1a678f4d23cc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 29 Nov 2018 09:46:54 -0600 Subject: [PATCH 0301/1995] ASoC: SOF: remove new_data from ops table Now that we've removed the code, let's remove the definition Suggested-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-priv.h | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index d5f386e81eef46..cd2af805522ed4 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -185,7 +185,6 @@ struct sof_arch_ops { struct sof_ops_table { const struct sof_dev_desc *desc; struct snd_sof_dsp_ops *ops; - struct platform_device *(*new_data)(struct snd_sof_pdata *pdata); }; /* FS entry for debug files that can expose DSP memories, registers */ From 12419503fa486bd27ac7abf103afb726993b0a60 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Thu, 15 Nov 2018 17:44:09 +0800 Subject: [PATCH 0302/1995] ASoC: SOF: set link dma channel in hda config Now FW set wrong link dma channel which make capture failed. My algorithm is: allocate link dma channel in host and send hda config to FW to config link dma. Signed-off-by: Rander Wang --- include/sound/sof/dai-intel.h | 3 +- sound/soc/sof/intel/hda-dai.c | 120 ++++++++++++++++++++----- sound/soc/sof/topology.c | 159 +++++++++++++++++++++++++++++++--- 3 files changed, 248 insertions(+), 34 deletions(-) diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h index 71f9b34d624427..e6ebd3ebac3c2c 100644 --- a/include/sound/sof/dai-intel.h +++ b/include/sound/sof/dai-intel.h @@ -82,8 +82,7 @@ struct sof_ipc_dai_ssp_params { /* HDA Configuration Request - SOF_IPC_DAI_HDA_CONFIG */ struct sof_ipc_dai_hda_params { - struct sof_ipc_hdr hdr; - /* TODO */ + uint32_t link_dma_ch; } __packed; /* DMIC Configuration Request - SOF_IPC_DAI_DMIC_CONFIG */ diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index dd68cbf00014dd..b0f90ce4604c46 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -33,7 +33,59 @@ struct hda_pipe_params { unsigned int link_bps; }; -/* TODO: add hda dai params in tplg, and configure this in topology parsing */ +/* Unlike GP dma, there is a set of stream registers in hda controller to + * control the link dma channels. Each register controls one link dma + * channel and the relation is fixed. To make sure FW uses the correct + * link dma channel, host allocates stream register and sends the + * corresponding link dma channel to FW to allocate link dma channel + */ +static int hda_link_dma_get_channels(struct snd_soc_dai *dai, + unsigned int *tx_num, + unsigned int *tx_slot, + unsigned int *rx_num, + unsigned int *rx_slot) +{ + struct hdac_bus *bus; + struct hdac_ext_stream *stream; + struct snd_pcm_substream substream = {0}; + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(dai->component); + + bus = sof_to_bus(sdev); + + if (*tx_num == 1) { + substream.stream = SNDRV_PCM_STREAM_PLAYBACK; + stream = snd_hdac_ext_stream_assign(bus, &substream, + HDAC_EXT_STREAM_TYPE_LINK); + if (!stream) { + dev_err(bus->dev, "failed to find a free hda ext stream for playback"); + return -EBUSY; + } + + snd_soc_dai_set_dma_data(dai, &substream, (void *)stream); + *tx_slot = hdac_stream(stream)->stream_tag - 1; + + dev_dbg(bus->dev, "link dma channel %d for playback", *tx_slot); + } + + if (*rx_num == 1) { + substream.stream = SNDRV_PCM_STREAM_CAPTURE; + stream = snd_hdac_ext_stream_assign(bus, &substream, + HDAC_EXT_STREAM_TYPE_LINK); + if (!stream) { + dev_err(bus->dev, "failed to find a free hda ext stream for capture"); + return -EBUSY; + } + + snd_soc_dai_set_dma_data(dai, &substream, (void *)stream); + *rx_slot = hdac_stream(stream)->stream_tag - 1; + + dev_dbg(bus->dev, "link dma channel %d for capture", *rx_slot); + } + + return 0; +} + static int hda_link_dma_params(struct hdac_ext_stream *stream, struct hda_pipe_params *params) { @@ -78,12 +130,7 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream, struct hdac_ext_link *link; int stream_tag; - link_dev = snd_hdac_ext_stream_assign(bus, substream, - HDAC_EXT_STREAM_TYPE_LINK); - if (!link_dev) - return -EBUSY; - - snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); + link_dev = snd_soc_dai_get_dma_data(dai, substream); link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name); if (!link) @@ -147,22 +194,50 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, static int hda_link_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct hdac_stream *hstream = substream->runtime->private_data; - struct hdac_bus *bus = hstream->bus; - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct hdac_ext_stream *link_dev = - snd_soc_dai_get_dma_data(dai, substream); + const char *name; + unsigned int stream_tag; + struct hdac_bus *bus; struct hdac_ext_link *link; - - link = snd_hdac_ext_bus_get_link(bus, rtd->codec_dai->component->name); - if (!link) - return -EINVAL; - - snd_hdac_ext_link_clear_stream_id(link, - hdac_stream(link_dev)->stream_tag); - snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); - - link_dev->link_prepared = 0; + struct snd_sof_dev *sdev; + struct hdac_stream *hstream; + struct hdac_ext_stream *stream; + struct snd_soc_pcm_runtime *rtd; + struct hdac_ext_stream *link_dev; + struct snd_pcm_substream pcm_substream = {0}; + + if (substream) { + hstream = substream->runtime->private_data; + bus = hstream->bus; + rtd = snd_pcm_substream_chip(substream); + link_dev = snd_soc_dai_get_dma_data(dai, substream); + name = rtd->codec_dai->component->name; + link = snd_hdac_ext_bus_get_link(bus, name); + if (!link) + return -EINVAL; + + stream_tag = hdac_stream(link_dev)->stream_tag; + snd_hdac_ext_link_clear_stream_id(link, stream_tag); + + link_dev->link_prepared = 0; + } else { + /* release all hda streams when dai link is unloaded */ + sdev = snd_soc_component_get_drvdata(dai->component); + pcm_substream.stream = SNDRV_PCM_STREAM_PLAYBACK; + stream = snd_soc_dai_get_dma_data(dai, &pcm_substream); + if (stream) { + snd_soc_dai_set_dma_data(dai, &pcm_substream, NULL); + snd_hdac_ext_stream_release(stream, + HDAC_EXT_STREAM_TYPE_LINK); + } + + pcm_substream.stream = SNDRV_PCM_STREAM_CAPTURE; + stream = snd_soc_dai_get_dma_data(dai, &pcm_substream); + if (stream) { + snd_soc_dai_set_dma_data(dai, &pcm_substream, NULL); + snd_hdac_ext_stream_release(stream, + HDAC_EXT_STREAM_TYPE_LINK); + } + } return 0; } @@ -171,6 +246,7 @@ static const struct snd_soc_dai_ops hda_link_dai_ops = { .hw_params = hda_link_hw_params, .hw_free = hda_link_hw_free, .trigger = hda_link_pcm_trigger, + .get_channel_map = hda_link_dma_get_channels, }; #endif diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 59c9d76bc2899f..87719ffd949f07 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2028,6 +2028,49 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, return ret; } +static int sof_link_hda_process(struct snd_sof_dev *sdev, + struct snd_soc_dai_link *link, + struct sof_ipc_dai_config *config, + int slot, + int direction) +{ + struct sof_ipc_reply reply; + u32 size = sizeof(*config); + struct snd_sof_dai *dai; + int found = 0; + int ret; + + /* for hda link, playback and capture are supported by different + * dai in FW. Here get the dai_index of each dai and send config + * to FW. In FW, each dai sets config by dai_index + */ + list_for_each_entry(dai, &sdev->dai_list, list) { + if (!dai->name) + continue; + + if (strcmp(link->name, dai->name) == 0 && + dai->comp_dai.direction == direction) { + config->dai_index = dai->comp_dai.dai_index; + found = 1; + break; + } + } + + if (!found) { + dev_err(sdev->dev, "failed to find dai %s", link->name); + return -EINVAL; + } + + config->hda.link_dma_ch = slot; + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + config->hdr.cmd, config, size, &reply, + sizeof(reply)); + + return ret; +} + static int sof_link_hda_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg, @@ -2035,9 +2078,15 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index, struct sof_ipc_dai_config *config) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_dai_link_component dai_component = {0}; struct snd_soc_tplg_private *private = &cfg->priv; - struct sof_ipc_reply reply; + struct snd_soc_dai *dai; + u32 size = sizeof(*config); + u32 tx_num = 0; + u32 tx_slot = 0; + u32 rx_num = 0; + u32 rx_slot = 0; int ret; /* init IPC */ @@ -2054,18 +2103,50 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index, return ret; } - dev_dbg(sdev->dev, "tplg: config HDA%d fmt 0x%x\n", - config->dai_index, config->format); + dai_component.dai_name = link->cpu_dai_name; + dai = snd_soc_find_dai(&dai_component); + if (!dai) { + dev_err(sdev->dev, "failed to find dai %s", dai->name); + return -EINVAL; + } - /* send message to DSP */ - ret = sof_ipc_tx_message(sdev->ipc, - config->hdr.cmd, config, size, &reply, - sizeof(reply)); + if (link->dpcm_playback) + tx_num = 1; - if (ret < 0) - dev_err(sdev->dev, "error: failed to set DAI config for HDA%d\n", + if (link->dpcm_capture) + rx_num = 1; + + ret = snd_soc_dai_get_channel_map(dai, &tx_num, &tx_slot, + &rx_num, &rx_slot); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to get dma channel for HDA%d\n", config->dai_index); + return ret; + } + + /* for hda link, playback and capture are supported by different + * dai in FW. Here send dai config according to capability of dai. + */ + if (link->dpcm_playback) { + ret = sof_link_hda_process(sdev, link, config, tx_slot, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DAI config for playback dai HDA%d\n", + config->dai_index); + + return ret; + } + } + + if (link->dpcm_capture) { + ret = sof_link_hda_process(sdev, link, config, rx_slot, + SNDRV_PCM_STREAM_CAPTURE); + if (ret < 0) + dev_err(sdev->dev, "error: failed to set DAI config for capture dai HDA%d\n", + config->dai_index); + } + return ret; } @@ -2152,10 +2233,68 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, return 0; } +static int sof_link_hda_unload(struct snd_sof_dev *sdev, + struct snd_soc_dai_link *link) +{ + struct snd_soc_dai_link_component dai_component = {0}; + struct snd_soc_dai *dai; + int ret = 0; + + dai_component.dai_name = link->cpu_dai_name; + dai = snd_soc_find_dai(&dai_component); + if (!dai) { + dev_err(sdev->dev, "failed to find dai %s", dai->name); + return -EINVAL; + } + + if (dai->driver->ops->hw_free) + ret = dai->driver->ops->hw_free(NULL, dai); + if (ret < 0) + dev_err(sdev->dev, "error: failed to free hda resource for %s\n", + link->name); + + return ret; +} + static int sof_link_unload(struct snd_soc_component *scomp, struct snd_soc_dobj *dobj) { - return 0; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_dai_link *link = + container_of(dobj, struct snd_soc_dai_link, dobj); + + struct snd_sof_dai *sof_dai = NULL; + int ret = 0; + + list_for_each_entry(sof_dai, &sdev->dai_list, list) { + if (!sof_dai->name) + continue; + + if (strcmp(link->name, sof_dai->name) == 0) + break; + } + + if (!sof_dai) { + dev_err(sdev->dev, "failed to find dai %s", link->name); + return -EINVAL; + } + + switch (sof_dai->dai_config.type) { + case SOF_DAI_INTEL_SSP: + case SOF_DAI_INTEL_DMIC: + /* no resource needs to be released for SSP and DMIC */ + break; + case SOF_DAI_INTEL_HDA: + ret = sof_link_hda_unload(sdev, link); + break; + default: + dev_err(sdev->dev, "error: invalid DAI type %d\n", + sof_dai->dai_config.type); + ret = -EINVAL; + break; + } + + return ret; } /* bind PCM ID to host component ID */ From ec3e29078eff1ad50fc0e8485deaad15056b63c2 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Thu, 29 Nov 2018 14:03:57 +0200 Subject: [PATCH 0303/1995] ASoC: SOF: Remove unnecessary SOF_ABI_MAGIC check from pm.c This patch removes a previous workaround that was used for effects binary control. The code is safe to remove now. Signed-off-by: Seppo Ingalsuo --- sound/soc/sof/pm.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 81b7050394ca75..403c08f1785e74 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -26,7 +26,7 @@ static int sof_restore_kcontrols(struct snd_sof_dev *sdev) { struct snd_sof_control *scontrol = NULL; - int ipc_cmd, ctrl_type, sof_abi; + int ipc_cmd, ctrl_type; int ret = 0; /* restore kcontrol values */ @@ -44,19 +44,11 @@ static int sof_restore_kcontrols(struct snd_sof_dev *sdev) scontrol->cmd); break; case SOF_CTRL_CMD_BINARY: - - /* Check if control data contains valid data. - * SOF_ABI_MAGIC will not match if there is no data. - */ ipc_cmd = SOF_IPC_COMP_SET_DATA; ctrl_type = SOF_CTRL_TYPE_DATA_SET; - sof_abi = scontrol->control_data->data->magic; - if (sof_abi == SOF_ABI_MAGIC) - ret = snd_sof_ipc_set_comp_data(sdev->ipc, - scontrol, - ipc_cmd, - ctrl_type, - scontrol->cmd); + ret = snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, + ipc_cmd, ctrl_type, + scontrol->cmd); break; default: From 912897e981e2c5cb53c87a492fd06bb97f51e612 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 28 Nov 2018 18:14:38 -0600 Subject: [PATCH 0304/1995] ASoC: SOF: reorder include files alphabetically Upstream reviews invariably suggest the include files be ordered alphabetically. Let's not give people an opportunity to provide useless comments. Obvious duplicates removed, as well as authors that are no longer or were never in the team, and a couple of typos. TODO: trim the list of includes to bare minimum, the list is redundant and mostly copy-paste stuff. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/compressed.c | 4 ++-- sound/soc/sof/control.c | 6 +++--- sound/soc/sof/core.c | 4 ++-- sound/soc/sof/debug.c | 7 +++---- sound/soc/sof/hw-spi.c | 19 ++++++++----------- sound/soc/sof/intel/apl.c | 14 ++++++-------- sound/soc/sof/intel/bdw.c | 14 ++++++-------- sound/soc/sof/intel/byt.c | 14 +++++++------- sound/soc/sof/intel/cnl.c | 14 ++++++-------- sound/soc/sof/intel/hda-bus.c | 4 ++-- sound/soc/sof/intel/hda-codec.c | 20 +++++++++----------- sound/soc/sof/intel/hda-ctrl.c | 16 +++++++--------- sound/soc/sof/intel/hda-dsp.c | 14 ++++++-------- sound/soc/sof/intel/hda-ipc.c | 12 +++++------- sound/soc/sof/intel/hda-loader-skl.c | 15 +++++++-------- sound/soc/sof/intel/hda-loader.c | 14 ++++++-------- sound/soc/sof/intel/hda-pcm.c | 14 ++++++-------- sound/soc/sof/intel/hda-stream.c | 14 ++++++-------- sound/soc/sof/intel/hda-trace.c | 14 ++++++-------- sound/soc/sof/intel/hda.c | 16 +++++++--------- sound/soc/sof/intel/hsw.c | 14 ++++++-------- sound/soc/sof/intel/skl.c | 14 ++++++-------- sound/soc/sof/ipc.c | 26 +++++++++++++------------- sound/soc/sof/loader.c | 8 ++++---- sound/soc/sof/nocodec.c | 6 +----- sound/soc/sof/ops.c | 8 ++++---- sound/soc/sof/ops.h | 4 ++-- sound/soc/sof/pcm.c | 6 +++--- sound/soc/sof/pm.c | 4 ++-- sound/soc/sof/sof-acpi-dev.c | 13 +++++++------ sound/soc/sof/sof-pci-dev.c | 7 +++---- sound/soc/sof/sof-priv.h | 14 +++++++------- sound/soc/sof/sof-spi-dev.c | 10 +++++----- sound/soc/sof/topology.c | 12 ++++++------ sound/soc/sof/trace.c | 15 +++++++-------- sound/soc/sof/virtio-be.c | 11 +++++------ sound/soc/sof/virtio-fe.c | 14 +++++--------- sound/soc/sof/xtensa/core.c | 2 +- 38 files changed, 197 insertions(+), 240 deletions(-) diff --git a/sound/soc/sof/compressed.c b/sound/soc/sof/compressed.c index 7cc35dda0979cc..36e1e5c07a0658 100644 --- a/sound/soc/sof/compressed.c +++ b/sound/soc/sof/compressed.c @@ -8,15 +8,15 @@ // Author: Liam Girdwood // -#include #include #include #include +#include #include #include #include -#include #include +#include #include "sof-priv.h" #define DRV_NAME "sof-audio" diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 9328c078f4bd42..18f14f1f5d7cbb 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -10,13 +10,13 @@ /* Mixer Controls */ -#include #include #include #include -#include -#include +#include #include +#include +#include #include "sof-priv.h" static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 8161fd2dbad947..ff809ef1fee782 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -8,11 +8,11 @@ // Author: Liam Girdwood // -#include +#include #include #include +#include #include -#include #include #include #include diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index fa25be01a09657..2f3ffd7adce34f 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -6,20 +6,19 @@ // Copyright(c) 2018 Intel Corporation. All rights reserved. // // Author: Liam Girdwood -// Yan Wang // // Generic debug routines used to export DSP MMIO and memories to userspace // for firmware debugging. // +#include #include -#include -#include #include +#include #include #include #include -#include +#include #include #include "sof-priv.h" #include "ops.h" diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index 75066bd79c4825..e4bcdb9ed51880 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -12,24 +12,21 @@ * Hardware interface for audio DSPs via SPI */ -#include -#include -#include #include -#include -#include #include -#include -#include #include #include -#include +#include +#include +#include +#include +#include +#include #include - -#include +#include +#include #include #include - #include "sof-priv.h" #include "ops.h" diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 19e98726060548..c773ab6f5225ae 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -7,7 +7,6 @@ // // Authors: Liam Girdwood // Ranjani Sridharan -// Jeeja KP // Rander Wang // Keyon Jie // @@ -17,19 +16,18 @@ */ #include -#include -#include #include -#include -#include #include +#include #include +#include +#include #include +#include +#include #include -#include #include -#include - +#include #include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index ff20528951a5da..9501f3309e4652 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -9,24 +9,22 @@ // /* - * Hardwre interface for audio DSP on Haswell and Broadwell + * Hardware interface for audio DSP on Broadwell */ #include -#include -#include #include +#include +#include +#include #include #include -#include #include -#include - +#include #include #include -#include #include - +#include #include "../sof-priv.h" #include "../ops.h" #include "shim.h" diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 67d7ba513bdc85..2ad850c698389f 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -13,18 +13,18 @@ */ #include -#include -#include #include -#include -#include #include #include -#include +#include +#include +#include +#include +#include +#include #include -#include #include - +#include #include "../sof-priv.h" #include "../ops.h" #include "shim.h" diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index e6f53afb1638c7..94701eff9c0ce2 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -7,7 +7,6 @@ // // Authors: Liam Girdwood // Ranjani Sridharan -// Jeeja KP // Rander Wang // Keyon Jie // @@ -17,19 +16,18 @@ */ #include -#include -#include #include -#include -#include #include #include +#include +#include +#include +#include #include +#include #include -#include #include -#include - +#include #include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index f515144b0a6bf5..89e40e9ed1f777 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -5,8 +5,8 @@ * * Copyright(c) 2018 Intel Corporation. All rights reserved. * - * Authors: Jeeja KP - * Keyon Jie + * Authors: Keyon Jie + * */ #include diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 9040293c38f018..67e3d1ca24dcd2 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -5,31 +5,29 @@ // // Copyright(c) 2018 Intel Corporation. All rights reserved. // -// Authors: Jeeja KP -// Rakesh Ughreja -// Keyon Jie +// Authors: Keyon Jie // #include -#include -#include #include +#include #include #include #include -#include -#include +#include #include +#include +#include #include #include -#include +#include +#include "../sof-priv.h" +#include "../ops.h" +#include "hda.h" #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) #include "../../codecs/hdac_hda.h" #endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ -#include "../sof-priv.h" -#include "../ops.h" -#include "hda.h" #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) #define IDISP_VID_INTEL 0x80860000 diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 1f6cd07f8c756a..60fe369f7da5e4 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -7,7 +7,6 @@ // // Authors: Liam Girdwood // Ranjani Sridharan -// Jeeja KP // Rander Wang // Keyon Jie // @@ -17,20 +16,19 @@ */ #include -#include -#include #include -#include -#include #include #include +#include +#include +#include +#include #include +#include #include -#include -#include -#include #include - +#include +#include #include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 413e76a46b300b..fc11362cb26083 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -7,7 +7,6 @@ // // Authors: Liam Girdwood // Ranjani Sridharan -// Jeeja KP // Rander Wang // Keyon Jie // @@ -17,21 +16,20 @@ */ #include -#include -#include #include -#include -#include #include #include +#include +#include +#include +#include #include +#include #include #include #include -#include #include -#include - +#include #include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index d17723ba243e02..94d1d7807eabef 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -7,7 +7,6 @@ // // Authors: Liam Girdwood // Ranjani Sridharan -// Jeeja KP // Rander Wang // Keyon Jie // @@ -17,19 +16,18 @@ */ #include -#include -#include #include +#include +#include #include #include -#include #include +#include #include +#include #include -#include #include -#include - +#include #include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 40e2b776e63e19..8dfa681dc9101e 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -9,21 +9,20 @@ // Zhu Yingjiang // -#include #include -#include -#include #include -#include -#include #include #include +#include +#include +#include +#include +#include #include +#include #include -#include #include -#include - +#include #include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 38460376e53b97..2cb6a5909313fd 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -7,7 +7,6 @@ // // Authors: Liam Girdwood // Ranjani Sridharan -// Jeeja KP // Rander Wang // Keyon Jie // @@ -17,19 +16,18 @@ */ #include -#include -#include #include -#include -#include #include #include +#include +#include +#include +#include #include +#include #include -#include #include -#include - +#include #include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 99d2586ddcc933..649f3af37aab04 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -7,7 +7,6 @@ // // Authors: Liam Girdwood // Ranjani Sridharan -// Jeeja KP // Rander Wang // Keyon Jie // @@ -17,20 +16,19 @@ */ #include -#include -#include #include -#include -#include #include #include +#include +#include +#include +#include #include +#include #include #include -#include #include -#include - +#include #include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 5d530305eda60f..86d079e1d9ba00 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -7,7 +7,6 @@ // // Authors: Liam Girdwood // Ranjani Sridharan -// Jeeja KP // Rander Wang // Keyon Jie // @@ -17,20 +16,19 @@ */ #include -#include -#include #include -#include -#include #include #include +#include +#include +#include +#include #include +#include #include #include -#include #include -#include - +#include #include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c index ca539589ebe306..809d0420a370e0 100644 --- a/sound/soc/sof/intel/hda-trace.c +++ b/sound/soc/sof/intel/hda-trace.c @@ -7,7 +7,6 @@ // // Authors: Liam Girdwood // Ranjani Sridharan -// Jeeja KP // Rander Wang // Keyon Jie // @@ -17,19 +16,18 @@ */ #include -#include -#include #include -#include -#include #include #include +#include +#include +#include +#include #include +#include #include -#include #include -#include - +#include #include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index ee8b9a0c9a74be..09965906e6f6c6 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -7,7 +7,6 @@ // // Authors: Liam Girdwood // Ranjani Sridharan -// Jeeja KP // Rander Wang // Keyon Jie // @@ -17,22 +16,21 @@ */ #include -#include -#include #include -#include -#include #include #include +#include +#include +#include +#include #include +#include #include -#include -#include -#include #include #include +#include +#include #include - #include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index b7e475ab99abaf..e3b499f861b51b 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -9,24 +9,22 @@ // /* - * Hardwre interface for audio DSP on Haswell + * Hardware interface for audio DSP on Haswell */ #include -#include -#include #include +#include +#include +#include #include #include -#include #include -#include - +#include #include #include - -#include #include +#include #include "../sof-priv.h" #include "../ops.h" #include "shim.h" diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index f9c33b23c9abcb..8a58b5d319cd6b 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -7,7 +7,6 @@ // // Authors: Liam Girdwood // Ranjani Sridharan -// Jeeja KP // Rander Wang // Keyon Jie // @@ -17,19 +16,18 @@ */ #include -#include -#include #include -#include -#include #include #include +#include +#include +#include #include +#include +#include #include -#include #include -#include - +#include #include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 02ca677ad22ed2..4b207cb8a0803e 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -11,23 +11,23 @@ // by platform driver code. // -#include -#include -#include +#include +#include #include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include #include -#include -#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include #include #include #include "sof-priv.h" diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 770a0eb2ac97a0..a15fd96570f628 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -11,14 +11,14 @@ // #include -#include -#include #include +#include +#include +#include #include #include -#include #include -#include +#include #include #include #include "sof-priv.h" diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index d3ea428ab8e262..85772a1b6c2692 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -8,17 +8,13 @@ // Author: Liam Girdwood // +#include #include #include #include -#include -#include -#include -#include #include #include #include -#include #include #include "sof-priv.h" diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index 37b114356d312b..cbcc4d1271502b 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -8,12 +8,12 @@ // Author: Liam Girdwood // -#include -#include -#include +#include #include +#include +#include #include -#include +#include #include "ops.h" #include "sof-priv.h" diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 708363a111d01f..a0a6f380acb3a0 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -11,10 +11,10 @@ #ifndef __SOUND_SOC_SOF_IO_H #define __SOUND_SOC_SOF_IO_H +#include +#include #include #include -#include -#include #include #include "sof-priv.h" diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 66887d9a088a44..c3c388cdc42f11 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -10,11 +10,11 @@ // PCM Layer, interface between ALSA and IPC. // -#include -#include -#include #include +#include +#include #include +#include #include #include #include diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 403c08f1785e74..4c0e009dd711e1 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -8,11 +8,11 @@ // Author: Liam Girdwood // +#include #include -#include #include +#include #include -#include #include #include #include diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 4430460a7c0150..28a7e1ff6cc924 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -8,19 +8,20 @@ // Author: Liam Girdwood // +#include +#include #include #include -#include #include -#include +#include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include + #include "sof-priv.h" #include "ops.h" diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index cdf10a9161783c..3eafb60c66c5da 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -8,17 +8,16 @@ // Author: Liam Girdwood // +#include +#include #include #include -#include #include -#include +#include #include #include #include #include -#include -#include #include "sof-priv.h" #include "ops.h" diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index cd2af805522ed4..71cfe8723397dd 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -11,14 +11,16 @@ #ifndef __SOUND_SOC_SOF_PRIV_H #define __SOUND_SOC_SOF_PRIV_H -#include -#include -#include #include -#include #include +#include +#include +#include +#include +#include #include #include +#include #include #include #include @@ -27,11 +29,9 @@ #include #include #include +#include #include #include -#include -#include -#include /* debug flags */ #define SOF_DBG_REGS BIT(1) diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index a09e0f8e57e51e..5f98820eeeafb1 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -8,16 +8,16 @@ // Author: Liam Girdwood // +#include #include +#include +#include #include -#include #include -#include +#include +#include #include #include -#include -#include -#include #include "sof-priv.h" #include "hw-spi.h" #include "ops.h" diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 87719ffd949f07..bdda1f4c567622 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -9,19 +9,19 @@ // #include -#include -#include #include +#include +#include +#include #include #include -#include #include -#include +#include #include -#include #include -#include +#include #include +#include #include #include "sof-priv.h" diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 0769f44db2a803..19f97a0ee381b6 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -6,21 +6,20 @@ // Copyright(c) 2018 Intel Corporation. All rights reserved. // // Author: Liam Girdwood -// Yan Wang // +#include #include -#include -#include -#include -#include #include +#include +#include +#include #include #include -#include #include -#include -#include +#include +#include +#include #include "sof-priv.h" #include "ops.h" diff --git a/sound/soc/sof/virtio-be.c b/sound/soc/sof/virtio-be.c index 4c07caeba41b0c..03480b34effdfe 100644 --- a/sound/soc/sof/virtio-be.c +++ b/sound/soc/sof/virtio-be.c @@ -5,20 +5,19 @@ * * Copyright(c) 2017 Intel Corporation. All rights reserved. * - * Author: Luo Xionghu - * Liam Girdwood + * Author: Liam Girdwood * */ #include -#include -#include #include +#include +#include +#include #include #include -#include #include -#include +#include #include #include #include "sof-priv.h" diff --git a/sound/soc/sof/virtio-fe.c b/sound/soc/sof/virtio-fe.c index 1019e65876b923..1f98d39f86035c 100644 --- a/sound/soc/sof/virtio-fe.c +++ b/sound/soc/sof/virtio-fe.c @@ -5,8 +5,7 @@ * * Copyright(c) 2017 Intel Corporation. All rights reserved. * - * Author: Luo Xionghu - * Liam Girdwood + * Author: Liam Girdwood */ /* @@ -26,21 +25,18 @@ */ #include -#include -#include #include -#include -#include #include #include -#include +#include +#include +#include +#include #include #include #include - #include "sof-priv.h" #include "ops.h" -#include "intel.h" /* * IPC Firmware ready. diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c index 330146fe70f3e3..dc90f31e7ca3cf 100644 --- a/sound/soc/sof/xtensa/core.c +++ b/sound/soc/sof/xtensa/core.c @@ -8,9 +8,9 @@ * Author: Pan Xiuli */ +#include #include #include -#include #include #include #include From 11195aa91832bd7f50d96bf9c702cdf18628d83f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 29 Nov 2018 10:36:03 -0600 Subject: [PATCH 0305/1995] ASoC: SOF: compressed: reorder missed includes C comes before P... Suggested-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/compressed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/compressed.c b/sound/soc/sof/compressed.c index 36e1e5c07a0658..3de2fab3075088 100644 --- a/sound/soc/sof/compressed.c +++ b/sound/soc/sof/compressed.c @@ -12,10 +12,10 @@ #include #include #include +#include #include #include #include -#include #include #include "sof-priv.h" From afc16429a9dbe32296cad281c5597553993ad27a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 28 Nov 2018 20:26:53 -0600 Subject: [PATCH 0306/1995] ASoC: SOF: control: fix error handling and error messages Make sure we never return without decrementing reference count on error. Fix typos in error messages, make sure they match the function name (too many copy/paste errors) Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/control.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 18f14f1f5d7cbb..9ab8305f4ca7c1 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -263,7 +263,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err(sdev->dev, "error: volume get failed to idle %d\n", + dev_err(sdev->dev, "error: bytes put failed to idle %d\n", err); return ret; } @@ -288,7 +288,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err(sdev->dev, "error: bytes put failed to resume %d\n", + dev_err(sdev->dev, "error: bytes_ext put failed to resume %d\n", ret); return ret; } @@ -297,9 +297,10 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, * the length (as bytes) is needed to know the correct copy * length of data from tlvd->tlv. */ - if (copy_from_user(&header, tlvd, sizeof(const struct snd_ctl_tlv))) - return -EFAULT; - + if (copy_from_user(&header, tlvd, sizeof(const struct snd_ctl_tlv))) { + ret = -EFAULT; + goto out; + } /* The maximum length that can be copied is limited by IPC max * length and topology defined length for ext bytes control. */ @@ -316,13 +317,15 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, /* Check that header id matches the command */ if (header.numid != scontrol->cmd) { - dev_err(sdev->dev, "error: incorred numid %d\n", header.numid); + dev_err(sdev->dev, "error: incorrect numid %d\n", header.numid); ret = -EINVAL; goto out; } - if (copy_from_user(cdata->data->data, tlvd->tlv, header.length)) - return -EFAULT; + if (copy_from_user(cdata->data->data, tlvd->tlv, header.length)) { + ret = -EFAULT; + goto out; + } /* set the ABI header values */ cdata->data->magic = SOF_ABI_MAGIC; @@ -336,7 +339,8 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err(sdev->dev, "error: failed to idle %d\n", err); + dev_err(sdev->dev, "error: bytes_ext put failed to idle %d\n", + err); return ret; } @@ -356,11 +360,12 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, int max_length = SOF_IPC_MSG_MAX_SIZE - sizeof(const struct sof_ipc_ctrl_data) - sizeof(const struct sof_abi_hdr); + int err; int ret; ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err(sdev->dev, "error: bytes get failed to resume %d\n", + dev_err(sdev->dev, "error: bytes_ext get failed to resume %d\n", ret); return ret; } @@ -394,14 +399,18 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, header.numid = scontrol->cmd; header.length = size; - if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) - return -EFAULT; - + if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) { + ret = -EFAULT; + goto out; + } if (copy_to_user(tlvd->tlv, cdata->data->data, size)) - return -EFAULT; + ret = -EFAULT; out: pm_runtime_mark_last_busy(sdev->dev); - pm_runtime_put_autosuspend(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err(sdev->dev, "error: bytes_ext get failed to idle %d\n", + err); return ret; } From da4b2919a969ef031afe7cc0ae92fc73d144e848 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 28 Nov 2018 20:42:00 -0600 Subject: [PATCH 0307/1995] ASoC: SOF: ipc: fix typo s/directio/direction -> needs to be applied to firmware as well Signed-off-by: Pierre-Louis Bossart --- include/sound/sof/stream.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/sof/stream.h b/include/sound/sof/stream.h index 31dd8a56de9ddc..b95797a18c8b75 100644 --- a/include/sound/sof/stream.h +++ b/include/sound/sof/stream.h @@ -69,7 +69,7 @@ struct sof_ipc_host_buffer { struct sof_ipc_stream_params { struct sof_ipc_host_buffer buffer; - uint32_t direction; /**< enum sof_ipc_stream_directio */ + uint32_t direction; /**< enum sof_ipc_stream_direction */ uint32_t frame_fmt; /**< enum sof_ipc_frame */ uint32_t buffer_fmt; /**< enum sof_ipc_buffer_format */ uint32_t rate; From 106d00189178f209bf3123056957f1a182d3b481 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 28 Nov 2018 21:53:47 -0600 Subject: [PATCH 0308/1995] ASoC: SOF: typos and comments removed no functional change Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/bdw.c | 2 +- sound/soc/sof/intel/hda-loader.c | 1 - sound/soc/sof/intel/hsw.c | 2 +- sound/soc/sof/sof-acpi-dev.c | 4 ---- 4 files changed, 2 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 9501f3309e4652..87f369f0786159 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -158,7 +158,7 @@ static u64 bdw_read64(struct snd_sof_dev *sdev, void __iomem *addr) static int bdw_run(struct snd_sof_dev *sdev) { - /* set oportunistic mode on engine 0,1 for all channels */ + /* set opportunistic mode on engine 0,1 for all channels */ snd_sof_dsp_update_bits(sdev, BDW_DSP_BAR, SHIM_HMDC, SHIM_HMDC_HDDA_E0_ALLCH | SHIM_HMDC_HDDA_E1_ALLCH, 0); diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 2cb6a5909313fd..568191ec9fcb60 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -179,7 +179,6 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, err: hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); - //sdev->dsp_ops.cleanup(sdev->dev, &sdev->dmab, tag); hda_dsp_core_reset_power_down(sdev, HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1)); return ret; diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index e3b499f861b51b..34b65fbffcde84 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -158,7 +158,7 @@ static u64 hsw_read64(struct snd_sof_dev *sdev, void __iomem *addr) static int hsw_run(struct snd_sof_dev *sdev) { - /* set oportunistic mode on engine 0,1 for all channels */ + /* set opportunistic mode on engine 0,1 for all channels */ snd_sof_dsp_update_bits(sdev, HSW_DSP_BAR, SHIM_HMDC, SHIM_HMDC_HDDA_E0_ALLCH | SHIM_HMDC_HDDA_E1_ALLCH, 0); diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 28a7e1ff6cc924..8c3fe4ead8c5fc 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -206,10 +206,6 @@ static int sof_acpi_probe(struct platform_device *pdev) mach->pdata = ops; sof_pdata->machine = mach; - /* - * FIXME, this can't work for baytrail cr: - * sof_pdata->desc = (struct sof_dev_desc*) id->driver_data; - */ sof_pdata->desc = desc; priv->sof_pdata = sof_pdata; sof_pdata->dev = &pdev->dev; From a11707bf5f3d3bd46c104005d2d44dc65edda814 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 29 Nov 2018 09:50:35 -0800 Subject: [PATCH 0309/1995] ASoC: SOF: do not delete dapm routes in free_topology() dapm routes are deleted when widgets that are associated with the route are freed. So no need to explicitly delete them in the SOF driver. Just freeing SOF sroute and its associated data is good enough. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/topology.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index bdda1f4c567622..7780a325019c30 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2639,9 +2639,6 @@ void snd_sof_free_topology(struct snd_sof_dev *sdev) /* remove routes */ list_for_each_entry_safe(sroute, temp, &sdev->route_list, list) { - /* delete dapm route */ - snd_soc_dapm_del_routes(dapm, &sroute->route, 1); - sof_route_remove(&sroute->route); /* free sroute and its private data */ From 2a9334648c29f581b2e353a6cd1fac486a09153b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 27 Nov 2018 11:30:15 -0800 Subject: [PATCH 0310/1995] ASoC: SOF: harden the FW boot sequence for SKL+ It is recommended to attempt FW boot more than once to harden the FW boot sequence for SKL+ platforms. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-loader.c | 51 ++++++++++++++++---------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 568191ec9fcb60..5dd9412626cfef 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -32,6 +32,8 @@ #include "../ops.h" #include "hda.h" +#define HDA_FW_BOOT_ATTEMPTS 3 + static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, unsigned int size, struct snd_dma_buffer *dmab, int direction) @@ -312,55 +314,54 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) { struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev); struct firmware stripped_firmware; - int ret, tag; + int ret, tag, i; stripped_firmware.data = plat_data->fw->data; stripped_firmware.size = plat_data->fw->size; - tag = cl_dsp_init(sdev, stripped_firmware.data, - stripped_firmware.size); + /* init for booting wait */ + init_waitqueue_head(&sdev->boot_wait); + sdev->boot_complete = false; - /* retry enabling core and ROM load. seemed to help */ - if (tag < 0) { + /* try attempting fw boot a few times before giving up */ + for (i = 0; i < HDA_FW_BOOT_ATTEMPTS; i++) { tag = cl_dsp_init(sdev, stripped_firmware.data, stripped_firmware.size); + if (tag <= 0) { dev_err(sdev->dev, "Error code=0x%x: FW status=0x%x\n", snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_ROM_ERROR), snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_ROM_STATUS)); - dev_err(sdev->dev, "Core En/ROM load fail:%d\n", - tag); + dev_err(sdev->dev, "iteration %d of Core En/ROM load fail:%d\n", + i, tag); ret = tag; - goto irq_err; + continue; } - } - - /* init for booting wait */ - init_waitqueue_head(&sdev->boot_wait); - sdev->boot_complete = false; - /* at this point DSP ROM has been initialized and should be ready for - * code loading and firmware boot - */ - ret = cl_copy_fw(sdev, tag); - if (ret < 0) { - dev_err(sdev->dev, "error: load fw failed err: %d\n", ret); - goto irq_err; - } + /* at this point DSP ROM has been initialized and + * should be ready for code loading and firmware boot + */ + ret = cl_copy_fw(sdev, tag); + if (ret < 0) { + dev_err(sdev->dev, "error: iteration %d of load fw failed err: %d\n", + i, ret); + continue; + } - dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); - return ret; + dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); + return ret; + } -irq_err: hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); /* disable DSP */ snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, SOF_HDA_PPCTL_GPROCEN, 0); - dev_err(sdev->dev, "error: load fw failed err: %d\n", ret); + dev_err(sdev->dev, "error: load fw failed after %d attempts with err: %d\n", + HDA_FW_BOOT_ATTEMPTS, ret); return ret; } From 7d469022ec191098851e1a1a050d1363c80c03dd Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 30 Nov 2018 13:22:53 +0800 Subject: [PATCH 0311/1995] ASoC: SOF: fix compile warning Delete unused variable Signed-off-by: Rander Wang --- sound/soc/sof/topology.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 7780a325019c30..96f7279c6169dc 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2629,8 +2629,6 @@ EXPORT_SYMBOL(snd_sof_load_topology); void snd_sof_free_topology(struct snd_sof_dev *sdev) { - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(sdev->component); struct snd_sof_route *sroute, *temp; int ret; @@ -2638,7 +2636,6 @@ void snd_sof_free_topology(struct snd_sof_dev *sdev) /* remove routes */ list_for_each_entry_safe(sroute, temp, &sdev->route_list, list) { - sof_route_remove(&sroute->route); /* free sroute and its private data */ From f4639276641d31f7b27a7de6156b04c364f8a8e9 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 30 Nov 2018 15:47:46 +0800 Subject: [PATCH 0312/1995] ASoC: SOF: IPC: correct an config item naming for debug xrun stop The kernel config item name should be CONFIG_SND_SOC_SOF_DEBUG_XRUN_STOP, here correct it. Signed-off-by: Keyon Jie --- sound/soc/sof/ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 4b207cb8a0803e..fff583bbe81418 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -577,7 +577,7 @@ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) dev_dbg(sdev->dev, "posn XRUN: host %llx comp %d size %d\n", posn.host_posn, posn.xrun_comp_id, posn.xrun_size); -#if defined(CONFIG_SOC_SOF_DEBUG_XRUN_STOP) +#if defined(CONFIG_SND_SOC_SOF_DEBUG_XRUN_STOP) /* stop PCM on XRUN - used for pipeline debug */ memcpy(&spcm->stream[direction].posn, &posn, sizeof(posn)); snd_pcm_stop_xrun(spcm->stream[direction].substream); From 1f5974afb4028fb7e3dc97139d87f7f790c264a7 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Mon, 26 Nov 2018 16:43:18 +0200 Subject: [PATCH 0313/1995] ASoC: SOF: Topology: Fix EQ feature by properly utilizing new user ABI This patch contains a number of updates. First, the EQ header in uapi is updated similarly as in firmware. The macros and structs were conflicting and prevented firmware EQs to work correctly. The topology.c sof_control_load_bytes() function is updated to check the ABI fields instead of creating them. The user space tools need to insert a valid ABI header into configuration data. The check for user data size is improved by adding DSP IPC max size check. The control.c ext bytes put/get code is similarly updated to retrieve/return the ABI header from user space. The checks are improved to cover size exceed and mismatch. The changed error messages help to know the limits for user data size without need to deep dive into source code. Signed-off-by: Seppo Ingalsuo --- include/uapi/sound/sof/eq.h | 22 ++++++---- sound/soc/sof/control.c | 81 +++++++++++++++++++++---------------- sound/soc/sof/topology.c | 33 +++++++++++---- 3 files changed, 86 insertions(+), 50 deletions(-) diff --git a/include/uapi/sound/sof/eq.h b/include/uapi/sound/sof/eq.h index 71a159502d069d..cf7ad9a01d4fc9 100644 --- a/include/uapi/sound/sof/eq.h +++ b/include/uapi/sound/sof/eq.h @@ -71,10 +71,12 @@ struct sof_eq_fir_coef_data { int16_t coef[]; /* FIR coefficients */ } __packed; -/* In the struct above there's two words (length, shift) before the actual - * FIR coefficients. This information is used in parsing of the config blob. +/* In the struct above there's two 16 bit words (length, shift) and four + * reserved 32 bit words before the actual FIR coefficients. This information + * is used in parsing of the configuration blob. */ -#define SOF_EQ_FIR_COEF_NHEADER 2 +#define SOF_EQ_FIR_COEF_NHEADER \ + (sizeof(const struct sof_eq_fir_coef_data) / sizeof(int16_t)) /* IIR EQ type */ @@ -155,10 +157,16 @@ struct sof_eq_iir_biquad_df2t { */ #define SOF_EQ_IIR_DF2T_BIQUADS_MAX 11 -/* The number of int32_t words in sof_eq_iir_header_df2t */ -#define SOF_EQ_IIR_NHEADER_DF2T 2 +/* The number of int32_t words in sof_eq_iir_header_df2t: + * num_sections, num_sections_in_series, reserved[4] + */ +#define SOF_EQ_IIR_NHEADER_DF2T \ + (sizeof(const struct sof_eq_iir_header_df2t) / sizeof(int32_t)) -/* The number of int32_t words in sof_eq_iir_biquad_df2t */ -#define SOF_EQ_IIR_NBIQUAD_DF2T 7 +/* The number of int32_t words in sof_eq_iir_biquad_df2t: + * a2, a1, b2, b1, b0, output_shift, output_gain + */ +#define SOF_EQ_IIR_NBIQUAD_DF2T \ + (sizeof(const struct sof_eq_iir_biquad_df2t) / sizeof(int32_t)) #endif diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 9ab8305f4ca7c1..4362ea2d1219e6 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -282,9 +282,8 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, (struct snd_ctl_tlv __user *)binary_data; int ret; int err; - int max_length = SOF_IPC_MSG_MAX_SIZE - - sizeof(const struct sof_ipc_ctrl_data) - - sizeof(const struct sof_abi_hdr); + int max_size = SOF_IPC_MSG_MAX_SIZE - + sizeof(const struct sof_ipc_ctrl_data); ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { @@ -304,13 +303,10 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, /* The maximum length that can be copied is limited by IPC max * length and topology defined length for ext bytes control. */ - if (max_length > be->max) - max_length = be->max; - - dev_dbg(sdev->dev, "size of bytes put data is %d, max is %d\n", - header.length, max_length); - if (header.length > max_length) { - dev_err(sdev->dev, "error: size is too large\n"); + max_size = (be->max < max_size) ? be->max : max_size; + if (header.length > max_size) { + dev_err(sdev->dev, "error: Bytes data size %d exceeds max %d.\n", + header.length, max_size); ret = -EINVAL; goto out; } @@ -322,14 +318,30 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, goto out; } - if (copy_from_user(cdata->data->data, tlvd->tlv, header.length)) { + if (copy_from_user(cdata->data, tlvd->tlv, header.length)) { ret = -EFAULT; goto out; } - /* set the ABI header values */ - cdata->data->magic = SOF_ABI_MAGIC; - cdata->data->abi = SOF_ABI_VERSION; + if (cdata->data->magic != SOF_ABI_MAGIC) { + dev_err(sdev->dev, "error: Wrong ABI magic 0x%08x.\n", + cdata->data->magic); + ret = -EINVAL; + goto out; + } + + if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { + dev_err(sdev->dev, "error: Incompatible ABI version 0x%08x.\n", + cdata->data->abi); + ret = -EINVAL; + goto out; + } + + if (cdata->data->size + sizeof(const struct sof_abi_hdr) > max_size) { + dev_err(sdev->dev, "error: Mismatch in ABI data size (truncated?).\n"); + ret = -EINVAL; + goto out; + } /* notify DSP of mixer updates */ snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_DATA, @@ -357,9 +369,9 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, struct snd_ctl_tlv header; struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data; - int max_length = SOF_IPC_MSG_MAX_SIZE - - sizeof(const struct sof_ipc_ctrl_data) - - sizeof(const struct sof_abi_hdr); + int max_size = SOF_IPC_MSG_MAX_SIZE - + sizeof(const struct sof_ipc_ctrl_data); + int data_size; int err; int ret; @@ -370,23 +382,10 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, return ret; } - /* Decrement size to fit the ext bytes header and get the the - * upper limit from ext bytes control size from topology and - * SOF IPC max. size limit. + /* Decrement the limit by ext bytes header size to ensure + * the user space buffer is not exceeded. */ size -= sizeof(const struct snd_ctl_tlv); - if (max_length > be->max) - max_length = be->max; - - dev_dbg(sdev->dev, "request size minus header is %d\n", size); - dev_dbg(sdev->dev, "max size is %d\n", max_length); - - /* Prevent read of other kernel data */ - if (size > max_length) { - dev_err(sdev->dev, "error: size is too large\n"); - ret = -EINVAL; - goto out; - } /* set the ABI header values */ cdata->data->magic = SOF_ABI_MAGIC; @@ -397,14 +396,26 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, SOF_IPC_COMP_GET_DATA, SOF_CTRL_TYPE_DATA_GET, scontrol->cmd); + /* Prevent read of other kernel data or possibly corrupt response */ + data_size = cdata->data->size + sizeof(const struct sof_abi_hdr); + max_size = (size < max_size) ? size : max_size; + max_size = (be->max < max_size) ? be->max : max_size; + if (data_size > max_size) { + dev_err(sdev->dev, "error: user data size %d exceeds max size %d.\n", + data_size, max_size); + ret = -EINVAL; + goto out; + } + header.numid = scontrol->cmd; - header.length = size; + header.length = data_size; if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) { ret = -EFAULT; goto out; } - if (copy_to_user(tlvd->tlv, cdata->data->data, size)) - ret = -EFAULT; + + if (copy_to_user(tlvd->tlv, cdata->data, data_size)) + return -EFAULT; out: pm_runtime_mark_last_busy(sdev->dev); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 96f7279c6169dc..5878a8fc27da37 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -302,6 +302,8 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, struct sof_ipc_ctrl_data *cdata; struct snd_soc_tplg_bytes_control *control = (struct snd_soc_tplg_bytes_control *)hdr; + const int max_size = SOF_IPC_MSG_MAX_SIZE - + sizeof(const struct sof_ipc_ctrl_data); /* init the get/put bytes data */ scontrol->size = SOF_IPC_MSG_MAX_SIZE; @@ -316,20 +318,35 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", scontrol->comp_id, scontrol->num_channels); - if (le32_to_cpu(control->priv.size) > SOF_IPC_MSG_MAX_SIZE) { - dev_warn(sdev->dev, "bytes priv data size %d too big\n", - control->priv.size); + if (le32_to_cpu(control->priv.size) > max_size) { + dev_err(sdev->dev, "bytes priv data size %d exceeds max %d.\n", + control->priv.size, max_size); return -EINVAL; } if (le32_to_cpu(control->priv.size) > 0) { - memcpy(cdata->data->data, control->priv.data, + memcpy(cdata->data, control->priv.data, le32_to_cpu(control->priv.size)); - cdata->data->size = le32_to_cpu(control->priv.size); - cdata->data->magic = SOF_ABI_MAGIC; - cdata->data->abi = SOF_ABI_VERSION; - } + if (cdata->data->magic != SOF_ABI_MAGIC) { + dev_err(sdev->dev, "error: Wrong ABI magic 0x%08x.\n", + cdata->data->magic); + return -EINVAL; + } + if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, + cdata->data->abi)) { + dev_err(sdev->dev, + "error: Incompatible ABI version 0x%08x.\n", + cdata->data->abi); + return -EINVAL; + } + if (cdata->data->size + sizeof(const struct sof_abi_hdr) != + control->priv.size) { + dev_err(sdev->dev, + "error: Conflict in bytes vs. priv size.\n"); + return -EINVAL; + } + } return 0; } From 1ba6eed1bc2fee8d457d6374102abf0e3fe4b5cf Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 8 Nov 2018 17:10:32 -0600 Subject: [PATCH 0314/1995] ASoC: SOF: pcm: topology_free should not be done on pcm_free pcm_free is called for each BE, which results in the topology being freed multiple times. The topology_free should only be done on pcm_remove to mirror the topology_load done on pcm_probe. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pcm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index c3c388cdc42f11..3383a14fd6e3a4 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -588,7 +588,6 @@ static void sof_pcm_free(struct snd_pcm *pcm) if (spcm->pcm.capture) snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_CAPTURE].page_table); - snd_sof_free_topology(sdev); } /* fixup the BE DAI link to match any values from topology */ @@ -716,7 +715,12 @@ static int sof_pcm_probe(struct snd_soc_component *component) static void sof_pcm_remove(struct snd_soc_component *component) { + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(component); + pm_runtime_disable(component->dev); + snd_sof_free_topology(sdev); + } void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) From 81eb5c63558299d2b2ac28af6ce3dacde24f72b9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 8 Nov 2018 17:13:44 -0600 Subject: [PATCH 0315/1995] ASoC: SOF: topology: add state variable to check topology load state With the complicated error flow, we don't have a record of whether the topology was loaded or not. Having a dmesg trace would help indicate an unintended path in error handling. Add a boolean to only load the topology if it's not already loaded, and free the topology if it's loaded, and log errors as needed. Note that the topology_free should itself never result in any crashes. If it does it's a separate issue from identifying bad error handling. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-priv.h | 1 + sound/soc/sof/topology.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 71cfe8723397dd..de9fb2bdb5b941 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -357,6 +357,7 @@ struct snd_sof_dev { struct list_head dai_list; struct list_head route_list; struct snd_soc_component *component; + int tplg_loaded; /* keep track of topology load success */ /* FW configuration */ struct sof_ipc_dma_buffer_data *info_buffer; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 5878a8fc27da37..62ccf541fb713e 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2620,6 +2620,11 @@ int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file) struct snd_soc_tplg_hdr *hdr; int ret; + if (sdev->tplg_loaded) { + dev_err(sdev->dev, "topology already loaded ?\n"); + return -EINVAL; + } + dev_dbg(sdev->dev, "loading topology:%s\n", file); ret = request_firmware(&fw, file, sdev->dev); @@ -2639,6 +2644,8 @@ int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file) ret = -EINVAL; } + sdev->tplg_loaded = true; + release_firmware(fw); return ret; } @@ -2650,6 +2657,10 @@ void snd_sof_free_topology(struct snd_sof_dev *sdev) int ret; dev_dbg(sdev->dev, "free topology...\n"); + if (!sdev->tplg_loaded) { + dev_dbg(sdev->dev, "No topology loaded, nothing to free ...\n"); + return; + } /* remove routes */ list_for_each_entry_safe(sroute, temp, &sdev->route_list, list) { @@ -2665,5 +2676,7 @@ void snd_sof_free_topology(struct snd_sof_dev *sdev) if (ret < 0) dev_err(sdev->dev, "error: tplg component free failed %d\n", ret); + + sdev->tplg_loaded = false; } EXPORT_SYMBOL(snd_sof_free_topology); From 17fa22dcf3ee0b42864d372b781752d68bb6ac16 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 29 Nov 2018 11:31:41 -0600 Subject: [PATCH 0316/1995] ASoC: SOF: add FIXME comments for link DMA handling Make it clear that the current solution is not acceptable and has to be reworked Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-dai.c | 12 ++++++++++++ sound/soc/sof/topology.c | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index b0f90ce4604c46..c4aae26502c090 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -38,6 +38,11 @@ struct hda_pipe_params { * channel and the relation is fixed. To make sure FW uses the correct * link dma channel, host allocates stream register and sends the * corresponding link dma channel to FW to allocate link dma channel + * + * FIXME: this API is abused in the sense that tx_num and rx_num are + * passed as arguments, not returned. We need to find a better way to + * retrieve the stream tag allocated for the link DMA + * */ static int hda_link_dma_get_channels(struct snd_soc_dai *dai, unsigned int *tx_num, @@ -191,6 +196,13 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, return 0; } +/* + * FIXME: This API is also abused since it's used for two purposes. + * when the substream argument is NULL this function is used for cleanups + * that aren't necessarily required, and called explicitly by handling + * ASoC core structures, which is not recommended. + * This part will be reworked in follow-up patches. + */ static int hda_link_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 62ccf541fb713e..0f5e11323c48f3 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2264,6 +2264,11 @@ static int sof_link_hda_unload(struct snd_sof_dev *sdev, return -EINVAL; } + /* + * FIXME: this call to hw_free is mainly to release the link DMA ID. + * This is abusing the API and handling SOC internals is not + * recommended. This part will be reworked. + */ if (dai->driver->ops->hw_free) ret = dai->driver->ops->hw_free(NULL, dai); if (ret < 0) From 338f5e3c5d078e45a0125b333c655437bf06b438 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 29 Nov 2018 11:34:54 -0600 Subject: [PATCH 0317/1995] ASoC: SOF: loader: fix error handling It is not clear why the parsing should continue, so for now exit and return an error. This is only used by BYT/CHT/BDW anyways so the odd of new features being added are slim. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/loader.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index a15fd96570f628..bc36359e2b70f9 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -84,6 +84,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) if (ret < 0) { dev_err(sdev->dev, "error: failed to parse ext data type %d\n", ext_hdr->type); + goto out; } /* move to next header */ @@ -92,7 +93,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) sizeof(*ext_hdr)); ext_hdr = (struct sof_ipc_ext_data_hdr *)ext_data; } - +out: kfree(ext_data); return ret; } From 7bbf67f2e6978f83868e529763ec044152ce3950 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 29 Nov 2018 13:23:41 -0600 Subject: [PATCH 0318/1995] ASoC: SOF: pcm: fix error handling in pcm_new The error flow in pcm_new was completely broken, make sure the page tables are released. The pre-allocated DMA buffer is not released since it's a task the ALSA core will do for us. Added comment of the intent so that people looking for balanced memory allocations understand this is not an omission. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pcm.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 3383a14fd6e3a4..cf1a147f8e94a5 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -523,7 +523,7 @@ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) if (ret < 0) { dev_err(sdev->dev, "error: can't alloc page table for %s %d\n", caps->name, ret); - return ret; + goto free_playback_dma_buffer; } capture: @@ -547,8 +547,7 @@ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) dev_err(sdev->dev, "error: can't alloc DMA buffer size 0x%x/0x%x for %s %d\n", caps->buffer_size_min, caps->buffer_size_max, caps->name, ret); - snd_dma_free_pages(&spcm->stream[stream].page_table); - return ret; + goto free_playback_tables; } /* allocate capture page table buffer */ @@ -557,13 +556,24 @@ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) if (ret < 0) { dev_err(sdev->dev, "error: can't alloc page table for %s %d\n", caps->name, ret); - snd_dma_free_pages(&spcm->stream[stream].page_table); - return ret; + goto free_playback_tables; } /* TODO: assign channel maps from topology */ return ret; + +free_playback_tables: + if (spcm->pcm.playback) + snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].page_table); + +free_playback_dma_buffer: + /* + * no need to explicitly release preallocated memory, + * snd_pcm_lib_preallocate_free_for_all() is called by the core + */ + + return ret; } static void sof_pcm_free(struct snd_pcm *pcm) @@ -588,6 +598,10 @@ static void sof_pcm_free(struct snd_pcm *pcm) if (spcm->pcm.capture) snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_CAPTURE].page_table); + /* + * no need to explicitly release preallocated memory, + * snd_pcm_lib_preallocate_free_for_all() is called by the core + */ } /* fixup the BE DAI link to match any values from topology */ From 0d89f7a47687a260aace441416974de297ce4be0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 28 Nov 2018 14:31:12 -0600 Subject: [PATCH 0319/1995] ASoC: SOF: cleanup for upstream Add comments and remove topology code that's not currently needed. The trace will not be renamed though, it's too invasive at this point. I'll change the commit messages Signed-off-by: Pierre-Louis Bossart --- include/sound/soc.h | 2 +- sound/soc/sof/topology.c | 26 +++++--------------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index e0b77ee10ed1e3..8d6dd011bc168b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1188,7 +1188,7 @@ struct snd_soc_pcm_runtime { unsigned int pop_wait:1; /* private data - core does not touch */ - void *private; + void *private; /* FIXME: still SOF-specific, needs to less ambiguous */ }; #define for_each_rtd_codec_dai(rtd, i, dai)\ for ((i) = 0; \ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 0f5e11323c48f3..3548ef425a82dd 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1624,18 +1624,6 @@ static int sof_widget_load_effect(struct snd_soc_component *scomp, int index, return 0; } -/* - * Generic widget loader. - */ - -static int sof_widget_load(struct snd_soc_component *scomp, int index, - struct snd_soc_dapm_widget *w, - struct snd_soc_tplg_dapm_widget *tw) -{ - /* nothing todo atm */ - return 0; -} - /* external widget init - used for any driver specific init */ static int sof_widget_ready(struct snd_soc_component *scomp, int index, struct snd_soc_dapm_widget *w, @@ -2501,13 +2489,6 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, return ret; } -static int sof_route_unload(struct snd_soc_component *scomp, - struct snd_soc_dobj *dobj) -{ - /* TODO: unload routes when topology is changed */ - return 0; -} - int snd_sof_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { @@ -2580,10 +2561,13 @@ static struct snd_soc_tplg_ops sof_tplg_ops = { /* external kcontrol init - used for any driver specific init */ .dapm_route_load = sof_route_load, - .dapm_route_unload = sof_route_unload, + /* + * .dapm_route_unload is not currently used, will be needed when + * topology is changed + */ /* external widget init - used for any driver specific init */ - .widget_load = sof_widget_load, + /* .widget_load is not currently used */ .widget_ready = sof_widget_ready, .widget_unload = sof_widget_unload, From ed9435ff1033d10974cd9e4c2d8ba3876f6d207e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 30 Nov 2018 13:19:50 -0600 Subject: [PATCH 0320/1995] ASoC: SOF: topology: fix dai->dai_name dereference when dai is NULL Use dai_component.dai_name used as input for search. Fixes: 12419503fa4 ('ASoC: SOF: set link dma channel in hda config') Reported-by: kbuild test robot Cc: Julia Lawall Cc: Rander Wang Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/topology.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 3548ef425a82dd..ac397e4b46f8a9 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2111,7 +2111,8 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index, dai_component.dai_name = link->cpu_dai_name; dai = snd_soc_find_dai(&dai_component); if (!dai) { - dev_err(sdev->dev, "failed to find dai %s", dai->name); + dev_err(sdev->dev, "failed to find dai %s", + dai_component.dai_name); return -EINVAL; } @@ -2248,7 +2249,8 @@ static int sof_link_hda_unload(struct snd_sof_dev *sdev, dai_component.dai_name = link->cpu_dai_name; dai = snd_soc_find_dai(&dai_component); if (!dai) { - dev_err(sdev->dev, "failed to find dai %s", dai->name); + dev_err(sdev->dev, "failed to find dai %s", + dai_component.dai_name); return -EINVAL; } From 715e2747f6156e1bcac2c42f12e78eb99a74a5c4 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 13 Nov 2018 10:34:55 -0800 Subject: [PATCH 0321/1995] ASoC: SOF: update dai_config for DAI's based on dai type dai_config for DAI's are of variable length depending on the type of DAI. For example, DMIC's have a variable length of pdm config array that are determined while parsing DMIC tokens in topology. So this patch modifies the dai_config member of struct snd_sof_dai to account for these changes. The changes included in the patch are: 1. Modify dai_config in struct snd_sof_dai to a pointer 2. Allocate memory for dai_config based on dai type after parsing the respective tokens for the DAI type 3. Update users of dai_config to use the pointer. 4. free dai_config when the dai widget is unloaded. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pcm.c | 14 +++--- sound/soc/sof/sof-priv.h | 2 +- sound/soc/sof/topology.c | 104 +++++++++++++++++++++++++++++---------- 3 files changed, 85 insertions(+), 35 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index cf1a147f8e94a5..49b1c40ed038a7 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -657,12 +657,12 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, } /* read rate and channels from topology */ - switch (dai->dai_config.type) { + switch (dai->dai_config->type) { case SOF_DAI_INTEL_SSP: - rate->min = dai->dai_config.ssp.fsync_rate; - rate->max = dai->dai_config.ssp.fsync_rate; - channels->min = dai->dai_config.ssp.tdm_slots; - channels->max = dai->dai_config.ssp.tdm_slots; + rate->min = dai->dai_config->ssp.fsync_rate; + rate->max = dai->dai_config->ssp.fsync_rate; + channels->min = dai->dai_config->ssp.tdm_slots; + channels->max = dai->dai_config->ssp.tdm_slots; dev_dbg(sdev->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max); @@ -677,7 +677,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, dev_err(sdev->dev, "error: invalid fmt %d for DAI type %d\n", dai->comp_dai.config.frame_fmt, - dai->dai_config.type); + dai->dai_config->type); } /* TODO: add any other DMIC specific fixups */ break; @@ -686,7 +686,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, break; default: dev_err(sdev->dev, "error: invalid DAI type %d\n", - dai->dai_config.type); + dai->dai_config->type); break; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index de9fb2bdb5b941..3169839bc6bf7a 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -297,7 +297,7 @@ struct snd_sof_dai { const char *name; struct sof_ipc_comp_dai comp_dai; - struct sof_ipc_dai_config dai_config; + struct sof_ipc_dai_config *dai_config; struct list_head list; /* list in sdev dai list */ }; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index ac397e4b46f8a9..938d0c4c0b1563 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1760,6 +1760,9 @@ static int sof_widget_unload(struct snd_soc_component *scomp, case snd_soc_dapm_dai_out: dai = swidget->private; + /* free dai config */ + kfree(dai->dai_config); + /* remove and free dai object */ if (dai) { list_del(&dai->list); @@ -1867,6 +1870,27 @@ static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config, } } +/* set config for all DAI's with name matching the link name */ +static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size, + struct snd_soc_dai_link *link, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dai *dai; + + list_for_each_entry(dai, &sdev->dai_list, list) { + if (!dai->name) + continue; + + if (strcmp(link->name, dai->name) == 0) { + dai->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!dai->dai_config) + return -ENOMEM; + } + } + + return 0; +} + static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg, @@ -1916,9 +1940,17 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, config->hdr.cmd, config, size, &reply, sizeof(reply)); - if (ret < 0) + if (ret < 0) { dev_err(sdev->dev, "error: failed to set DAI config for SSP%d\n", config->dai_index); + return ret; + } + + /* set config for all DAI's with name matching the link name */ + ret = sof_set_dai_config(sdev, size, link, config); + if (ret < 0) + dev_err(sdev->dev, "error: failed to save DAI config for SSP%d\n", + config->dai_index); return ret; } @@ -1936,6 +1968,11 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, u32 size; int ret, j; + /* + * config is only used for the common params in dmic_params structure + * that does not include the PDM controller config array + * Set the common params to 0. + */ memset(&config->dmic, 0, sizeof(struct sof_ipc_dai_dmic_params)); /* get DMIC tokens */ @@ -1949,13 +1986,14 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, } /* - * allocate memory for common dai params, dmic params - * and dmic pdm controller params + * allocate memory for dmic dai config accounting for the + * variable number of active pdm controllers + * This will be the ipc payload for setting dai config */ - ipc_config = kzalloc(sizeof(*config) + - sizeof(struct sof_ipc_dai_dmic_pdm_ctrl) * - config->dmic.num_pdm_active, - GFP_KERNEL); + size = sizeof(*config) + sizeof(struct sof_ipc_dai_dmic_pdm_ctrl) * + config->dmic.num_pdm_active; + + ipc_config = kzalloc(size, GFP_KERNEL); if (!ipc_config) { dev_err(sdev->dev, "error: allocating memory for config\n"); return -ENOMEM; @@ -1969,6 +2007,10 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, * Used to track the pdm config array index currently being parsed */ sdev->private = kzalloc(sizeof(u32), GFP_KERNEL); + if (!sdev->private) { + kfree(ipc_config); + return -ENOMEM; + } /* get DMIC PDM tokens */ ret = sof_parse_tokens(scomp, &ipc_config->dmic.pdm[0], dmic_pdm_tokens, @@ -1977,12 +2019,10 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, if (ret != 0) { dev_err(sdev->dev, "error: parse dmic pdm tokens failed %d\n", le32_to_cpu(private->size)); - kfree(ipc_config); - return ret; + goto err; } /* set IPC header size */ - size = sizeof(*ipc_config); ipc_config->hdr.size = size; /* debug messages */ @@ -2020,13 +2060,19 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, ipc_config->hdr.cmd, ipc_config, size, &reply, sizeof(reply)); - if (ret < 0) + if (ret < 0) { dev_err(sdev->dev, "error: failed to set DAI config for DMIC%d\n", config->dai_index); + goto err; + } - /* update config with pdm config */ - memcpy(config, ipc_config, sizeof(*ipc_config)); + /* set config for all DAI's with name matching the link name */ + ret = sof_set_dai_config(sdev, size, link, ipc_config); + if (ret < 0) + dev_err(sdev->dev, "error: failed to save DAI config for DMIC%d\n", + config->dai_index); +err: kfree(sdev->private); kfree(ipc_config); @@ -2148,9 +2194,24 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index, if (link->dpcm_capture) { ret = sof_link_hda_process(sdev, link, config, rx_slot, SNDRV_PCM_STREAM_CAPTURE); - if (ret < 0) + if (ret < 0) { dev_err(sdev->dev, "error: failed to set DAI config for capture dai HDA%d\n", config->dai_index); + + return ret; + } + } + + /* set config for all DAI's with name matching the link name */ + ret = sof_set_dai_config(sdev, size, link, config); + if (ret < 0) { + if (link->dpcm_playback) + dev_err(sdev->dev, "error: failed to save DAI config for playback HDA%d\n", + config->dai_index); + + if (link->dpcm_capture) + dev_err(sdev->dev, "error: failed to save DAI config for capture HDA%d\n", + config->dai_index); } return ret; @@ -2165,7 +2226,6 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_private *private = &cfg->priv; struct sof_ipc_dai_config config; struct snd_soc_tplg_hw_config *hw_config; - struct snd_sof_dai *dai; int ret = 0; link->platform_name = "sof-audio"; @@ -2226,16 +2286,6 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, if (ret < 0) return ret; - /* set config for all DAI's with name matching the link name */ - list_for_each_entry(dai, &sdev->dai_list, list) { - if (!dai->name) - continue; - - if (strcmp(link->name, dai->name) == 0) - memcpy(&dai->dai_config, &config, - sizeof(struct sof_ipc_dai_config)); - } - return 0; } @@ -2291,7 +2341,7 @@ static int sof_link_unload(struct snd_soc_component *scomp, return -EINVAL; } - switch (sof_dai->dai_config.type) { + switch (sof_dai->dai_config->type) { case SOF_DAI_INTEL_SSP: case SOF_DAI_INTEL_DMIC: /* no resource needs to be released for SSP and DMIC */ @@ -2301,7 +2351,7 @@ static int sof_link_unload(struct snd_soc_component *scomp, break; default: dev_err(sdev->dev, "error: invalid DAI type %d\n", - sof_dai->dai_config.type); + sof_dai->dai_config->type); ret = -EINVAL; break; } From 9f727bec27d867021e075caec1cdc29e4273db18 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 13 Nov 2018 10:38:50 -0800 Subject: [PATCH 0322/1995] ASoC: SOF: use actual config size while restoring dai links While restoring dai links during resume, use the actual size of the config as they may vary depending on dai type. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 4c0e009dd711e1..644eecb0d737df 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -141,11 +141,11 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev) /* restore dai links */ list_for_each_entry_reverse(dai, &sdev->dai_list, list) { struct sof_ipc_reply reply; - struct sof_ipc_dai_config *config = &dai->dai_config; + struct sof_ipc_dai_config *config = dai->dai_config; ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, - sizeof(*config), + config->hdr.size, &reply, sizeof(reply)); if (ret < 0) { From de1f57acf732560b9e49f93bbdd369872468e087 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 29 Nov 2018 15:31:06 -0800 Subject: [PATCH 0323/1995] Revert "ASoC: SOF: dmic: fix size of pdm config array" This reverts commit ddf853b87b701ccf347e4245e23d3ab40e457301. Signed-off-by: Ranjani Sridharan --- include/sound/sof/dai-intel.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h index e6ebd3ebac3c2c..bd6e9b6a4401e0 100644 --- a/include/sound/sof/dai-intel.h +++ b/include/sound/sof/dai-intel.h @@ -46,12 +46,6 @@ /* bclk idle */ #define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_IDLE_HIGH BIT(5) -/* - * Max number of DMIC PDM controllers supported - * Needs to be re-visited for platforms with > 2 controllers. - */ -#define SOF_DAI_INTEL_DMIC_MAX_PDM 2 - /* SSP Configuration Request - SOF_IPC_DAI_SSP_CONFIG */ struct sof_ipc_dai_ssp_params { uint16_t reserved1; @@ -170,8 +164,8 @@ struct sof_ipc_dai_dmic_params { /* reserved for future use */ uint32_t reserved[6]; - /**< pdm controller config */ - struct sof_ipc_dai_dmic_pdm_ctrl pdm[SOF_DAI_INTEL_DMIC_MAX_PDM]; + /**< variable number of pdm controller config */ + struct sof_ipc_dai_dmic_pdm_ctrl pdm[0]; } __packed; #endif From d72b338b01375ad78530e7a2630ba371311c5dc7 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 30 Nov 2018 14:02:36 +0800 Subject: [PATCH 0324/1995] ASoC: SOF: fix a ipc issue on CNL&WHL&ICL Follow the fix on APL: ASoC: SOF: hda-ipc: fix IPC handled wrong issue When IPC interrupt arrived, we need to check HDA_DSP_REG_HIPCCTL to make sure we can tell the message initiator(new or reply from DSP), otherwise, we may treat new message as reply one by mistake, and see error message reported as "error: rx list empty but received ...". On APL, HIPCCTL is used to control both reply and new message. But on CNL, there is another register named HIPCTDR for new message. HIPCTDR is cleared in irq function, so we don't need to check its value. Signed-off-by: Keyon Jie Signed-off-by: Rander Wang --- sound/soc/sof/intel/cnl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 94701eff9c0ce2..d7291b62f378b4 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -43,7 +43,7 @@ static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; - u32 hipci, hipcida, hipctdr, hipctdd, msg = 0, msg_ext = 0; + u32 hipci, hipcctl, hipcida, hipctdr, hipctdd, msg = 0, msg_ext = 0; irqreturn_t ret = IRQ_NONE; /* here we handle IPC interrupts only */ @@ -51,9 +51,11 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) return ret; hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); + hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL); /* reply message from DSP */ - if (hipcida & CNL_DSP_REG_HIPCIDA_DONE) { + if (hipcida & CNL_DSP_REG_HIPCIDA_DONE && + hipcctl & CNL_DSP_REG_HIPCCTL_DONE) { hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR); msg_ext = hipci & CNL_DSP_REG_HIPCIDR_MSG_MASK; From da1ba2beebe19eea0f5e01ee6cfe8fee57ead7cc Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Sun, 2 Dec 2018 23:08:28 -0800 Subject: [PATCH 0325/1995] ASoC: SOF: add check to see if core is already enabled Modify hda_dsp_enable_core() to add a check to see if the requested core is already enabled. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dsp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index fc11362cb26083..7ae95644a784e6 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -212,6 +212,10 @@ int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask) { int ret; + /* return if core is already enabled */ + if (hda_dsp_core_is_enabled(sdev, core_mask)) + return 0; + /* power up */ ret = hda_dsp_core_power_up(sdev, core_mask); if (ret < 0) { From 7032cf6004d4e008d2d0289db27e8e8442a1841a Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Wed, 28 Nov 2018 14:36:22 +0800 Subject: [PATCH 0326/1995] ASoC: SOF: enable msi for sof hda audio Use MSI interrupt instead of legacy interrupt for sof hda audio. Signed-off-by: Libin Yang --- sound/soc/sof/intel/hda.c | 19 +++++++++++++------ sound/soc/sof/sof-priv.h | 1 + 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 09965906e6f6c6..160974bcd3c911 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -605,18 +605,22 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) * TODO: support interrupt mode selection with kernel parameter * support msi multiple vectors */ -// ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI); - /* todo: MSI mode doesn't work for HDMI yet, debug it later */ - ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_LEGACY); + ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI); if (ret < 0) { dev_info(sdev->dev, "use legacy interrupt mode\n"); + /* + * in IO-APIC mode, hda->irq and ipc_irq are using the same + * irq number of pci->irq + */ sdev->hda->irq = pci->irq; sdev->ipc_irq = pci->irq; + sdev->msi_enabled = 0; } else { dev_info(sdev->dev, "use msi interrupt mode\n"); sdev->hda->irq = pci_irq_vector(pci, 0); /* ipc irq number is the same of hda irq */ sdev->ipc_irq = sdev->hda->irq; + sdev->msi_enabled = 1; } dev_dbg(sdev->dev, "using HDA IRQ %d\n", sdev->hda->irq); @@ -626,7 +630,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "error: failed to register HDA IRQ %d\n", sdev->hda->irq); - goto free_streams; + goto free_irq_vector; } dev_dbg(sdev->dev, "using IPC IRQ %d\n", sdev->ipc_irq); @@ -716,7 +720,9 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) free_irq(sdev->ipc_irq, sdev); free_hda_irq: free_irq(sdev->hda->irq, bus); - pci_free_irq_vectors(pci); +free_irq_vector: + if (sdev->msi_enabled) + pci_free_irq_vectors(pci); free_streams: hda_dsp_stream_free(sdev); /* dsp_unmap: not currently used */ @@ -762,7 +768,8 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) free_irq(sdev->ipc_irq, sdev); free_irq(sdev->hda->irq, bus); - pci_free_irq_vectors(pci); + if (sdev->msi_enabled) + pci_free_irq_vectors(pci); hda_dsp_stream_free(sdev); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 3169839bc6bf7a..3f619f5f2691cb 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -379,6 +379,7 @@ struct snd_sof_dev { u32 host_offset; u32 dtrace_is_enabled; u32 dtrace_error; + u32 msi_enabled; /* PM */ u32 restore_kcontrols; /* restore kcontrols upon resume */ From e30ff18e8f84fc2548fe4041cf97b2e78036dc3d Mon Sep 17 00:00:00 2001 From: Bard liao Date: Sat, 1 Dec 2018 07:26:46 +0800 Subject: [PATCH 0327/1995] ASoC: SOF: debug: use devm_kzalloc and devm_kfree dfse is not freed when the debugfs is removed. Use devm_ functions and kernel will free it for us when device is removed. Signed-off-by: Bard liao --- sound/soc/sof/debug.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 2f3ffd7adce34f..6f61a39cbb2cd1 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -98,7 +98,7 @@ int snd_sof_debugfs_create_item(struct snd_sof_dev *sdev, if (!sdev) return -EINVAL; - dfse = kzalloc(sizeof(*dfse), GFP_KERNEL); + dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); if (!dfse) return -ENOMEM; @@ -110,7 +110,6 @@ int snd_sof_debugfs_create_item(struct snd_sof_dev *sdev, dfse, &sof_dfs_fops); if (!dfse->dfsentry) { dev_err(sdev->dev, "cannot create debugfs entry.\n"); - kfree(dfse); return -ENODEV; } From 46d135947f7f69e5e10a0d16f8ff19869e004196 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 3 Dec 2018 15:36:23 -0800 Subject: [PATCH 0328/1995] ASoC: SOF: use GENMASK and BIT macros wherever possible Replace hard coded values with GENMASK and BIT macros wherever possible. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/byt.c | 2 +- sound/soc/sof/intel/hda-loader-skl.c | 8 ++-- sound/soc/sof/intel/hda.h | 6 ++- sound/soc/sof/intel/shim.h | 70 ++++++++++++++-------------- 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 2ad850c698389f..2c54e376a139f2 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -57,7 +57,7 @@ #define BYT_PCI_BAR_SIZE 0x200000 -#define BYT_PANIC_OFFSET(x) (((x) & (0xFFFFll << 32)) >> 32) +#define BYT_PANIC_OFFSET(x) (((x) & GENMASK_ULL(47, 32)) >> 32) /* * Debug diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 8dfa681dc9101e..6ae4f60f46ea40 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -95,14 +95,16 @@ /* Buffer Descriptor List Lower Base Address */ #define HDA_CL_SD_BDLPLBA_SHIFT 7 -#define HDA_CL_SD_BDLPLBA_MASK (0x1ffffff << HDA_CL_SD_BDLPLBA_SHIFT) +#define HDA_CL_SD_BDLPLBA_MASK GENMASK(HDA_CL_SD_BDLPLBA_SHIFT + 24,\ + HDA_CL_SD_BDLPLBA_SHIFT) #define HDA_CL_SD_BDLPLBA(x) \ ((BDL_ALIGN(lower_32_bits(x)) << HDA_CL_SD_BDLPLBA_SHIFT) & \ HDA_CL_SD_BDLPLBA_MASK) /* Buffer Descriptor List Upper Base Address */ #define HDA_CL_SD_BDLPUBA_SHIFT 0 -#define HDA_CL_SD_BDLPUBA_MASK (0xffffffff << HDA_CL_SD_BDLPUBA_SHIFT) +#define HDA_CL_SD_BDLPUBA_MASK GENMASK(HDA_CL_SD_BDLPUBA_SHIFT + 31,\ + HDA_CL_SD_BDLPUBA_SHIFT) #define HDA_CL_SD_BDLPUBA(x) \ ((upper_32_bits(x) << HDA_CL_SD_BDLPUBA_SHIFT) & \ HDA_CL_SD_BDLPUBA_MASK) @@ -110,7 +112,7 @@ /* Software Position in Buffer Enable */ #define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT 0 #define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK \ - (1 << HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) + BIT(HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) #define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE(x) \ (((x) << HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & \ diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 6cf4d84a88a396..6ffc733e9f5aea 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -49,7 +49,8 @@ #define SOF_HDA_MAX_CAPS 10 #define SOF_HDA_CAP_ID_OFF 16 -#define SOF_HDA_CAP_ID_MASK (0xFFF << SOF_HDA_CAP_ID_OFF) +#define SOF_HDA_CAP_ID_MASK GENMASK(SOF_HDA_CAP_ID_OFF + 11,\ + SOF_HDA_CAP_ID_OFF) #define SOF_HDA_CAP_NEXT_MASK 0xFFFF #define SOF_HDA_GTS_CAP_ID 0x1 @@ -129,7 +130,8 @@ /* Stream Number */ #define SOF_HDA_CL_SD_CTL_STREAM_TAG_SHIFT 20 #define SOF_HDA_CL_SD_CTL_STREAM_TAG_MASK \ - (0xf << SOF_HDA_CL_SD_CTL_STREAM_TAG_SHIFT) + GENMASK(SOF_HDA_CL_SD_CTL_STREAM_TAG_SHIFT + 3,\ + SOF_HDA_CL_SD_CTL_STREAM_TAG_SHIFT) #define HDA_DSP_HDA_BAR 0 #define HDA_DSP_PP_BAR 1 diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index b6481fc65b2de7..2fdcb2d262f468 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -43,56 +43,56 @@ */ /* CSR / CS */ -#define SHIM_CSR_RST (0x1 << 1) -#define SHIM_CSR_SBCS0 (0x1 << 2) -#define SHIM_CSR_SBCS1 (0x1 << 3) +#define SHIM_CSR_RST BIT(1) +#define SHIM_CSR_SBCS0 BIT(2) +#define SHIM_CSR_SBCS1 BIT(3) #define SHIM_CSR_DCS(x) ((x) << 4) #define SHIM_CSR_DCS_MASK (0x7 << 4) -#define SHIM_CSR_STALL (0x1 << 10) -#define SHIM_CSR_S0IOCS (0x1 << 21) -#define SHIM_CSR_S1IOCS (0x1 << 23) -#define SHIM_CSR_LPCS (0x1 << 31) +#define SHIM_CSR_STALL BIT(10) +#define SHIM_CSR_S0IOCS BIT(21) +#define SHIM_CSR_S1IOCS BIT(23) +#define SHIM_CSR_LPCS BIT(31) #define SHIM_CSR_24MHZ_LPCS \ (SHIM_CSR_SBCS0 | SHIM_CSR_SBCS1 | SHIM_CSR_LPCS) #define SHIM_CSR_24MHZ_NO_LPCS (SHIM_CSR_SBCS0 | SHIM_CSR_SBCS1) -#define SHIM_BYT_CSR_RST (0x1 << 0) -#define SHIM_BYT_CSR_VECTOR_SEL (0x1 << 1) -#define SHIM_BYT_CSR_STALL (0x1 << 2) -#define SHIM_BYT_CSR_PWAITMODE (0x1 << 3) +#define SHIM_BYT_CSR_RST BIT(0) +#define SHIM_BYT_CSR_VECTOR_SEL BIT(1) +#define SHIM_BYT_CSR_STALL BIT(2) +#define SHIM_BYT_CSR_PWAITMODE BIT(3) /* ISRX / ISC */ -#define SHIM_ISRX_BUSY (0x1 << 1) -#define SHIM_ISRX_DONE (0x1 << 0) -#define SHIM_BYT_ISRX_REQUEST (0x1 << 1) +#define SHIM_ISRX_BUSY BIT(1) +#define SHIM_ISRX_DONE BIT(0) +#define SHIM_BYT_ISRX_REQUEST BIT(1) /* ISRD / ISD */ -#define SHIM_ISRD_BUSY (0x1 << 1) -#define SHIM_ISRD_DONE (0x1 << 0) +#define SHIM_ISRD_BUSY BIT(1) +#define SHIM_ISRD_DONE BIT(0) /* IMRX / IMC */ -#define SHIM_IMRX_BUSY (0x1 << 1) -#define SHIM_IMRX_DONE (0x1 << 0) -#define SHIM_BYT_IMRX_REQUEST (0x1 << 1) +#define SHIM_IMRX_BUSY BIT(1) +#define SHIM_IMRX_DONE BIT(0) +#define SHIM_BYT_IMRX_REQUEST BIT(1) /* IMRD / IMD */ -#define SHIM_IMRD_DONE (0x1 << 0) -#define SHIM_IMRD_BUSY (0x1 << 1) -#define SHIM_IMRD_SSP0 (0x1 << 16) -#define SHIM_IMRD_DMAC0 (0x1 << 21) -#define SHIM_IMRD_DMAC1 (0x1 << 22) +#define SHIM_IMRD_DONE BIT(0) +#define SHIM_IMRD_BUSY BIT(1) +#define SHIM_IMRD_SSP0 BIT(16) +#define SHIM_IMRD_DMAC0 BIT(21) +#define SHIM_IMRD_DMAC1 BIT(22) #define SHIM_IMRD_DMAC (SHIM_IMRD_DMAC0 | SHIM_IMRD_DMAC1) /* IPCX / IPCC */ -#define SHIM_IPCX_DONE (0x1 << 30) -#define SHIM_IPCX_BUSY (0x1 << 31) -#define SHIM_BYT_IPCX_DONE ((u64)0x1 << 62) -#define SHIM_BYT_IPCX_BUSY ((u64)0x1 << 63) +#define SHIM_IPCX_DONE BIT(30) +#define SHIM_IPCX_BUSY BIT(31) +#define SHIM_BYT_IPCX_DONE BIT_ULL(62) +#define SHIM_BYT_IPCX_BUSY BIT_ULL(63) /* IPCD */ -#define SHIM_IPCD_DONE (0x1 << 30) -#define SHIM_IPCD_BUSY (0x1 << 31) -#define SHIM_BYT_IPCD_DONE ((u64)0x1 << 62) -#define SHIM_BYT_IPCD_BUSY ((u64)0x1 << 63) +#define SHIM_IPCD_DONE BIT(30) +#define SHIM_IPCD_BUSY BIT(31) +#define SHIM_BYT_IPCD_DONE BIT_ULL(62) +#define SHIM_BYT_IPCD_BUSY BIT_ULL(63) /* CLKCTL */ #define SHIM_CLKCTL_SMOS(x) ((x) << 24) @@ -136,9 +136,11 @@ #define PCI_VDRTCL0_D3PGD BIT(0) #define PCI_VDRTCL0_D3SRAMPGD BIT(1) #define PCI_VDRTCL0_DSRAMPGE_SHIFT 12 -#define PCI_VDRTCL0_DSRAMPGE_MASK (0xfffff << PCI_VDRTCL0_DSRAMPGE_SHIFT) +#define PCI_VDRTCL0_DSRAMPGE_MASK GENMASK(PCI_VDRTCL0_DSRAMPGE_SHIFT + 19,\ + PCI_VDRTCL0_DSRAMPGE_SHIFT) #define PCI_VDRTCL0_ISRAMPGE_SHIFT 2 -#define PCI_VDRTCL0_ISRAMPGE_MASK (0x3ff << PCI_VDRTCL0_ISRAMPGE_SHIFT) +#define PCI_VDRTCL0_ISRAMPGE_MASK GENMASK(PCI_VDRTCL0_ISRAMPGE_SHIFT + 9,\ + PCI_VDRTCL0_ISRAMPGE_SHIFT) /* VDRTCTL2 */ #define PCI_VDRTCL2_DCLCGE BIT(1) From 9960ca2576938be16e7d8034769cf5c4506c5193 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Tue, 4 Dec 2018 01:58:25 +0800 Subject: [PATCH 0329/1995] ASoC: SOF: remove redundant else else is redundant after return in the if conduction. Signed-off-by: Bard liao --- sound/soc/sof/control.c | 4 +- sound/soc/sof/intel/byt.c | 8 +-- sound/soc/sof/ops.h | 104 +++++++++++++++++++------------------- sound/soc/sof/trace.c | 4 +- 4 files changed, 60 insertions(+), 60 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 4362ea2d1219e6..47a059be02310d 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -23,8 +23,8 @@ static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size) { if (value >= size) return volume_map[size - 1]; - else - return volume_map[value]; + + return volume_map[value]; } static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 2c54e376a139f2..f7d3479e958660 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -747,8 +747,8 @@ static int byt_probe(struct snd_sof_dev *sdev) { if (sdev->pci) return byt_pci_probe(sdev); - else - return byt_acpi_probe(sdev); + + return byt_acpi_probe(sdev); } static int byt_acpi_remove(struct snd_sof_dev *sdev) @@ -770,8 +770,8 @@ static int byt_remove(struct snd_sof_dev *sdev) { if (sdev->pci) return byt_pci_remove(sdev); - else - return byt_acpi_remove(sdev); + + return byt_acpi_remove(sdev); } #define BYT_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index a0a6f380acb3a0..e2298155f3529e 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -23,16 +23,16 @@ static inline int snd_sof_probe(struct snd_sof_dev *sdev) { if (sdev->ops->probe) return sdev->ops->probe(sdev); - else - return 0; + + return 0; } static inline int snd_sof_remove(struct snd_sof_dev *sdev) { if (sdev->ops->remove) return sdev->ops->remove(sdev); - else - return 0; + + return 0; } /* control */ @@ -40,24 +40,24 @@ static inline int snd_sof_dsp_run(struct snd_sof_dev *sdev) { if (sdev->ops->run) return sdev->ops->run(sdev); - else - return 0; + + return 0; } static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev) { if (sdev->ops->stall) return sdev->ops->stall(sdev); - else - return 0; + + return 0; } static inline int snd_sof_dsp_reset(struct snd_sof_dev *sdev) { if (sdev->ops->reset) return sdev->ops->reset(sdev); - else - return 0; + + return 0; } /* pre/post fw load */ @@ -65,16 +65,16 @@ static inline int snd_sof_dsp_pre_fw_run(struct snd_sof_dev *sdev) { if (sdev->ops->pre_fw_run) return sdev->ops->pre_fw_run(sdev); - else - return 0; + + return 0; } static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev) { if (sdev->ops->post_fw_run) return sdev->ops->post_fw_run(sdev); - else - return 0; + + return 0; } /* power management */ @@ -82,24 +82,24 @@ static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev) { if (sdev->ops->resume) return sdev->ops->resume(sdev); - else - return 0; + + return 0; } static inline int snd_sof_dsp_suspend(struct snd_sof_dev *sdev, int state) { if (sdev->ops->suspend) return sdev->ops->suspend(sdev, state); - else - return 0; + + return 0; } static inline int snd_sof_dsp_runtime_resume(struct snd_sof_dev *sdev) { if (sdev->ops->runtime_resume) return sdev->ops->runtime_resume(sdev); - else - return 0; + + return 0; } static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev, @@ -107,16 +107,16 @@ static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev, { if (sdev->ops->runtime_suspend) return sdev->ops->runtime_suspend(sdev, state); - else - return 0; + + return 0; } static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq) { if (sdev->ops->set_clk) return sdev->ops->set_clk(sdev, freq); - else - return 0; + + return 0; } /* debug */ @@ -147,8 +147,8 @@ static inline u32 snd_sof_dsp_read(struct snd_sof_dev *sdev, u32 bar, { if (sdev->ops->read) return sdev->ops->read(sdev, sdev->bar[bar] + offset); - else - return 0; + + return 0; } static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar, @@ -156,8 +156,8 @@ static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar, { if (sdev->ops->read64) return sdev->ops->read64(sdev, sdev->bar[bar] + offset); - else - return 0; + + return 0; } /* block IO */ @@ -198,8 +198,8 @@ static inline int snd_sof_dsp_send_msg(struct snd_sof_dev *sdev, { if (sdev->ops->send_msg) return sdev->ops->send_msg(sdev, msg); - else - return 0; + + return 0; } static inline int snd_sof_dsp_get_reply(struct snd_sof_dev *sdev, @@ -207,16 +207,16 @@ static inline int snd_sof_dsp_get_reply(struct snd_sof_dev *sdev, { if (sdev->ops->get_reply) return sdev->ops->get_reply(sdev, msg); - else - return 0; + + return 0; } static inline int snd_sof_dsp_is_ready(struct snd_sof_dev *sdev) { if (sdev->ops->is_ready) return sdev->ops->is_ready(sdev); - else - return 0; + + return 0; } static inline int snd_sof_dsp_cmd_done(struct snd_sof_dev *sdev, @@ -224,8 +224,8 @@ static inline int snd_sof_dsp_cmd_done(struct snd_sof_dev *sdev, { if (sdev->ops->cmd_done) return sdev->ops->cmd_done(sdev, dir); - else - return 0; + + return 0; } /* host DMA trace */ @@ -234,24 +234,24 @@ static inline int snd_sof_dma_trace_init(struct snd_sof_dev *sdev, { if (sdev->ops->trace_init) return sdev->ops->trace_init(sdev, stream_tag); - else - return 0; + + return 0; } static inline int snd_sof_dma_trace_release(struct snd_sof_dev *sdev) { if (sdev->ops->trace_release) return sdev->ops->trace_release(sdev); - else - return 0; + + return 0; } static inline int snd_sof_dma_trace_trigger(struct snd_sof_dev *sdev, int cmd) { if (sdev->ops->trace_trigger) return sdev->ops->trace_trigger(sdev, cmd); - else - return 0; + + return 0; } /* host PCM ops */ @@ -261,8 +261,8 @@ snd_sof_pcm_platform_open(struct snd_sof_dev *sdev, { if (sdev->ops && sdev->ops->pcm_open) return sdev->ops->pcm_open(sdev, substream); - else - return 0; + + return 0; } /* disconnect pcm substream to a host stream */ @@ -272,8 +272,8 @@ snd_sof_pcm_platform_close(struct snd_sof_dev *sdev, { if (sdev->ops && sdev->ops->pcm_close) return sdev->ops->pcm_close(sdev, substream); - else - return 0; + + return 0; } /* host stream hw params */ @@ -286,8 +286,8 @@ snd_sof_pcm_platform_hw_params(struct snd_sof_dev *sdev, if (sdev->ops && sdev->ops->pcm_hw_params) return sdev->ops->pcm_hw_params(sdev, substream, params, ipc_params); - else - return 0; + + return 0; } /* host stream trigger */ @@ -297,8 +297,8 @@ snd_sof_pcm_platform_trigger(struct snd_sof_dev *sdev, { if (sdev->ops && sdev->ops->pcm_trigger) return sdev->ops->pcm_trigger(sdev, substream, cmd); - else - return 0; + + return 0; } /* host stream pointer */ @@ -308,8 +308,8 @@ snd_sof_pcm_platform_pointer(struct snd_sof_dev *sdev, { if (sdev->ops && sdev->ops->pcm_pointer) return sdev->ops->pcm_pointer(sdev, substream); - else - return 0; + + return 0; } static inline struct snd_sof_dsp_ops diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 19f97a0ee381b6..c6ba28c35dd27f 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -58,8 +58,8 @@ static size_t sof_wait_trace_avail(struct snd_sof_dev *sdev, /* return bytes available for copy */ if (sdev->host_offset < pos) return buffer_size - pos; - else - return sdev->host_offset - pos; + + return sdev->host_offset - pos; } static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer, From b94a163858adc75ec917f8613ab925084085d889 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Tue, 4 Dec 2018 03:16:46 +0800 Subject: [PATCH 0330/1995] ASoC: SOF: use device_get_match_data to get dsec Use device_get_match_data() instead of get id by acpi_match_device() and get dsec by id->driver_data. Signed-off-by: Bard liao --- sound/soc/sof/sof-acpi-dev.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 8c3fe4ead8c5fc..71327b875e3da3 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -143,7 +143,6 @@ static const struct sof_ops_table acpi_mach_ops[] = { static int sof_acpi_probe(struct platform_device *pdev) { - const struct acpi_device_id *id; struct device *dev = &pdev->dev; const struct sof_dev_desc *desc; struct snd_soc_acpi_mach *mach; @@ -162,11 +161,10 @@ static int sof_acpi_probe(struct platform_device *pdev) if (!sof_pdata) return -ENOMEM; - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) + desc = (const struct sof_dev_desc *)device_get_match_data(dev); + if (!desc) return -ENODEV; - desc = (const struct sof_dev_desc *)id->driver_data; #if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) if (desc == &sof_acpi_baytrail_desc && is_byt_cr(dev)) desc = &sof_acpi_baytrailcr_desc; From ec221f8934717f93ea7603b5a48177d865ed47d7 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Tue, 4 Dec 2018 03:37:42 +0800 Subject: [PATCH 0331/1995] ASoC: SOF: use pcim_enable_device Use pcim_enable_device() and remove pci_disable_device(). Signed-off-by: Bard liao --- sound/soc/sof/sof-pci-dev.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 3eafb60c66c5da..f60b8bae5b6dd3 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -191,13 +191,13 @@ static int sof_pci_probe(struct pci_dev *pci, if (!sof_pdata) return -ENOMEM; - ret = pci_enable_device(pci); + ret = pcim_enable_device(pci); if (ret < 0) return ret; ret = pci_request_regions(pci, "Audio DSP"); if (ret < 0) - goto disable_dev; + return ret; #if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) /* force nocodec mode */ @@ -270,8 +270,6 @@ static int sof_pci_probe(struct pci_dev *pci, release_regions: pci_release_regions(pci); -disable_dev: - pci_disable_device(pci); return ret; } @@ -298,7 +296,6 @@ static void sof_pci_remove(struct pci_dev *pci) /* release pci regions and disable device */ pci_release_regions(pci); - pci_disable_device(pci); } /* PCI IDs */ From 2ebd0d250ccb5f6f8c78eca7999f1e8d3cffcbf1 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Tue, 4 Dec 2018 04:38:46 +0800 Subject: [PATCH 0332/1995] ASoC: SOF: intel: use devm_ioremap Replace ioremap with devm_ioremap and remove corresponding iounmap. Signed-off-by: Bard liao --- sound/soc/sof/intel/bdw.c | 23 ++++++----------------- sound/soc/sof/intel/byt.c | 39 ++++++++++----------------------------- sound/soc/sof/intel/hsw.c | 23 ++++++----------------- 3 files changed, 22 insertions(+), 63 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 87f369f0786159..46833e90ae26d1 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -642,7 +642,7 @@ static int bdw_probe(struct snd_sof_dev *sdev) } dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); - sdev->bar[BDW_DSP_BAR] = ioremap(base, size); + sdev->bar[BDW_DSP_BAR] = devm_ioremap(sdev->dev, base, size); if (!sdev->bar[BDW_DSP_BAR]) { dev_err(sdev->dev, "error: failed to ioremap LPE base 0x%x size 0x%x\n", @@ -664,18 +664,16 @@ static int bdw_probe(struct snd_sof_dev *sdev) } else { dev_err(sdev->dev, "error: failed to get PCI base at idx %d\n", desc->resindex_pcicfg_base); - ret = -ENODEV; - goto pci_err; + return -ENODEV; } dev_dbg(sdev->dev, "PCI base at 0x%x size 0x%x", base, size); - sdev->bar[BDW_PCI_BAR] = ioremap(base, size); + sdev->bar[BDW_PCI_BAR] = devm_ioremap(sdev->dev, base, size); if (!sdev->bar[BDW_PCI_BAR]) { dev_err(sdev->dev, "error: failed to ioremap PCI base 0x%x size 0x%x\n", base, size); - ret = -ENODEV; - goto pci_err; + return -ENODEV; } dev_dbg(sdev->dev, "PCI VADDR %p\n", sdev->bar[BDW_PCI_BAR]); @@ -684,8 +682,7 @@ static int bdw_probe(struct snd_sof_dev *sdev) if (sdev->ipc_irq < 0) { dev_err(sdev->dev, "error: failed to get IRQ at index %d\n", desc->irqindex_host_ipc); - ret = sdev->ipc_irq; - goto irq_err; + return sdev->ipc_irq; } dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); @@ -695,7 +692,7 @@ static int bdw_probe(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "error: failed to register IRQ %d\n", sdev->ipc_irq); - goto irq_err; + return ret; } /* enable the DSP SHIM */ @@ -719,18 +716,10 @@ static int bdw_probe(struct snd_sof_dev *sdev) snd_sof_dsp_mailbox_init(sdev, MBOX_OFFSET, MBOX_SIZE, 0, 0); return ret; - -irq_err: - iounmap(sdev->bar[BDW_DSP_BAR]); -pci_err: - iounmap(sdev->bar[BDW_PCI_BAR]); - return ret; } static int bdw_remove(struct snd_sof_dev *sdev) { - iounmap(sdev->bar[BDW_DSP_BAR]); - iounmap(sdev->bar[BDW_PCI_BAR]); free_irq(sdev->ipc_irq, sdev); return 0; } diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index f7d3479e958660..2d360f7e7ecbb0 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -578,7 +578,7 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) } dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); - sdev->bar[BYT_DSP_BAR] = ioremap(base, size); + sdev->bar[BYT_DSP_BAR] = devm_ioremap(sdev->dev, base, size); if (!sdev->bar[BYT_DSP_BAR]) { dev_err(sdev->dev, "error: failed to ioremap LPE base 0x%x size 0x%x\n", base, size); @@ -602,8 +602,7 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) } else { dev_err(sdev->dev, "error: failed to get IMR base at idx %d\n", desc->resindex_imr_base); - ret = -ENODEV; - goto imr_err; + return -ENODEV; } /* some BIOSes don't map IMR */ @@ -613,12 +612,11 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) } dev_dbg(sdev->dev, "IMR base at 0x%x size 0x%x", base, size); - sdev->bar[BYT_IMR_BAR] = ioremap(base, size); + sdev->bar[BYT_IMR_BAR] = devm_ioremap(sdev->dev, base, size); if (!sdev->bar[BYT_IMR_BAR]) { dev_err(sdev->dev, "error: failed to ioremap IMR base 0x%x size 0x%x\n", base, size); - ret = -ENODEV; - goto imr_err; + return -ENODEV; } dev_dbg(sdev->dev, "IMR VADDR %p\n", sdev->bar[BYT_IMR_BAR]); @@ -628,8 +626,7 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) if (sdev->ipc_irq < 0) { dev_err(sdev->dev, "error: failed to get IRQ at index %d\n", desc->irqindex_host_ipc); - ret = sdev->ipc_irq; - goto irq_err; + return sdev->ipc_irq; } dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); @@ -639,7 +636,7 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "error: failed to register IRQ %d\n", sdev->ipc_irq); - goto irq_err; + return ret; } /* enable Interrupt from both sides */ @@ -653,12 +650,6 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) sdev->dsp_box.offset = MBOX_OFFSET; return ret; - -irq_err: - iounmap(sdev->bar[BYT_IMR_BAR]); -imr_err: - iounmap(sdev->bar[BYT_DSP_BAR]); - return ret; } static int byt_pci_probe(struct snd_sof_dev *sdev) @@ -681,7 +672,7 @@ static int byt_pci_probe(struct snd_sof_dev *sdev) size = BYT_PCI_BAR_SIZE; dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); - sdev->bar[BYT_DSP_BAR] = ioremap(base, size); + sdev->bar[BYT_DSP_BAR] = devm_ioremap(sdev->dev, base, size); if (!sdev->bar[BYT_DSP_BAR]) { dev_err(sdev->dev, "error: failed to ioremap LPE base 0x%x size 0x%x\n", base, size); @@ -703,12 +694,11 @@ static int byt_pci_probe(struct snd_sof_dev *sdev) } dev_dbg(sdev->dev, "IMR base at 0x%x size 0x%x", base, size); - sdev->bar[BYT_IMR_BAR] = ioremap(base, size); + sdev->bar[BYT_IMR_BAR] = devm_ioremap(sdev->dev, base, size); if (!sdev->bar[BYT_IMR_BAR]) { dev_err(sdev->dev, "error: failed to ioremap IMR base 0x%x size 0x%x\n", base, size); - ret = -ENODEV; - goto imr_err; + return -ENODEV; } dev_dbg(sdev->dev, "IMR VADDR %p\n", sdev->bar[BYT_IMR_BAR]); @@ -721,7 +711,7 @@ static int byt_pci_probe(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "error: failed to register IRQ %d\n", sdev->ipc_irq); - goto irq_err; + return ret; } /* enable Interrupt from both sides */ @@ -735,12 +725,6 @@ static int byt_pci_probe(struct snd_sof_dev *sdev) sdev->dsp_box.offset = MBOX_OFFSET; return ret; - -irq_err: - iounmap(sdev->bar[BYT_IMR_BAR]); -imr_err: - iounmap(sdev->bar[BYT_DSP_BAR]); - return ret; } static int byt_probe(struct snd_sof_dev *sdev) @@ -753,9 +737,6 @@ static int byt_probe(struct snd_sof_dev *sdev) static int byt_acpi_remove(struct snd_sof_dev *sdev) { - iounmap(sdev->bar[BYT_DSP_BAR]); - iounmap(sdev->bar[BYT_PCI_BAR]); - iounmap(sdev->bar[BYT_IMR_BAR]); free_irq(sdev->ipc_irq, sdev); return 0; } diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 34b65fbffcde84..3b3f59a73a298c 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -642,7 +642,7 @@ static int hsw_probe(struct snd_sof_dev *sdev) } dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); - sdev->bar[HSW_DSP_BAR] = ioremap(base, size); + sdev->bar[HSW_DSP_BAR] = devm_ioremap(sdev->dev, base, size); if (!sdev->bar[HSW_DSP_BAR]) { dev_err(sdev->dev, "error: failed to ioremap LPE base 0x%x size 0x%x\n", @@ -664,18 +664,16 @@ static int hsw_probe(struct snd_sof_dev *sdev) } else { dev_err(sdev->dev, "error: failed to get PCI base at idx %d\n", desc->resindex_pcicfg_base); - ret = -ENODEV; - goto pci_err; + return -ENODEV; } dev_dbg(sdev->dev, "PCI base at 0x%x size 0x%x", base, size); - sdev->bar[HSW_PCI_BAR] = ioremap(base, size); + sdev->bar[HSW_PCI_BAR] = devm_ioremap(sdev->dev, base, size); if (!sdev->bar[HSW_PCI_BAR]) { dev_err(sdev->dev, "error: failed to ioremap PCI base 0x%x size 0x%x\n", base, size); - ret = -ENODEV; - goto pci_err; + return -ENODEV; } dev_dbg(sdev->dev, "PCI VADDR %p\n", sdev->bar[HSW_PCI_BAR]); @@ -684,8 +682,7 @@ static int hsw_probe(struct snd_sof_dev *sdev) if (sdev->ipc_irq < 0) { dev_err(sdev->dev, "error: failed to get IRQ at index %d\n", desc->irqindex_host_ipc); - ret = sdev->ipc_irq; - goto irq_err; + return sdev->ipc_irq; } dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); @@ -694,7 +691,7 @@ static int hsw_probe(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "error: failed to register IRQ %d\n", sdev->ipc_irq); - goto irq_err; + return ret; } /* enable the DSP SHIM */ @@ -718,18 +715,10 @@ static int hsw_probe(struct snd_sof_dev *sdev) snd_sof_dsp_mailbox_init(sdev, MBOX_OFFSET, MBOX_SIZE, 0, 0); return ret; - -irq_err: - iounmap(sdev->bar[HSW_DSP_BAR]); -pci_err: - iounmap(sdev->bar[HSW_PCI_BAR]); - return ret; } static int hsw_remove(struct snd_sof_dev *sdev) { - iounmap(sdev->bar[HSW_DSP_BAR]); - iounmap(sdev->bar[HSW_PCI_BAR]); free_irq(sdev->ipc_irq, sdev); return 0; } From 1c9ccf8a5467b8e4bf36059bcde454d4f4b498be Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 4 Dec 2018 10:10:47 -0800 Subject: [PATCH 0333/1995] ASoC: SOF: remove unnecessary variable in snd_sof_dsp_register_poll Remove the unnecassary "done" variable in the snd_sof_dsp_register_poll() method and use the variable "time" instead. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/ops.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index cbcc4d1271502b..0cc33cd7cbb657 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -153,7 +153,6 @@ int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 mask, u32 target, u32 timeout) { int time, ret; - bool done = false; /* * we will poll for couple of ms using mdelay, if not successful @@ -161,19 +160,17 @@ int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset, */ /* check if set state successful */ - for (time = 0; time < 5; time++) { - if ((snd_sof_dsp_read(sdev, bar, offset) & mask) == target) { - done = true; + for (time = 5; time > 0; time--) { + if ((snd_sof_dsp_read(sdev, bar, offset) & mask) == target) break; - } msleep(20); } - if (!done) { + if (!time) { /* sleeping in 10ms steps so adjust timeout value */ timeout /= 10; - for (time = 0; time < timeout; time++) { + for (time = timeout; time > 0; time--) { if ((snd_sof_dsp_read(sdev, bar, offset) & mask) == target) break; @@ -182,7 +179,7 @@ int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset, } } - ret = time < timeout ? 0 : -ETIME; + ret = time ? 0 : -ETIME; return ret; } From 07e069601aaa1d055249ebdc73c055ca445dc8f0 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 3 Dec 2018 14:00:54 -0800 Subject: [PATCH 0334/1995] ASoC: SOF: introduce ops for power up/down dsp core Introduce core_power_up/core_power_down dsp ops. These will be called while topology is parsed to schedule pipelines based on the core specified in topology. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/ops.h | 19 +++++++++++++++++++ sound/soc/sof/sof-priv.h | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index e2298155f3529e..405e39155645a9 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -60,6 +60,25 @@ static inline int snd_sof_dsp_reset(struct snd_sof_dev *sdev) return 0; } +/* dsp core power up/power down */ +static inline int snd_sof_dsp_core_power_up(struct snd_sof_dev *sdev, + unsigned int core_mask) +{ + if (sdev->ops->core_power_up) + return sdev->ops->core_power_up(sdev, core_mask); + + return 0; +} + +static inline int snd_sof_dsp_core_power_down(struct snd_sof_dev *sdev, + unsigned int core_mask) +{ + if (sdev->ops->core_power_down) + return sdev->ops->core_power_down(sdev, core_mask); + + return 0; +} + /* pre/post fw load */ static inline int snd_sof_dsp_pre_fw_run(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 3f619f5f2691cb..785158de5d91dc 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -85,6 +85,10 @@ struct snd_sof_dsp_ops { int (*run)(struct snd_sof_dev *sof_dev); int (*stall)(struct snd_sof_dev *sof_dev); int (*reset)(struct snd_sof_dev *sof_dev); + int (*core_power_up)(struct snd_sof_dev *sof_dev, + unsigned int core_mask); + int (*core_power_down)(struct snd_sof_dev *sof_dev, + unsigned int core_mask); /* pre/post firmware run */ int (*pre_fw_run)(struct snd_sof_dev *sof_dev); From 8e2bdc22c1af1128f9bc24f85bad29bc8e5577d1 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 3 Dec 2018 14:02:06 -0800 Subject: [PATCH 0335/1995] ASoC: SOF: add CORE_ENABLE to verbose ipc log Add CORE_ENABLE ipc to verbose ipc log decoder. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/ipc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index fff583bbe81418..afccdde9925375 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -133,6 +133,8 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) str = "GLB_PM_MSG: CLK_GET"; break; case SOF_IPC_PM_CLK_REQ: str = "GLB_PM_MSG: CLK_REQ"; break; + case SOF_IPC_PM_CORE_ENABLE: + str = "GLB_PM_MSG: CORE_ENABLE"; break; default: str = "GLB_PM_MSG: unknown type"; break; } From eb19aea47fea415e1269db3f0f359a29776b5617 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 3 Dec 2018 14:05:58 -0800 Subject: [PATCH 0336/1995] ASoC: SOF: power up schedule core after setting up pipeline comp With multicore support added in the FW, this patch adds support to power up the core that a pipeline is scheduled on. After creating the pipeline comp, power up the schedule core and notify the DSP. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/sof-priv.h | 4 ++++ sound/soc/sof/topology.c | 47 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 785158de5d91dc..26f4fc11e64406 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -493,6 +493,10 @@ void snd_sof_free_topology(struct snd_sof_dev *sdev); int snd_sof_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget); +int sof_load_pipeline_ipc(struct snd_sof_dev *sdev, + struct sof_ipc_pipe_new *pipeline, + struct sof_ipc_comp_reply *r); + /* * Trace/debug */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 938d0c4c0b1563..8e1c236ec75389 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -24,6 +24,7 @@ #include #include #include "sof-priv.h" +#include "ops.h" #define COMP_ID_UNASSIGNED 0xffffffff /* Constants used in the computation of linear volume gain from dB gain */ @@ -1088,6 +1089,48 @@ static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index, /* * Pipeline Topology */ +int sof_load_pipeline_ipc(struct snd_sof_dev *sdev, + struct sof_ipc_pipe_new *pipeline, + struct sof_ipc_comp_reply *r) +{ + struct sof_ipc_pm_core_config pm_core_config; + int ret = 0; + + ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline, + sizeof(*pipeline), r, sizeof(*r)); + if (ret < 0) { + dev_err(sdev->dev, "error: load pipeline ipc failure\n"); + return ret; + } + + /* power up the core that this pipeline is scheduled on */ + ret = snd_sof_dsp_core_power_up(sdev, 1 << pipeline->core); + if (ret < 0) { + dev_err(sdev->dev, "error: powering up pipeline schedule core %d\n", + pipeline->core); + return ret; + } + + /* + * Now notify DSP that the core that this pipeline is scheduled on + * has been powered up + */ + memset(&pm_core_config, 0, sizeof(pm_core_config)); + pm_core_config.enable_mask = 1 << pipeline->core; + + /* configure CORE_ENABLE ipc message */ + pm_core_config.hdr.size = sizeof(pm_core_config); + pm_core_config.hdr.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE; + + /* send ipc */ + ret = sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd, + &pm_core_config, sizeof(pm_core_config), + &pm_core_config, sizeof(pm_core_config)); + if (ret < 0) + dev_err(sdev->dev, "error: core enable ipc failure\n"); + + return ret; +} static int sof_widget_load_pipeline(struct snd_soc_component *scomp, int index, struct snd_sof_widget *swidget, @@ -1139,8 +1182,8 @@ static int sof_widget_load_pipeline(struct snd_soc_component *scomp, swidget->private = (void *)pipeline; - ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline, - sizeof(*pipeline), r, sizeof(*r)); + /* send ipc's to create pipeline comp and power up schedule core */ + ret = sof_load_pipeline_ipc(sdev, pipeline, r); if (ret >= 0) return ret; err: From ac354cfdc4306ae0b29aea6166e839487afbce9e Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 3 Dec 2018 14:10:01 -0800 Subject: [PATCH 0337/1995] ASoC: SOF: power down the pipeline schedule core in widget unload When the pipeline widget is unloaded, the core that the pipeline is scheduled on should be powered off. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/topology.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 8e1c236ec75389..278d251f1928a2 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1785,12 +1785,15 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, static int sof_widget_unload(struct snd_soc_component *scomp, struct snd_soc_dobj *dobj) { + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); const struct snd_kcontrol_new *kc = NULL; struct snd_soc_dapm_widget *widget; + struct sof_ipc_pipe_new *pipeline; struct snd_sof_control *scontrol; struct snd_sof_widget *swidget; struct soc_mixer_control *sm; struct snd_sof_dai *dai; + int ret = 0; swidget = dobj->private; if (!swidget) @@ -1811,6 +1814,19 @@ static int sof_widget_unload(struct snd_soc_component *scomp, list_del(&dai->list); kfree(dai); } + break; + case snd_soc_dapm_scheduler: + + /* power down the pipeline schedule core */ + pipeline = (struct sof_ipc_pipe_new *)swidget->private; + ret = snd_sof_dsp_core_power_down(sdev, 1 << pipeline->core); + if (ret < 0) + dev_err(sdev->dev, "error: powering down pipeline schedule core %d\n", + pipeline->core); + + /* free private value */ + kfree(swidget->private); + break; case snd_soc_dapm_pga: @@ -1833,7 +1849,7 @@ static int sof_widget_unload(struct snd_soc_component *scomp, list_del(&swidget->list); kfree(swidget); - return 0; + return ret; } /* From f028d55e01cb6e90905a7c0648dd411513912b12 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 3 Dec 2018 14:14:44 -0800 Subject: [PATCH 0338/1995] ASoC: SOF: clean up widget_unload routine Move the code that frees the widget's private data outside the switch case as it is common for all widgets. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/topology.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 278d251f1928a2..cbd6565037968e 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1804,15 +1804,12 @@ static int sof_widget_unload(struct snd_soc_component *scomp, switch (swidget->id) { case snd_soc_dapm_dai_in: case snd_soc_dapm_dai_out: - dai = swidget->private; + dai = (struct snd_sof_dai *)swidget->private; - /* free dai config */ - kfree(dai->dai_config); - - /* remove and free dai object */ if (dai) { + /* free dai config */ + kfree(dai->dai_config); list_del(&dai->list); - kfree(dai); } break; case snd_soc_dapm_scheduler: @@ -1823,10 +1820,6 @@ static int sof_widget_unload(struct snd_soc_component *scomp, if (ret < 0) dev_err(sdev->dev, "error: powering down pipeline schedule core %d\n", pipeline->core); - - /* free private value */ - kfree(swidget->private); - break; case snd_soc_dapm_pga: @@ -1837,14 +1830,14 @@ static int sof_widget_unload(struct snd_soc_component *scomp, /* free volume table */ kfree(scontrol->volume_table); - - /* fallthrough */ + break; default: - /* free private value */ - kfree(swidget->private); break; } + /* free private value */ + kfree(swidget->private); + /* remove and free swidget object */ list_del(&swidget->list); kfree(swidget); From 3b95e0babd29068f8561a52168947094ab392f0d Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 3 Dec 2018 14:22:13 -0800 Subject: [PATCH 0339/1995] ASoC: SOF: power up pipeline schedule core upon resume During system suspend or runtime suspend, all DSP cores are powered off. So upon resume, after creating the pipeline comp, the core that the pipeline is scheduled to run on must be power back on. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pm.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 644eecb0d737df..80be44929c3b4b 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -70,6 +70,7 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev) { struct snd_sof_widget *swidget = NULL; struct snd_sof_route *sroute = NULL; + struct sof_ipc_pipe_new *pipeline; struct snd_sof_dai *dai; struct sof_ipc_comp_dai *comp_dai; struct sof_ipc_hdr *hdr; @@ -94,6 +95,17 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev) comp_dai, sizeof(*comp_dai), &r, sizeof(r)); break; + case snd_soc_dapm_scheduler: + + /* + * During suspend, all DSP cores are powered off. + * Therefore upon resume, create the pipeline comp + * and power up the core that the pipeline is + * scheduled on. + */ + pipeline = (struct sof_ipc_pipe_new *)swidget->private; + ret = sof_load_pipeline_ipc(sdev, pipeline, &r); + break; default: hdr = (struct sof_ipc_hdr *)swidget->private; ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, @@ -338,7 +350,7 @@ static int sof_suspend(struct device *dev, int runtime_suspend) /* drop all ipc */ sof_ipc_drop_all(sdev->ipc); - /* power down DSP */ + /* power down all DSP cores */ if (runtime_suspend) ret = snd_sof_dsp_runtime_suspend(sdev, 0); else From f10eda3d8db5f249e03ab7e66f58397f66518e07 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 3 Dec 2018 14:23:37 -0800 Subject: [PATCH 0340/1995] ASoC: SOF: add core_power_down/up ops implementation for SKL+ Add implementation for core_power_up/down ops for SKL+ platforms. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/apl.c | 4 ++++ sound/soc/sof/intel/cnl.c | 4 ++++ sound/soc/sof/intel/skl.c | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index c773ab6f5225ae..7e28fba1768239 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -91,6 +91,10 @@ struct snd_sof_dsp_ops sof_apl_ops = { .pre_fw_run = hda_dsp_pre_fw_run, .post_fw_run = hda_dsp_post_fw_run, + /* dsp core power up/down */ + .core_power_up = hda_dsp_enable_core, + .core_power_down = hda_dsp_core_reset_power_down, + /* trace callback */ .trace_init = hda_dsp_trace_init, .trace_release = hda_dsp_trace_release, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index d7291b62f378b4..b561d287368592 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -237,6 +237,10 @@ struct snd_sof_dsp_ops sof_cnl_ops = { .pre_fw_run = hda_dsp_pre_fw_run, .post_fw_run = hda_dsp_post_fw_run, + /* dsp core power up/down */ + .core_power_up = hda_dsp_enable_core, + .core_power_down = hda_dsp_core_reset_power_down, + /* firmware run */ .run = hda_dsp_cl_boot_firmware, diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 8a58b5d319cd6b..9531d531478ad9 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -87,6 +87,10 @@ struct snd_sof_dsp_ops sof_skl_ops = { .pre_fw_run = hda_dsp_pre_fw_run, .post_fw_run = hda_dsp_post_fw_run, + /* dsp core power up/down */ + .core_power_up = hda_dsp_enable_core, + .core_power_down = hda_dsp_core_reset_power_down, + /* firmware run */ .run = hda_dsp_cl_boot_firmware_skl, From 59464fdcd7c1b42f970355b79720cbfbced57ab8 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Tue, 4 Dec 2018 21:48:36 +0800 Subject: [PATCH 0341/1995] ASoC: SOF: intel: request irq with devm_ function We can use devm_request_threaded_irq() so that kernel will free irq for us. Signed-off-by: Bard liao --- sound/soc/sof/intel/bdw.c | 13 +++---------- sound/soc/sof/intel/byt.c | 33 ++++++--------------------------- sound/soc/sof/intel/hsw.c | 12 +++--------- 3 files changed, 12 insertions(+), 46 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 46833e90ae26d1..5d1e4bc9f9c5e5 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -686,9 +686,9 @@ static int bdw_probe(struct snd_sof_dev *sdev) } dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); - ret = request_threaded_irq(sdev->ipc_irq, bdw_irq_handler, - bdw_irq_thread, IRQF_SHARED, "AudioDSP", - sdev); + ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, + bdw_irq_handler, bdw_irq_thread, + IRQF_SHARED, "AudioDSP", sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to register IRQ %d\n", sdev->ipc_irq); @@ -718,12 +718,6 @@ static int bdw_probe(struct snd_sof_dev *sdev) return ret; } -static int bdw_remove(struct snd_sof_dev *sdev) -{ - free_irq(sdev->ipc_irq, sdev); - return 0; -} - #define BDW_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE) @@ -749,7 +743,6 @@ static struct snd_soc_dai_driver bdw_dai[] = { struct snd_sof_dsp_ops sof_bdw_ops = { /*Device init */ .probe = bdw_probe, - .remove = bdw_remove, /* DSP Core Control */ .run = bdw_run, diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 2d360f7e7ecbb0..6c2c673c25efca 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -630,9 +630,9 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) } dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); - ret = request_threaded_irq(sdev->ipc_irq, byt_irq_handler, - byt_irq_thread, IRQF_SHARED, "AudioDSP", - sdev); + ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, + byt_irq_handler, byt_irq_thread, + IRQF_SHARED, "AudioDSP", sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to register IRQ %d\n", sdev->ipc_irq); @@ -706,8 +706,9 @@ static int byt_pci_probe(struct snd_sof_dev *sdev) /* register our IRQ */ sdev->ipc_irq = pci->irq; dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); - ret = request_threaded_irq(sdev->ipc_irq, byt_irq_handler, - byt_irq_thread, 0, "AudioDSP", sdev); + ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, + byt_irq_handler, byt_irq_thread, + 0, "AudioDSP", sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to register IRQ %d\n", sdev->ipc_irq); @@ -735,26 +736,6 @@ static int byt_probe(struct snd_sof_dev *sdev) return byt_acpi_probe(sdev); } -static int byt_acpi_remove(struct snd_sof_dev *sdev) -{ - free_irq(sdev->ipc_irq, sdev); - return 0; -} - -static int byt_pci_remove(struct snd_sof_dev *sdev) -{ - free_irq(sdev->ipc_irq, sdev); - return 0; -} - -static int byt_remove(struct snd_sof_dev *sdev) -{ - if (sdev->pci) - return byt_pci_remove(sdev); - - return byt_acpi_remove(sdev); -} - #define BYT_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE) @@ -808,7 +789,6 @@ static struct snd_soc_dai_driver byt_dai[] = { struct snd_sof_dsp_ops sof_byt_ops = { /* device init */ .probe = byt_probe, - .remove = byt_remove, /* DSP core boot / reset */ .run = byt_run, @@ -860,7 +840,6 @@ EXPORT_SYMBOL(sof_byt_ops); struct snd_sof_dsp_ops sof_cht_ops = { /* device init */ .probe = byt_probe, - .remove = byt_remove, /* DSP core boot / reset */ .run = byt_run, diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 3b3f59a73a298c..aa0242e5516963 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -686,8 +686,9 @@ static int hsw_probe(struct snd_sof_dev *sdev) } dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); - ret = request_threaded_irq(sdev->ipc_irq, hsw_irq_handler, - hsw_irq_thread, 0, "AudioDSP", sdev); + ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, + hsw_irq_handler, hsw_irq_thread, + 0, "AudioDSP", sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to register IRQ %d\n", sdev->ipc_irq); @@ -717,12 +718,6 @@ static int hsw_probe(struct snd_sof_dev *sdev) return ret; } -static int hsw_remove(struct snd_sof_dev *sdev) -{ - free_irq(sdev->ipc_irq, sdev); - return 0; -} - #define HSW_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE) @@ -748,7 +743,6 @@ static struct snd_soc_dai_driver hsw_dai[] = { struct snd_sof_dsp_ops sof_hsw_ops = { /*Device init */ .probe = hsw_probe, - .remove = hsw_remove, /* DSP Core Control */ .run = hsw_run, From d0fbf1c67da1edd21395e3604745f751591683fe Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 4 Dec 2018 12:20:54 -0800 Subject: [PATCH 0342/1995] ASoC: SOF: separate snd_sof_debugfs_create_item into 2 flavours debugfs entries can be used to expose two different types of memories: 1. DSP memory and registers 2. kernel buffers We should use type struct snd_sof_dfsentry_io for the first one and type struct snd_sof_dfsentry_buf for the second type. So split the snd_sof_debugfs_create_item() into two flavours based on the memory pointed to. snd_sof_debugfs_io_create_item() should be used for io memory and snd_sof_debugfs_buf_create_item() should beused for kernel buffers, for example, the fw_version member of snd_sof_dev. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/debug.c | 40 +++++++++++++++--- sound/soc/sof/intel/bdw.c | 60 ++++++++++++++------------- sound/soc/sof/intel/byt.c | 60 ++++++++++++++------------- sound/soc/sof/intel/hda-ipc.c | 76 +++++++++++++++++------------------ sound/soc/sof/intel/hsw.c | 60 ++++++++++++++------------- sound/soc/sof/loader.c | 6 +-- sound/soc/sof/sof-priv.h | 9 +++-- 7 files changed, 178 insertions(+), 133 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 6f61a39cbb2cd1..2dbc98423d2739 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -89,9 +89,10 @@ static const struct file_operations sof_dfs_fops = { .llseek = default_llseek, }; -int snd_sof_debugfs_create_item(struct snd_sof_dev *sdev, - void __iomem *base, size_t size, - const char *name) +/* create FS entry for debug files that can expose DSP memories, registers */ +int snd_sof_debugfs_io_create_item(struct snd_sof_dev *sdev, + void __iomem *base, size_t size, + const char *name) { struct snd_sof_dfsentry_io *dfse; @@ -115,7 +116,36 @@ int snd_sof_debugfs_create_item(struct snd_sof_dev *sdev, return 0; } -EXPORT_SYMBOL(snd_sof_debugfs_create_item); +EXPORT_SYMBOL(snd_sof_debugfs_io_create_item); + +/* create FS entry for debug files to expose kernel memory */ +int snd_sof_debugfs_buf_create_item(struct snd_sof_dev *sdev, + void *base, size_t size, + const char *name) +{ + struct snd_sof_dfsentry_buf *dfse; + + if (!sdev) + return -EINVAL; + + dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); + if (!dfse) + return -ENOMEM; + + dfse->buf = base; + dfse->size = size; + dfse->sdev = sdev; + + dfse->dfsentry = debugfs_create_file(name, 0444, sdev->debugfs_root, + dfse, &sof_dfs_fops); + if (!dfse->dfsentry) { + dev_err(sdev->dev, "cannot create debugfs entry.\n"); + return -ENODEV; + } + + return 0; +} +EXPORT_SYMBOL(snd_sof_debugfs_buf_create_item); int snd_sof_dbg_init(struct snd_sof_dev *sdev) { @@ -134,7 +164,7 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) for (i = 0; i < ops->debug_map_count; i++) { map = &ops->debug_map[i]; - err = snd_sof_debugfs_create_item(sdev, sdev->bar[map->bar] + + err = snd_sof_debugfs_io_create_item(sdev, sdev->bar[map->bar] + map->offset, map->size, map->name); if (err < 0) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 5d1e4bc9f9c5e5..2e18b11746472b 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -426,51 +426,55 @@ static void bdw_get_windows(struct snd_sof_dev *sdev) case SOF_IPC_REGION_UPBOX: inbox_offset = elem->offset + MBOX_OFFSET; inbox_size = elem->size; - snd_sof_debugfs_create_item(sdev, - sdev->bar[BDW_DSP_BAR] + - inbox_offset, - elem->size, "inbox"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[BDW_DSP_BAR] + + inbox_offset, + elem->size, "inbox"); break; case SOF_IPC_REGION_DOWNBOX: outbox_offset = elem->offset + MBOX_OFFSET; outbox_size = elem->size; - snd_sof_debugfs_create_item(sdev, - sdev->bar[BDW_DSP_BAR] + - outbox_offset, - elem->size, "outbox"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[BDW_DSP_BAR] + + outbox_offset, + elem->size, "outbox"); break; case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_create_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + MBOX_OFFSET, - elem->size, "etrace"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[BDW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "etrace"); break; case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_create_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + MBOX_OFFSET, - elem->size, "debug"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[BDW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "debug"); break; case SOF_IPC_REGION_STREAM: stream_offset = elem->offset + MBOX_OFFSET; stream_size = elem->size; - snd_sof_debugfs_create_item(sdev, - sdev->bar[BDW_DSP_BAR] + - stream_offset, - elem->size, "stream"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[BDW_DSP_BAR] + + stream_offset, + elem->size, "stream"); break; case SOF_IPC_REGION_REGS: - snd_sof_debugfs_create_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + MBOX_OFFSET, - elem->size, "regs"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[BDW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "regs"); break; case SOF_IPC_REGION_EXCEPTION: sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; - snd_sof_debugfs_create_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + MBOX_OFFSET, - elem->size, "exception"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[BDW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "exception"); break; default: dev_err(sdev->dev, "error: get illegal window info\n"); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 6c2c673c25efca..c4683e90eee902 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -186,51 +186,55 @@ static void byt_get_windows(struct snd_sof_dev *sdev) case SOF_IPC_REGION_UPBOX: inbox_offset = elem->offset + MBOX_OFFSET; inbox_size = elem->size; - snd_sof_debugfs_create_item(sdev, - sdev->bar[BYT_DSP_BAR] + - inbox_offset, - elem->size, "inbox"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[BYT_DSP_BAR] + + inbox_offset, + elem->size, "inbox"); break; case SOF_IPC_REGION_DOWNBOX: outbox_offset = elem->offset + MBOX_OFFSET; outbox_size = elem->size; - snd_sof_debugfs_create_item(sdev, - sdev->bar[BYT_DSP_BAR] + - outbox_offset, - elem->size, "outbox"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[BYT_DSP_BAR] + + outbox_offset, + elem->size, "outbox"); break; case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_create_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + MBOX_OFFSET, - elem->size, "etrace"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[BYT_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "etrace"); break; case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_create_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + MBOX_OFFSET, - elem->size, "debug"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[BYT_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "debug"); break; case SOF_IPC_REGION_STREAM: stream_offset = elem->offset + MBOX_OFFSET; stream_size = elem->size; - snd_sof_debugfs_create_item(sdev, - sdev->bar[BYT_DSP_BAR] + - stream_offset, - elem->size, "stream"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[BYT_DSP_BAR] + + stream_offset, + elem->size, "stream"); break; case SOF_IPC_REGION_REGS: - snd_sof_debugfs_create_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + MBOX_OFFSET, - elem->size, "regs"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[BYT_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "regs"); break; case SOF_IPC_REGION_EXCEPTION: sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; - snd_sof_debugfs_create_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + MBOX_OFFSET, - elem->size, "exception"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[BYT_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "exception"); break; default: dev_err(sdev->dev, "error: get illegal window info\n"); diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 94d1d7807eabef..efaf293c2c77dc 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -285,64 +285,64 @@ static void ipc_get_windows(struct snd_sof_dev *sdev) inbox_offset = elem->offset + SRAM_WINDOW_OFFSET(elem->id); inbox_size = elem->size; - snd_sof_debugfs_create_item(sdev, - sdev->bar[HDA_DSP_BAR] + - inbox_offset, - elem->size, "inbox"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[HDA_DSP_BAR] + + inbox_offset, + elem->size, "inbox"); break; case SOF_IPC_REGION_DOWNBOX: outbox_offset = elem->offset + SRAM_WINDOW_OFFSET(elem->id); outbox_size = elem->size; - snd_sof_debugfs_create_item(sdev, - sdev->bar[HDA_DSP_BAR] + - outbox_offset, - elem->size, "outbox"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[HDA_DSP_BAR] + + outbox_offset, + elem->size, "outbox"); break; case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_create_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "etrace"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "etrace"); break; case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_create_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "debug"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "debug"); break; case SOF_IPC_REGION_STREAM: stream_offset = elem->offset + SRAM_WINDOW_OFFSET(elem->id); stream_size = elem->size; - snd_sof_debugfs_create_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "stream"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "stream"); break; case SOF_IPC_REGION_REGS: - snd_sof_debugfs_create_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "regs"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "regs"); break; case SOF_IPC_REGION_EXCEPTION: sdev->dsp_oops_offset = elem->offset + SRAM_WINDOW_OFFSET(elem->id); - snd_sof_debugfs_create_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "exception"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "exception"); break; default: dev_err(sdev->dev, "error: get illegal window info\n"); diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index aa0242e5516963..555810476b78d2 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -427,51 +427,55 @@ static void hsw_get_windows(struct snd_sof_dev *sdev) case SOF_IPC_REGION_UPBOX: inbox_offset = elem->offset + MBOX_OFFSET; inbox_size = elem->size; - snd_sof_debugfs_create_item(sdev, - sdev->bar[HSW_DSP_BAR] + - inbox_offset, - elem->size, "inbox"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[HSW_DSP_BAR] + + inbox_offset, + elem->size, "inbox"); break; case SOF_IPC_REGION_DOWNBOX: outbox_offset = elem->offset + MBOX_OFFSET; outbox_size = elem->size; - snd_sof_debugfs_create_item(sdev, - sdev->bar[HSW_DSP_BAR] + - outbox_offset, - elem->size, "outbox"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[HSW_DSP_BAR] + + outbox_offset, + elem->size, "outbox"); break; case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_create_item(sdev, - sdev->bar[HSW_DSP_BAR] + - elem->offset + MBOX_OFFSET, - elem->size, "etrace"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[HSW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "etrace"); break; case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_create_item(sdev, - sdev->bar[HSW_DSP_BAR] + - elem->offset + MBOX_OFFSET, - elem->size, "debug"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[HSW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "debug"); break; case SOF_IPC_REGION_STREAM: stream_offset = elem->offset + MBOX_OFFSET; stream_size = elem->size; - snd_sof_debugfs_create_item(sdev, - sdev->bar[HSW_DSP_BAR] + - stream_offset, - elem->size, "stream"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[HSW_DSP_BAR] + + stream_offset, + elem->size, "stream"); break; case SOF_IPC_REGION_REGS: - snd_sof_debugfs_create_item(sdev, - sdev->bar[HSW_DSP_BAR] + - elem->offset + MBOX_OFFSET, - elem->size, "regs"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[HSW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "regs"); break; case SOF_IPC_REGION_EXCEPTION: sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; - snd_sof_debugfs_create_item(sdev, - sdev->bar[HSW_DSP_BAR] + - elem->offset + MBOX_OFFSET, - elem->size, "exception"); + snd_sof_debugfs_io_create_item(sdev, + sdev->bar[HSW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "exception"); break; default: dev_err(sdev->dev, "error: get illegal window info\n"); diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index bc36359e2b70f9..b23fa0fe6a328c 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -280,9 +280,9 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) /* create fw_version debugfs to store boot version info */ if (sdev->first_boot) { - ret = snd_sof_debugfs_create_item(sdev, &sdev->fw_version, - sizeof(sdev->fw_version), - "fw_version"); + ret = snd_sof_debugfs_buf_create_item(sdev, &sdev->fw_version, + sizeof(sdev->fw_version), + "fw_version"); if (ret < 0) { dev_err(sdev->dev, "cannot create debugfs for fw_version\n"); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 26f4fc11e64406..61069d77c5151a 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -505,9 +505,12 @@ void snd_sof_release_trace(struct snd_sof_dev *sdev); void snd_sof_free_trace(struct snd_sof_dev *sdev); int snd_sof_dbg_init(struct snd_sof_dev *sdev); void snd_sof_free_debug(struct snd_sof_dev *sdev); -int snd_sof_debugfs_create_item(struct snd_sof_dev *sdev, - void __iomem *base, size_t size, - const char *name); +int snd_sof_debugfs_io_create_item(struct snd_sof_dev *sdev, + void __iomem *base, size_t size, + const char *name); +int snd_sof_debugfs_buf_create_item(struct snd_sof_dev *sdev, + void *base, size_t size, + const char *name); int snd_sof_trace_update_pos(struct snd_sof_dev *sdev, struct sof_ipc_dma_trace_posn *posn); void snd_sof_trace_notify_for_error(struct snd_sof_dev *sdev); From ac14451e2e105b8b3b8427bc1a70628878a1d0ab Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 30 Nov 2018 19:07:52 +0800 Subject: [PATCH 0343/1995] ASoC: SOF: byt: fix IPC handled wrong issue Align with apl/cnl, to fix the issue with dmesg shows "error: rx list empty but received ...", add mask check for interrupt handling. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/byt.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index c4683e90eee902..219872463a70ec 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -367,21 +367,8 @@ static irqreturn_t byt_irq_handler(int irq, void *context) /* Interrupt arrived, check src */ isr = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_ISRX); - if (isr & SHIM_ISRX_DONE) { - /* Mask Done interrupt before return */ - snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_DONE, - SHIM_IMRX_DONE); + if (isr & (SHIM_ISRX_DONE | SHIM_ISRX_BUSY)) ret = IRQ_WAKE_THREAD; - } - - if (isr & SHIM_ISRX_BUSY) { - /* Mask Busy interrupt before return */ - snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_BUSY, - SHIM_IMRX_BUSY); - ret = IRQ_WAKE_THREAD; - } return ret; } @@ -390,11 +377,19 @@ static irqreturn_t byt_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; u64 ipcx, ipcd; + u64 imrx; + imrx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IMRX); ipcx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCX); /* reply message from DSP */ - if (ipcx & SHIM_BYT_IPCX_DONE) { + if (ipcx & SHIM_BYT_IPCX_DONE && + !(imrx & SHIM_IMRX_DONE)) { + /* Mask Done interrupt before first */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, + SHIM_IMRX, + SHIM_IMRX_DONE, + SHIM_IMRX_DONE); /* * handle immediate reply from DSP core. If the msg is * found, set done bit in cmd_done which is called at the @@ -408,7 +403,14 @@ static irqreturn_t byt_irq_thread(int irq, void *context) /* new message from DSP */ ipcd = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCD); - if (ipcd & SHIM_BYT_IPCD_BUSY) { + if (ipcd & SHIM_BYT_IPCD_BUSY && + !(imrx & SHIM_IMRX_BUSY)) { + /* Mask Busy interrupt before return */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, + SHIM_IMRX, + SHIM_IMRX_BUSY, + SHIM_IMRX_BUSY); + /* Handle messages from DSP Core */ if ((ipcd & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { snd_sof_dsp_panic(sdev, BYT_PANIC_OFFSET(ipcd) + From d7b104c1746778ae3ba33c417bac501aec821a64 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Tue, 4 Dec 2018 20:47:15 +0800 Subject: [PATCH 0344/1995] ASoC: SOF: intel: use kzalloc to allocate hdac_device snd_hdac_ext_bus_device_remove() will finally call kfree to free the hdac_device. Kernel will crash if we use devm_kzalloc to allocate the hdac_device and call snd_hdac_ext_bus_device_init() to init it. Signed-off-by: Bard liao --- sound/soc/sof/intel/hda-codec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 67e3d1ca24dcd2..4b93721f03b052 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -72,8 +72,8 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) address, resp); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) - hda_priv = devm_kzalloc(&hbus->pci->dev, sizeof(*hda_priv), - GFP_KERNEL); + /* snd_hdac_ext_bus_device_exit will use kfree to free hdev */ + hda_priv = kzalloc(sizeof(*hda_priv), GFP_KERNEL); if (!hda_priv) return -ENOMEM; @@ -92,8 +92,8 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) return 0; #else - hdev = devm_kzalloc(&hbus->pci->dev, sizeof(*hdev), - GFP_KERNEL); + /* snd_hdac_ext_bus_device_exit will use kfree to free hdev */ + hdev = kzalloc(sizeof(*hdev), GFP_KERNEL); if (!hdev) return -ENOMEM; From bbf1c4803971cba75f4f969119c23755cbabadd9 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Tue, 4 Dec 2018 17:44:42 +0800 Subject: [PATCH 0345/1995] ASoC: SOF: Intel: optimize write64() / read64() For write64() and read64(), switch to use writeq() and readq(). And apply these changes to all BYT/HSW/BDW/SKL+ platforms. Signed-off-by: Keyon Jie Signed-off-by: Bard liao --- sound/soc/sof/intel/bdw.c | 8 +++----- sound/soc/sof/intel/byt.c | 8 +++----- sound/soc/sof/intel/hda.c | 8 +++----- sound/soc/sof/intel/hsw.c | 8 +++----- 4 files changed, 12 insertions(+), 20 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 2e18b11746472b..edf46dce0a773f 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -141,15 +142,12 @@ static u32 bdw_read(struct snd_sof_dev *sdev, void __iomem *addr) static void bdw_write64(struct snd_sof_dev *sdev, void __iomem *addr, u64 value) { - memcpy_toio(addr, &value, sizeof(value)); + writeq(value, addr); } static u64 bdw_read64(struct snd_sof_dev *sdev, void __iomem *addr) { - u64 val; - - memcpy_fromio(&val, addr, sizeof(val)); - return val; + return readq(addr); } /* diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 219872463a70ec..6766c971d2488c 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -116,15 +117,12 @@ static u32 byt_read(struct snd_sof_dev *sdev, void __iomem *addr) static void byt_write64(struct snd_sof_dev *sdev, void __iomem *addr, u64 value) { - memcpy_toio(addr, &value, sizeof(value)); + writeq(value, addr); } static u64 byt_read64(struct snd_sof_dev *sdev, void __iomem *addr) { - u64 val; - - memcpy_fromio(&val, addr, sizeof(val)); - return val; + return readq(addr); } /* diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 160974bcd3c911..31d6108d3bff9f 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -57,15 +58,12 @@ u32 hda_dsp_read(struct snd_sof_dev *sdev, void __iomem *addr) void hda_dsp_write64(struct snd_sof_dev *sdev, void __iomem *addr, u64 value) { - memcpy_toio(addr, &value, sizeof(value)); + writeq(value, addr); } u64 hda_dsp_read64(struct snd_sof_dev *sdev, void __iomem *addr) { - u64 val; - - memcpy_fromio(&val, addr, sizeof(val)); - return val; + return readq(addr); } /* diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 555810476b78d2..675a75baff2eb9 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -141,15 +142,12 @@ static u32 hsw_read(struct snd_sof_dev *sdev, void __iomem *addr) static void hsw_write64(struct snd_sof_dev *sdev, void __iomem *addr, u64 value) { - memcpy_toio(addr, &value, sizeof(value)); + writeq(value, addr); } static u64 hsw_read64(struct snd_sof_dev *sdev, void __iomem *addr) { - u64 val; - - memcpy_fromio(&val, addr, sizeof(val)); - return val; + return readq(addr); } /* From b0eb2bedc44ca045c484809c3cb7e057b56861f3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 30 Nov 2018 17:49:10 -0600 Subject: [PATCH 0346/1995] ASoC: SOF: Intel: use __le32 type for BDL Fix issues reported by Sparse Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-loader-skl.c | 8 ++++---- sound/soc/sof/intel/hda-stream.c | 4 ++-- sound/soc/sof/intel/hda.h | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 6ae4f60f46ea40..106caf3fbf71b7 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -120,9 +120,9 @@ static int cl_skl_cldma_setup_bdle(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab_data, - u32 **bdlp, int size, int with_ioc) + __le32 **bdlp, int size, int with_ioc) { - u32 *bdl = *bdlp; + __le32 *bdl = *bdlp; int frags = 0; while (size > 0) { @@ -283,7 +283,7 @@ static int cl_stream_prepare_skl(struct snd_sof_dev *sdev) struct pci_dev *pci = sdev->pci; int frags = 0; int ret = 0; - u32 *bdl; + __le32 *bdl; unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, bufsize, @@ -302,7 +302,7 @@ static int cl_stream_prepare_skl(struct snd_sof_dev *sdev) return ret; } - bdl = (u32 *)sdev->dmab_bdl.area; + bdl = (__le32 *)sdev->dmab_bdl.area; frags = cl_skl_cldma_setup_bdle(sdev, &sdev->dmab, &bdl, bufsize, 1); cl_skl_cldma_setup_controller(sdev, &sdev->dmab_bdl, bufsize, frags); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 86d079e1d9ba00..bfcc0cd63a6693 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -56,8 +56,8 @@ static int hda_setup_bdle(struct snd_sof_dev *sdev, addr = snd_sgbuf_get_addr(dmab, offset); /* program BDL addr */ - bdl->addr_l = lower_32_bits(addr); - bdl->addr_h = upper_32_bits(addr); + bdl->addr_l = cpu_to_le32(lower_32_bits(addr)); + bdl->addr_h = cpu_to_le32(upper_32_bits(addr)); /* program BDL size */ chunk = snd_sgbuf_get_chunk_size(dmab, offset, size); /* one BDLE should not cross 4K boundary */ diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 6ffc733e9f5aea..d0ce487d2678f2 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -337,10 +337,10 @@ #define HDA_ADSP_ERROR_CODE_SKL (HDA_ADSP_FW_STATUS_SKL + 0x4) struct sof_intel_dsp_bdl { - u32 addr_l; - u32 addr_h; - u32 size; - u32 ioc; + __le32 addr_l; + __le32 addr_h; + __le32 size; + __le32 ioc; } __attribute((packed)); /* DSP hardware descriptor */ From 526a4d7889bc2d17d7c76a8196710364e5c72d3d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 30 Nov 2018 17:54:36 -0600 Subject: [PATCH 0347/1995] ASoC: SOF: Intel: hda-dai: remove {0} assignment Sparse complains about this, use memset instead Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-dai.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index c4aae26502c090..724ce957b1b07f 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -52,12 +52,13 @@ static int hda_link_dma_get_channels(struct snd_soc_dai *dai, { struct hdac_bus *bus; struct hdac_ext_stream *stream; - struct snd_pcm_substream substream = {0}; + struct snd_pcm_substream substream; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component); bus = sof_to_bus(sdev); + memset(&substream, 0, sizeof(substream)); if (*tx_num == 1) { substream.stream = SNDRV_PCM_STREAM_PLAYBACK; stream = snd_hdac_ext_stream_assign(bus, &substream, @@ -215,8 +216,9 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream, struct hdac_ext_stream *stream; struct snd_soc_pcm_runtime *rtd; struct hdac_ext_stream *link_dev; - struct snd_pcm_substream pcm_substream = {0}; + struct snd_pcm_substream pcm_substream; + memset(&pcm_substream, 0, sizeof(pcm_substream)); if (substream) { hstream = substream->runtime->private_data; bus = hstream->bus; From 092eb2b1e5e4c548fc7e80b377d5bc33003a1726 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 30 Nov 2018 18:07:39 -0600 Subject: [PATCH 0348/1995] ASoC: SOF: topology: use cpu_to_le32 Fix sparse issue Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index cbd6565037968e..1b267bc7106454 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -342,7 +342,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, return -EINVAL; } if (cdata->data->size + sizeof(const struct sof_abi_hdr) != - control->priv.size) { + le32_to_cpu(control->priv.size)) { dev_err(sdev->dev, "error: Conflict in bytes vs. priv size.\n"); return -EINVAL; From af642222e5197fd086a056f58c6a98850e68838b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 30 Nov 2018 18:10:30 -0600 Subject: [PATCH 0349/1995] ASoC: SOF: topology: remove {0} Sparse complains about this, use explicit memset Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/topology.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 1b267bc7106454..d9d5ee3351e8cc 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2181,7 +2181,7 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index, struct sof_ipc_dai_config *config) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_dai_link_component dai_component = {0}; + struct snd_soc_dai_link_component dai_component; struct snd_soc_tplg_private *private = &cfg->priv; struct snd_soc_dai *dai; @@ -2193,6 +2193,7 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index, int ret; /* init IPC */ + memset(&dai_component, 0, sizeof(dai_component)); memset(&config->hda, 0, sizeof(struct sof_ipc_dai_hda_params)); config->hdr.size = size; @@ -2344,10 +2345,11 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, static int sof_link_hda_unload(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link) { - struct snd_soc_dai_link_component dai_component = {0}; + struct snd_soc_dai_link_component dai_component; struct snd_soc_dai *dai; int ret = 0; + memset(&dai_component, 0, sizeof(dai_component)); dai_component.dai_name = link->cpu_dai_name; dai = snd_soc_find_dai(&dai_component); if (!dai) { From 62e8db9df769d7fd7879cc80e71c48df6dd059b3 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Wed, 5 Dec 2018 11:41:45 +0800 Subject: [PATCH 0350/1995] [DEBUG][CI]travis: add more build checks Add Werror and Wall flag to check if there are any warnings. Add sparse check. Signed-off-by: Pan Xiuli --- .travis.yml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index f6803541df8691..b5c403c9d60b3d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ git: before_install: - sudo apt-get update -qq - - sudo apt-get install python-ply python-git libelf-dev codespell + - sudo apt-get install python-ply python-git libelf-dev codespell sparse - git clone https://github.com/thesofproject/kconfig.git jobs: @@ -16,17 +16,22 @@ jobs: - SHA_PR=`git log --oneline -1 | sed -rn "s/.*Merge (.*) into.*/\1/p"` - SHA_MAIN=`git log --oneline -1 | sed -rn "s/.*Merge .* into (.*)/\1/p"` - scripts/checkpatch.pl --strict --codespell -g $SHA_MAIN..$SHA_PR + - name: "sparse check" + script: + - export ARCH=x86_64 + - make defconfig + - scripts/kconfig/merge_config.sh .config kconfig/base-defconfig kconfig/sof-defconfig kconfig/hdaudio-codecs-defconfig + - make modules_prepare + - make SUBDIRS=sound/soc/sof C=2 - name: "BUILD SOF Kernel x86_64" script: - export ARCH=x86_64 - make defconfig - scripts/kconfig/merge_config.sh .config kconfig/base-defconfig kconfig/sof-defconfig - - echo `getconf _NPROCESSORS_ONLN` - - make -j`getconf _NPROCESSORS_ONLN` + - KCFLAGS="-Wall -Werror" make -j`getconf _NPROCESSORS_ONLN` - name: "BUILD SST Kernel x86_64" script: - export ARCH=x86_64 - make defconfig - scripts/kconfig/merge_config.sh .config kconfig/base-defconfig kconfig/sst-defconfig - - echo `getconf _NPROCESSORS_ONLN` - - make -j`getconf _NPROCESSORS_ONLN` + - KCFLAGS="-Wall -Werror" make -j`getconf _NPROCESSORS_ONLN` From 4052ad89a474a84b2bae05680f126ec9a42c85a9 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 5 Dec 2018 08:24:51 -0800 Subject: [PATCH 0351/1995] ASoC: SOF: remove duplicate controller reset for HDA platforms For HDA platforms, hda_dsp_ctrl_init_chip() does a full controller reset. So move the duplicate controller reset calls that were added for non-HDA platforms into the else block. This should fix the failures seen with suspend/resume stress tests on GLK. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dsp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 7ae95644a784e6..d5975795fa791b 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -338,7 +338,7 @@ static int hda_resume(struct snd_sof_dev *sdev) /* enable ppcap interrupt */ snd_hdac_ext_bus_ppcap_enable(bus, true); snd_hdac_ext_bus_ppcap_int_enable(bus, true); -#endif +#else /* reset controller */ ret = hda_dsp_ctrl_link_reset(sdev, true); @@ -355,6 +355,7 @@ static int hda_resume(struct snd_sof_dev *sdev) "error: failed to ready controller during resume\n"); return ret; } +#endif /* power up the DSP */ ret = hda_dsp_core_power_up(sdev, chip->cores_mask); From 0dd835f66675c9dc32311bc256d75846c03c9b37 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 5 Dec 2018 16:34:07 -0600 Subject: [PATCH 0352/1995] ASoC: SOF: Intel: Harden DSP detection with class/subclass/prog-if The use of PPCAP and GCAP to detect the DSP presence is not reliable or meaningful. The recommendation is to use the class/subclass/prog-if information instead (as done by Windows drivers) Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 31d6108d3bff9f..d3343c2e8ef359 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -524,6 +524,22 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) const struct sof_intel_dsp_desc *chip; int sd_offset, ret = 0; + /* + * detect DSP by checking class/subclass/prog-id information + * class=04 subclass 03 prog-if 00: no DSP, legacy driver is required + * class=04 subclass 01 prog-if 00: DSP is present + * (and may be required e.g. for DMIC or SSP support) + * class=04 subclass 03 prog-if 80: either of DSP or legacy mode works + */ + if (pci->class == 0x040300) { + dev_err(sdev->dev, "The DSP is not enabled on this platform, aborting probe\n"); + return -ENODEV; + } else if (pci->class != 0x040100 && pci->class != 0x040380) { + dev_err(sdev->dev, "Unknown PCI class/subclass/prog-if 0x%06x found, aborting probe\n", pci->class); + return -ENODEV; + } + dev_info(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n", pci->class); + /* set DSP arch ops */ sdev->arch_ops = &sof_xtensa_arch_ops; From 6536401915d72710faa10d3ec335decdd904fb35 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 5 Dec 2018 17:12:06 -0600 Subject: [PATCH 0353/1995] ASoC: SOF: harden error flow for machine driver selection Make sure there are no memory allocation issues and double-check that a machine driver is found in the end. Reported-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-acpi-dev.c | 2 ++ sound/soc/sof/sof-pci-dev.c | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 71327b875e3da3..7724bc4fcfcc96 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -181,6 +181,8 @@ static int sof_acpi_probe(struct platform_device *pdev) /* force nocodec mode */ dev_warn(dev, "Force to use nocodec mode\n"); mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); + if (!mach) + return -ENOMEM; ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); if (ret < 0) return ret; diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index f60b8bae5b6dd3..59d2710ff2bbf5 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -203,6 +203,10 @@ static int sof_pci_probe(struct pci_dev *pci, /* force nocodec mode */ dev_warn(dev, "Force to use nocodec mode\n"); mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); + if (!mach) { + ret = -ENOMEM; + goto release_regions; + } ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); if (ret < 0) goto release_regions; @@ -227,6 +231,10 @@ static int sof_pci_probe(struct pci_dev *pci, /* fallback to nocodec mode */ dev_warn(dev, "No matching ASoC machine driver found - using nocodec\n"); mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); + if (!mach) { + ret = -ENOMEM; + goto release_regions; + } ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); if (ret < 0) goto release_regions; @@ -235,6 +243,12 @@ static int sof_pci_probe(struct pci_dev *pci, #endif /* CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE */ + if (!mach) { + dev_err(dev, "No matching ASoC machine driver found - aborting probe\n"); + ret = -ENODEV; + goto release_regions; + } + mach->pdata = ops; sof_pdata->id = pci_id->device; From c8a04a18de27b383cb1839f528a481dc73d802f5 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Tue, 4 Dec 2018 17:44:42 +0800 Subject: [PATCH 0354/1995] ASoC: SOF: Intel: optimize block_write() and move comon ops to utils.c For block_write(), optimize the connection of fragment bytes. As all BYT/HSW/BDW/SKL+ platforms are actually using same write() / read() / write64() / read64() / block_read() / block_write() / mailbox_read() / mailbox_write(), so move them to utils.c. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/apl.c | 16 ++-- sound/soc/sof/intel/bdw.c | 108 ++++---------------------- sound/soc/sof/intel/byt.c | 125 ++++++------------------------- sound/soc/sof/intel/cnl.c | 20 ++--- sound/soc/sof/intel/hda-ipc.c | 13 ++-- sound/soc/sof/intel/hda-stream.c | 2 +- sound/soc/sof/intel/hda.c | 98 ++---------------------- sound/soc/sof/intel/hda.h | 16 ---- sound/soc/sof/intel/hsw.c | 108 ++++---------------------- sound/soc/sof/intel/skl.c | 16 ++-- sound/soc/sof/sof-priv.h | 13 ++++ sound/soc/sof/utils.c | 106 ++++++++++++++++++++++++++ 12 files changed, 213 insertions(+), 428 deletions(-) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 7e28fba1768239..0f10e2a100cc4d 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -45,22 +45,22 @@ struct snd_sof_dsp_ops sof_apl_ops = { .remove = hda_dsp_remove, /* Register IO */ - .write = hda_dsp_write, - .read = hda_dsp_read, - .write64 = hda_dsp_write64, - .read64 = hda_dsp_read64, + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, /* Block IO */ - .block_read = hda_dsp_block_read, - .block_write = hda_dsp_block_write, + .block_read = sof_block_read, + .block_write = sof_block_write, /* doorbell */ .irq_handler = hda_dsp_ipc_irq_handler, .irq_thread = hda_dsp_ipc_irq_thread, /* mailbox */ - .mailbox_read = hda_dsp_mailbox_read, - .mailbox_write = hda_dsp_mailbox_write, + .mailbox_read = sof_mailbox_read, + .mailbox_write = sof_mailbox_write, /* ipc */ .send_msg = hda_dsp_ipc_send_msg, diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index edf46dce0a773f..8cbe5af59d07e2 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -74,82 +74,6 @@ static const struct snd_sof_debugfs_map bdw_debugfs[] = { static int bdw_cmd_done(struct snd_sof_dev *sdev, int dir); -/* - * Memory copy. - */ - -/* write has to deal with copying non 32 bit sized data */ -static void bdw_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, - size_t size) -{ - void __iomem *dest = sdev->bar[sdev->mmio_bar] + offset; - u32 tmp = 0; - int i, m, n; - const u8 *src_byte = src; - - m = size / 4; - n = size % 4; - - /* __iowrite32_copy use 32bit size values so divide by 4 */ - __iowrite32_copy(dest, src, m); - - if (n) { - for (i = 0; i < n; i++) - tmp |= (u32)*(src_byte + m * 4 + i) << (i * 8); - __iowrite32_copy(dest + m * 4, &tmp, 1); - } -} - -static void bdw_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, - size_t size) -{ - void __iomem *src = sdev->bar[sdev->mmio_bar] + offset; - - memcpy_fromio(dest, src, size); -} - -static void bdw_mailbox_write(struct snd_sof_dev *sdev, u32 offset, - void *message, size_t bytes) -{ - void __iomem *dest = sdev->bar[sdev->mailbox_bar] + offset; - - memcpy_toio(dest, message, bytes); -} - -static void bdw_mailbox_read(struct snd_sof_dev *sdev, u32 offset, - void *message, size_t bytes) -{ - void __iomem *src = sdev->bar[sdev->mailbox_bar] + offset; - - memcpy_fromio(message, src, bytes); -} - -/* - * Register IO - */ - -static void bdw_write(struct snd_sof_dev *sdev, void __iomem *addr, - u32 value) -{ - writel(value, addr); -} - -static u32 bdw_read(struct snd_sof_dev *sdev, void __iomem *addr) -{ - return readl(addr); -} - -static void bdw_write64(struct snd_sof_dev *sdev, void __iomem *addr, - u64 value) -{ - writeq(value, addr); -} - -static u64 bdw_read64(struct snd_sof_dev *sdev, void __iomem *addr) -{ - return readq(addr); -} - /* * DSP Control. */ @@ -299,14 +223,14 @@ static void bdw_get_registers(struct snd_sof_dev *sdev, u32 *stack, size_t stack_words) { /* first read regsisters */ - bdw_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); + sof_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); /* then get panic info */ - bdw_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), + sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), panic_info, sizeof(*panic_info)); /* then get the stack */ - bdw_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + + sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + sizeof(*panic_info), stack, stack_words * sizeof(u32)); } @@ -368,7 +292,7 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) /* reply message from DSP */ if (ipcx & SHIM_IPCX_DONE) { /* Handle Immediate reply from DSP Core */ - bdw_mailbox_read(sdev, sdev->host_box.offset, &hdr, + sof_mailbox_read(sdev, sdev->host_box.offset, &hdr, sizeof(hdr)); /* @@ -511,7 +435,7 @@ static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) msg_id, offset); /* copy data from the DSP FW ready offset */ - bdw_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); + sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, fw_ready->dspbox_size, @@ -553,7 +477,7 @@ static int bdw_is_ready(struct snd_sof_dev *sdev) static int bdw_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { /* send the message */ - bdw_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, msg->msg_size); snd_sof_dsp_write(sdev, BDW_DSP_BAR, SHIM_IPCX, SHIM_IPCX_BUSY); @@ -567,7 +491,7 @@ static int bdw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) u32 size; /* get reply */ - bdw_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); + sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); if (reply.error < 0) { size = sizeof(reply); ret = reply.error; @@ -585,7 +509,7 @@ static int bdw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) /* read the message */ if (msg->msg_data && size > 0) - bdw_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, + sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, size); return ret; @@ -751,18 +675,18 @@ struct snd_sof_dsp_ops sof_bdw_ops = { .reset = bdw_reset, /* Register IO */ - .read = bdw_read, - .write = bdw_write, - .read64 = bdw_read64, - .write64 = bdw_write64, + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, /* Block IO */ - .block_read = bdw_block_read, - .block_write = bdw_block_write, + .block_read = sof_block_read, + .block_write = sof_block_write, /* mailbox */ - .mailbox_read = bdw_mailbox_read, - .mailbox_write = bdw_mailbox_write, + .mailbox_read = sof_mailbox_read, + .mailbox_write = sof_mailbox_write, /* ipc */ .send_msg = bdw_send_msg, diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 6766c971d2488c..99571bd1560c86 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -99,65 +99,6 @@ static const struct snd_sof_debugfs_map cht_debugfs[] = { static int byt_cmd_done(struct snd_sof_dev *sdev, int dir); -/* - * Register IO - */ - -static void byt_write(struct snd_sof_dev *sdev, void __iomem *addr, - u32 value) -{ - writel(value, addr); -} - -static u32 byt_read(struct snd_sof_dev *sdev, void __iomem *addr) -{ - return readl(addr); -} - -static void byt_write64(struct snd_sof_dev *sdev, void __iomem *addr, - u64 value) -{ - writeq(value, addr); -} - -static u64 byt_read64(struct snd_sof_dev *sdev, void __iomem *addr) -{ - return readq(addr); -} - -/* - * Memory copy. - */ - -static void byt_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, - size_t size) -{ - void __iomem *dest = sdev->bar[sdev->mmio_bar] + offset; - u32 tmp = 0; - int i, m, n; - const u8 *src_byte = src; - - m = size / 4; - n = size % 4; - - /* __iowrite32_copy use 32bit size values so divide by 4 */ - __iowrite32_copy(dest, src, m); - - if (n) { - for (i = 0; i < n; i++) - tmp |= (u32)*(src_byte + m * 4 + i) << (i * 8); - __iowrite32_copy(dest + m * 4, &tmp, 1); - } -} - -static void byt_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, - size_t size) -{ - void __iomem *src = sdev->bar[sdev->mmio_bar] + offset; - - memcpy_fromio(dest, src, size); -} - /* * IPC Firmware ready. */ @@ -271,7 +212,7 @@ static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) msg_id, offset); /* copy data from the DSP FW ready offset */ - byt_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); + sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, fw_ready->dspbox_size, @@ -295,26 +236,6 @@ static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return 0; } -/* - * IPC Mailbox IO - */ - -static void byt_mailbox_write(struct snd_sof_dev *sdev, u32 offset, - void *message, size_t bytes) -{ - void __iomem *dest = sdev->bar[sdev->mailbox_bar] + offset; - - memcpy_toio(dest, message, bytes); -} - -static void byt_mailbox_read(struct snd_sof_dev *sdev, u32 offset, - void *message, size_t bytes) -{ - void __iomem *src = sdev->bar[sdev->mailbox_bar] + offset; - - memcpy_fromio(message, src, bytes); -} - /* * Debug */ @@ -325,14 +246,14 @@ static void byt_get_registers(struct snd_sof_dev *sdev, u32 *stack, size_t stack_words) { /* first read regsisters */ - byt_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); + sof_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); /* then get panic info */ - byt_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), + sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), panic_info, sizeof(*panic_info)); /* then get the stack */ - byt_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + + sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + sizeof(*panic_info), stack, stack_words * sizeof(u32)); } @@ -437,7 +358,7 @@ static int byt_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) u64 cmd = msg->header; /* send the message */ - byt_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, msg->msg_size); snd_sof_dsp_write64(sdev, BYT_DSP_BAR, SHIM_IPCX, cmd | SHIM_BYT_IPCX_BUSY); @@ -452,7 +373,7 @@ static int byt_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) u32 size; /* get reply */ - byt_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); + sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); if (reply.error < 0) { size = sizeof(reply); ret = reply.error; @@ -470,7 +391,7 @@ static int byt_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) /* read the message */ if (msg->msg_data && size > 0) - byt_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, + sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, size); return ret; @@ -799,22 +720,22 @@ struct snd_sof_dsp_ops sof_byt_ops = { .reset = byt_reset, /* Register IO */ - .write = byt_write, - .read = byt_read, - .write64 = byt_write64, - .read64 = byt_read64, + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, /* Block IO */ - .block_read = byt_block_read, - .block_write = byt_block_write, + .block_read = sof_block_read, + .block_write = sof_block_write, /* doorbell */ .irq_handler = byt_irq_handler, .irq_thread = byt_irq_thread, /* mailbox */ - .mailbox_read = byt_mailbox_read, - .mailbox_write = byt_mailbox_write, + .mailbox_read = sof_mailbox_read, + .mailbox_write = sof_mailbox_write, /* ipc */ .send_msg = byt_send_msg, @@ -850,22 +771,22 @@ struct snd_sof_dsp_ops sof_cht_ops = { .reset = byt_reset, /* Register IO */ - .write = byt_write, - .read = byt_read, - .write64 = byt_write64, - .read64 = byt_read64, + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, /* Block IO */ - .block_read = byt_block_read, - .block_write = byt_block_write, + .block_read = sof_block_read, + .block_write = sof_block_write, /* doorbell */ .irq_handler = byt_irq_handler, .irq_thread = byt_irq_thread, /* mailbox */ - .mailbox_read = byt_mailbox_read, - .mailbox_write = byt_mailbox_write, + .mailbox_read = sof_mailbox_read, + .mailbox_write = sof_mailbox_write, /* ipc */ .send_msg = byt_send_msg, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index b561d287368592..76ab0be961b008 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -180,8 +180,8 @@ static int cnl_ipc_send_msg(struct snd_sof_dev *sdev, u32 cmd = msg->header; /* send the message */ - hda_dsp_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, - msg->msg_size); + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, cmd | CNL_DSP_REG_HIPCIDR_BUSY); @@ -195,22 +195,22 @@ struct snd_sof_dsp_ops sof_cnl_ops = { .remove = hda_dsp_remove, /* Register IO */ - .write = hda_dsp_write, - .read = hda_dsp_read, - .write64 = hda_dsp_write64, - .read64 = hda_dsp_read64, + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, /* Block IO */ - .block_read = hda_dsp_block_read, - .block_write = hda_dsp_block_write, + .block_read = sof_block_read, + .block_write = sof_block_write, /* doorbell */ .irq_handler = hda_dsp_ipc_irq_handler, .irq_thread = cnl_ipc_irq_thread, /* mailbox */ - .mailbox_read = hda_dsp_mailbox_read, - .mailbox_write = hda_dsp_mailbox_write, + .mailbox_read = sof_mailbox_read, + .mailbox_write = sof_mailbox_write, /* ipc */ .send_msg = cnl_ipc_send_msg, diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index efaf293c2c77dc..c307a8a67e839c 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -88,8 +88,8 @@ int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) u32 cmd = msg->header; /* send IPC message to DSP */ - hda_dsp_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, - msg->msg_size); + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI, cmd | HDA_DSP_REG_HIPCI_BUSY); @@ -104,8 +104,7 @@ int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev, u32 size; /* get IPC reply from DSP in the mailbox */ - hda_dsp_mailbox_read(sdev, sdev->host_box.offset, &reply, - sizeof(reply)); + sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); if (reply.error < 0) { size = sizeof(reply); ret = reply.error; @@ -123,8 +122,8 @@ int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev, /* read the message */ if (msg->msg_data && size > 0) - hda_dsp_mailbox_read(sdev, sdev->host_box.offset, - msg->reply_data, size); + sof_mailbox_read(sdev, sdev->host_box.offset, + msg->reply_data, size); return ret; } @@ -381,7 +380,7 @@ int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) msg_id, offset); /* copy data from the DSP FW ready offset */ - hda_dsp_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); + sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); dev_info(sdev->dev, " Firmware info: version %d.%d-%s build %d on %s:%s\n", v->major, v->minor, v->tag, v->build, v->date, v->time); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index bfcc0cd63a6693..0c9c2d794061d3 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -155,7 +155,7 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, enable << hstream->index); /* set the SPIB value */ - hda_dsp_write(sdev, stream->spib_addr, size); + sof_io_write(sdev, stream->spib_addr, size); return 0; } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index d3343c2e8ef359..11a2322e9a1e68 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -42,72 +42,6 @@ /* platform specific devices */ #include "shim.h" -/* - * Register IO - */ - -void hda_dsp_write(struct snd_sof_dev *sdev, void __iomem *addr, u32 value) -{ - writel(value, addr); -} - -u32 hda_dsp_read(struct snd_sof_dev *sdev, void __iomem *addr) -{ - return readl(addr); -} - -void hda_dsp_write64(struct snd_sof_dev *sdev, void __iomem *addr, u64 value) -{ - writeq(value, addr); -} - -u64 hda_dsp_read64(struct snd_sof_dev *sdev, void __iomem *addr) -{ - return readq(addr); -} - -/* - * Memory copy. - */ - -void hda_dsp_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, - size_t size) -{ - void __iomem *dest = sdev->bar[sdev->mmio_bar] + offset; - u32 tmp = 0; - int i, m, n; - const u8 *src_byte = src; - u8 *dst_byte; - - m = size / 4; - n = size % 4; - - /* __iowrite32_copy use 32bit size values so divide by 4 */ - __iowrite32_copy(dest, src, m); - - if (n) { - /* first read the 32bit data of dest, then change affected - * bytes, and write back to dest. For unaffected bytes, it - * should not be changed - */ - __ioread32_copy(&tmp, dest + m * 4, 1); - - dst_byte = (u8 *)&tmp; - for (i = 0; i < n; i++) - dst_byte[i] = src_byte[m * 4 + i]; - - __iowrite32_copy(dest + m * 4, &tmp, 1); - } -} - -void hda_dsp_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, - size_t size) -{ - void __iomem *src = sdev->bar[sdev->mmio_bar] + offset; - - memcpy_fromio(dest, src, size); -} - /* * Debug */ @@ -185,16 +119,16 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev, u32 *stack, size_t stack_words) { /* first read registers */ - hda_dsp_block_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); + sof_block_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); /* then get panic info */ - hda_dsp_block_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), - panic_info, sizeof(*panic_info)); + sof_block_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), + panic_info, sizeof(*panic_info)); /* then get the stack */ - hda_dsp_block_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + - sizeof(*panic_info), stack, - stack_words * sizeof(u32)); + sof_block_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + + sizeof(*panic_info), stack, + stack_words * sizeof(u32)); } void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags) @@ -254,26 +188,6 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) } } -/* - * IPC Mailbox IO - */ - -void hda_dsp_mailbox_write(struct snd_sof_dev *sdev, u32 offset, - void *message, size_t bytes) -{ - void __iomem *dest = sdev->bar[sdev->mailbox_bar] + offset; - - memcpy_toio(dest, message, bytes); -} - -void hda_dsp_mailbox_read(struct snd_sof_dev *sdev, u32 offset, - void *message, size_t bytes) -{ - void __iomem *src = sdev->bar[sdev->mailbox_bar] + offset; - - memcpy_fromio(message, src, bytes); -} - /* * Supported devices. */ diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index d0ce487d2678f2..8a31e60068af51 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -413,22 +413,6 @@ int hda_dsp_runtime_resume(struct snd_sof_dev *sdev); void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags); void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags); -/* - * DSP IO - */ -void hda_dsp_write(struct snd_sof_dev *sdev, void __iomem *addr, u32 value); -u32 hda_dsp_read(struct snd_sof_dev *sdev, void __iomem *addr); -void hda_dsp_write64(struct snd_sof_dev *sdev, void __iomem *addr, u64 value); -u64 hda_dsp_read64(struct snd_sof_dev *sdev, void __iomem *addr); -void hda_dsp_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, - size_t size); -void hda_dsp_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, - size_t size); -void hda_dsp_mailbox_write(struct snd_sof_dev *sdev, u32 offset, - void *message, size_t bytes); -void hda_dsp_mailbox_read(struct snd_sof_dev *sdev, u32 offset, - void *message, size_t bytes); - /* * DSP PCM Operations. */ diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 675a75baff2eb9..0a329bc5a30f70 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -74,82 +74,6 @@ static const struct snd_sof_debugfs_map hsw_debugfs[] = { static int hsw_cmd_done(struct snd_sof_dev *sdev, int dir); -/* - * Memory copy. - */ - -/* write has to deal with copying non 32 bit sized data */ -static void hsw_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, - size_t size) -{ - void __iomem *dest = sdev->bar[sdev->mmio_bar] + offset; - u32 tmp = 0; - int i, m, n; - const u8 *src_byte = src; - - m = size / 4; - n = size % 4; - - /* __iowrite32_copy use 32bit size values so divide by 4 */ - __iowrite32_copy(dest, src, m); - - if (n) { - for (i = 0; i < n; i++) - tmp |= (u32)*(src_byte + m * 4 + i) << (i * 8); - __iowrite32_copy(dest + m * 4, &tmp, 1); - } -} - -static void hsw_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, - size_t size) -{ - void __iomem *src = sdev->bar[sdev->mmio_bar] + offset; - - memcpy_fromio(dest, src, size); -} - -static void hsw_mailbox_write(struct snd_sof_dev *sdev, u32 offset, - void *message, size_t bytes) -{ - void __iomem *dest = sdev->bar[sdev->mailbox_bar] + offset; - - memcpy_toio(dest, message, bytes); -} - -static void hsw_mailbox_read(struct snd_sof_dev *sdev, u32 offset, - void *message, size_t bytes) -{ - void __iomem *src = sdev->bar[sdev->mailbox_bar] + offset; - - memcpy_fromio(message, src, bytes); -} - -/* - * Register IO - */ - -static void hsw_write(struct snd_sof_dev *sdev, void __iomem *addr, - u32 value) -{ - writel(value, addr); -} - -static u32 hsw_read(struct snd_sof_dev *sdev, void __iomem *addr) -{ - return readl(addr); -} - -static void hsw_write64(struct snd_sof_dev *sdev, void __iomem *addr, - u64 value) -{ - writeq(value, addr); -} - -static u64 hsw_read64(struct snd_sof_dev *sdev, void __iomem *addr) -{ - return readq(addr); -} - /* * DSP Control. */ @@ -297,14 +221,14 @@ static void hsw_get_registers(struct snd_sof_dev *sdev, u32 *stack, size_t stack_words) { /* first read regsisters */ - hsw_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); + sof_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); /* then get panic info */ - hsw_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), + sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), panic_info, sizeof(*panic_info)); /* then get the stack */ - hsw_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + + sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + sizeof(*panic_info), stack, stack_words * sizeof(u32)); } @@ -369,7 +293,7 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) /* reply message from DSP */ if (ipcx & SHIM_IPCX_DONE) { /* Handle Immediate reply from DSP Core */ - hsw_mailbox_read(sdev, sdev->host_box.offset, &hdr, + sof_mailbox_read(sdev, sdev->host_box.offset, &hdr, sizeof(hdr)); /* @@ -512,7 +436,7 @@ static int hsw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) msg_id, offset); /* copy data from the DSP FW ready offset */ - hsw_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); + sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, fw_ready->dspbox_size, @@ -554,7 +478,7 @@ static int hsw_is_ready(struct snd_sof_dev *sdev) static int hsw_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { /* send the message */ - hsw_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, msg->msg_size); snd_sof_dsp_write(sdev, HSW_DSP_BAR, SHIM_IPCX, SHIM_IPCX_BUSY); @@ -568,7 +492,7 @@ static int hsw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) u32 size; /* get reply */ - hsw_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); + sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); if (reply.error < 0) { size = sizeof(reply); ret = reply.error; @@ -586,7 +510,7 @@ static int hsw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) /* read the message */ if (msg->msg_data && size > 0) - hsw_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, + sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, size); return ret; } @@ -751,18 +675,18 @@ struct snd_sof_dsp_ops sof_hsw_ops = { .reset = hsw_reset, /* Register IO */ - .read = hsw_read, - .write = hsw_write, - .read64 = hsw_read64, - .write64 = hsw_write64, + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, /* Block IO */ - .block_read = hsw_block_read, - .block_write = hsw_block_write, + .block_read = sof_block_read, + .block_write = sof_block_write, /* mailbox */ - .mailbox_read = hsw_mailbox_read, - .mailbox_write = hsw_mailbox_write, + .mailbox_read = sof_mailbox_read, + .mailbox_write = sof_mailbox_write, /* ipc */ .send_msg = hsw_send_msg, diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 9531d531478ad9..83a61d58d3c1b6 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -45,22 +45,22 @@ struct snd_sof_dsp_ops sof_skl_ops = { .remove = hda_dsp_remove, /* Register IO */ - .write = hda_dsp_write, - .read = hda_dsp_read, - .write64 = hda_dsp_write64, - .read64 = hda_dsp_read64, + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, /* Block IO */ - .block_read = hda_dsp_block_read, - .block_write = hda_dsp_block_write, + .block_read = sof_block_read, + .block_write = sof_block_write, /* doorbell */ .irq_handler = hda_dsp_ipc_irq_handler, .irq_thread = hda_dsp_ipc_irq_thread, /* mailbox */ - .mailbox_read = hda_dsp_mailbox_read, - .mailbox_write = hda_dsp_mailbox_write, + .mailbox_read = sof_mailbox_read, + .mailbox_write = sof_mailbox_write, /* ipc */ .send_msg = hda_dsp_ipc_send_msg, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 61069d77c5151a..5c311e437c58c2 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -570,4 +570,17 @@ extern const struct sof_arch_ops sof_xtensa_arch_ops; * Utilities */ int sof_create_platform_device(struct sof_platform_priv *priv); +void sof_io_write(struct snd_sof_dev *sdev, void __iomem *addr, u32 value); +void sof_io_write64(struct snd_sof_dev *sdev, void __iomem *addr, u64 value); +u32 sof_io_read(struct snd_sof_dev *sdev, void __iomem *addr); +u64 sof_io_read64(struct snd_sof_dev *sdev, void __iomem *addr); +void sof_mailbox_write(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes); +void sof_mailbox_read(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes); +void sof_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, + size_t size); +void sof_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, + size_t size); + #endif diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index 23597064b8e33b..de2b4fa8a66329 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -9,6 +9,7 @@ // #include +#include #include #include #include @@ -66,3 +67,108 @@ int sof_create_platform_device(struct sof_platform_priv *priv) return 0; } EXPORT_SYMBOL(sof_create_platform_device); + +/* + * Register IO + */ + +void sof_io_write(struct snd_sof_dev *sdev, void __iomem *addr, u32 value) +{ + writel(value, addr); +} +EXPORT_SYMBOL(sof_io_write); + +u32 sof_io_read(struct snd_sof_dev *sdev, void __iomem *addr) +{ + return readl(addr); +} +EXPORT_SYMBOL(sof_io_read); + +void sof_io_write64(struct snd_sof_dev *sdev, void __iomem *addr, u64 value) +{ +#ifdef CONFIG_64BIT + writeq(value, addr); +#else + memcpy_toio(addr, &value, sizeof(value)); +#endif +} +EXPORT_SYMBOL(sof_io_write64); + +u64 sof_io_read64(struct snd_sof_dev *sdev, void __iomem *addr) +{ +#ifdef CONFIG_64BIT + return readq(addr); +#else + u64 val; + + memcpy_fromio(&val, addr, sizeof(val)); + return val; +#endif +} +EXPORT_SYMBOL(sof_io_read64); + +/* + * IPC Mailbox IO + */ + +void sof_mailbox_write(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes) +{ + void __iomem *dest = sdev->bar[sdev->mailbox_bar] + offset; + + memcpy_toio(dest, message, bytes); +} +EXPORT_SYMBOL(sof_mailbox_write); + +void sof_mailbox_read(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes) +{ + void __iomem *src = sdev->bar[sdev->mailbox_bar] + offset; + + memcpy_fromio(message, src, bytes); +} +EXPORT_SYMBOL(sof_mailbox_read); + +/* + * Memory copy. + */ + +void sof_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, + size_t size) +{ + void __iomem *dest = sdev->bar[sdev->mmio_bar] + offset; + const u8 *src_byte = src; + u32 affected_mask; + u32 tmp = 0; + int m, n; + + m = size / 4; + n = size % 4; + + /* __iowrite32_copy use 32bit size values so divide by 4 */ + __iowrite32_copy(dest, src, m); + + if (n) { + affected_mask = (1 << (8 * n)) - 1; + + /* first read the 32bit data of dest, then change affected + * bytes, and write back to dest. For unaffected bytes, it + * should not be changed + */ + __ioread32_copy(&tmp, dest + m * 4, 1); + tmp &= ~affected_mask; + + tmp |= *(u32 *)(src_byte + m * 4) & affected_mask; + __iowrite32_copy(dest + m * 4, &tmp, 1); + } +} +EXPORT_SYMBOL(sof_block_write); + +void sof_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, + size_t size) +{ + void __iomem *src = sdev->bar[sdev->mmio_bar] + offset; + + memcpy_fromio(dest, src, size); +} +EXPORT_SYMBOL(sof_block_read); From ef42b5338bbf852634d794751e52426e1997a6cb Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Thu, 6 Dec 2018 13:14:11 +0800 Subject: [PATCH 0355/1995] ASoC: SOF: remove unnecessary header files including Only keep header files we do need included. Signed-off-by: Keyon Jie --- include/sound/sof.h | 5 ----- sound/soc/sof/compressed.c | 7 ------- sound/soc/sof/control.c | 6 ------ sound/soc/sof/core.c | 7 ------- sound/soc/sof/debug.c | 8 -------- sound/soc/sof/intel/apl.c | 14 -------------- sound/soc/sof/intel/bdw.c | 12 ------------ sound/soc/sof/intel/byt.c | 12 ------------ sound/soc/sof/intel/cnl.c | 14 -------------- sound/soc/sof/intel/hda-bus.c | 2 -- sound/soc/sof/intel/hda-codec.c | 10 ---------- sound/soc/sof/intel/hda-ctrl.c | 13 ------------- sound/soc/sof/intel/hda-dai.c | 1 - sound/soc/sof/intel/hda-dsp.c | 14 -------------- sound/soc/sof/intel/hda-ipc.c | 14 -------------- sound/soc/sof/intel/hda-loader-skl.c | 12 ------------ sound/soc/sof/intel/hda-loader.c | 11 ----------- sound/soc/sof/intel/hda-pcm.c | 12 ------------ sound/soc/sof/intel/hda-stream.c | 11 ----------- sound/soc/sof/intel/hda-trace.c | 13 ------------- sound/soc/sof/intel/hda.c | 14 -------------- sound/soc/sof/intel/hsw.c | 12 ------------ sound/soc/sof/intel/skl.c | 14 -------------- sound/soc/sof/ipc.c | 19 ------------------- sound/soc/sof/loader.c | 10 ---------- sound/soc/sof/nocodec.c | 6 ------ sound/soc/sof/ops.c | 6 ------ sound/soc/sof/pcm.c | 12 ------------ sound/soc/sof/pm.c | 10 ---------- sound/soc/sof/sof-acpi-dev.c | 9 +-------- sound/soc/sof/sof-pci-dev.c | 5 ----- sound/soc/sof/sof-priv.h | 10 ---------- sound/soc/sof/topology.c | 12 ------------ sound/soc/sof/trace.c | 10 ---------- sound/soc/sof/utils.c | 1 - sound/soc/sof/xtensa/core.c | 8 -------- 36 files changed, 1 insertion(+), 355 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index fea176e35551f9..4ed6e23791412e 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -11,11 +11,6 @@ #ifndef __INCLUDE_SOUND_SOF_H #define __INCLUDE_SOUND_SOF_H -#include -#include -#include -#include -#include #include #include #include diff --git a/sound/soc/sof/compressed.c b/sound/soc/sof/compressed.c index 3de2fab3075088..fba5f8a931ffad 100644 --- a/sound/soc/sof/compressed.c +++ b/sound/soc/sof/compressed.c @@ -8,15 +8,8 @@ // Author: Liam Girdwood // -#include -#include #include -#include #include -#include -#include -#include -#include #include "sof-priv.h" #define DRV_NAME "sof-audio" diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 47a059be02310d..2000f62e931b6e 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -10,13 +10,7 @@ /* Mixer Controls */ -#include -#include #include -#include -#include -#include -#include #include "sof-priv.h" static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index ff809ef1fee782..8836e0eba4eae4 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -8,14 +8,7 @@ // Author: Liam Girdwood // -#include -#include #include -#include -#include -#include -#include -#include #include #include #include "sof-priv.h" diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 2dbc98423d2739..b32e6c105ae72e 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -12,16 +12,8 @@ // #include -#include -#include -#include -#include -#include #include -#include -#include #include "sof-priv.h" -#include "ops.h" static int sof_dfsentry_open(struct inode *inode, struct file *file) { diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 0f10e2a100cc4d..61832da260d8bf 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -15,21 +15,7 @@ * Hardware interface for audio DSP on Apollolake and GeminiLake */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "../sof-priv.h" -#include "../ops.h" #include "hda.h" static const struct snd_sof_debugfs_map apl_dsp_debugfs[] = { diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 8cbe5af59d07e2..8b0e83688d92d3 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -12,21 +12,9 @@ * Hardware interface for audio DSP on Broadwell */ -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include #include #include -#include -#include "../sof-priv.h" #include "../ops.h" #include "shim.h" diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 99571bd1560c86..f33b9b4c101ecf 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -12,21 +12,9 @@ * Hardware interface for audio DSP on Baytrail, Braswell and Cherrytrail. */ -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include #include #include -#include -#include "../sof-priv.h" #include "../ops.h" #include "shim.h" diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 76ab0be961b008..8e10441d6c8403 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -15,20 +15,6 @@ * Hardware interface for audio DSP on Cannonlake. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index 89e40e9ed1f777..7cfc690e12495f 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -10,8 +10,6 @@ */ #include -#include "../sof-priv.h" -#include "hda.h" #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 4b93721f03b052..7154369a34061d 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -8,20 +8,10 @@ // Authors: Keyon Jie // -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include -#include #include -#include "../sof-priv.h" #include "../ops.h" #include "hda.h" #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 60fe369f7da5e4..e8f27012ec119b 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -15,21 +15,8 @@ * Hardware interface for generic Intel audio DSP HDA IP */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include -#include -#include -#include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 724ce957b1b07f..24c13cf0c2dd04 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -10,7 +10,6 @@ #include #include -#include #include "../sof-priv.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index d5975795fa791b..115b5fa708b34e 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -15,22 +15,8 @@ * Hardware interface for generic Intel audio DSP HDA IP */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include #include -#include -#include -#include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index c307a8a67e839c..0b8d29c64ad360 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -15,20 +15,6 @@ * Hardware interface for generic Intel audio DSP HDA IP */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 106caf3fbf71b7..53255e72222da9 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -9,21 +9,9 @@ // Zhu Yingjiang // -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include #include -#include #include -#include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 5dd9412626cfef..0726e98f34a03e 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -15,20 +15,9 @@ * Hardware interface for HDA DSP code loader */ -#include -#include -#include #include -#include -#include -#include -#include -#include -#include #include -#include #include -#include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 649f3af37aab04..862283ff02a2bc 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -15,21 +15,9 @@ * Hardware interface for generic Intel audio DSP HDA IP */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include -#include -#include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 0c9c2d794061d3..815a74994bbc49 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -15,21 +15,10 @@ * Hardware interface for generic Intel audio DSP HDA IP */ -#include -#include -#include -#include -#include -#include -#include #include -#include -#include #include #include -#include #include -#include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c index 809d0420a370e0..5e9f73f0954469 100644 --- a/sound/soc/sof/intel/hda-trace.c +++ b/sound/soc/sof/intel/hda-trace.c @@ -15,20 +15,7 @@ * Hardware interface for generic Intel audio DSP HDA IP */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include "../sof-priv.h" #include "../ops.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 11a2322e9a1e68..bc3eab8599d570 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -15,24 +15,10 @@ * Hardware interface for generic Intel audio DSP HDA IP */ -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include #include -#include -#include -#include #include #include -#include "../sof-priv.h" #include "../ops.h" #include "hda.h" #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 0a329bc5a30f70..62d578553951d1 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -12,21 +12,9 @@ * Hardware interface for audio DSP on Haswell */ -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include #include #include -#include -#include "../sof-priv.h" #include "../ops.h" #include "shim.h" diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 83a61d58d3c1b6..f876bee744d320 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -15,21 +15,7 @@ * Hardware interface for audio DSP on Skylake and Kabylake. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "../sof-priv.h" -#include "../ops.h" #include "hda.h" static const struct snd_sof_debugfs_map skl_dsp_debugfs[] = { diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index afccdde9925375..91ff83f88cad64 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -11,25 +11,6 @@ // by platform driver code. // -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "sof-priv.h" #include "ops.h" diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index b23fa0fe6a328c..403f8aabf8a4c0 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -10,18 +10,8 @@ // Generic firmware loader. // -#include -#include -#include #include -#include -#include -#include -#include -#include #include -#include -#include "sof-priv.h" #include "ops.h" static int get_ext_windows(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index 85772a1b6c2692..686324b30a5708 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -8,13 +8,7 @@ // Author: Liam Girdwood // -#include -#include #include -#include -#include -#include -#include #include #include "sof-priv.h" diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index 0cc33cd7cbb657..41143fd9777212 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -8,14 +8,8 @@ // Author: Liam Girdwood // -#include -#include -#include -#include #include -#include #include "ops.h" -#include "sof-priv.h" int snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset, u32 mask, u32 value) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 49b1c40ed038a7..afdbb4597b9508 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -10,20 +10,8 @@ // PCM Layer, interface between ALSA and IPC. // -#include -#include -#include #include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include #include #include "sof-priv.h" #include "ops.h" diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 80be44929c3b4b..3c6781f2498ddf 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -8,16 +8,6 @@ // Author: Liam Girdwood // -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "ops.h" #include "sof-priv.h" diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 7724bc4fcfcc96..4e75d160c6ef8a 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -8,26 +8,19 @@ // Author: Liam Girdwood // +#include #include #include #include -#include -#include #include -#include -#include -#include -#include #include #include #include -#include "sof-priv.h" #include "ops.h" /* platform specific devices */ #include "intel/shim.h" -#include "intel/hda.h" #if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL) static struct sof_dev_desc sof_acpi_haswell_desc = { diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 59d2710ff2bbf5..94bf1ff0e89e57 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -8,17 +8,12 @@ // Author: Liam Girdwood // -#include #include #include -#include -#include #include -#include #include #include #include -#include "sof-priv.h" #include "ops.h" /* platform specific devices */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 5c311e437c58c2..ea248d0be32ba7 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -12,16 +12,8 @@ #define __SOUND_SOC_SOF_PRIV_H #include -#include -#include -#include -#include -#include -#include -#include #include #include -#include #include #include #include @@ -29,8 +21,6 @@ #include #include #include -#include -#include #include /* debug flags */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index d9d5ee3351e8cc..69718b11b72388 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -8,20 +8,8 @@ // Author: Liam Girdwood // -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include #include #include "sof-priv.h" #include "ops.h" diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index c6ba28c35dd27f..09ce14eb1799c1 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -9,17 +9,7 @@ // #include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include #include "sof-priv.h" #include "ops.h" diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index de2b4fa8a66329..3b3eb39cea397e 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -8,7 +8,6 @@ // Author: Keyon Jie // -#include #include #include #include diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c index dc90f31e7ca3cf..b9b00a0675919b 100644 --- a/sound/soc/sof/xtensa/core.c +++ b/sound/soc/sof/xtensa/core.c @@ -8,17 +8,9 @@ * Author: Pan Xiuli */ -#include -#include -#include -#include -#include -#include -#include #include #include #include "../sof-priv.h" -#include "../ops.h" struct xtensa_exception_cause { u32 id; From 3229438c666944bd4ce5a00fd1c05543dcd7b2b8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 5 Dec 2018 18:27:50 -0600 Subject: [PATCH 0356/1995] ASoC: SOF: Make ALSA compress support optional Make sure this module can be compiled out. The code isn't functional anyways for now. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/Kconfig | 10 +++++++++- sound/soc/sof/Makefile | 4 +++- sound/soc/sof/compressed.c | 1 + sound/soc/sof/pcm.c | 2 ++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 8db9ce50a29018..d7440208261685 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -10,13 +10,21 @@ config SND_SOC_SOF_SPI config SND_SOC_SOF tristate "Sound Open Firmware Support" select SND_SOC_TOPOLOGY - select SND_SOC_COMPRESS help This adds support for Sound Open Firmware (SOF). SOF is a free and generic open source audio DSP firmware for multiple devices. Say Y if you have such a device that is supported by SOF. If unsure select "N". +config SND_SOC_SOF_COMPRESS + tristate "SOF ALSA Compressed API support" + depends on SND_SOC_SOF + select SND_SOC_COMPRESS + help + This adds support for the ALSA compressed API in SOF + Say Y if you need this option + If unsure select "N". + config SND_SOC_SOF_NOCODEC tristate "SOF nocodec mode Support" depends on SND_SOC_SOF diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index b8f6c67fbb7b70..65c150ee3baab3 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -3,15 +3,17 @@ ccflags-y += -DDEBUG snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ - control.o trace.o compressed.o utils.o + control.o trace.o utils.o snd-sof-spi-objs := hw-spi.o snd-sof-pci-objs := sof-pci-dev.o snd-sof-acpi-objs := sof-acpi-dev.o snd-sof-nocodec-objs := nocodec.o +snd-sof-compress-objs := compressed.o obj-$(CONFIG_SND_SOC_SOF) += snd-sof.o obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o +obj-$(CONFIG_SND_SOC_SOF_COMPRESS) += snd-sof-compress.o obj-$(CONFIG_SND_SOC_SOF_ACPI) += sof-acpi-dev.o obj-$(CONFIG_SND_SOC_SOF_PCI) += sof-pci-dev.o diff --git a/sound/soc/sof/compressed.c b/sound/soc/sof/compressed.c index fba5f8a931ffad..8c86f6b8883eca 100644 --- a/sound/soc/sof/compressed.c +++ b/sound/soc/sof/compressed.c @@ -178,3 +178,4 @@ struct snd_compr_ops sof_compressed_ops = { .get_caps = sof_compressed_get_caps, .get_codec_caps = sof_compressed_get_codec_caps, }; +EXPORT_SYMBOL(sof_compressed_ops); diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index afdbb4597b9508..af61677169565e 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -740,7 +740,9 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) pd->probe = sof_pcm_probe; pd->remove = sof_pcm_remove; pd->ops = &sof_pcm_ops; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) pd->compr_ops = &sof_compressed_ops; +#endif pd->pcm_new = sof_pcm_new; pd->pcm_free = sof_pcm_free; pd->ignore_machine = drv_name; From ecae97b9a94dab2e050f99be1dfe54069f80e41c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 6 Dec 2018 11:29:49 -0600 Subject: [PATCH 0357/1995] ASoC: SOF: Intel: re-add missing headers Fix sparse issues, re-add headers that were removed Fixes: ef42b5338bb ('ASoC: SOF: remove unnecessary header files including') Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-bus.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index 7cfc690e12495f..89e40e9ed1f777 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -10,6 +10,8 @@ */ #include +#include "../sof-priv.h" +#include "hda.h" #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) From 7553fa9b7a789ac9c6c6d62b6aaed8b0606469c1 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 6 Dec 2018 14:05:39 +0000 Subject: [PATCH 0358/1995] ASoC: SOF: topology: Standardise error message Missing error prefix. Signed-off-by: Liam Girdwood --- sound/soc/sof/topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 69718b11b72388..e36bcf25a777b8 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2704,7 +2704,7 @@ int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file) int ret; if (sdev->tplg_loaded) { - dev_err(sdev->dev, "topology already loaded ?\n"); + dev_err(sdev->dev, "error: topology already loaded ?\n"); return -EINVAL; } From daf0afc988e80a47bf66b73d458092cda361a039 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 6 Dec 2018 13:09:05 -0600 Subject: [PATCH 0359/1995] ASoC: SOF: add error prefix for dev_err Quite a few places where this was missed. I don't particularly like this style but since it's used everywhere let's be consistent. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/debug.c | 6 +++--- sound/soc/sof/hw-spi.c | 10 +++++----- sound/soc/sof/intel/hda-codec.c | 6 +++--- sound/soc/sof/intel/hda-dai.c | 4 ++-- sound/soc/sof/intel/hda-dsp.c | 6 +++--- sound/soc/sof/intel/hda-loader-skl.c | 10 +++++----- sound/soc/sof/intel/hda-loader.c | 4 ++-- sound/soc/sof/intel/hda.c | 14 +++++++------- sound/soc/sof/ipc.c | 8 ++++---- sound/soc/sof/loader.c | 2 +- sound/soc/sof/pcm.c | 2 +- sound/soc/sof/sof-acpi-dev.c | 2 +- sound/soc/sof/sof-pci-dev.c | 2 +- sound/soc/sof/sof-spi-dev.c | 4 ++-- sound/soc/sof/topology.c | 12 ++++++------ sound/soc/sof/utils.c | 2 +- 16 files changed, 47 insertions(+), 47 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index b32e6c105ae72e..268f621b057fb0 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -102,7 +102,7 @@ int snd_sof_debugfs_io_create_item(struct snd_sof_dev *sdev, dfse->dfsentry = debugfs_create_file(name, 0444, sdev->debugfs_root, dfse, &sof_dfs_fops); if (!dfse->dfsentry) { - dev_err(sdev->dev, "cannot create debugfs entry.\n"); + dev_err(sdev->dev, "error: cannot create debugfs entry.\n"); return -ENODEV; } @@ -131,7 +131,7 @@ int snd_sof_debugfs_buf_create_item(struct snd_sof_dev *sdev, dfse->dfsentry = debugfs_create_file(name, 0444, sdev->debugfs_root, dfse, &sof_dfs_fops); if (!dfse->dfsentry) { - dev_err(sdev->dev, "cannot create debugfs entry.\n"); + dev_err(sdev->dev, "error: cannot create debugfs entry.\n"); return -ENODEV; } @@ -160,7 +160,7 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) map->offset, map->size, map->name); if (err < 0) - dev_err(sdev->dev, "cannot create debugfs for %s\n", + dev_err(sdev->dev, "error: cannot create debugfs for %s\n", map->name); } diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index e4bcdb9ed51880..1b54e122cc02cf 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -43,7 +43,7 @@ static void spi_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, if (offset) { buf = kmalloc(size + offset, GFP_KERNEL); if (!buf) { - dev_err(sdev->dev, "Buffer allocation failed\n"); + dev_err(sdev->dev, "error: buffer allocation failed\n"); return; } } else { @@ -52,7 +52,7 @@ static void spi_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, ret = spi_read(to_spi_device(sdev->dev), buf, size + offset); if (ret < 0) - dev_err(sdev->dev, "SPI read failed: %d\n", ret); + dev_err(sdev->dev, "error: SPI read failed: %d\n", ret); if (offset) { memcpy(dest, buf + offset, size); @@ -69,14 +69,14 @@ static void spi_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, if (offset) { buf = kmalloc(size + offset, GFP_KERNEL); if (!buf) { - dev_err(sdev->dev, "Buffer allocation failed\n"); + dev_err(sdev->dev, "error: buffer allocation failed\n"); return; } /* Use Read-Modify-Wwrite */ ret = spi_read(to_spi_device(sdev->dev), buf, size + offset); if (ret < 0) { - dev_err(sdev->dev, "SPI read failed: %d\n", ret); + dev_err(sdev->dev, "error: SPI read failed: %d\n", ret); goto free; } @@ -87,7 +87,7 @@ static void spi_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, ret = spi_write(to_spi_device(sdev->dev), buf, size + offset); if (ret < 0) - dev_err(sdev->dev, "SPI write failed: %d\n", ret); + dev_err(sdev->dev, "error: SPI write failed: %d\n", ret); free: if (offset) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 7154369a34061d..8d0fe7b7554efc 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -107,7 +107,7 @@ int hda_codec_probe_bus(struct snd_sof_dev *sdev) ret = hda_codec_probe(sdev, i); if (ret < 0) { - dev_err(bus->dev, "codec #%d probe error, ret: %d\n", + dev_err(bus->dev, "error: codec #%d probe error, ret: %d\n", i, ret); return ret; } @@ -127,7 +127,7 @@ int hda_codec_i915_get(struct snd_sof_dev *sdev) dev_dbg(bus->dev, "Turning i915 HDAC power on\n"); ret = snd_hdac_display_power(bus, true); if (ret < 0) - dev_err(bus->dev, "i915 HDAC power on failed %d\n", ret); + dev_err(bus->dev, "error: i915 HDAC power on failed %d\n", ret); return ret; } @@ -141,7 +141,7 @@ int hda_codec_i915_put(struct snd_sof_dev *sdev) dev_dbg(bus->dev, "Turning i915 HDAC power off\n"); ret = snd_hdac_display_power(bus, false); if (ret < 0) - dev_err(bus->dev, "i915 HDAC power off failed %d\n", ret); + dev_err(bus->dev, "error: i915 HDAC power off failed %d\n", ret); return ret; } diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 24c13cf0c2dd04..801d45e0218e8e 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -63,7 +63,7 @@ static int hda_link_dma_get_channels(struct snd_soc_dai *dai, stream = snd_hdac_ext_stream_assign(bus, &substream, HDAC_EXT_STREAM_TYPE_LINK); if (!stream) { - dev_err(bus->dev, "failed to find a free hda ext stream for playback"); + dev_err(bus->dev, "error: failed to find a free hda ext stream for playback"); return -EBUSY; } @@ -78,7 +78,7 @@ static int hda_link_dma_get_channels(struct snd_soc_dai *dai, stream = snd_hdac_ext_stream_assign(bus, &substream, HDAC_EXT_STREAM_TYPE_LINK); if (!stream) { - dev_err(bus->dev, "failed to find a free hda ext stream for capture"); + dev_err(bus->dev, "error: failed to find a free hda ext stream for capture"); return -EBUSY; } diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 115b5fa708b34e..bdcbc9c8d43f60 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -205,7 +205,7 @@ int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask) /* power up */ ret = hda_dsp_core_power_up(sdev, core_mask); if (ret < 0) { - dev_err(sdev->dev, "dsp core power up failed: core_mask %x\n", + dev_err(sdev->dev, "error: dsp core power up failed: core_mask %x\n", core_mask); return ret; } @@ -374,7 +374,7 @@ int hda_dsp_resume(struct snd_sof_dev *sdev) /* turn display power on */ ret = hda_codec_i915_get(sdev); if (ret < 0) { - dev_err(bus->dev, "Cannot turn on display power on i915 after resume\n"); + dev_err(bus->dev, "error: cannot turn on display power on i915 after resume\n"); return ret; } @@ -409,7 +409,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state) /* turn display power off */ ret = hda_codec_i915_put(sdev); if (ret < 0) { - dev_err(bus->dev, "Cannot turn OFF display power on i915 during suspend\n"); + dev_err(bus->dev, "error: cannot turn OFF display power on i915 during suspend\n"); return ret; } diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 53255e72222da9..8437ce7201c735 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -333,12 +333,12 @@ static int cl_dsp_init_skl(struct snd_sof_dev *sdev) */ ret = hda_dsp_core_reset_power_down(sdev, HDA_DSP_CORE_MASK(0)); if (ret < 0) { - dev_err(sdev->dev, "dsp core0 disable fail: %d\n", ret); + dev_err(sdev->dev, "error: dsp core0 disable fail: %d\n", ret); goto err; } ret = hda_dsp_enable_core(sdev, HDA_DSP_CORE_MASK(0)); if (ret < 0) { - dev_err(sdev->dev, "dsp core0 enable fail: %d\n", ret); + dev_err(sdev->dev, "error: dsp core0 enable fail: %d\n", ret); goto err; } } @@ -472,7 +472,7 @@ static int cl_copy_fw_skl(struct snd_sof_dev *sdev) HDA_DSP_ROM_FW_FW_LOADED, HDA_DSP_BASEFW_TIMEOUT); if (ret < 0) - dev_err(sdev->dev, "firmware transfer timeout!"); + dev_err(sdev->dev, "error: firmware transfer timeout!"); cl_skl_cldma_stream_run(sdev, false); cl_cleanup_skl(sdev); @@ -490,12 +490,12 @@ int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev) if (ret < 0) { ret = cl_dsp_init_skl(sdev); if (ret < 0) { - dev_err(sdev->dev, "Error code=0x%x: FW status=0x%x\n", + dev_err(sdev->dev, "error: Error code=0x%x: FW status=0x%x\n", snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_ADSP_ERROR_CODE_SKL), snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_ADSP_FW_STATUS_SKL)); - dev_err(sdev->dev, "Core En/ROM load fail:%d\n", ret); + dev_err(sdev->dev, "error: Core En/ROM load fail:%d\n", ret); goto irq_err; } } diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 0726e98f34a03e..0ffa8bfaabb7d4 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -318,12 +318,12 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) stripped_firmware.size); if (tag <= 0) { - dev_err(sdev->dev, "Error code=0x%x: FW status=0x%x\n", + dev_err(sdev->dev, "error: Error code=0x%x: FW status=0x%x\n", snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_ROM_ERROR), snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_ROM_STATUS)); - dev_err(sdev->dev, "iteration %d of Core En/ROM load fail:%d\n", + dev_err(sdev->dev, "error: iteration %d of Core En/ROM load fail:%d\n", i, tag); ret = tag; continue; diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index bc3eab8599d570..b726e270821027 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -311,7 +311,7 @@ static int hda_init(struct snd_sof_dev *sdev) bus->addr = pci_resource_start(pci, 0); bus->remap_addr = pci_ioremap_bar(pci, 0); if (!bus->remap_addr) { - dev_err(bus->dev, "ioremap error\n"); + dev_err(bus->dev, "error: ioremap error\n"); return -ENXIO; } @@ -349,13 +349,13 @@ static int hda_init_caps(struct snd_sof_dev *sdev) /* init i915 and HDMI codecs */ ret = hda_codec_i915_init(sdev); if (ret < 0) { - dev_err(&pci->dev, "no HDMI audio devices found\n"); + dev_err(&pci->dev, "error: no HDMI audio devices found\n"); return ret; } ret = hda_dsp_ctrl_init_chip(sdev, true); if (ret < 0) { - dev_err(bus->dev, "Init chip failed with ret: %d\n", ret); + dev_err(bus->dev, "error: init chip failed with ret: %d\n", ret); err = hda_codec_i915_put(sdev); if (err < 0) return err; @@ -432,10 +432,10 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) * class=04 subclass 03 prog-if 80: either of DSP or legacy mode works */ if (pci->class == 0x040300) { - dev_err(sdev->dev, "The DSP is not enabled on this platform, aborting probe\n"); + dev_err(sdev->dev, "error: the DSP is not enabled on this platform, aborting probe\n"); return -ENODEV; } else if (pci->class != 0x040100 && pci->class != 0x040380) { - dev_err(sdev->dev, "Unknown PCI class/subclass/prog-if 0x%06x found, aborting probe\n", pci->class); + dev_err(sdev->dev, "error: unknown PCI class/subclass/prog-if 0x%06x found, aborting probe\n", pci->class); return -ENODEV; } dev_info(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n", pci->class); @@ -445,7 +445,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) chip = get_chip_info(pci->device); if (!chip) { - dev_err(sdev->dev, "no such device supported, chip id:%x\n", + dev_err(sdev->dev, "error: no such device supported, chip id:%x\n", pci->device); ret = -EIO; goto err; @@ -460,7 +460,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) hdev->dmic_dev = platform_device_register_data(&pci->dev, "dmic-codec", -1, NULL, 0); if (IS_ERR(hdev->dmic_dev)) { - dev_err(&pci->dev, "Failed to create DMIC device\n"); + dev_err(&pci->dev, "error: failed to create DMIC device\n"); return PTR_ERR(hdev->dmic_dev); } diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 91ff83f88cad64..2a322d144a7f02 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -404,7 +404,7 @@ static void ipc_msgs_rx(struct work_struct *work) if (sdev->ops->fw_ready) err = sdev->ops->fw_ready(sdev, cmd); if (err < 0) { - dev_err(sdev->dev, "DSP firmware boot timeout %d\n", + dev_err(sdev->dev, "error: DSP firmware boot timeout %d\n", err); } else { /* firmware boot completed OK */ @@ -427,7 +427,7 @@ static void ipc_msgs_rx(struct work_struct *work) ipc_trace_message(sdev, type); break; default: - dev_err(sdev->dev, "unknown DSP message 0x%x\n", cmd); + dev_err(sdev->dev, "error: unknown DSP message 0x%x\n", cmd); break; } @@ -497,7 +497,7 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) if (!spcm) { dev_err(sdev->dev, - "period elapsed for unknown stream, msg_id %d\n", + "error: period elapsed for unknown stream, msg_id %d\n", msg_id); return; } @@ -542,7 +542,7 @@ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) } if (!spcm) { - dev_err(sdev->dev, "XRUN for unknown stream, msg_id %d\n", + dev_err(sdev->dev, "error: XRUN for unknown stream, msg_id %d\n", msg_id); return; } diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 403f8aabf8a4c0..0dcc7a23df5853 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -275,7 +275,7 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) "fw_version"); if (ret < 0) { - dev_err(sdev->dev, "cannot create debugfs for fw_version\n"); + dev_err(sdev->dev, "error: cannot create debugfs for fw_version\n"); return ret; } } diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index af61677169565e..2abf01b7f15b01 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -640,7 +640,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, snd_mask_set(fmt, (__force int)SNDRV_PCM_FORMAT_S32_LE); break; default: - dev_err(sdev->dev, "No available DAI format!\n"); + dev_err(sdev->dev, "error: No available DAI format!\n"); return -EINVAL; } diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 4e75d160c6ef8a..52de8ac8ede0e8 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -191,7 +191,7 @@ static int sof_acpi_probe(struct platform_device *pdev) if (ret < 0) return ret; #else - dev_err(dev, "No matching ASoC machine driver found - aborting probe\n"); + dev_err(dev, "error: no matching ASoC machine driver found - aborting probe\n"); return -ENODEV; #endif } diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 94bf1ff0e89e57..449ff9cbc793aa 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -239,7 +239,7 @@ static int sof_pci_probe(struct pci_dev *pci, #endif /* CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE */ if (!mach) { - dev_err(dev, "No matching ASoC machine driver found - aborting probe\n"); + dev_err(dev, "error: no matching ASoC machine driver found - aborting probe\n"); ret = -ENODEV; goto release_regions; } diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index 5f98820eeeafb1..372a5d1ed00e75 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -109,7 +109,7 @@ static int sof_spi_probe(struct spi_device *spi) /* TODO: add any required regulators */ /* use nocodec machine atm */ - dev_err(dev, "No matching ASoC machine driver found - using nocodec\n"); + dev_err(dev, "error: no matching ASoC machine driver found - using nocodec\n"); sof_pdata->drv_name = "sof-nocodec"; mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); if (!mach) @@ -125,7 +125,7 @@ static int sof_spi_probe(struct spi_device *spi) mach->asoc_plat_name = "sof-platform"; mach->pdata = sof_get_ops(desc, spi_mach_ops, ARRAY_SIZE(spi_mach_ops)); if (!mach->pdata) { - dev_err(dev, "No matching SPI descriptor ops\n"); + dev_err(dev, "error: no matching SPI descriptor ops\n"); return -ENODEV; } diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index e36bcf25a777b8..461b6be671b3e0 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -308,7 +308,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, scontrol->comp_id, scontrol->num_channels); if (le32_to_cpu(control->priv.size) > max_size) { - dev_err(sdev->dev, "bytes priv data size %d exceeds max %d.\n", + dev_err(sdev->dev, "error: bytes priv data size %d exceeds max %d.\n", control->priv.size, max_size); return -EINVAL; } @@ -1007,7 +1007,7 @@ static int sof_widget_load_buffer(struct snd_soc_component *scomp, int index, ret = sof_ipc_tx_message(sdev->ipc, buffer->comp.hdr.cmd, buffer, sizeof(*buffer), r, sizeof(*r)); if (ret < 0) { - dev_err(sdev->dev, "buffer %s load failed\n", + dev_err(sdev->dev, "error: buffer %s load failed\n", swidget->widget->name); kfree(buffer); } @@ -2148,7 +2148,7 @@ static int sof_link_hda_process(struct snd_sof_dev *sdev, } if (!found) { - dev_err(sdev->dev, "failed to find dai %s", link->name); + dev_err(sdev->dev, "error: failed to find dai %s", link->name); return -EINVAL; } @@ -2198,7 +2198,7 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index, dai_component.dai_name = link->cpu_dai_name; dai = snd_soc_find_dai(&dai_component); if (!dai) { - dev_err(sdev->dev, "failed to find dai %s", + dev_err(sdev->dev, "error: failed to find dai %s", dai_component.dai_name); return -EINVAL; } @@ -2341,7 +2341,7 @@ static int sof_link_hda_unload(struct snd_sof_dev *sdev, dai_component.dai_name = link->cpu_dai_name; dai = snd_soc_find_dai(&dai_component); if (!dai) { - dev_err(sdev->dev, "failed to find dai %s", + dev_err(sdev->dev, "error: failed to find dai %s", dai_component.dai_name); return -EINVAL; } @@ -2379,7 +2379,7 @@ static int sof_link_unload(struct snd_soc_component *scomp, } if (!sof_dai) { - dev_err(sdev->dev, "failed to find dai %s", link->name); + dev_err(sdev->dev, "error: failed to find dai %s", link->name); return -EINVAL; } diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index 3b3eb39cea397e..bf66e14bc258b1 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -58,7 +58,7 @@ int sof_create_platform_device(struct sof_platform_priv *priv) platform_device_register_data(dev, "sof-audio", -1, sof_pdata, sizeof(*sof_pdata)); if (IS_ERR(priv->pdev_pcm)) { - dev_err(dev, "Cannot register device sof-audio. Error %d\n", + dev_err(dev, "error: cannot register device sof-audio. Error %d\n", (int)PTR_ERR(priv->pdev_pcm)); return PTR_ERR(priv->pdev_pcm); } From 6b7c9d1b6cb35d899e801a764a560ee6394b69ce Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 6 Dec 2018 14:48:07 -0600 Subject: [PATCH 0360/1995] ASoC: SOF: fix SPDX licenses Move to C++ comments in all C files Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-bus.c | 16 +++++++--------- sound/soc/sof/xtensa/core.c | 16 ++++++++-------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index 89e40e9ed1f777..cadf559f5a82fd 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -1,13 +1,11 @@ // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - * - * Authors: Keyon Jie - * - */ +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Keyon Jie #include #include "../sof-priv.h" diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c index b9b00a0675919b..8bc3b782c16e0f 100644 --- a/sound/soc/sof/xtensa/core.c +++ b/sound/soc/sof/xtensa/core.c @@ -1,12 +1,12 @@ // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - * - * Author: Pan Xiuli - */ +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Pan Xiuli +// #include #include From a71221dc5b70fd10fba2d3d6eadb4602bbcc3ff7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 6 Dec 2018 14:51:19 -0600 Subject: [PATCH 0361/1995] ASoC: SOF: more SPDX fixes C++ comments in C files Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/virtio-be.c | 17 ++++++++--------- sound/soc/sof/virtio-fe.c | 16 ++++++++-------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/sound/soc/sof/virtio-be.c b/sound/soc/sof/virtio-be.c index 03480b34effdfe..eca63a8765fe1d 100644 --- a/sound/soc/sof/virtio-be.c +++ b/sound/soc/sof/virtio-be.c @@ -1,13 +1,12 @@ // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * Copyright(c) 2017 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood - * - */ +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2017 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// #include #include diff --git a/sound/soc/sof/virtio-fe.c b/sound/soc/sof/virtio-fe.c index 1f98d39f86035c..6e9de114c2384c 100644 --- a/sound/soc/sof/virtio-fe.c +++ b/sound/soc/sof/virtio-fe.c @@ -1,12 +1,12 @@ // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * Copyright(c) 2017 Intel Corporation. All rights reserved. - * - * Author: Liam Girdwood - */ +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2017 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// /* * virt IO FE driver From 4d2fd0624528c5a109adb277f344c44f6da8d7cb Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Thu, 6 Dec 2018 15:41:51 +0800 Subject: [PATCH 0362/1995] ASoC: SOF: refine interrupt function on BDW & HSW This patch follows commit: ASoC: SOF: byt: fix IPC handled wrong issue Align with apl/cnl, to fix the issue with dmesg shows "error: rx list empty but received ...", add mask check for interrupt handling. two special change: (1) remove memory read in IRQ function, it be done in ipc_msgs_rx So this memory read is duplicated. (2) msg id is stored in ipcx not in hdr. Now we set zero in ipcx and hdr is zero, so no problem is found. Signed-off-by: Keyon Jie Signed-off-by: Rander Wang --- sound/soc/sof/intel/bdw.c | 38 +++++++++++++++++--------------------- sound/soc/sof/intel/hsw.c | 38 +++++++++++++++++--------------------- 2 files changed, 34 insertions(+), 42 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 8b0e83688d92d3..1169f71ec6e29a 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -251,21 +251,8 @@ static irqreturn_t bdw_irq_handler(int irq, void *context) /* Interrupt arrived, check src */ isr = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_ISRX); - if (isr & SHIM_ISRX_DONE) { - /* Mask Done interrupt before return */ - snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, - SHIM_IMRX, SHIM_IMRX_DONE, - SHIM_IMRX_DONE); + if (isr & (SHIM_ISRX_DONE | SHIM_ISRX_BUSY)) ret = IRQ_WAKE_THREAD; - } - - if (isr & SHIM_ISRX_BUSY) { - /* Mask Busy interrupt before return */ - snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, - SHIM_IMRX, SHIM_IMRX_BUSY, - SHIM_IMRX_BUSY); - ret = IRQ_WAKE_THREAD; - } return ret; } @@ -273,15 +260,18 @@ static irqreturn_t bdw_irq_handler(int irq, void *context) static irqreturn_t bdw_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; - u32 ipcx, ipcd, hdr; + u32 ipcx, ipcd, imrx; + imrx = snd_sof_dsp_read64(sdev, BDW_DSP_BAR, SHIM_IMRX); ipcx = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCX); /* reply message from DSP */ - if (ipcx & SHIM_IPCX_DONE) { - /* Handle Immediate reply from DSP Core */ - sof_mailbox_read(sdev, sdev->host_box.offset, &hdr, - sizeof(hdr)); + if (ipcx & SHIM_IPCX_DONE && + !(imrx & SHIM_IMRX_DONE)) { + /* Mask Done interrupt before return */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, + SHIM_IMRX, SHIM_IMRX_DONE, + SHIM_IMRX_DONE); /* * handle immediate reply from DSP core. If the msg is @@ -290,14 +280,20 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) * because the done bit can't be set in cmd_done function * which is triggered by msg */ - if (snd_sof_ipc_reply(sdev, hdr)) + if (snd_sof_ipc_reply(sdev, ipcx)) bdw_cmd_done(sdev, SOF_IPC_DSP_REPLY); } ipcd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD); /* new message from DSP */ - if (ipcd & SHIM_IPCD_BUSY) { + if (ipcd & SHIM_IPCD_BUSY && + !(imrx & SHIM_IMRX_BUSY)) { + /* Mask Busy interrupt before return */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, + SHIM_IMRX, SHIM_IMRX_BUSY, + SHIM_IMRX_BUSY); + /* Handle messages from DSP Core */ if ((ipcd & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { snd_sof_dsp_panic(sdev, BDW_PANIC_OFFSET(ipcx) + diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 62d578553951d1..14d315a6579132 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -251,21 +251,8 @@ static irqreturn_t hsw_irq_handler(int irq, void *context) /* Interrupt arrived, check src */ isr = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_ISRX); - if (isr & SHIM_ISRX_DONE) { - /* Mask Done interrupt before return */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_DONE, - SHIM_IMRX_DONE); + if (isr & (SHIM_ISRX_DONE | SHIM_ISRX_BUSY)) ret = IRQ_WAKE_THREAD; - } - - if (isr & SHIM_ISRX_BUSY) { - /* Mask Busy interrupt before return */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_BUSY, - SHIM_IMRX_BUSY); - ret = IRQ_WAKE_THREAD; - } spin_unlock(&sdev->hw_lock); return ret; @@ -274,15 +261,18 @@ static irqreturn_t hsw_irq_handler(int irq, void *context) static irqreturn_t hsw_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; - u32 ipcx, ipcd, hdr; + u32 ipcx, ipcd, imrx; + imrx = snd_sof_dsp_read64(sdev, HSW_DSP_BAR, SHIM_IMRX); ipcx = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_IPCX); /* reply message from DSP */ - if (ipcx & SHIM_IPCX_DONE) { - /* Handle Immediate reply from DSP Core */ - sof_mailbox_read(sdev, sdev->host_box.offset, &hdr, - sizeof(hdr)); + if (ipcx & SHIM_IPCX_DONE && + !(imrx & SHIM_IMRX_DONE)) { + /* Mask Done interrupt before return */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, + SHIM_IMRX, SHIM_IMRX_DONE, + SHIM_IMRX_DONE); /* * handle immediate reply from DSP core. If the msg is @@ -291,14 +281,20 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) * because the done bit can't be set in cmd_done function * which is triggered by msg */ - if (snd_sof_ipc_reply(sdev, hdr)) + if (snd_sof_ipc_reply(sdev, ipcx)) hsw_cmd_done(sdev, SOF_IPC_DSP_REPLY); } ipcd = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_IPCD); /* new message from DSP */ - if (ipcd & SHIM_IPCD_BUSY) { + if (ipcd & SHIM_IPCD_BUSY && + !(imrx & SHIM_IMRX_BUSY)) { + /* Mask Busy interrupt before return */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, + SHIM_IMRX, SHIM_IMRX_BUSY, + SHIM_IMRX_BUSY); + /* Handle messages from DSP Core */ if ((ipcd & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { snd_sof_dsp_panic(sdev, HSW_PANIC_OFFSET(ipcx) + From 8cf9a6a703446e82d28f595d7e98ef8b2602a758 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 7 Dec 2018 12:10:53 -0600 Subject: [PATCH 0363/1995] ASoC: SOF: debug: re-add missing header for ARM compilation Not sure how it ever compiled for Intel platforms Reported-by: kbuild test robot Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/debug.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 268f621b057fb0..67f6cf79b72947 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -12,6 +12,7 @@ // #include +#include #include #include "sof-priv.h" From 15fd0316d36c16c228c8aaeda335175c98222a62 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 10 Dec 2018 15:16:34 +0800 Subject: [PATCH 0364/1995] ASoC: SOF: trace: initialize stream_tag to zero Stream_tag is used by platforms with hda streams supported. For legacy platforms like byt or bdw, it is not initialized, so the debug output is a strange value on these legacy platforms. On BDW, the debug msg is like: [ 4.195365] sof-audio sof-audio: stream_tag: -24362 This makes developers puzzled. Signed-off-by: Rander Wang --- sound/soc/sof/trace.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 09ce14eb1799c1..9871a174f9ca11 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -148,6 +148,7 @@ int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) params.buffer.size = sdev->dmatb.bytes; params.buffer.offset = 0; params.buffer.pages = sdev->dma_trace_pages; + params.stream_tag = 0; sdev->host_offset = 0; From 7923fc5dff95c1a6fbf5d4e0e0b9747be5d74d15 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Sat, 8 Dec 2018 04:29:24 +0800 Subject: [PATCH 0365/1995] ASoC: SOF: topology: goto found: if a dai is found sof_dai will be assigned when list_for_each_entry walk through list. So, sof_dai won't be null even there is no dai found. Use goto statement instead. Signed-off-by: Bard liao --- sound/soc/sof/topology.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 461b6be671b3e0..5964ad06950e5d 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2375,13 +2375,12 @@ static int sof_link_unload(struct snd_soc_component *scomp, continue; if (strcmp(link->name, sof_dai->name) == 0) - break; + goto found; } - if (!sof_dai) { - dev_err(sdev->dev, "error: failed to find dai %s", link->name); - return -EINVAL; - } + dev_err(sdev->dev, "failed to find dai %s", link->name); + return -EINVAL; +found: switch (sof_dai->dai_config->type) { case SOF_DAI_INTEL_SSP: From 0308bd231f00142a1a1f3096013c7da2d2221c47 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 7 Dec 2018 12:18:01 -0600 Subject: [PATCH 0366/1995] ASoC: SOF: compressed: add missing module license Also missing header file Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/compressed.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/compressed.c b/sound/soc/sof/compressed.c index 8c86f6b8883eca..13af378bdebf08 100644 --- a/sound/soc/sof/compressed.c +++ b/sound/soc/sof/compressed.c @@ -8,6 +8,7 @@ // Author: Liam Girdwood // +#include #include #include #include "sof-priv.h" @@ -179,3 +180,5 @@ struct snd_compr_ops sof_compressed_ops = { .get_codec_caps = sof_compressed_get_codec_caps, }; EXPORT_SYMBOL(sof_compressed_ops); + +MODULE_LICENSE("Dual BSD/GPL"); From eb848f1eccc62ebef18e1c2d39c75a9d475fce20 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 10 Dec 2018 08:20:37 -0600 Subject: [PATCH 0367/1995] ASoC: SOF: topology: add missing error prefix Missed by 7923fc5dff9 ('ASoC: SOF: topology: goto found: if a dai is found') Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 5964ad06950e5d..5955f061e152ce 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2378,7 +2378,7 @@ static int sof_link_unload(struct snd_soc_component *scomp, goto found; } - dev_err(sdev->dev, "failed to find dai %s", link->name); + dev_err(sdev->dev, "error: failed to find dai %s", link->name); return -EINVAL; found: From fa0806558f755c9d6fab01be3eb705e71e00141c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 10 Dec 2018 16:57:09 -0600 Subject: [PATCH 0368/1995] ASoC: SOF: tone: clean-up uapi include file Likely leftovers from previous versions, remove. Not sure how the other defines are used, or if they are even needed? Signed-off-by: Pierre-Louis Bossart --- include/uapi/sound/sof/tone.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/uapi/sound/sof/tone.h b/include/uapi/sound/sof/tone.h index ec792ccdf51260..d7c6e5d8317ebb 100644 --- a/include/uapi/sound/sof/tone.h +++ b/include/uapi/sound/sof/tone.h @@ -9,11 +9,6 @@ #ifndef __INCLUDE_UAPI_SOUND_SOF_USER_TONE_H__ #define __INCLUDE_UAPI_SOUND_SOF_USER_TONE_H__ -/* Component will reject non-matching configuration. The version number need - * to be incremented with any ABI changes in function fir_cmd(). - */ -#define SOF_TONE_ABI_VERSION 1 - #define SOF_TONE_IDX_FREQUENCY 0 #define SOF_TONE_IDX_AMPLITUDE 1 #define SOF_TONE_IDX_FREQ_MULT 2 From cbc36a8fc880c80c938a533fa2f97fdd06b9463e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 10:00:14 -0600 Subject: [PATCH 0369/1995] ASoC: SOF: SPI: fix compilation issues with yesconfig static variables should not be exported, makes no sense Also add header file to make sure prototypes are aligned. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/hw-spi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index 1b54e122cc02cf..2d5f34e66f7487 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -28,6 +28,7 @@ #include #include #include "sof-priv.h" +#include "hw-spi.h" #include "ops.h" /* @@ -274,7 +275,7 @@ static int spi_cmd_done(struct snd_sof_dev *sof_dev __maybe_unused, int dir __ma } /* SPI SOF ops */ -static struct snd_sof_dsp_ops snd_sof_spi_ops = { +struct snd_sof_dsp_ops snd_sof_spi_ops = { /* device init */ .probe = spi_sof_probe, .remove = spi_sof_remove, From 5299a4108e977e9f9b75052a1a051dc47eeeb664 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 10:43:23 -0600 Subject: [PATCH 0370/1995] ASoC: SOF: compress: don't create module for sof-compress The recent move to use a module broke rules on circular module dependencies, move to a simpler boolean to take out the entire compressed support instead. Tested with make bin-debpkg target Reported-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/Kconfig | 4 ++-- sound/soc/sof/Makefile | 4 ++-- sound/soc/sof/compressed.c | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index d7440208261685..ebd2495ff3b50d 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -10,6 +10,7 @@ config SND_SOC_SOF_SPI config SND_SOC_SOF tristate "Sound Open Firmware Support" select SND_SOC_TOPOLOGY + select SND_SOC_COMPRESS if SND_SOC_SOF_COMPRESS=y help This adds support for Sound Open Firmware (SOF). SOF is a free and generic open source audio DSP firmware for multiple devices. @@ -17,9 +18,8 @@ config SND_SOC_SOF If unsure select "N". config SND_SOC_SOF_COMPRESS - tristate "SOF ALSA Compressed API support" + bool "SOF ALSA Compressed API support" depends on SND_SOC_SOF - select SND_SOC_COMPRESS help This adds support for the ALSA compressed API in SOF Say Y if you need this option diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 65c150ee3baab3..035ee0c7268394 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -4,16 +4,16 @@ ccflags-y += -DDEBUG snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ control.o trace.o utils.o +snd-sof-objs += compressed.o snd-sof-spi-objs := hw-spi.o snd-sof-pci-objs := sof-pci-dev.o snd-sof-acpi-objs := sof-acpi-dev.o snd-sof-nocodec-objs := nocodec.o -snd-sof-compress-objs := compressed.o obj-$(CONFIG_SND_SOC_SOF) += snd-sof.o obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o -obj-$(CONFIG_SND_SOC_SOF_COMPRESS) += snd-sof-compress.o + obj-$(CONFIG_SND_SOC_SOF_ACPI) += sof-acpi-dev.o obj-$(CONFIG_SND_SOC_SOF_PCI) += sof-pci-dev.o diff --git a/sound/soc/sof/compressed.c b/sound/soc/sof/compressed.c index 13af378bdebf08..e85ad4727d9e8b 100644 --- a/sound/soc/sof/compressed.c +++ b/sound/soc/sof/compressed.c @@ -13,6 +13,8 @@ #include #include "sof-priv.h" +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) + #define DRV_NAME "sof-audio" static int sof_compressed_open(struct snd_compr_stream *cstream) @@ -179,6 +181,4 @@ struct snd_compr_ops sof_compressed_ops = { .get_caps = sof_compressed_get_caps, .get_codec_caps = sof_compressed_get_codec_caps, }; -EXPORT_SYMBOL(sof_compressed_ops); - -MODULE_LICENSE("Dual BSD/GPL"); +#endif From 664df19efaad406fb7d51f385b261319454eb5f0 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 15 Nov 2018 21:47:27 +0000 Subject: [PATCH 0371/1995] ASoC: SOF: ABI: consolidate ABI version check. Make sure ABI versions are compatible between FW and host otherwise bail. Signed-off-by: Liam Girdwood --- include/sound/sof/control.h | 2 +- include/sound/sof/dai-intel.h | 4 +++ include/sound/sof/dai.h | 2 +- include/sound/sof/header.h | 45 +++++++++----------------------- include/sound/sof/info.h | 16 ++++++++---- include/sound/sof/pm.h | 5 ++-- include/sound/sof/stream.h | 13 +++++++-- include/sound/sof/topology.h | 28 +++++++++++++++----- include/sound/sof/trace.h | 22 +++++++++++++++- include/sound/sof/xtensa.h | 3 +++ include/uapi/sound/sof/abi.h | 2 +- include/uapi/sound/sof/eq.h | 22 +++++----------- sound/soc/sof/core.c | 6 ++++- sound/soc/sof/intel/bdw.c | 17 ++++++------ sound/soc/sof/intel/byt.c | 17 ++++++------ sound/soc/sof/intel/hda-ipc.c | 19 +++++++------- sound/soc/sof/intel/hda-loader.c | 2 +- sound/soc/sof/intel/hda.h | 2 +- sound/soc/sof/intel/hsw.c | 17 ++++++------ sound/soc/sof/ipc.c | 44 +++++++++++++++++++++++++++++-- sound/soc/sof/loader.c | 10 +++---- sound/soc/sof/pcm.c | 1 + sound/soc/sof/pm.c | 6 ++--- sound/soc/sof/sof-priv.h | 12 ++++----- sound/soc/sof/topology.c | 9 +++++++ 25 files changed, 204 insertions(+), 122 deletions(-) diff --git a/include/sound/sof/control.h b/include/sound/sof/control.h index e2f6696d953aac..7d7d2eba7d7639 100644 --- a/include/sound/sof/control.h +++ b/include/sound/sof/control.h @@ -106,7 +106,7 @@ struct sof_ipc_ctrl_data { /* control data - can either be appended or DMAed from host */ struct sof_ipc_host_buffer buffer; - uint32_t num_elems; /**< in array elems or bytes */ + uint32_t num_elems; /**< in array elems or bytes for data type */ /* reserved for future use */ uint32_t reserved[8]; diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h index bd6e9b6a4401e0..700e1ed2345026 100644 --- a/include/sound/sof/dai-intel.h +++ b/include/sound/sof/dai-intel.h @@ -48,6 +48,7 @@ /* SSP Configuration Request - SOF_IPC_DAI_SSP_CONFIG */ struct sof_ipc_dai_ssp_params { + struct sof_ipc_hdr hdr; uint16_t reserved1; uint16_t mclk_id; @@ -76,6 +77,7 @@ struct sof_ipc_dai_ssp_params { /* HDA Configuration Request - SOF_IPC_DAI_HDA_CONFIG */ struct sof_ipc_dai_hda_params { + struct sof_ipc_hdr hdr; uint32_t link_dma_ch; } __packed; @@ -99,6 +101,7 @@ struct sof_ipc_dai_hda_params { * data integrity problems. */ struct sof_ipc_dai_dmic_pdm_ctrl { + struct sof_ipc_hdr hdr; uint16_t id; /**< PDM controller ID */ uint16_t enable_mic_a; /**< Use A (left) channel mic (0 or 1)*/ @@ -143,6 +146,7 @@ struct sof_ipc_dai_dmic_pdm_ctrl { * treated as an error. */ struct sof_ipc_dai_dmic_params { + struct sof_ipc_hdr hdr; uint32_t driver_ipc_version; /**< Version (1..N) */ uint32_t pdmclk_min; /**< Minimum microphone clock in Hz (100000..N) */ diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 5ebf9648d3fa4e..3b67c93ff101b5 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -53,7 +53,7 @@ enum sof_ipc_dai_type { /* general purpose DAI configuration */ struct sof_ipc_dai_config { - struct sof_ipc_hdr hdr; + struct sof_ipc_cmd_hdr hdr; uint32_t type; /**< DAI type - enum sof_ipc_dai_type */ uint32_t dai_index; /**< index of this type dai */ diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index 1a66cdb9353741..ccb6a004b37b78 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -108,53 +108,34 @@ #define SOF_IPC_MSG_MAX_SIZE 384 /* - * SOF panic codes + * Structure Header - Header for all IPC structures except command structs. + * The size can be greater than the structure size and that means there is + * extended bespoke data beyond the end of the structure including variable + * arrays. */ -#define SOF_IPC_PANIC_MAGIC 0x0dead000 -#define SOF_IPC_PANIC_MAGIC_MASK 0x0ffff000 -#define SOF_IPC_PANIC_CODE_MASK 0x00000fff -#define SOF_IPC_PANIC_MEM (SOF_IPC_PANIC_MAGIC | 0x0) -#define SOF_IPC_PANIC_WORK (SOF_IPC_PANIC_MAGIC | 0x1) -#define SOF_IPC_PANIC_IPC (SOF_IPC_PANIC_MAGIC | 0x2) -#define SOF_IPC_PANIC_ARCH (SOF_IPC_PANIC_MAGIC | 0x3) -#define SOF_IPC_PANIC_PLATFORM (SOF_IPC_PANIC_MAGIC | 0x4) -#define SOF_IPC_PANIC_TASK (SOF_IPC_PANIC_MAGIC | 0x5) -#define SOF_IPC_PANIC_EXCEPTION (SOF_IPC_PANIC_MAGIC | 0x6) -#define SOF_IPC_PANIC_DEADLOCK (SOF_IPC_PANIC_MAGIC | 0x7) -#define SOF_IPC_PANIC_STACK (SOF_IPC_PANIC_MAGIC | 0x8) -#define SOF_IPC_PANIC_IDLE (SOF_IPC_PANIC_MAGIC | 0x9) -#define SOF_IPC_PANIC_WFI (SOF_IPC_PANIC_MAGIC | 0xa) -/* - * SOF memory capabilities, add new ones at the end - */ -#define SOF_MEM_CAPS_RAM (1 << 0) -#define SOF_MEM_CAPS_ROM (1 << 1) -#define SOF_MEM_CAPS_EXT (1 << 2) /**< external */ -#define SOF_MEM_CAPS_LP (1 << 3) /**< low power */ -#define SOF_MEM_CAPS_HP (1 << 4) /**< high performance */ -#define SOF_MEM_CAPS_DMA (1 << 5) /**< DMA'able */ -#define SOF_MEM_CAPS_CACHE (1 << 6) /**< cacheable */ -#define SOF_MEM_CAPS_EXEC (1 << 7) /**< executable */ +struct sof_ipc_hdr { + uint32_t size; /**< size of structure */ +} __packed; /* - * Command Header - Header for all IPC. Identifies IPC message. + * Command Header - Header for all IPC commands. Identifies IPC message. * The size can be greater than the structure size and that means there is * extended bespoke data beyond the end of the structure including variable * arrays. */ -struct sof_ipc_hdr { - uint32_t cmd; /**< SOF_IPC_GLB_ + cmd */ +struct sof_ipc_cmd_hdr { uint32_t size; /**< size of structure */ -} __packed; + uint32_t cmd; /**< SOF_IPC_GLB_ + cmd */ +} __packed; /* * Generic reply message. Some commands override this with their own reply * types that must include this at start. */ struct sof_ipc_reply { - struct sof_ipc_hdr hdr; + struct sof_ipc_cmd_hdr hdr; int32_t error; /**< negative error numbers */ } __packed; @@ -168,7 +149,7 @@ struct sof_ipc_reply { */ struct sof_ipc_compound_hdr { - struct sof_ipc_hdr hdr; + struct sof_ipc_cmd_hdr hdr; uint32_t count; /**< count of 0 means end of compound sequence */ } __packed; diff --git a/include/sound/sof/info.h b/include/sound/sof/info.h index aa99e12e3bc97c..21dae04d818398 100644 --- a/include/sound/sof/info.h +++ b/include/sound/sof/info.h @@ -26,6 +26,7 @@ enum sof_ipc_ext_data { /* FW version - SOF_IPC_GLB_VERSION */ struct sof_ipc_fw_version { + struct sof_ipc_hdr hdr; uint16_t major; uint16_t minor; uint16_t micro; @@ -41,7 +42,7 @@ struct sof_ipc_fw_version { /* FW ready Message - sent by firmware when boot has completed */ struct sof_ipc_fw_ready { - struct sof_ipc_hdr hdr; + struct sof_ipc_cmd_hdr hdr; uint32_t dspbox_offset; /* dsp initiated IPC mailbox */ uint32_t hostbox_offset; /* host initiated IPC mailbox */ uint32_t dspbox_size; @@ -51,9 +52,12 @@ struct sof_ipc_fw_ready { /* Miscellaneous debug flags showing build/debug features enabled */ union { uint64_t reserved; - uint64_t build:1; - uint64_t locks:1; - uint64_t locks_verbose:1; + struct { + uint64_t build:1; + uint64_t locks:1; + uint64_t locks_verbose:1; + uint64_t gdb:1; + } bits; } debug; /* reserved for future use */ @@ -74,11 +78,12 @@ enum sof_ipc_region { }; struct sof_ipc_ext_data_hdr { - struct sof_ipc_hdr hdr; + struct sof_ipc_cmd_hdr hdr; uint32_t type; /**< SOF_IPC_EXT_ */ } __packed; struct sof_ipc_dma_buffer_elem { + struct sof_ipc_hdr hdr; uint32_t type; /**< SOF_IPC_REGION_ */ uint32_t id; /**< platform specific - used to map to host memory */ struct sof_ipc_host_buffer buffer; @@ -94,6 +99,7 @@ struct sof_ipc_dma_buffer_data { } __packed; struct sof_ipc_window_elem { + struct sof_ipc_hdr hdr; uint32_t type; /**< SOF_IPC_REGION_ */ uint32_t id; /**< platform specific - used to map to host memory */ uint32_t flags; /**< R, W, RW, etc - to define */ diff --git a/include/sound/sof/pm.h b/include/sound/sof/pm.h index 5f725fdd3e161d..8ae3ad45bdf7ca 100644 --- a/include/sound/sof/pm.h +++ b/include/sound/sof/pm.h @@ -17,6 +17,7 @@ /* PM context element */ struct sof_ipc_pm_ctx_elem { + struct sof_ipc_hdr hdr; uint32_t type; uint32_t size; uint64_t addr; @@ -27,7 +28,7 @@ struct sof_ipc_pm_ctx_elem { * SOF_IPC_PM_CTX_SIZE */ struct sof_ipc_pm_ctx { - struct sof_ipc_hdr hdr; + struct sof_ipc_cmd_hdr hdr; struct sof_ipc_host_buffer buffer; uint32_t num_elems; uint32_t size; @@ -40,7 +41,7 @@ struct sof_ipc_pm_ctx { /* enable or disable cores - SOF_IPC_PM_CORE_ENABLE */ struct sof_ipc_pm_core_config { - struct sof_ipc_hdr hdr; + struct sof_ipc_cmd_hdr hdr; uint32_t enable_mask; } __packed; diff --git a/include/sound/sof/stream.h b/include/sound/sof/stream.h index b95797a18c8b75..0b436649f1e471 100644 --- a/include/sound/sof/stream.h +++ b/include/sound/sof/stream.h @@ -37,6 +37,9 @@ #define SOF_RATE_CONTINUOUS (1 << 30) /**< range */ #define SOF_RATE_KNOT (1 << 31) /**< non-continuous */ +/* generic PCM flags for runtime settings */ +#define SOF_PCM_FLAG_XRUN_STOP (1 << 0) /**< Stop on any XRUN */ + /* stream PCM frame format */ enum sof_ipc_frame { SOF_IPC_FRAME_S16_LE = 0, @@ -61,13 +64,16 @@ enum sof_ipc_stream_direction { /* stream ring info */ struct sof_ipc_host_buffer { + struct sof_ipc_hdr hdr; uint32_t phy_addr; uint32_t pages; uint32_t size; uint32_t offset; + uint32_t reserved[2]; } __packed; struct sof_ipc_stream_params { + struct sof_ipc_hdr hdr; struct sof_ipc_host_buffer buffer; uint32_t direction; /**< enum sof_ipc_stream_direction */ uint32_t frame_fmt; /**< enum sof_ipc_frame */ @@ -81,13 +87,16 @@ struct sof_ipc_stream_params { /* for notifying host period has completed - 0 means no period IRQ */ uint32_t host_period_bytes; + uint32_t reserved[2]; uint16_t chmap[SOF_IPC_MAX_CHANNELS]; /**< channel map - SOF_CHMAP_ */ } __packed; /* PCM params info - SOF_IPC_STREAM_PCM_PARAMS */ struct sof_ipc_pcm_params { - struct sof_ipc_hdr hdr; + struct sof_ipc_cmd_hdr hdr; uint32_t comp_id; + uint32_t flags; /**< generic PCM flags - SOF_PCM_FLAG_ */ + uint32_t reserved[2]; struct sof_ipc_stream_params params; } __packed; @@ -100,7 +109,7 @@ struct sof_ipc_pcm_params_reply { /* free stream - SOF_IPC_STREAM_PCM_PARAMS */ struct sof_ipc_stream { - struct sof_ipc_hdr hdr; + struct sof_ipc_cmd_hdr hdr; uint32_t comp_id; } __packed; diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h index b63cc41deb20a9..155758598ed532 100644 --- a/include/sound/sof/topology.h +++ b/include/sound/sof/topology.h @@ -43,7 +43,7 @@ enum sof_comp_type { /* create new generic component - SOF_IPC_TPLG_COMP_NEW */ struct sof_ipc_comp { - struct sof_ipc_hdr hdr; + struct sof_ipc_cmd_hdr hdr; uint32_t id; enum sof_comp_type type; uint32_t pipeline_id; @@ -56,6 +56,18 @@ struct sof_ipc_comp { * Component Buffers */ +/* + * SOF memory capabilities, add new ones at the end + */ +#define SOF_MEM_CAPS_RAM (1 << 0) +#define SOF_MEM_CAPS_ROM (1 << 1) +#define SOF_MEM_CAPS_EXT (1 << 2) /**< external */ +#define SOF_MEM_CAPS_LP (1 << 3) /**< low power */ +#define SOF_MEM_CAPS_HP (1 << 4) /**< high performance */ +#define SOF_MEM_CAPS_DMA (1 << 5) /**< DMA'able */ +#define SOF_MEM_CAPS_CACHE (1 << 6) /**< cacheable */ +#define SOF_MEM_CAPS_EXEC (1 << 7) /**< executable */ + /* create new component buffer - SOF_IPC_TPLG_BUFFER_NEW */ struct sof_ipc_buffer { struct sof_ipc_comp comp; @@ -65,6 +77,7 @@ struct sof_ipc_buffer { /* generic component config data - must always be after struct sof_ipc_comp */ struct sof_ipc_comp_config { + struct sof_ipc_cmd_hdr hdr; uint32_t periods_sink; /**< 0 means variable */ uint32_t periods_source; /**< 0 means variable */ uint32_t preload_count; /**< how many periods to preload */ @@ -159,6 +172,7 @@ enum sof_ipc_effect_type { /* general purpose EFFECT configuration */ struct sof_ipc_comp_effect { + struct sof_ipc_hdr hdr; uint32_t type; /** sof_ipc_effect_type */ } __packed; @@ -190,7 +204,7 @@ struct sof_ipc_comp_eq_iir { * SOF_IPC_TPLG_COMP_FREE, SOF_IPC_TPLG_PIPE_FREE, SOF_IPC_TPLG_BUFFER_FREE */ struct sof_ipc_free { - struct sof_ipc_hdr hdr; + struct sof_ipc_cmd_hdr hdr; uint32_t id; } __packed; @@ -206,10 +220,10 @@ struct sof_ipc_comp_reply { /* new pipeline - SOF_IPC_TPLG_PIPE_NEW */ struct sof_ipc_pipe_new { - struct sof_ipc_hdr hdr; + struct sof_ipc_cmd_hdr hdr; uint32_t comp_id; /**< component id for pipeline */ uint32_t pipeline_id; /**< pipeline id */ - uint32_t sched_id; /**< sheduling component id */ + uint32_t sched_id; /**< Scheduling component id */ uint32_t core; /**< core we run on */ uint32_t deadline; /**< execution completion deadline in us*/ uint32_t priority; /**< priority level 0 (low) to 10 (max) */ @@ -223,18 +237,18 @@ struct sof_ipc_pipe_new { /* pipeline construction complete - SOF_IPC_TPLG_PIPE_COMPLETE */ struct sof_ipc_pipe_ready { - struct sof_ipc_hdr hdr; + struct sof_ipc_cmd_hdr hdr; uint32_t comp_id; } __packed; struct sof_ipc_pipe_free { - struct sof_ipc_hdr hdr; + struct sof_ipc_cmd_hdr hdr; uint32_t comp_id; } __packed; /* connect two components in pipeline - SOF_IPC_TPLG_COMP_CONNECT */ struct sof_ipc_pipe_comp_connect { - struct sof_ipc_hdr hdr; + struct sof_ipc_cmd_hdr hdr; uint32_t source_id; uint32_t sink_id; } __packed; diff --git a/include/sound/sof/trace.h b/include/sound/sof/trace.h index 1fba59798bb070..49f0f310d9029b 100644 --- a/include/sound/sof/trace.h +++ b/include/sound/sof/trace.h @@ -20,7 +20,7 @@ /* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS */ struct sof_ipc_dma_trace_params { - struct sof_ipc_hdr hdr; + struct sof_ipc_cmd_hdr hdr; struct sof_ipc_host_buffer buffer; uint32_t stream_tag; } __packed; @@ -37,8 +37,28 @@ struct sof_ipc_dma_trace_posn { * Commom debug */ +/* + * SOF panic codes + */ +#define SOF_IPC_PANIC_MAGIC 0x0dead000 +#define SOF_IPC_PANIC_MAGIC_MASK 0x0ffff000 +#define SOF_IPC_PANIC_CODE_MASK 0x00000fff +#define SOF_IPC_PANIC_MEM (SOF_IPC_PANIC_MAGIC | 0x0) +#define SOF_IPC_PANIC_WORK (SOF_IPC_PANIC_MAGIC | 0x1) +#define SOF_IPC_PANIC_IPC (SOF_IPC_PANIC_MAGIC | 0x2) +#define SOF_IPC_PANIC_ARCH (SOF_IPC_PANIC_MAGIC | 0x3) +#define SOF_IPC_PANIC_PLATFORM (SOF_IPC_PANIC_MAGIC | 0x4) +#define SOF_IPC_PANIC_TASK (SOF_IPC_PANIC_MAGIC | 0x5) +#define SOF_IPC_PANIC_EXCEPTION (SOF_IPC_PANIC_MAGIC | 0x6) +#define SOF_IPC_PANIC_DEADLOCK (SOF_IPC_PANIC_MAGIC | 0x7) +#define SOF_IPC_PANIC_STACK (SOF_IPC_PANIC_MAGIC | 0x8) +#define SOF_IPC_PANIC_IDLE (SOF_IPC_PANIC_MAGIC | 0x9) +#define SOF_IPC_PANIC_WFI (SOF_IPC_PANIC_MAGIC | 0xa) + /* panic info include filename and line number */ struct sof_ipc_panic_info { + struct sof_ipc_hdr hdr; + uint32_t code; /* SOF_IPC_PANIC_ */ char filename[SOF_TRACE_FILENAME_SIZE]; uint32_t linenum; } __packed; diff --git a/include/sound/sof/xtensa.h b/include/sound/sof/xtensa.h index 07f46385ea5f0d..a7189984000d5d 100644 --- a/include/sound/sof/xtensa.h +++ b/include/sound/sof/xtensa.h @@ -9,12 +9,15 @@ #ifndef __INCLUDE_SOUND_SOF_XTENSA_H__ #define __INCLUDE_SOUND_SOF_XTENSA_H__ +#include + /* * Architecture specific debug */ /* Xtensa Firmware Oops data */ struct sof_ipc_dsp_oops_xtensa { + struct sof_ipc_hdr hdr; uint32_t exccause; uint32_t excvaddr; uint32_t ps; diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index dbc80cde3ed6e2..cc0d3d2a47a74b 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -25,7 +25,7 @@ #define __INCLUDE_UAPI_SOUND_SOF_ABI_H__ /* SOF ABI version major, minor and patch numbers */ -#define SOF_ABI_MAJOR 2 +#define SOF_ABI_MAJOR 3 #define SOF_ABI_MINOR 0 #define SOF_ABI_PATCH 0 diff --git a/include/uapi/sound/sof/eq.h b/include/uapi/sound/sof/eq.h index cf7ad9a01d4fc9..71a159502d069d 100644 --- a/include/uapi/sound/sof/eq.h +++ b/include/uapi/sound/sof/eq.h @@ -71,12 +71,10 @@ struct sof_eq_fir_coef_data { int16_t coef[]; /* FIR coefficients */ } __packed; -/* In the struct above there's two 16 bit words (length, shift) and four - * reserved 32 bit words before the actual FIR coefficients. This information - * is used in parsing of the configuration blob. +/* In the struct above there's two words (length, shift) before the actual + * FIR coefficients. This information is used in parsing of the config blob. */ -#define SOF_EQ_FIR_COEF_NHEADER \ - (sizeof(const struct sof_eq_fir_coef_data) / sizeof(int16_t)) +#define SOF_EQ_FIR_COEF_NHEADER 2 /* IIR EQ type */ @@ -157,16 +155,10 @@ struct sof_eq_iir_biquad_df2t { */ #define SOF_EQ_IIR_DF2T_BIQUADS_MAX 11 -/* The number of int32_t words in sof_eq_iir_header_df2t: - * num_sections, num_sections_in_series, reserved[4] - */ -#define SOF_EQ_IIR_NHEADER_DF2T \ - (sizeof(const struct sof_eq_iir_header_df2t) / sizeof(int32_t)) +/* The number of int32_t words in sof_eq_iir_header_df2t */ +#define SOF_EQ_IIR_NHEADER_DF2T 2 -/* The number of int32_t words in sof_eq_iir_biquad_df2t: - * a2, a1, b2, b1, b0, output_shift, output_gain - */ -#define SOF_EQ_IIR_NBIQUAD_DF2T \ - (sizeof(const struct sof_eq_iir_biquad_df2t) / sizeof(int32_t)) +/* The number of int32_t words in sof_eq_iir_biquad_df2t */ +#define SOF_EQ_IIR_NBIQUAD_DF2T 7 #endif diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 8836e0eba4eae4..480e4a3110ddf6 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -244,6 +244,7 @@ static int sof_probe(struct platform_device *pdev) sdev->ops = plat_data->machine->pdata; sdev->pdata = plat_data; + sdev->first_boot = true; INIT_LIST_HEAD(&sdev->pcm_list); INIT_LIST_HEAD(&sdev->kcontrol_list); INIT_LIST_HEAD(&sdev->widget_list); @@ -289,7 +290,7 @@ static int sof_probe(struct platform_device *pdev) } /* load the firmware */ - ret = snd_sof_load_firmware(sdev, true); + ret = snd_sof_load_firmware(sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to load DSP firmware %d\n", ret); @@ -312,6 +313,9 @@ static int sof_probe(struct platform_device *pdev) "warning: failed to initialize trace %d\n", ret); } + /* hereafter all FW boot flows are for PM reasons */ + sdev->first_boot = false; + /* now register audio DSP platform driver and dai */ ret = snd_soc_register_component(&pdev->dev, &sdev->plat_drv, sdev->ops->drv, diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 1169f71ec6e29a..a81f278e8c38b4 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -409,8 +409,8 @@ static void bdw_get_windows(struct snd_sof_dev *sdev) static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) { struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; - struct sof_ipc_fw_version *v = &fw_ready->version; u32 offset; + int ret; /* mailbox must be on 4k boundary */ offset = MBOX_OFFSET; @@ -418,6 +418,10 @@ static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset %d\n", msg_id, offset); + /* no need to re-check version/ABI for subsequent boots */ + if (!sdev->first_boot) + return 0; + /* copy data from the DSP FW ready offset */ sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); @@ -426,13 +430,10 @@ static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) fw_ready->hostbox_offset, fw_ready->hostbox_size); - dev_info(sdev->dev, - " Firmware info: version %d:%d-%s build %d on %s:%s\n", - v->major, v->minor, v->tag, v->build, v->date, v->time); - - /* only copy the fw_version into debugfs at first boot */ - if (sdev->first_boot) - memcpy(&sdev->fw_version, v, sizeof(*v)); + /* make sure ABI version is compatible */ + ret = snd_sof_ipc_valid(sdev); + if (ret < 0) + return ret; /* now check for extended data */ snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index f33b9b4c101ecf..1695d67c336084 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -190,8 +190,8 @@ static void byt_get_windows(struct snd_sof_dev *sdev) static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) { struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; - struct sof_ipc_fw_version *v = &fw_ready->version; u32 offset; + int ret; /* mailbox must be on 4k boundary */ offset = MBOX_OFFSET; @@ -199,6 +199,10 @@ static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n", msg_id, offset); + /* no need to re-check version/ABI for subsequent boots */ + if (!sdev->first_boot) + return 0; + /* copy data from the DSP FW ready offset */ sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); @@ -207,13 +211,10 @@ static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) fw_ready->hostbox_offset, fw_ready->hostbox_size); - dev_info(sdev->dev, - " Firmware info: version %d:%d-%s build %d on %s:%s\n", - v->major, v->minor, v->tag, v->build, v->date, v->time); - - /* only copy the fw_version into debugfs at first boot */ - if (sdev->first_boot) - memcpy(&sdev->fw_version, v, sizeof(*v)); + /* make sure ABI version is compatible */ + ret = snd_sof_ipc_valid(sdev); + if (ret < 0) + return ret; /* now check for extended data */ snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 0b8d29c64ad360..5673905046cf3f 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -356,8 +356,8 @@ static void ipc_get_windows(struct snd_sof_dev *sdev) int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) { struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; - struct sof_ipc_fw_version *v = &fw_ready->version; u32 offset; + int ret; /* mailbox must be on 4k boundary */ offset = HDA_DSP_MBOX_UPLINK_OFFSET; @@ -365,22 +365,23 @@ int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n", msg_id, offset); + /* no need to re-check version/ABI for subsequent boots */ + if (!sdev->first_boot) + return 0; + /* copy data from the DSP FW ready offset */ sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); - dev_info(sdev->dev, - " Firmware info: version %d.%d-%s build %d on %s:%s\n", - v->major, v->minor, v->tag, v->build, v->date, v->time); - /* only copy the fw_version into debugfs at first boot */ - if (sdev->first_boot) - memcpy(&sdev->fw_version, v, sizeof(*v)); + /* make sure ABI version is compatible */ + ret = snd_sof_ipc_valid(sdev); + if (ret < 0) + return ret; /* now check for extended data */ snd_sof_fw_parse_ext_data(sdev, HDA_DSP_MBOX_UPLINK_OFFSET + sizeof(struct sof_ipc_fw_ready)); - if (sdev->first_boot) - ipc_get_windows(sdev); + ipc_get_windows(sdev); return 0; } diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 0ffa8bfaabb7d4..9cadaaf246146f 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -287,7 +287,7 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, int tag) return status; } -int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, bool first_boot) +int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev) { struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev); const char *fw_filename; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 8a31e60068af51..4a1bbc948b9fdd 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -470,7 +470,7 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); /* * DSP Code loader. */ -int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev, bool first_boot); +int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev); int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev); int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev); diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 14d315a6579132..27e5675f7c9623 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -410,8 +410,8 @@ static void hsw_get_windows(struct snd_sof_dev *sdev) static int hsw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) { struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; - struct sof_ipc_fw_version *v = &fw_ready->version; u32 offset; + int ret; /* mailbox must be on 4k boundary */ offset = MBOX_OFFSET; @@ -419,6 +419,10 @@ static int hsw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset %d\n", msg_id, offset); + /* no need to re-check version/ABI for subsequent boots */ + if (!sdev->first_boot) + return 0; + /* copy data from the DSP FW ready offset */ sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); @@ -427,13 +431,10 @@ static int hsw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) fw_ready->hostbox_offset, fw_ready->hostbox_size); - dev_info(sdev->dev, - " Firmware info: version %d:%d-%s build %d on %s:%s\n", - v->major, v->minor, v->tag, v->build, v->date, v->time); - - /* only copy the fw_version into debugfs at first boot */ - if (sdev->first_boot) - memcpy(&sdev->fw_version, v, sizeof(*v)); + /* make sure ABI version is compatible */ + ret = snd_sof_ipc_valid(sdev); + if (ret < 0) + return ret; /* now check for extended data */ snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 2a322d144a7f02..918cd7b732ddf0 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -196,7 +196,7 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, void *reply_data) { struct snd_sof_dev *sdev = ipc->sdev; - struct sof_ipc_hdr *hdr = (struct sof_ipc_hdr *)msg->msg_data; + struct sof_ipc_cmd_hdr *hdr = (struct sof_ipc_cmd_hdr *)msg->msg_data; unsigned long flags; int ret; @@ -382,7 +382,7 @@ static void ipc_msgs_rx(struct work_struct *work) struct snd_sof_ipc *ipc = container_of(work, struct snd_sof_ipc, rx_kwork); struct snd_sof_dev *sdev = ipc->sdev; - struct sof_ipc_hdr hdr; + struct sof_ipc_cmd_hdr hdr; u32 cmd, type; int err = -EINVAL; @@ -719,6 +719,46 @@ int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox, } EXPORT_SYMBOL(snd_sof_dsp_mailbox_init); +int snd_sof_ipc_valid(struct snd_sof_dev *sdev) +{ + struct sof_ipc_fw_ready *ready = &sdev->fw_ready; + struct sof_ipc_fw_version *v = &ready->version; + + dev_info(sdev->dev, + " Firmware info: version %d:%d:%d-%s\n", v->major, v->minor, + v->micro, v->tag); + dev_info(sdev->dev, + " Firmware: ABI %d:%d:%d Kernel ABI %d:%d:%d\n", + SOF_ABI_VERSION_MAJOR(v->abi_version), + SOF_ABI_VERSION_MINOR(v->abi_version), + SOF_ABI_VERSION_PATCH(v->abi_version), + SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH); + + if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, v->abi_version)) { + dev_err(sdev->dev, "error: incompatible FW ABI version\n"); + return -EINVAL; + } + + if (ready->debug.bits.build) { + dev_info(sdev->dev, + " Firmware debug build %d on %s-%s - options:\n" + " GDB: %s\n" + " lock debug: %s\n" + " lock vdebug: %s\n", + v->build, v->date, v->time, + ready->debug.bits.gdb ? "enabled" : "disabled", + ready->debug.bits.locks ? "enabled" : "disabled", + ready->debug.bits.locks_verbose ? + "enabled" : "disabled"); + } + + /* copy the fw_version into debugfs at first boot */ + memcpy(&sdev->fw_version, v, sizeof(*v)); + + return 0; +} +EXPORT_SYMBOL(snd_sof_ipc_valid); + struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) { struct snd_sof_ipc *ipc; diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 0dcc7a23df5853..dbadd8c521e605 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -199,8 +199,7 @@ static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw) return 0; } -int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev, - bool first_boot) +int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev) { struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev); const char *fw_filename; @@ -248,15 +247,12 @@ int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev, } EXPORT_SYMBOL(snd_sof_load_firmware_memcpy); -int snd_sof_load_firmware(struct snd_sof_dev *sdev, - bool first_boot) +int snd_sof_load_firmware(struct snd_sof_dev *sdev) { dev_dbg(sdev->dev, "loading firmware\n"); - sdev->first_boot = first_boot; - if (sdev->ops->load_firmware) - return sdev->ops->load_firmware(sdev, first_boot); + return sdev->ops->load_firmware(sdev); return 0; } EXPORT_SYMBOL(snd_sof_load_firmware); diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 2abf01b7f15b01..1b01383a380dba 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -84,6 +84,7 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, pcm.hdr.size = sizeof(pcm); pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS; pcm.comp_id = spcm->stream[substream->stream].comp_id; + pcm.params.hdr.size = sizeof(pcm.params); pcm.params.buffer.phy_addr = spcm->stream[substream->stream].page_table.addr; pcm.params.buffer.size = runtime->dma_bytes; diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 3c6781f2498ddf..4e056bb0d7a440 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -63,7 +63,7 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev) struct sof_ipc_pipe_new *pipeline; struct snd_sof_dai *dai; struct sof_ipc_comp_dai *comp_dai; - struct sof_ipc_hdr *hdr; + struct sof_ipc_cmd_hdr *hdr; int ret = 0; /* restore pipeline components */ @@ -97,7 +97,7 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev) ret = sof_load_pipeline_ipc(sdev, pipeline, &r); break; default: - hdr = (struct sof_ipc_hdr *)swidget->private; + hdr = (struct sof_ipc_cmd_hdr *)swidget->private; ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, swidget->private, hdr->size, &r, sizeof(r)); @@ -264,7 +264,7 @@ static int sof_resume(struct device *dev, int runtime_resume) } /* load the firmware */ - ret = snd_sof_load_firmware(sdev, false); + ret = snd_sof_load_firmware(sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to load DSP firmware after resume %d\n", diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index ea248d0be32ba7..f3c609320a3bb2 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -152,8 +152,7 @@ struct snd_sof_dsp_ops { struct snd_pcm_substream *substream); /* FW loading */ - int (*load_firmware)(struct snd_sof_dev *sof_dev, - bool first_boot); + int (*load_firmware)(struct snd_sof_dev *sof_dev); int (*load_module)(struct snd_sof_dev *sof_dev, struct snd_sof_mod_hdr *hdr); int (*fw_ready)(struct snd_sof_dev *sdev, u32 msg_id); @@ -311,6 +310,7 @@ struct snd_sof_dev { /* DSP firmware boot */ wait_queue_head_t boot_wait; u32 boot_complete; + u32 first_boot; /* DSP HW differentiation */ struct snd_sof_pdata *pdata; @@ -377,7 +377,6 @@ struct snd_sof_dev { /* PM */ u32 restore_kcontrols; /* restore kcontrols upon resume */ - u32 first_boot; void *private; /* core does not touch this */ }; @@ -414,10 +413,8 @@ int snd_sof_create_page_table(struct snd_sof_dev *sdev, /* * Firmware loading. */ -int snd_sof_load_firmware(struct snd_sof_dev *sdev, - bool first_boot); -int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev, - bool first_boot); +int snd_sof_load_firmware(struct snd_sof_dev *sdev); +int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev); int snd_sof_run_firmware(struct snd_sof_dev *sdev); int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, struct snd_sof_mod_hdr *module); @@ -437,6 +434,7 @@ int snd_sof_ipc_stream_pcm_params(struct snd_sof_dev *sdev, int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox, size_t dspbox_size, u32 hostbox, size_t hostbox_size); +int snd_sof_ipc_valid(struct snd_sof_dev *sdev); int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes); struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 5955f061e152ce..06e94809aa3586 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -930,6 +930,7 @@ static int sof_widget_load_dai(struct snd_soc_component *scomp, int index, comp_dai.comp.id = swidget->comp_id; comp_dai.comp.type = SOF_COMP_DAI; comp_dai.comp.pipeline_id = index; + comp_dai.config.hdr.size = sizeof(comp_dai.config); ret = sof_parse_tokens(scomp, &comp_dai, dai_tokens, ARRAY_SIZE(dai_tokens), private->array, @@ -1041,6 +1042,7 @@ static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index, host->comp.type = SOF_COMP_HOST; host->comp.pipeline_id = index; host->direction = dir; + host->config.hdr.size = sizeof(host->config); ret = sof_parse_tokens(scomp, host, pcm_tokens, ARRAY_SIZE(pcm_tokens), private->array, @@ -1203,6 +1205,7 @@ static int sof_widget_load_mixer(struct snd_soc_component *scomp, int index, mixer->comp.id = swidget->comp_id; mixer->comp.type = SOF_COMP_MIXER; mixer->comp.pipeline_id = index; + mixer->config.hdr.size = sizeof(mixer->config); ret = sof_parse_tokens(scomp, &mixer->config, comp_tokens, ARRAY_SIZE(comp_tokens), private->array, @@ -1291,6 +1294,7 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, volume->comp.id = swidget->comp_id; volume->comp.type = SOF_COMP_VOLUME; volume->comp.pipeline_id = index; + volume->config.hdr.size = sizeof(volume->config); ret = sof_parse_tokens(scomp, volume, volume_tokens, ARRAY_SIZE(volume_tokens), private->array, @@ -1353,6 +1357,7 @@ static int sof_widget_load_src(struct snd_soc_component *scomp, int index, src->comp.id = swidget->comp_id; src->comp.type = SOF_COMP_SRC; src->comp.pipeline_id = index; + src->config.hdr.size = sizeof(src->config); ret = sof_parse_tokens(scomp, src, src_tokens, ARRAY_SIZE(src_tokens), private->array, @@ -1411,6 +1416,7 @@ static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index, tone->comp.id = swidget->comp_id; tone->comp.type = SOF_COMP_TONE; tone->comp.pipeline_id = index; + tone->config.hdr.size = sizeof(tone->config); ret = sof_parse_tokens(scomp, tone, tone_tokens, ARRAY_SIZE(tone_tokens), private->array, @@ -1494,6 +1500,8 @@ static int sof_effect_fir_load(struct snd_soc_component *scomp, int index, fir->comp.id = swidget->comp_id; fir->comp.type = SOF_COMP_EQ_FIR; fir->comp.pipeline_id = index; + fir->config.hdr.size = sizeof(fir->config); + ret = sof_parse_tokens(scomp, &fir->config, comp_tokens, ARRAY_SIZE(comp_tokens), private->array, @@ -1571,6 +1579,7 @@ static int sof_effect_iir_load(struct snd_soc_component *scomp, int index, iir->comp.id = swidget->comp_id; iir->comp.type = SOF_COMP_EQ_IIR; iir->comp.pipeline_id = index; + iir->config.hdr.size = sizeof(iir->config); ret = sof_parse_tokens(scomp, &iir->config, comp_tokens, ARRAY_SIZE(comp_tokens), private->array, From 56d03d6192dd021b438acfffad32eac952f362bc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 18:11:49 -0600 Subject: [PATCH 0372/1995] ASoC: SOF: Intel: hda-dai: fix compilation with W=1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sound/soc/sof/intel/hda-dai.c: In function ‘hda_link_hw_free’: sound/soc/sof/intel/hda-dai.c:213:22: warning: variable ‘sdev’ set but not used [-Wunused-but-set-variable] struct snd_sof_dev *sdev; ^~~~ Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-dai.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 801d45e0218e8e..ae7258450f3d2c 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -210,7 +210,6 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream, unsigned int stream_tag; struct hdac_bus *bus; struct hdac_ext_link *link; - struct snd_sof_dev *sdev; struct hdac_stream *hstream; struct hdac_ext_stream *stream; struct snd_soc_pcm_runtime *rtd; @@ -234,7 +233,6 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream, link_dev->link_prepared = 0; } else { /* release all hda streams when dai link is unloaded */ - sdev = snd_soc_component_get_drvdata(dai->component); pcm_substream.stream = SNDRV_PCM_STREAM_PLAYBACK; stream = snd_soc_dai_get_dma_data(dai, &pcm_substream); if (stream) { From 1ec0aec36e482a416f2831ec456345380072c745 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 18:16:04 -0600 Subject: [PATCH 0373/1995] ASoC: SOF: debug: fix issue with W=1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sound/soc/sof/debug.c: In function ‘sof_dfsentry_read’: sound/soc/sof/debug.c:62:10: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits] if (ret < 0) Defining a 'ret' variable as size_t was borderline criminal in the first place... Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/debug.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 67f6cf79b72947..e5a951ef9829f2 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -31,7 +31,8 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, int size; u32 *buf; loff_t pos = *ppos; - size_t ret; + size_t size_ret; + int ret; size = dfse->size; @@ -60,17 +61,17 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, */ ret = pm_runtime_put_sync_autosuspend(sdev->dev); if (ret < 0) - dev_warn(sdev->dev, "warn: debugFS failed to autosuspend %zd\n", + dev_warn(sdev->dev, "warn: debugFS failed to autosuspend %d\n", ret); /* copy to userspace */ - ret = copy_to_user(buffer, buf, count); + size_ret = copy_to_user(buffer, buf, count); kfree(buf); /* update count & position if copy succeeded */ - if (ret == count) + if (size_ret == count) return -EFAULT; - count -= ret; + count -= size_ret; *ppos = pos + count; return count; From 413103f3b7c5e1286e54cb9867acb89cee10c17d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 18:20:15 -0600 Subject: [PATCH 0374/1995] ASoC: SOF: topology: fix issues with W=1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sound/soc/sof/topology.c: In function ‘sof_control_load_volume’: sound/soc/sof/topology.c:261:28: warning: variable ‘cdata’ set but not used [-Wunused-but-set-variable] struct sof_ipc_ctrl_data *cdata; ^~~~~ sound/soc/sof/topology.c: In function ‘snd_sof_load_topology’: sound/soc/sof/topology.c:2711:27: warning: variable ‘hdr’ set but not used [-Wunused-but-set-variable] struct snd_soc_tplg_hdr *hdr; ^~~ Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/topology.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 06e94809aa3586..b09db12d829844 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -258,7 +258,6 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_mixer_control *mc = (struct snd_soc_tplg_mixer_control *)hdr; - struct sof_ipc_ctrl_data *cdata; /* validate topology data */ if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN) @@ -269,7 +268,6 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, sizeof(struct sof_ipc_ctrl_value_chan) * le32_to_cpu(mc->num_channels); scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); - cdata = scontrol->control_data; if (!scontrol->control_data) return -ENOMEM; @@ -2708,7 +2706,6 @@ EXPORT_SYMBOL(snd_sof_init_topology); int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file) { const struct firmware *fw; - struct snd_soc_tplg_hdr *hdr; int ret; if (sdev->tplg_loaded) { @@ -2725,7 +2722,6 @@ int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file) return ret; } - hdr = (struct snd_soc_tplg_hdr *)fw->data; ret = snd_soc_tplg_component_load(sdev->component, &sof_tplg_ops, fw, SND_SOC_TPLG_INDEX_ALL); From 914de4b2e7b0b72c4cc43925f11da36ef9243110 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 18:25:43 -0600 Subject: [PATCH 0375/1995] ASoC: SOF: core: feedback from Andy Shevchenko Constants with _MS suffix simplification of search loop Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 480e4a3110ddf6..3ff1bc45ceda1b 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -15,8 +15,8 @@ #include "ops.h" /* SOF defaults if not provided by the platform in ms */ -#define TIMEOUT_DEFAULT_IPC 5 -#define TIMEOUT_DEFAULT_BOOT 100 +#define TIMEOUT_DEFAULT_IPC_MS 5 +#define TIMEOUT_DEFAULT_BOOT_MS 100 /* * Generic object lookup APIs. @@ -107,10 +107,7 @@ struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev, struct snd_sof_dai *dai = NULL; list_for_each_entry(dai, &sdev->dai_list, list) { - if (!dai->name) - continue; - - if (strcmp(name, dai->name) == 0) + if (dai->name && (strcmp(name, dai->name) == 0)) return dai; } @@ -259,11 +256,11 @@ static int sof_probe(struct platform_device *pdev) /* set default timeouts if none provided */ if (plat_data->desc->ipc_timeout == 0) - sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC; + sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC_MS; else sdev->ipc_timeout = plat_data->desc->ipc_timeout; if (plat_data->desc->boot_timeout == 0) - sdev->boot_timeout = TIMEOUT_DEFAULT_BOOT; + sdev->boot_timeout = TIMEOUT_DEFAULT_BOOT_MS; else sdev->boot_timeout = plat_data->desc->boot_timeout; From 664c5548e9d84b816655e671e47e476a224e0ec4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 18:30:57 -0600 Subject: [PATCH 0376/1995] ASoC: SOF: remove .shutdown callback Not used, remove for now Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 5 ----- sound/soc/sof/sof-acpi-dev.c | 6 ------ sound/soc/sof/sof-pci-dev.c | 6 ------ sound/soc/sof/sof-priv.h | 1 - 4 files changed, 18 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 3ff1bc45ceda1b..003ae3961c4f15 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -374,11 +374,6 @@ static int sof_remove(struct platform_device *pdev) return 0; } -void snd_sof_shutdown(struct device *dev) -{ -} -EXPORT_SYMBOL(snd_sof_shutdown); - static struct platform_driver sof_driver = { .driver = { .name = "sof-audio", diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 52de8ac8ede0e8..78038916032873 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -221,11 +221,6 @@ static int sof_acpi_probe(struct platform_device *pdev) return ret; } -static void sof_acpi_shutdown(struct platform_device *pdev) -{ - snd_sof_shutdown(&pdev->dev); -} - static int sof_acpi_remove(struct platform_device *pdev) { struct sof_platform_priv *priv = dev_get_drvdata(&pdev->dev); @@ -257,7 +252,6 @@ MODULE_DEVICE_TABLE(acpi, sof_acpi_match); static struct platform_driver snd_sof_acpi_driver = { .probe = sof_acpi_probe, .remove = sof_acpi_remove, - .shutdown = sof_acpi_shutdown, .driver = { .name = "sof-audio-acpi", .pm = &sof_acpi_pm, diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 449ff9cbc793aa..f36f011087dce8 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -283,11 +283,6 @@ static int sof_pci_probe(struct pci_dev *pci, return ret; } -static void sof_pci_shutdown(struct pci_dev *pci) -{ - snd_sof_shutdown(&pci->dev); -} - static void sof_pci_remove(struct pci_dev *pci) { struct sof_platform_priv *priv = pci_get_drvdata(pci); @@ -351,7 +346,6 @@ static struct pci_driver snd_sof_pci_driver = { .id_table = sof_pci_ids, .probe = sof_pci_probe, .remove = sof_pci_remove, - .shutdown = sof_pci_shutdown, .driver = { .pm = &sof_pci_pm, }, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index f3c609320a3bb2..6efea9696adfdb 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -396,7 +396,6 @@ struct sof_platform_priv { /* * Device Level. */ -void snd_sof_shutdown(struct device *dev); int snd_sof_runtime_suspend(struct device *dev); int snd_sof_runtime_resume(struct device *dev); int snd_sof_resume(struct device *dev); From d6bd79f53013f73b9280d16a328a80bbb9a6f674 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 18:34:16 -0600 Subject: [PATCH 0377/1995] ASoC: SOF: add _MS suffix to SND_SOF_SUSPEND_DELAY Feedback from Andy Shevchenko Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pcm.c | 2 +- sound/soc/sof/sof-acpi-dev.c | 2 +- sound/soc/sof/sof-pci-dev.c | 2 +- sound/soc/sof/sof-priv.h | 2 +- sound/soc/sof/sof-spi-dev.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 1b01383a380dba..a6b11217ee509e 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -703,7 +703,7 @@ static int sof_pcm_probe(struct snd_soc_component *component) /* enable runtime PM with auto suspend */ pm_runtime_set_autosuspend_delay(component->dev, - SND_SOF_SUSPEND_DELAY); + SND_SOF_SUSPEND_DELAY_MS); pm_runtime_use_autosuspend(component->dev); pm_runtime_enable(component->dev); diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 78038916032873..5c388e7f07d7d1 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -214,7 +214,7 @@ static int sof_acpi_probe(struct platform_device *pdev) } /* allow runtime_pm */ - pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY); + pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); pm_runtime_use_autosuspend(dev); pm_runtime_allow(dev); diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index f36f011087dce8..4c03ba30411468 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -263,7 +263,7 @@ static int sof_pci_probe(struct pci_dev *pci, } /* allow runtime_pm */ - pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY); + pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); pm_runtime_use_autosuspend(dev); /* diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 6efea9696adfdb..a5f8f2d2baa9fc 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -33,7 +33,7 @@ #define SND_SOF_BARS 8 /* time in ms for runtime suspend delay */ -#define SND_SOF_SUSPEND_DELAY 2000 +#define SND_SOF_SUSPEND_DELAY_MS 2000 /* DMA buffer size for trace */ #define DMA_BUF_SIZE_FOR_TRACE (PAGE_SIZE * 16) diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index 372a5d1ed00e75..1eda25a68703c2 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -147,7 +147,7 @@ static int sof_spi_probe(struct spi_device *spi) spi->irq = irq; /* allow runtime_pm */ - pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY); + pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); pm_runtime_use_autosuspend(dev); pm_runtime_allow(dev); From 6b1f637a890f9d04ebcadbdeec29c65336f3e217 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 18:38:00 -0600 Subject: [PATCH 0378/1995] ASoC: SOF: test for NULL before platform_device_unregister Unclear if platform_device_register_data can return NULL, err on the side of caution Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 2 +- sound/soc/sof/intel/hda.c | 2 +- sound/soc/sof/sof-acpi-dev.c | 2 +- sound/soc/sof/sof-pci-dev.c | 2 +- sound/soc/sof/sof-spi-dev.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 003ae3961c4f15..efa58d78b5b31d 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -362,7 +362,7 @@ static int sof_remove(struct platform_device *pdev) struct snd_sof_dev *sdev = dev_get_drvdata(&pdev->dev); struct snd_sof_pdata *pdata = sdev->pdata; - if (pdata && !IS_ERR(pdata->pdev_mach)) + if (pdata && !IS_ERR_OR_NULL(pdata->pdev_mach)) platform_device_unregister(pdata->pdev_mach); snd_soc_unregister_component(&pdev->dev); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index b726e270821027..fcefc1ab498d88 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -661,7 +661,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) snd_hdac_ext_bus_device_remove(bus); #endif - if (sdev->hda && (!IS_ERR(sdev->hda->dmic_dev))) + if (sdev->hda && (!IS_ERR_OR_NULL(sdev->hda->dmic_dev))) platform_device_unregister(sdev->hda->dmic_dev); /* disable DSP IRQ */ diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 5c388e7f07d7d1..ad9902bc706217 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -226,7 +226,7 @@ static int sof_acpi_remove(struct platform_device *pdev) struct sof_platform_priv *priv = dev_get_drvdata(&pdev->dev); struct snd_sof_pdata *sof_pdata = priv->sof_pdata; - if (!IS_ERR(priv->pdev_pcm)) + if (!IS_ERR_OR_NULL(priv->pdev_pcm)) platform_device_unregister(priv->pdev_pcm); release_firmware(sof_pdata->fw); diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 4c03ba30411468..cf7976fb4335b2 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -289,7 +289,7 @@ static void sof_pci_remove(struct pci_dev *pci) struct snd_sof_pdata *sof_pdata = priv->sof_pdata; /* unregister sof-audio platform driver */ - if (!IS_ERR(priv->pdev_pcm)) + if (!IS_ERR_OR_NULL(priv->pdev_pcm)) platform_device_unregister(priv->pdev_pcm); /* release firmware */ diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index 1eda25a68703c2..3bb284c2bffeea 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -159,7 +159,7 @@ static int sof_spi_remove(struct spi_device *spi) struct sof_platform_priv *priv = spi_get_drvdata(spi); struct snd_sof_pdata *sof_pdata = priv->sof_pdata; - if (!IS_ERR(priv->pdev_pcm)) + if (!IS_ERR_OR_NULL(priv->pdev_pcm)) platform_device_unregister(priv->pdev_pcm); release_firmware(sof_pdata->fw); From 5b589864f15e364f717c47ce1af98e7938a7c5b3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 18:43:03 -0600 Subject: [PATCH 0379/1995] ASoC: SOF: use PLATFORM_DEVID_NONE for platform_device_register_data Suggested by Andy Shevchenko Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 2 +- sound/soc/sof/intel/hda.c | 3 ++- sound/soc/sof/utils.c | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index efa58d78b5b31d..46c9962c7bba59 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -330,7 +330,7 @@ static int sof_probe(struct platform_device *pdev) /* register machine driver, pass machine info as pdata */ plat_data->pdev_mach = platform_device_register_data(sdev->dev, drv_name, - -1, mach, size); + PLATFORM_DEVID_NONE, mach, size); if (IS_ERR(plat_data->pdev_mach)) { ret = PTR_ERR(plat_data->pdev_mach); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index fcefc1ab498d88..14942829ff16aa 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -458,7 +458,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) hdev->desc = chip; hdev->dmic_dev = platform_device_register_data(&pci->dev, "dmic-codec", - -1, NULL, 0); + PLATFORM_DEVID_NONE, + NULL, 0); if (IS_ERR(hdev->dmic_dev)) { dev_err(&pci->dev, "error: failed to create DMIC device\n"); return PTR_ERR(hdev->dmic_dev); diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index bf66e14bc258b1..ccaf58d8c2264d 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -55,7 +55,8 @@ int sof_create_platform_device(struct sof_platform_priv *priv) struct device *dev = sof_pdata->dev; priv->pdev_pcm = - platform_device_register_data(dev, "sof-audio", -1, + platform_device_register_data(dev, "sof-audio", + PLATFORM_DEVID_NONE, sof_pdata, sizeof(*sof_pdata)); if (IS_ERR(priv->pdev_pcm)) { dev_err(dev, "error: cannot register device sof-audio. Error %d\n", From a454e63dcfc32bbb8ed6e3632e7b1e6ac5a18721 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 18:59:19 -0600 Subject: [PATCH 0380/1995] ASoC: SOF: use min when checking two or three values Maybe there are other cases where this is needed Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/control.c | 5 ++--- sound/soc/sof/debug.c | 5 ++--- sound/soc/sof/trace.c | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 2000f62e931b6e..3587f9f26a7473 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -297,7 +297,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, /* The maximum length that can be copied is limited by IPC max * length and topology defined length for ext bytes control. */ - max_size = (be->max < max_size) ? be->max : max_size; + max_size = min(be->max, max_size); if (header.length > max_size) { dev_err(sdev->dev, "error: Bytes data size %d exceeds max %d.\n", header.length, max_size); @@ -392,8 +392,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, /* Prevent read of other kernel data or possibly corrupt response */ data_size = cdata->data->size + sizeof(const struct sof_abi_hdr); - max_size = (size < max_size) ? size : max_size; - max_size = (be->max < max_size) ? be->max : max_size; + max_size = min3(be->max, max_size, (int)size); if (data_size > max_size) { dev_err(sdev->dev, "error: user data size %d exceeds max size %d.\n", data_size, max_size); diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index e5a951ef9829f2..2224d086566535 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -41,11 +41,10 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, return -EINVAL; if (pos >= size || !count) return 0; - if (count > size - pos) - count = size - pos; + count = min(count, (size_t)(size - pos)); /* intermediate buffer size must be u32 multiple */ - size = (count + 3) & ~3; + size = round_up(count, 4); buf = kzalloc(size, GFP_KERNEL); if (!buf) return -ENOMEM; diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 9871a174f9ca11..c268b560b12f07 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -75,8 +75,7 @@ static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer, lpos_64 = lpos; lpos = do_div(lpos_64, buffer_size); - if (count > buffer_size - lpos) - count = buffer_size - lpos; + count = min(count, (size_t)(buffer_size - lpos)); /* get available count based on current host offset */ avail = sof_wait_trace_avail(sdev, lpos, buffer_size); @@ -86,7 +85,7 @@ static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer, } /* make sure count is <= avail */ - count = avail > count ? count : avail; + count = min(avail, count); /* copy available trace data to debugfs */ rem = copy_to_user(buffer, dfse->buf + lpos, count); From fb662e6a542ba788a7dfb160fe4860ec719ab7e9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 19:01:31 -0600 Subject: [PATCH 0381/1995] ASoC: SOF: ipc: use MS instead of MSEC SI units people. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/ipc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 918cd7b732ddf0..2fd2ad4249c93b 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -15,10 +15,10 @@ #include "ops.h" /* - * IPC message default size and timeout (msecs). + * IPC message default size and timeout (ms). * TODO: allow platforms to set size and timeout. */ -#define IPC_TIMEOUT_MSECS 300 +#define IPC_TIMEOUT_MS 300 #define IPC_EMPTY_LIST_SIZE 8 static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id); @@ -202,7 +202,7 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, /* wait for DSP IPC completion */ ret = wait_event_timeout(msg->waitq, msg->ipc_complete, - msecs_to_jiffies(IPC_TIMEOUT_MSECS)); + msecs_to_jiffies(IPC_TIMEOUT_MS)); spin_lock_irqsave(&sdev->ipc_lock, flags); From 5de0de8471eb7b3babd2d754646dd698416cff0f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 19:03:05 -0600 Subject: [PATCH 0382/1995] ASoC: SOF: ipc: don't check for empty list before list_for_each_entry Feedback from Andy Shevchenko Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/ipc.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 2fd2ad4249c93b..1b4b6abb0e7051 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -312,15 +312,11 @@ static struct snd_sof_ipc_msg *sof_ipc_reply_find_msg(struct snd_sof_ipc *ipc, header = SOF_IPC_MESSAGE_ID(header); - if (list_empty(&ipc->reply_list)) - goto err; - list_for_each_entry(msg, &ipc->reply_list, list) { if (SOF_IPC_MESSAGE_ID(msg->header) == header) return msg; } -err: dev_err(sdev->dev, "error: rx list empty but received 0x%x\n", header); return NULL; From 83d64864472a4179d2bd418a946d9607121bfbb2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 19:04:56 -0600 Subject: [PATCH 0383/1995] ASoC: SOF: ipc: indentations and style Feedback from Andy Shevchenko. Keep indent on for subparts of the log Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/ipc.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 1b4b6abb0e7051..0fdd72a801f73f 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -721,10 +721,10 @@ int snd_sof_ipc_valid(struct snd_sof_dev *sdev) struct sof_ipc_fw_version *v = &ready->version; dev_info(sdev->dev, - " Firmware info: version %d:%d:%d-%s\n", v->major, v->minor, + "Firmware info: version %d:%d:%d-%s\n", v->major, v->minor, v->micro, v->tag); dev_info(sdev->dev, - " Firmware: ABI %d:%d:%d Kernel ABI %d:%d:%d\n", + "Firmware: ABI %d:%d:%d Kernel ABI %d:%d:%d\n", SOF_ABI_VERSION_MAJOR(v->abi_version), SOF_ABI_VERSION_MINOR(v->abi_version), SOF_ABI_VERSION_PATCH(v->abi_version), @@ -737,15 +737,14 @@ int snd_sof_ipc_valid(struct snd_sof_dev *sdev) if (ready->debug.bits.build) { dev_info(sdev->dev, - " Firmware debug build %d on %s-%s - options:\n" - " GDB: %s\n" - " lock debug: %s\n" - " lock vdebug: %s\n", + "Firmware debug build %d on %s-%s - options:\n" + " GDB: %s\n" + " lock debug: %s\n" + " lock vdebug: %s\n", v->build, v->date, v->time, ready->debug.bits.gdb ? "enabled" : "disabled", ready->debug.bits.locks ? "enabled" : "disabled", - ready->debug.bits.locks_verbose ? - "enabled" : "disabled"); + ready->debug.bits.locks_verbose ? "enabled" : "disabled"); } /* copy the fw_version into debugfs at first boot */ From 1f05c53208264513a0d13fc6af95f15455b039ad Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 19:16:51 -0600 Subject: [PATCH 0384/1995] ASoC: SOF: ops: simplify PCI access remove change variable, use return false/true instead Feedback from Andy Shevchenko Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/ops.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index 41143fd9777212..778b0aadf34539 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -14,7 +14,6 @@ int snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset, u32 mask, u32 value) { - bool change; unsigned int old, new; u32 ret = ~0; /* explicit init to remove uninitialized use warnings */ @@ -25,14 +24,14 @@ int snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset, old = ret; new = (old & (~mask)) | (value & mask); - change = (old != new); - if (change) { - pci_write_config_dword(sdev->pci, offset, new); - dev_dbg(sdev->dev, "Debug PCIW: %8.8x at %8.8x\n", value, - offset); - } + if (old == new) + return false; - return change; + pci_write_config_dword(sdev->pci, offset, new); + dev_dbg(sdev->dev, "Debug PCIW: %8.8x at %8.8x\n", value, + offset); + + return true; } EXPORT_SYMBOL(snd_sof_pci_update_bits_unlocked); @@ -52,7 +51,6 @@ EXPORT_SYMBOL(snd_sof_pci_update_bits); int snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 mask, u32 value) { - bool change; unsigned int old, new; u32 ret; @@ -61,29 +59,30 @@ int snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, old = ret; new = (old & (~mask)) | (value & mask); - change = (old != new); - if (change) - snd_sof_dsp_write(sdev, bar, offset, new); + if (old == new) + return false; - return change; + snd_sof_dsp_write(sdev, bar, offset, new); + + return true; } EXPORT_SYMBOL(snd_sof_dsp_update_bits_unlocked); int snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar, u32 offset, u64 mask, u64 value) { - bool change; u64 old, new; old = snd_sof_dsp_read64(sdev, bar, offset); new = (old & (~mask)) | (value & mask); - change = (old != new); - if (change) - snd_sof_dsp_write64(sdev, bar, offset, new); + if (old == new) + return false; - return change; + snd_sof_dsp_write64(sdev, bar, offset, new); + + return true; } EXPORT_SYMBOL(snd_sof_dsp_update_bits64_unlocked); From d09af6483b359359fa9585ad4ff33bd03e40191c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 19:20:07 -0600 Subject: [PATCH 0385/1995] ASoC: SOF: ops: improve readability remove new line, even if it makes checkpatch unhappy Feedback from Andy Shevchenko Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/ops.c | 3 +-- sound/soc/sof/ops.h | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index 778b0aadf34539..1eb759c6569c76 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -164,8 +164,7 @@ int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset, timeout /= 10; for (time = timeout; time > 0; time--) { - if ((snd_sof_dsp_read(sdev, bar, offset) & mask) == - target) + if ((snd_sof_dsp_read(sdev, bar, offset) & mask) == target) break; usleep_range(5000, 10000); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 405e39155645a9..fc4868712af9ae 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -157,8 +157,7 @@ static inline void snd_sof_dsp_write64(struct snd_sof_dev *sdev, u32 bar, u32 offset, u64 value) { if (sdev->ops->write64) - sdev->ops->write64(sdev, - sdev->bar[bar] + offset, value); + sdev->ops->write64(sdev, sdev->bar[bar] + offset, value); } static inline u32 snd_sof_dsp_read(struct snd_sof_dev *sdev, u32 bar, From df9ed1ff2a38a951b45b0843b4bd898420ca654d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 19:22:08 -0600 Subject: [PATCH 0386/1995] ASoC: SOF: loader.c: remove unused variable Feedback from Andy Shevchenko Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/loader.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index dbadd8c521e605..70b3038e3e2b59 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -18,8 +18,6 @@ static int get_ext_windows(struct snd_sof_dev *sdev, struct sof_ipc_ext_data_hdr *ext_hdr) { struct sof_ipc_window *w = (struct sof_ipc_window *)ext_hdr; - - int ret = 0; size_t size; if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS) @@ -32,7 +30,7 @@ static int get_ext_windows(struct snd_sof_dev *sdev, if (!sdev->info_window) return -ENOMEM; - return ret; + return 0; } /* parse the extended FW boot data structures from FW boot message */ From 16923160c35087ee57f3979df3cda18426eb1e05 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Dec 2018 19:44:38 -0600 Subject: [PATCH 0387/1995] ASoC: SOF: spi: fix error with W=1 remove spi_pm, will be added back when needed Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-spi-dev.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index 3bb284c2bffeea..81d79bcee10f4d 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -22,13 +22,6 @@ #include "hw-spi.h" #include "ops.h" -static const struct dev_pm_ops spi_pm = { - SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) - SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, - NULL) - .suspend_late = snd_sof_suspend_late, -}; - /* FIXME: replace with some meaningful values */ static struct snd_soc_acpi_mach spi_machines[] = { { From 099e1fdb2f0705a80c95232caa20ec0ddc112c0f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 12 Dec 2018 11:16:58 -0600 Subject: [PATCH 0388/1995] ASoC: SOF: sof.h: move gpio to int Apparently cannot be unsigned int Signed-off-by: Pierre-Louis Bossart --- include/sound/sof.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index 4ed6e23791412e..c69d636a0c30a9 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -42,7 +42,7 @@ struct snd_sof_pdata { const struct sof_dev_desc *desc; /* SPI data */ - unsigned int gpio; + int gpio; unsigned int active; /* machine */ From 685d182c4cd7af5169e0d9f460ed22c443a41e10 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 12 Dec 2018 10:33:47 -0800 Subject: [PATCH 0389/1995] ASoC: SOF: pm: use loop to suspend stream in both directions Use a loop to suspend streams in both directions. Remove RUNTIME_PM macro and use bool instead. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pm.c | 53 +++++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 4e056bb0d7a440..e34b2a5bd0f358 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -11,8 +11,6 @@ #include "ops.h" #include "sof-priv.h" -#define RUNTIME_PM 1 - static int sof_restore_kcontrols(struct snd_sof_dev *sdev) { struct snd_sof_control *scontrol = NULL; @@ -198,48 +196,37 @@ static void sof_suspend_streams(struct snd_sof_dev *sdev) { struct snd_sof_pcm *spcm; struct snd_pcm_substream *substream; - int dir; + int dir, playback_dir, capture_dir; /* suspend all running streams */ list_for_each_entry(spcm, &sdev->pcm_list, list) { mutex_lock(&spcm->mutex); - /* suspend running playback stream */ - dir = SNDRV_PCM_STREAM_PLAYBACK; - substream = spcm->stream[dir].substream; - - if (substream && substream->runtime) { + playback_dir = SNDRV_PCM_STREAM_PLAYBACK; + capture_dir = SNDRV_PCM_STREAM_CAPTURE; - snd_pcm_suspend(substream); + /* suspend running streams in both directions */ + for (dir = playback_dir; dir <= capture_dir; dir++) { + substream = spcm->stream[dir].substream; - /* - * set restore_stream so that hw_params can be - * restored during resume - */ - spcm->restore_stream[dir] = 1; - } + if (substream && substream->runtime) { - /* suspend running capture stream */ - dir = SNDRV_PCM_STREAM_CAPTURE; - substream = spcm->stream[dir].substream; + snd_pcm_suspend(substream); - if (substream && substream->runtime) { - - snd_pcm_suspend(substream); - - /* - * set restore_stream so that hw_params can be - * restored during resume - */ - spcm->restore_stream[dir] = 1; + /* + * set restore_stream so that hw_params can be + * restored during resume + */ + spcm->restore_stream[dir] = 1; + } } mutex_unlock(&spcm->mutex); } } -static int sof_resume(struct device *dev, int runtime_resume) +static int sof_resume(struct device *dev, bool runtime_resume) { struct sof_platform_priv *priv = dev_get_drvdata(dev); struct snd_sof_dev *sdev = dev_get_drvdata(&priv->pdev_pcm->dev); @@ -309,7 +296,7 @@ static int sof_resume(struct device *dev, int runtime_resume) return ret; } -static int sof_suspend(struct device *dev, int runtime_suspend) +static int sof_suspend(struct device *dev, bool runtime_suspend) { struct sof_platform_priv *priv = dev_get_drvdata(dev); struct snd_sof_dev *sdev = dev_get_drvdata(&priv->pdev_pcm->dev); @@ -358,19 +345,19 @@ static int sof_suspend(struct device *dev, int runtime_suspend) int snd_sof_runtime_suspend(struct device *dev) { - return sof_suspend(dev, RUNTIME_PM); + return sof_suspend(dev, true); } EXPORT_SYMBOL(snd_sof_runtime_suspend); int snd_sof_runtime_resume(struct device *dev) { - return sof_resume(dev, RUNTIME_PM); + return sof_resume(dev, true); } EXPORT_SYMBOL(snd_sof_runtime_resume); int snd_sof_resume(struct device *dev) { - return sof_resume(dev, !RUNTIME_PM); + return sof_resume(dev, false); } EXPORT_SYMBOL(snd_sof_resume); @@ -382,7 +369,7 @@ EXPORT_SYMBOL(snd_sof_suspend); int snd_sof_suspend_late(struct device *dev) { - return sof_suspend(dev, !RUNTIME_PM); + return sof_suspend(dev, false); } EXPORT_SYMBOL(snd_sof_suspend_late); From 4e0bdc809ef3577700eac2c3eec112bd2442258f Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 11 Dec 2018 16:31:12 -0800 Subject: [PATCH 0390/1995] ASoC: SOF: remove dsp core power up from hda_resume Remove the call to power up dsp cores from hda_resume() as they will be powered up during firmware boot. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dsp.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index bdcbc9c8d43f60..1471aa3834811d 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -291,7 +291,6 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state) static int hda_resume(struct snd_sof_dev *sdev) { - const struct sof_intel_dsp_desc *chip = sdev->hda->desc; #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_ext_link *hlink = NULL; @@ -343,14 +342,6 @@ static int hda_resume(struct snd_sof_dev *sdev) } #endif - /* power up the DSP */ - ret = hda_dsp_core_power_up(sdev, chip->cores_mask); - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to power up core after resume\n"); - return ret; - } - #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* turn off the links that were off before suspend */ list_for_each_entry(hlink, &bus->hlink_list, list) { @@ -378,13 +369,13 @@ int hda_dsp_resume(struct snd_sof_dev *sdev) return ret; } - /* init hda controller and power dsp up */ + /* init hda controller. DSP cores will be powered up during fw boot */ return hda_resume(sdev); } int hda_dsp_runtime_resume(struct snd_sof_dev *sdev) { - /* init hda controller and power dsp up */ + /* init hda controller. DSP cores will be powered up during fw boot */ return hda_resume(sdev); } From 37755affe407ae38071dd959c1449d0ff8e7cf0f Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 12 Dec 2018 16:46:01 +0800 Subject: [PATCH 0391/1995] ASoC: Intel: Haswell/Broadwell: fix setting for .dynamic field For some reason this field was set to zero when all other drivers use .dynamic = 1 for front-ends. This change was tested on Dell XPS13 and has no impact with the existing legacy driver. The SOF driver also works with this change which enables it to override the fixed topology. Signed-off-by: Rander Wang --- sound/soc/intel/boards/broadwell.c | 2 +- sound/soc/intel/boards/haswell.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 56dd8463c75dc9..0d67511f7fd92e 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -196,7 +196,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { .stream_name = "Loopback", .cpu_dai_name = "Loopback Pin", .platform_name = "haswell-pcm-audio", - .dynamic = 0, + .dynamic = 1, .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index ce7d7f6422bfb8..8c8da57c4c9380 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -150,7 +150,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = { .stream_name = "Loopback", .cpu_dai_name = "Loopback Pin", .platform_name = "haswell-pcm-audio", - .dynamic = 0, + .dynamic = 1, .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, From e19136ed5b844e0096dba55e9e767aa207e0414c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 12 Dec 2018 12:11:12 -0600 Subject: [PATCH 0392/1995] ASoC: SOF: utils: use linux/io-64-nonatomic-lo-hi.h Feedback from Andy Shevchenko, helps use readq and writeq across architectures Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/utils.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index ccaf58d8c2264d..144b6e49eb4caf 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -8,7 +8,7 @@ // Author: Keyon Jie // -#include +#include #include #include #include @@ -86,24 +86,13 @@ EXPORT_SYMBOL(sof_io_read); void sof_io_write64(struct snd_sof_dev *sdev, void __iomem *addr, u64 value) { -#ifdef CONFIG_64BIT writeq(value, addr); -#else - memcpy_toio(addr, &value, sizeof(value)); -#endif } EXPORT_SYMBOL(sof_io_write64); u64 sof_io_read64(struct snd_sof_dev *sdev, void __iomem *addr) { -#ifdef CONFIG_64BIT return readq(addr); -#else - u64 val; - - memcpy_fromio(&val, addr, sizeof(val)); - return val; -#endif } EXPORT_SYMBOL(sof_io_read64); From 1e546d65fab0bb7e016d778215ab4ebb16912995 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 12 Dec 2018 12:20:28 -0600 Subject: [PATCH 0393/1995] ASoC: SOF: utils: use plain vanilla ioread32/iowrite32 Feedback from Andy Shevchenko. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index 144b6e49eb4caf..2e741a2a132978 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -144,11 +144,11 @@ void sof_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, * bytes, and write back to dest. For unaffected bytes, it * should not be changed */ - __ioread32_copy(&tmp, dest + m * 4, 1); + tmp = ioread32(dest + m * 4); tmp &= ~affected_mask; tmp |= *(u32 *)(src_byte + m * 4) & affected_mask; - __iowrite32_copy(dest + m * 4, &tmp, 1); + iowrite32(tmp, dest + m * 4); } } EXPORT_SYMBOL(sof_block_write); From d13b3949dbc980b15247e50e64f3afd617a65505 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 12 Dec 2018 12:27:11 -0600 Subject: [PATCH 0394/1995] ASoC: SOF: pcm: use DIV_ROUND_UP Feedback from Takashi Iwai and Andy Shevchenko Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pcm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index a6b11217ee509e..55186bf28539be 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -75,10 +75,7 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, return ret; /* number of pages should be rounded up */ - if (runtime->dma_bytes % PAGE_SIZE) - pcm.params.buffer.pages = (runtime->dma_bytes / PAGE_SIZE) + 1; - else - pcm.params.buffer.pages = runtime->dma_bytes / PAGE_SIZE; + pcm.params.buffer.pages = DIV_ROUND_UP(runtime->dma_bytes, PAGE_SIZE); /* set IPC PCM parameters */ pcm.hdr.size = sizeof(pcm); From 0e89a683f3aeded393fb4dfff2518af06ea40bae Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 12 Dec 2018 12:40:25 -0600 Subject: [PATCH 0395/1995] ASoC: SOF: control: keep const for binary data Feedback from Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/control.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 3587f9f26a7473..a16eef4124dccb 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -272,8 +272,8 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct snd_ctl_tlv header; - struct snd_ctl_tlv __user *tlvd = - (struct snd_ctl_tlv __user *)binary_data; + const struct snd_ctl_tlv __user *tlvd = + (const struct snd_ctl_tlv __user *)binary_data; int ret; int err; int max_size = SOF_IPC_MSG_MAX_SIZE - From 654614ab69bf5b786e2fe8533f8df684eda466c0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 12 Dec 2018 12:46:19 -0600 Subject: [PATCH 0396/1995] ASoC: SOF: control: use dev_err_ratelimited We can't control what applications do, so avoid flooding the console if errors happen Feedback from Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/control.c | 93 +++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index a16eef4124dccb..505be9a0d66c17 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -46,8 +46,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err(sdev->dev, "error: volume get failed to resume %d\n", - ret); + dev_err_ratelimited(sdev->dev, "error: volume get failed to resume %d\n", + ret); return ret; } @@ -65,8 +65,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err(sdev->dev, "error: volume get failed to idle %d\n", - err); + dev_err_ratelimited(sdev->dev, "error: volume get failed to idle %d\n", + err); return 0; } @@ -83,8 +83,8 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err(sdev->dev, "error: volume put failed to resume %d\n", - ret); + dev_err_ratelimited(sdev->dev, "error: volume put failed to resume %d\n", + ret); return ret; } @@ -104,8 +104,8 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err(sdev->dev, "error: volume put failed to idle %d\n", - err); + dev_err_ratelimited(sdev->dev, "error: volume put failed to idle %d\n", + err); return 0; } @@ -122,8 +122,8 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err(sdev->dev, "error: enum get failed to resume %d\n", - ret); + dev_err_ratelimited(sdev->dev, "error: enum get failed to resume %d\n", + ret); return ret; } @@ -139,8 +139,8 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err(sdev->dev, "error: enum get failed to idle %d\n", - ret); + dev_err_ratelimited(sdev->dev, "error: enum get failed to idle %d\n", + ret); return 0; } @@ -157,8 +157,8 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err(sdev->dev, "error: enum put failed to resume %d\n", - ret); + dev_err_ratelimited(sdev->dev, "error: enum put failed to resume %d\n", + ret); return ret; } @@ -174,8 +174,8 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err(sdev->dev, "error: enum put failed to idle %d\n", - err); + dev_err_ratelimited(sdev->dev, "error: enum put failed to idle %d\n", + err); return 0; } @@ -193,8 +193,8 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err(sdev->dev, "error: bytes get failed to resume %d\n", - ret); + dev_err_ratelimited(sdev->dev, "error: bytes get failed to resume %d\n", + ret); return ret; } @@ -203,8 +203,8 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, SOF_CTRL_TYPE_DATA_GET, scontrol->cmd); size = data->size + sizeof(*data); if (size > be->max) { - dev_err(sdev->dev, "error: DSP sent %zu bytes max is %d\n", - size, be->max); + dev_err_ratelimited(sdev->dev, "error: DSP sent %zu bytes max is %d\n", + size, be->max); ret = -EINVAL; goto out; } @@ -216,8 +216,8 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err(sdev->dev, "error: bytes get failed to idle %d\n", - err); + dev_err_ratelimited(sdev->dev, "error: bytes get failed to idle %d\n", + err); return ret; } @@ -234,14 +234,14 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err(sdev->dev, "error: bytes put failed to resume %d\n", - ret); + dev_err_ratelimited(sdev->dev, "error: bytes put failed to resume %d\n", + ret); return ret; } if (data->size > be->max) { - dev_err(sdev->dev, "error: size too big %d bytes max is %d\n", - data->size, be->max); + dev_err_ratelimited(sdev->dev, "error: size too big %d bytes max is %d\n", + data->size, be->max); ret = -EINVAL; goto out; } @@ -257,8 +257,8 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err(sdev->dev, "error: bytes put failed to idle %d\n", - err); + dev_err_ratelimited(sdev->dev, "error: bytes put failed to idle %d\n", + err); return ret; } @@ -281,8 +281,8 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err(sdev->dev, "error: bytes_ext put failed to resume %d\n", - ret); + dev_err_ratelimited(sdev->dev, "error: bytes_ext put failed to resume %d\n", + ret); return ret; } @@ -299,15 +299,16 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, */ max_size = min(be->max, max_size); if (header.length > max_size) { - dev_err(sdev->dev, "error: Bytes data size %d exceeds max %d.\n", - header.length, max_size); + dev_err_ratelimited(sdev->dev, "error: Bytes data size %d exceeds max %d.\n", + header.length, max_size); ret = -EINVAL; goto out; } /* Check that header id matches the command */ if (header.numid != scontrol->cmd) { - dev_err(sdev->dev, "error: incorrect numid %d\n", header.numid); + dev_err_ratelimited(sdev->dev, "error: incorrect numid %d\n", + header.numid); ret = -EINVAL; goto out; } @@ -318,21 +319,21 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, } if (cdata->data->magic != SOF_ABI_MAGIC) { - dev_err(sdev->dev, "error: Wrong ABI magic 0x%08x.\n", - cdata->data->magic); + dev_err_ratelimited(sdev->dev, "error: Wrong ABI magic 0x%08x.\n", + cdata->data->magic); ret = -EINVAL; goto out; } if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { - dev_err(sdev->dev, "error: Incompatible ABI version 0x%08x.\n", - cdata->data->abi); + dev_err_ratelimited(sdev->dev, "error: Incompatible ABI version 0x%08x.\n", + cdata->data->abi); ret = -EINVAL; goto out; } if (cdata->data->size + sizeof(const struct sof_abi_hdr) > max_size) { - dev_err(sdev->dev, "error: Mismatch in ABI data size (truncated?).\n"); + dev_err_ratelimited(sdev->dev, "error: Mismatch in ABI data size (truncated?).\n"); ret = -EINVAL; goto out; } @@ -345,8 +346,8 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err(sdev->dev, "error: bytes_ext put failed to idle %d\n", - err); + dev_err_ratelimited(sdev->dev, "error: bytes_ext put failed to idle %d\n", + err); return ret; } @@ -371,8 +372,8 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err(sdev->dev, "error: bytes_ext get failed to resume %d\n", - ret); + dev_err_ratelimited(sdev->dev, "error: bytes_ext get failed to resume %d\n", + ret); return ret; } @@ -394,8 +395,8 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, data_size = cdata->data->size + sizeof(const struct sof_abi_hdr); max_size = min3(be->max, max_size, (int)size); if (data_size > max_size) { - dev_err(sdev->dev, "error: user data size %d exceeds max size %d.\n", - data_size, max_size); + dev_err_ratelimited(sdev->dev, "error: user data size %d exceeds max size %d.\n", + data_size, max_size); ret = -EINVAL; goto out; } @@ -414,7 +415,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err(sdev->dev, "error: bytes_ext get failed to idle %d\n", - err); + dev_err_ratelimited(sdev->dev, "error: bytes_ext get failed to idle %d\n", + err); return ret; } From f91b468d75122955d27dfa39f1d2534ce74992f2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 12 Dec 2018 13:31:19 -0600 Subject: [PATCH 0397/1995] ASoC: SOF: make ops constant Feedback from Takashi Sakamoto: we can constantify these structures. TODO: the generic soc-acpi structure doesn't have a const field, this will need to be added in the future. Signed-off-by: Pierre-Louis Bossart --- include/sound/sof.h | 4 ++-- sound/soc/sof/intel/apl.c | 2 +- sound/soc/sof/intel/bdw.c | 2 +- sound/soc/sof/intel/byt.c | 4 ++-- sound/soc/sof/intel/cnl.c | 2 +- sound/soc/sof/intel/hda.h | 8 ++++---- sound/soc/sof/intel/hsw.c | 2 +- sound/soc/sof/intel/shim.h | 8 ++++---- sound/soc/sof/intel/skl.c | 2 +- sound/soc/sof/nocodec.c | 2 +- sound/soc/sof/ops.h | 2 +- sound/soc/sof/sof-acpi-dev.c | 10 ++++++++-- sound/soc/sof/sof-pci-dev.c | 10 ++++++++-- sound/soc/sof/sof-priv.h | 2 +- sound/soc/sof/sof-spi-dev.c | 11 ++++++++++- sound/soc/sof/utils.c | 2 +- 16 files changed, 47 insertions(+), 26 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index c69d636a0c30a9..880d756470ab57 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -83,9 +83,9 @@ int sof_nocodec_setup(struct device *dev, struct snd_sof_pdata *sof_pdata, struct snd_soc_acpi_mach *mach, const struct sof_dev_desc *desc, - struct snd_sof_dsp_ops *ops); + const struct snd_sof_dsp_ops *ops); -int sof_bes_setup(struct device *dev, struct snd_sof_dsp_ops *ops, +int sof_bes_setup(struct device *dev, const struct snd_sof_dsp_ops *ops, struct snd_soc_dai_link *links, int link_num, struct snd_soc_card *card); #endif diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 61832da260d8bf..5de30087ded6d7 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -25,7 +25,7 @@ static const struct snd_sof_debugfs_map apl_dsp_debugfs[] = { }; /* apollolake ops */ -struct snd_sof_dsp_ops sof_apl_ops = { +const struct snd_sof_dsp_ops sof_apl_ops = { /* probe and remove */ .probe = hda_dsp_probe, .remove = hda_dsp_remove, diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index a81f278e8c38b4..b1876cc025804b 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -651,7 +651,7 @@ static struct snd_soc_dai_driver bdw_dai[] = { }; /* broadwell ops */ -struct snd_sof_dsp_ops sof_bdw_ops = { +const struct snd_sof_dsp_ops sof_bdw_ops = { /*Device init */ .probe = bdw_probe, diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 1695d67c336084..1442c47840024d 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -700,7 +700,7 @@ static struct snd_soc_dai_driver byt_dai[] = { }; /* baytrail ops */ -struct snd_sof_dsp_ops sof_byt_ops = { +const struct snd_sof_dsp_ops sof_byt_ops = { /* device init */ .probe = byt_probe, @@ -751,7 +751,7 @@ struct snd_sof_dsp_ops sof_byt_ops = { EXPORT_SYMBOL(sof_byt_ops); /* cherrytrail and braswell ops */ -struct snd_sof_dsp_ops sof_cht_ops = { +const struct snd_sof_dsp_ops sof_cht_ops = { /* device init */ .probe = byt_probe, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 8e10441d6c8403..dfa441d219837c 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -175,7 +175,7 @@ static int cnl_ipc_send_msg(struct snd_sof_dev *sdev, } /* cannonlake ops */ -struct snd_sof_dsp_ops sof_cnl_ops = { +const struct snd_sof_dsp_ops sof_cnl_ops = { /* probe and remove */ .probe = hda_dsp_probe, .remove = hda_dsp_remove, diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 4a1bbc948b9fdd..c11999e1cae3fa 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -353,7 +353,7 @@ struct sof_intel_dsp_desc { int ipc_ack; int ipc_ack_mask; int ipc_ctl; - struct snd_sof_dsp_ops *ops; + const struct snd_sof_dsp_ops *ops; }; #define SOF_HDA_PLAYBACK_STREAMS 16 @@ -530,8 +530,8 @@ extern struct snd_soc_dai_driver skl_dai[]; /* * Platform Specific HW abstraction Ops. */ -extern struct snd_sof_dsp_ops sof_apl_ops; -extern struct snd_sof_dsp_ops sof_cnl_ops; -extern struct snd_sof_dsp_ops sof_skl_ops; +extern const struct snd_sof_dsp_ops sof_apl_ops; +extern const struct snd_sof_dsp_ops sof_cnl_ops; +extern const struct snd_sof_dsp_ops sof_skl_ops; #endif diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 27e5675f7c9623..b64f84a92bf5a4 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -651,7 +651,7 @@ static struct snd_soc_dai_driver hsw_dai[] = { }; /* haswell ops */ -struct snd_sof_dsp_ops sof_hsw_ops = { +const struct snd_sof_dsp_ops sof_hsw_ops = { /*Device init */ .probe = hsw_probe, diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 2fdcb2d262f468..06fc3df26c50ad 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -151,9 +151,9 @@ #define PCI_PMCS 0x84 #define PCI_PMCS_PS_MASK 0x3 -extern struct snd_sof_dsp_ops sof_byt_ops; -extern struct snd_sof_dsp_ops sof_cht_ops; -extern struct snd_sof_dsp_ops sof_hsw_ops; -extern struct snd_sof_dsp_ops sof_bdw_ops; +extern const struct snd_sof_dsp_ops sof_byt_ops; +extern const struct snd_sof_dsp_ops sof_cht_ops; +extern const struct snd_sof_dsp_ops sof_hsw_ops; +extern const struct snd_sof_dsp_ops sof_bdw_ops; #endif diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index f876bee744d320..275000d7884070 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -25,7 +25,7 @@ static const struct snd_sof_debugfs_map skl_dsp_debugfs[] = { }; /* skylake ops */ -struct snd_sof_dsp_ops sof_skl_ops = { +const struct snd_sof_dsp_ops sof_skl_ops = { /* probe and remove */ .probe = hda_dsp_probe, .remove = hda_dsp_remove, diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index 686324b30a5708..e8b28b12051a00 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -20,7 +20,7 @@ int sof_nocodec_setup(struct device *dev, struct snd_sof_pdata *sof_pdata, struct snd_soc_acpi_mach *mach, const struct sof_dev_desc *desc, - struct snd_sof_dsp_ops *ops) + const struct snd_sof_dsp_ops *ops) { struct snd_soc_dai_link *links; int ret; diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index fc4868712af9ae..cf7438ce19eb20 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -330,7 +330,7 @@ snd_sof_pcm_platform_pointer(struct snd_sof_dev *sdev, return 0; } -static inline struct snd_sof_dsp_ops +static inline const struct snd_sof_dsp_ops *sof_get_ops(const struct sof_dev_desc *d, const struct sof_ops_table mach_ops[], int asize) { diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index ad9902bc706217..054e1d67e894d7 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -141,7 +141,7 @@ static int sof_acpi_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach; struct snd_sof_pdata *sof_pdata; struct sof_platform_priv *priv; - struct snd_sof_dsp_ops *ops; + const struct snd_sof_dsp_ops *ops; int ret = 0; dev_dbg(&pdev->dev, "ACPI DSP detected"); @@ -197,7 +197,13 @@ static int sof_acpi_probe(struct platform_device *pdev) } #endif - mach->pdata = ops; + /* + * save ops in pdata. + * TODO: the explicit cast removes the const attribute, we'll need + * to add a dedicated ops field in the generic soc-acpi structure + * to avoid such issues + */ + mach->pdata = (void *)ops; sof_pdata->machine = mach; sof_pdata->desc = desc; priv->sof_pdata = sof_pdata; diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index cf7976fb4335b2..3a60c67c962500 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -164,7 +164,7 @@ static int sof_pci_probe(struct pci_dev *pci, struct snd_soc_acpi_mach *mach; struct snd_sof_pdata *sof_pdata; struct sof_platform_priv *priv; - struct snd_sof_dsp_ops *ops; + const struct snd_sof_dsp_ops *ops; int ret = 0; dev_dbg(&pci->dev, "PCI DSP detected"); @@ -244,7 +244,13 @@ static int sof_pci_probe(struct pci_dev *pci, goto release_regions; } - mach->pdata = ops; + /* + * save ops in pdata. + * TODO: the explicit cast removes the const attribute, we'll need + * to add a dedicated ops field in the generic soc-acpi structure + * to avoid such issues + */ + mach->pdata = (void *)ops; sof_pdata->id = pci_id->device; sof_pdata->name = pci_name(pci); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index a5f8f2d2baa9fc..40c5e664ca78e3 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -177,7 +177,7 @@ struct sof_arch_ops { /* DSP device HW descriptor mapping between bus ID and ops */ struct sof_ops_table { const struct sof_dev_desc *desc; - struct snd_sof_dsp_ops *ops; + const struct snd_sof_dsp_ops *ops; }; /* FS entry for debug files that can expose DSP memories, registers */ diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index 81d79bcee10f4d..4068aac39001dc 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -116,7 +116,16 @@ static int sof_spi_probe(struct spi_device *spi) mach->sof_fw_filename = desc->nocodec_fw_filename; mach->sof_tplg_filename = desc->nocodec_tplg_filename; mach->asoc_plat_name = "sof-platform"; - mach->pdata = sof_get_ops(desc, spi_mach_ops, ARRAY_SIZE(spi_mach_ops)); + + /* + * save ops in pdata. + * TODO: the explicit cast removes the const attribute, we'll need + * to add a dedicated ops field in the generic soc-acpi structure + * to avoid such issues + */ + + mach->pdata = (void *)sof_get_ops(desc, spi_mach_ops, + ARRAY_SIZE(spi_mach_ops)); if (!mach->pdata) { dev_err(dev, "error: no matching SPI descriptor ops\n"); return -ENODEV; diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index 2e741a2a132978..6071b5fa6574e2 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -14,7 +14,7 @@ #include #include "sof-priv.h" -int sof_bes_setup(struct device *dev, struct snd_sof_dsp_ops *ops, +int sof_bes_setup(struct device *dev, const struct snd_sof_dsp_ops *ops, struct snd_soc_dai_link *links, int link_num, struct snd_soc_card *card) { From ad61991f7fe4ad872fbf6fd5c17b34636c9bb60a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 12 Dec 2018 14:00:18 -0600 Subject: [PATCH 0398/1995] ASoc: SOF: Kconfig: simplify if/depends Use if for top-level cases, use depends when there is a single item Feedback from Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/Kconfig | 7 +++++-- sound/soc/sof/intel/Kconfig | 6 +----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index ebd2495ff3b50d..bd6ca5b0c342f5 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -17,9 +17,10 @@ config SND_SOC_SOF Say Y if you have such a device that is supported by SOF. If unsure select "N". +if SND_SOC_SOF + config SND_SOC_SOF_COMPRESS bool "SOF ALSA Compressed API support" - depends on SND_SOC_SOF help This adds support for the ALSA compressed API in SOF Say Y if you need this option @@ -27,7 +28,6 @@ config SND_SOC_SOF_COMPRESS config SND_SOC_SOF_NOCODEC tristate "SOF nocodec mode Support" - depends on SND_SOC_SOF help This adds support for a dummy/nocodec machine driver fallback option if no known codec is detected. This is typically only @@ -92,3 +92,6 @@ config SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION source "sound/soc/sof/intel/Kconfig" source "sound/soc/sof/xtensa/Kconfig" + +endif + diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 87e4eb507abdaf..acc31134481fcf 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -1,6 +1,5 @@ config SND_SOC_SOF_SPIDSP tristate "SOF support over the SPI bus" - depends on SND_SOC_SOF depends on SPI select SND_SOC_SOF_SPI help @@ -11,7 +10,6 @@ config SND_SOC_SOF_SPIDSP config SND_SOC_SOF_INTEL tristate "SOF support for Intel audio DSPs" - depends on SND_SOC_SOF depends on SND_DMA_SGBUF select SND_SOC_INTEL_MACH select SND_SOC_SOF_XTENSA @@ -44,7 +42,6 @@ config SND_SOC_SOF_HASWELL config SND_SOC_SOF_BROADWELL tristate "SOF support for Broadwell" - depends on SND_SOC_SOF_INTEL select SND_SOC_SOF_ACPI select SND_SOC_ACPI_INTEL_MATCH help @@ -123,15 +120,14 @@ config SND_SOC_SOF_HDA_LINK Say Y if you want to enble HDA links with SOF. If unsure select "N". -if SND_SOC_SOF_HDA_LINK config SND_SOC_SOF_HDA_AUDIO_CODEC bool "SOF support for HDAudio codecs" + depends on SND_SOC_SOF_HDA_LINK help This adds support for HDAudio codecs with Sound Open Firmware for Intel(R) platforms. Say Y if you want to enble HDAudio codecs with SOF. If unsure select "N". -endif ## SND_SOC_SOF_HDA_LINK endif ## SND_SOC_SOF_HDA_COMMON From 0f7c3f1addecd52830c26b69a96739a3a28ac923 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 12 Dec 2018 14:21:26 -0600 Subject: [PATCH 0399/1995] ASoC: SOF: remove warnings with min() and min3() sparse complains with tons of warnings such as CHECK sound/soc/sof/trace.c sound/soc/sof/trace.c:78:17: warning: expression using sizeof(void) sound/soc/sof/trace.c:78:17: warning: expression using sizeof(void) sound/soc/sof/trace.c:88:17: warning: expression using sizeof(void) sound/soc/sof/trace.c:88:17: warning: expression using sizeof(void) This essentially reverts a454e63dcfc ('ASoC: SOF: use min when checking two or three values') Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/control.c | 10 ++++++++-- sound/soc/sof/debug.c | 4 +++- sound/soc/sof/trace.c | 5 +++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 505be9a0d66c17..4b72daee909784 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -297,7 +297,8 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, /* The maximum length that can be copied is limited by IPC max * length and topology defined length for ext bytes control. */ - max_size = min(be->max, max_size); + if (be->max < max_size) /* min() not used to avoid sparse warnings */ + max_size = be->max; if (header.length > max_size) { dev_err_ratelimited(sdev->dev, "error: Bytes data size %d exceeds max %d.\n", header.length, max_size); @@ -393,7 +394,12 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, /* Prevent read of other kernel data or possibly corrupt response */ data_size = cdata->data->size + sizeof(const struct sof_abi_hdr); - max_size = min3(be->max, max_size, (int)size); + + /* check size. min3() is not used to avoid sparse warnings */ + if (size < max_size) + max_size = size; + if (be->max < max_size) + max_size = be->max; if (data_size > max_size) { dev_err_ratelimited(sdev->dev, "error: user data size %d exceeds max size %d.\n", data_size, max_size); diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 2224d086566535..5a7fc5559f9e5d 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -41,7 +41,9 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, return -EINVAL; if (pos >= size || !count) return 0; - count = min(count, (size_t)(size - pos)); + /* find the minimum. min() is not used since it adds sparse warnings */ + if (count > size - pos) + count = size - pos; /* intermediate buffer size must be u32 multiple */ size = round_up(count, 4); diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index c268b560b12f07..fb0209dc8d060c 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -75,7 +75,8 @@ static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer, lpos_64 = lpos; lpos = do_div(lpos_64, buffer_size); - count = min(count, (size_t)(buffer_size - lpos)); + if (count > buffer_size - lpos) /* min() not used to avoid sparse warnings */ + count = buffer_size - lpos; /* get available count based on current host offset */ avail = sof_wait_trace_avail(sdev, lpos, buffer_size); @@ -85,7 +86,7 @@ static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer, } /* make sure count is <= avail */ - count = min(avail, count); + count = avail > count ? count : avail; /* copy available trace data to debugfs */ rem = copy_to_user(buffer, dfse->buf + lpos, count); From 58995e97bd510185cd3d8bc8ef58f95bc221e12b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 12 Dec 2018 14:29:30 -0600 Subject: [PATCH 0400/1995] ASoC: SOF: utils: fix typecast in error log Feedback from Andy Shevchenko Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index 6071b5fa6574e2..93ac71483ef6e0 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -59,8 +59,8 @@ int sof_create_platform_device(struct sof_platform_priv *priv) PLATFORM_DEVID_NONE, sof_pdata, sizeof(*sof_pdata)); if (IS_ERR(priv->pdev_pcm)) { - dev_err(dev, "error: cannot register device sof-audio. Error %d\n", - (int)PTR_ERR(priv->pdev_pcm)); + dev_err(dev, "error: cannot register device sof-audio. Error %ld\n", + PTR_ERR(priv->pdev_pcm)); return PTR_ERR(priv->pdev_pcm); } From 687e5083f9bfc84f66b22ff61f22688e420f2211 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 12 Dec 2018 18:39:36 -0600 Subject: [PATCH 0401/1995] ASoC: SOF: core: fix error handling on snd_soc_register_component failure There is no reason to unregister the component if it's not been registered successfully. Opens: 1. this assumes that all resources are freed 2. not sure we need to free the topology on comp_err Reported-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 46c9962c7bba59..9c9f97d70dc2e2 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -320,7 +320,7 @@ static int sof_probe(struct platform_device *pdev) if (ret < 0) { dev_err(sdev->dev, "error: failed to register DSP DAI driver %d\n", ret); - goto comp_err; + goto fw_run_err; } drv_name = plat_data->machine->drv_name; From 347f39429116969fc8ad082c067fcd268883da72 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 12 Dec 2018 18:46:12 -0600 Subject: [PATCH 0402/1995] ASoC: SOF: pcm: fix typo s/craete/create Reported-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 55186bf28539be..bd397c5461feb8 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -68,7 +68,7 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, return ret; } - /* craete compressed page table for audio firmware */ + /* create compressed page table for audio firmware */ ret = create_page_table(substream, runtime->dma_area, runtime->dma_bytes); if (ret < 0) From 504cfc1ec6b68b13fe053930a392846262de81db Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 12 Dec 2018 12:19:24 -0800 Subject: [PATCH 0403/1995] ASoC: SOF: pcm: check return value for errors and print proper error messages Check the return value for platform_hw_params() and hw_params ipc and return appropriate values. Also fix the pcm id value in the other error messages. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pcm.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index bd397c5461feb8..1e0914a49265c1 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -64,7 +64,7 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); if (ret < 0) { dev_err(sdev->dev, "error: could not allocate %d bytes for PCM %d\n", - params_buffer_bytes(params), ret); + params_buffer_bytes(params), spcm->pcm.pcm_id); return ret; } @@ -131,11 +131,21 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, substream, params, &pcm.params); + if (ret < 0) { + dev_err(sdev->dev, "error: platform hw params failed\n"); + return ret; + } + dev_dbg(sdev->dev, "stream_tag %d", pcm.params.stream_tag); /* send IPC to the DSP */ ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm), &ipc_params_reply, sizeof(ipc_params_reply)); + if (ret < 0) { + dev_err(sdev->dev, "error: hw params ipc failed for stream %d\n", + pcm.params.stream_tag); + return ret; + } /* validate offset */ posn_offset = ipc_params_reply.posn_offset; @@ -144,8 +154,8 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, if (posn_offset > sdev->stream_box.size || posn_offset % sizeof(struct sof_ipc_stream_posn) != 0) { dev_err(sdev->dev, "error: got wrong posn offset 0x%x for PCM %d\n", - posn_offset, ret); - return ret; + posn_offset, spcm->pcm.pcm_id); + return -EINVAL; } spcm->posn_offset[substream->stream] = sdev->stream_box.offset + posn_offset; From ce8accebdcfd849c0f8f2473c745722ca5003d51 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 12 Dec 2018 11:24:00 -0800 Subject: [PATCH 0404/1995] ASoC: SOF: core: use generic calls to get pci device Use generic dev_is_pci() and to_pci_dev() calls to get pci device and remove the enum to define the device types. Also add a comment to explain how the page table idx is calculated. Signed-off-by: Ranjani Sridharan --- include/sound/sof.h | 8 -------- sound/soc/sof/core.c | 13 ++++++++++--- sound/soc/sof/sof-acpi-dev.c | 1 - sound/soc/sof/sof-pci-dev.c | 1 - sound/soc/sof/sof-spi-dev.c | 1 - 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index 880d756470ab57..87d6f8fd9c9a8e 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -17,13 +17,6 @@ struct snd_sof_dsp_ops; -/* SOF probe type */ -enum sof_device_type { - SOF_DEVICE_PCI = 0, - SOF_DEVICE_APCI, - SOF_DEVICE_SPI -}; - /* * SOF Platform data. */ @@ -36,7 +29,6 @@ struct snd_sof_pdata { /* parent device */ struct device *dev; - enum sof_device_type type; /* descriptor */ const struct sof_dev_desc *desc; diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 9c9f97d70dc2e2..6aa2ce7355e889 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -197,7 +197,14 @@ int snd_sof_create_page_table(struct snd_sof_dev *sdev, dmab->area, size, pages); for (i = 0; i < pages; i++) { - u32 idx = (((i << 2) + i)) >> 1; + /* + * The number of valid address bits for each page is 20. + * idx determines the byte position within page_table + * where the current page's address is stored + * in the compressed page_table. + * This can be calculated by multiplying the page number by 2.5. + */ + u32 idx = (5 * i) >> 1; u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT; u32 *pg_table; @@ -236,8 +243,8 @@ static int sof_probe(struct platform_device *pdev) /* initialize sof device */ sdev->dev = &pdev->dev; sdev->parent = plat_data->dev; - if (plat_data->type == SOF_DEVICE_PCI) - sdev->pci = container_of(plat_data->dev, struct pci_dev, dev); + if dev_is_pci(plat_data->dev) + sdev->pci = to_pci_dev(plat_data->dev); sdev->ops = plat_data->machine->pdata; sdev->pdata = plat_data; diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 054e1d67e894d7..03d45c5ce2224b 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -208,7 +208,6 @@ static int sof_acpi_probe(struct platform_device *pdev) sof_pdata->desc = desc; priv->sof_pdata = sof_pdata; sof_pdata->dev = &pdev->dev; - sof_pdata->type = SOF_DEVICE_APCI; sof_pdata->platform = "sof-audio"; dev_set_drvdata(&pdev->dev, priv); diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 3a60c67c962500..65dd7be78655b1 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -258,7 +258,6 @@ static int sof_pci_probe(struct pci_dev *pci, sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data; priv->sof_pdata = sof_pdata; sof_pdata->dev = &pci->dev; - sof_pdata->type = SOF_DEVICE_PCI; sof_pdata->platform = "sof-audio"; /* register sof-audio platform driver */ diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index 4068aac39001dc..cee4ef517a94fd 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -137,7 +137,6 @@ static int sof_spi_probe(struct spi_device *spi) sof_pdata->desc = desc; priv->sof_pdata = sof_pdata; sof_pdata->dev = dev; - sof_pdata->type = SOF_DEVICE_SPI; /* register sof-audio platform driver */ ret = sof_create_platform_device(priv); From 830fc036f861727ab293f1c5d0b95953c2bdb8e1 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Thu, 13 Dec 2018 21:02:55 +0800 Subject: [PATCH 0405/1995] ASoC: SOF: Fix wrong print for PCIR PCIR output will always be 0, since it print the ret value of pci_read_config_dword. Signed-off-by: Pan Xiuli --- sound/soc/sof/ops.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index 1eb759c6569c76..387baeb6b9ed2d 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -18,10 +18,9 @@ int snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset, u32 ret = ~0; /* explicit init to remove uninitialized use warnings */ pci_read_config_dword(sdev->pci, offset, &ret); - dev_dbg(sdev->dev, "Debug PCIR: %8.8x at %8.8x\n", - pci_read_config_dword(sdev->pci, offset, &ret), offset); - old = ret; + dev_dbg(sdev->dev, "Debug PCIR: %8.8x at %8.8x\n", old & mask, offset); + new = (old & (~mask)) | (value & mask); if (old == new) From 1b3972d22dcb4a9163c508a3ddd9aae1b4f344c9 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Thu, 13 Dec 2018 23:41:13 +0800 Subject: [PATCH 0406/1995] [DEBUG][CI]travis: add make deb check add make bindeb-pkg check to travis-ci Signed-off-by: Pan Xiuli --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b5c403c9d60b3d..cb349457aaff70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ git: before_install: - sudo apt-get update -qq - - sudo apt-get install python-ply python-git libelf-dev codespell sparse + - sudo apt-get install python-ply python-git libelf-dev codespell sparse fakeroot - git clone https://github.com/thesofproject/kconfig.git jobs: @@ -29,6 +29,7 @@ jobs: - make defconfig - scripts/kconfig/merge_config.sh .config kconfig/base-defconfig kconfig/sof-defconfig - KCFLAGS="-Wall -Werror" make -j`getconf _NPROCESSORS_ONLN` + - make bindeb-pkg -j`getconf _NPROCESSORS_ONLN` - name: "BUILD SST Kernel x86_64" script: - export ARCH=x86_64 From 48d46cbaaa234426354a9bd7c4f2d7453dab44af Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 13 Dec 2018 09:32:47 -0800 Subject: [PATCH 0407/1995] ASoC: SOF: kcontrols: remove enum control get/put functions enum controls are not supported in topology yet. So no need to have get/put control IO calls since there is no way to test these yet. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/control.c | 70 ---------------------------------------- sound/soc/sof/sof-priv.h | 4 --- sound/soc/sof/topology.c | 1 - 3 files changed, 75 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 4b72daee909784..6163948975ac64 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -109,76 +109,6 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, return 0; } -int snd_sof_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_enum *se = - (struct soc_enum *)kcontrol->private_value; - struct snd_sof_control *scontrol = se->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; - struct sof_ipc_ctrl_data *cdata = scontrol->control_data; - unsigned int i, channels = scontrol->num_channels; - int err, ret; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, "error: enum get failed to resume %d\n", - ret); - return ret; - } - - /* get all the mixer data from DSP */ - snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_ENUM); - - /* read back each channel */ - for (i = 0; i < channels; i++) - ucontrol->value.integer.value[i] = cdata->chanv[i].value; - - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, "error: enum get failed to idle %d\n", - ret); - return 0; -} - -int snd_sof_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_enum *se = - (struct soc_enum *)kcontrol->private_value; - struct snd_sof_control *scontrol = se->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; - struct sof_ipc_ctrl_data *cdata = scontrol->control_data; - unsigned int i, channels = scontrol->num_channels; - int ret, err; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, "error: enum put failed to resume %d\n", - ret); - return ret; - } - - /* update each channel */ - for (i = 0; i < channels; i++) - cdata->chanv[i].value = ucontrol->value.integer.value[i]; - - /* notify DSP of mixer updates */ - snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_SET, - SOF_CTRL_CMD_ENUM); - - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, "error: enum put failed to idle %d\n", - err); - return 0; -} - int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 40c5e664ca78e3..1ada7eab46c887 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -520,10 +520,6 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_sof_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_sof_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -int snd_sof_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index b09db12d829844..79bf2b255c9bc9 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2645,7 +2645,6 @@ static int sof_manifest(struct snd_soc_component *scomp, int index, /* vendor specific kcontrol handlers available for binding */ static const struct snd_soc_tplg_kcontrol_ops sof_io_ops[] = { {SOF_TPLG_KCTL_VOL_ID, snd_sof_volume_get, snd_sof_volume_put}, - {SOF_TPLG_KCTL_ENUM_ID, snd_sof_enum_get, snd_sof_enum_put}, {SOF_TPLG_KCTL_BYTES_ID, snd_sof_bytes_get, snd_sof_bytes_put}, }; From f0fa1071d8967683628513cb9a2fa7ea943d1762 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 13 Dec 2018 10:26:44 -0600 Subject: [PATCH 0408/1995] ASoC: SOF: debug: ignore debugfs errors We can't rely on debugfs so in case of error we only log an error message and keep going. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 5 +++++ sound/soc/sof/debug.c | 18 ++++++++++-------- sound/soc/sof/loader.c | 4 ++-- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 6aa2ce7355e889..c6f871cbf4f17e 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -281,6 +281,11 @@ static int sof_probe(struct platform_device *pdev) /* register any debug/trace capabilities */ ret = snd_sof_dbg_init(sdev); if (ret < 0) { + /* + * errors can only happen due to memory allocation. + * we cannot rely on debugfs so debugfs issues are only + * logged and we don't stop execution + */ dev_err(sdev->dev, "error: failed to init DSP trace/debug %d\n", ret); goto dbg_err; diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 5a7fc5559f9e5d..5722346f954d8d 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -105,8 +105,9 @@ int snd_sof_debugfs_io_create_item(struct snd_sof_dev *sdev, dfse->dfsentry = debugfs_create_file(name, 0444, sdev->debugfs_root, dfse, &sof_dfs_fops); if (!dfse->dfsentry) { - dev_err(sdev->dev, "error: cannot create debugfs entry.\n"); - return -ENODEV; + /* can't rely on debugfs, only log error and keep going */ + dev_err(sdev->dev, "error: cannot create debugfs entry %s\n", + name); } return 0; @@ -134,8 +135,9 @@ int snd_sof_debugfs_buf_create_item(struct snd_sof_dev *sdev, dfse->dfsentry = debugfs_create_file(name, 0444, sdev->debugfs_root, dfse, &sof_dfs_fops); if (!dfse->dfsentry) { - dev_err(sdev->dev, "error: cannot create debugfs entry.\n"); - return -ENODEV; + /* can't rely on debugfs, only log error and keep going */ + dev_err(sdev->dev, "error: cannot create debugfs entry %s\n", + name); } return 0; @@ -152,7 +154,7 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) sdev->debugfs_root = debugfs_create_dir("sof", NULL); if (IS_ERR_OR_NULL(sdev->debugfs_root)) { dev_err(sdev->dev, "error: failed to create debugfs directory\n"); - return -EINVAL; + return 0; } /* create debugFS files for platform specific MMIO/DSP memories */ @@ -162,12 +164,12 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) err = snd_sof_debugfs_io_create_item(sdev, sdev->bar[map->bar] + map->offset, map->size, map->name); + /* errors are only due to memory allocation, not debugfs */ if (err < 0) - dev_err(sdev->dev, "error: cannot create debugfs for %s\n", - map->name); + return err; } - return err; + return 0; } EXPORT_SYMBOL(snd_sof_dbg_init); diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 70b3038e3e2b59..0c61c03b051566 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -267,9 +267,9 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) ret = snd_sof_debugfs_buf_create_item(sdev, &sdev->fw_version, sizeof(sdev->fw_version), "fw_version"); - + /* errors are only due to memory allocation, not debugfs */ if (ret < 0) { - dev_err(sdev->dev, "error: cannot create debugfs for fw_version\n"); + dev_err(sdev->dev, "error: snd_sof_debugfs_buf_create_item failed\n"); return ret; } } From 1335122fdeb0035292706b3a8ec169f7a0dd1da1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 13 Dec 2018 10:31:46 -0600 Subject: [PATCH 0409/1995] ASoC: SOF: trace: fix memory leak, use devm_kzalloc Follow same code pattern as for other debugfs entries. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/trace.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index fb0209dc8d060c..1f5fff892fdf5b 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -112,7 +112,7 @@ static int trace_debugfs_create(struct snd_sof_dev *sdev) if (!sdev) return -EINVAL; - dfse = kzalloc(sizeof(*dfse), GFP_KERNEL); + dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); if (!dfse) return -ENOMEM; @@ -125,7 +125,6 @@ static int trace_debugfs_create(struct snd_sof_dev *sdev) if (!dfse->dfsentry) { dev_err(sdev->dev, "error: cannot create debugfs entry for trace\n"); - kfree(dfse); return -ENODEV; } From eadeca4d3d3d7f4f54ff68b4b1934962b270eb59 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 13 Dec 2018 10:34:11 -0600 Subject: [PATCH 0410/1995] ASoC: SOF: trace: ignore debugfs errors Same pattern as other debugfs cases, don't return an error since we can't rely on debugfs Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 1f5fff892fdf5b..40b6396b9b5ef7 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -123,9 +123,9 @@ static int trace_debugfs_create(struct snd_sof_dev *sdev) dfse->dfsentry = debugfs_create_file("trace", 0444, sdev->debugfs_root, dfse, &sof_dfs_trace_fops); if (!dfse->dfsentry) { + /* can't rely on debugfs, only log error and keep going */ dev_err(sdev->dev, "error: cannot create debugfs entry for trace\n"); - return -ENODEV; } return 0; From b8db053ebce3636f5d3eca2c25b544cd15ee14ef Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 14 Dec 2018 15:35:16 -0600 Subject: [PATCH 0411/1995] ASoC: Intel: Haswell/Broadwell: fix SOF-specific changes Compile-out SST-specific code when Haswell or Broadwell are handled by SOF, not if SOF is enabled on other platforms. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bdw-rt5677.c | 4 ++-- sound/soc/intel/boards/broadwell.c | 4 ++-- sound/soc/intel/boards/haswell.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 0654bd94389ca8..a61ab83c420fac 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -179,7 +179,7 @@ static const struct snd_soc_ops bdw_rt5677_ops = { .hw_params = bdw_rt5677_hw_params, }; -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); @@ -266,7 +266,7 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { .dynamic = 1, .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) .init = bdw_rt5677_rtd_init, #endif .trigger = { diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 0d67511f7fd92e..c5a0256e392608 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -130,7 +130,7 @@ static const struct snd_soc_ops broadwell_rt286_ops = { .hw_params = broadwell_rt286_hw_params, }; -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); @@ -162,7 +162,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { .dynamic = 1, .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) .init = broadwell_rtd_init, #endif .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index 8c8da57c4c9380..7d317de633d033 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -85,7 +85,7 @@ static const struct snd_soc_ops haswell_rt5640_ops = { .hw_params = haswell_rt5640_hw_params, }; -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL) static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); @@ -116,7 +116,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = { .dynamic = 1, .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL) .init = haswell_rtd_init, #endif .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, From 2d3fcf16aeac8e519d0ed2db26cf93e1bebe84c9 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Sun, 16 Dec 2018 14:51:32 +0800 Subject: [PATCH 0412/1995] ASoC:SOF:CNL enable suspend resume enable power management on cannonlake, add suspend, resume, runtime_suspend and runtime_resume. Tested on whiskeylake RVP. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/cnl.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index dfa441d219837c..a9cea84fa56ff1 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -238,5 +238,11 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { /* DAI drivers */ .drv = skl_dai, .num_drv = SOF_SKL_NUM_DAIS, + + /* PM */ + .suspend = hda_dsp_suspend, + .resume = hda_dsp_resume, + .runtime_suspend = hda_dsp_runtime_suspend, + .runtime_resume = hda_dsp_runtime_resume, }; EXPORT_SYMBOL(sof_cnl_ops); From 66cc82d8af154317ec47ec5af21be3f7aacaf549 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 14 Dec 2018 04:51:27 +0800 Subject: [PATCH 0413/1995] ASoC: SOF: loader: add firmware size check on loading User may want to load an invalid firmware with incorrect size value in the header. So we need to make sure we won't read data beyond the firmware data. Signed-off-by: Bard liao --- sound/soc/sof/loader.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 0c61c03b051566..61cedeb2c4c887 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -94,13 +94,23 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, struct snd_sof_blk_hdr *block; int count; u32 offset; + size_t remaining; dev_dbg(sdev->dev, "new module size 0x%x blocks 0x%x type 0x%x\n", module->size, module->num_blocks, module->type); block = (void *)module + sizeof(*module); + /* module->size doesn't include header size */ + remaining = module->size; for (count = 0; count < module->num_blocks; count++) { + /* minus header size of block */ + remaining -= sizeof(*block); + if (remaining < block->size) { + dev_err(sdev->dev, "error: not enough data remaining\n"); + return -EINVAL; + } + if (block->size == 0) { dev_warn(sdev->dev, "warning: block %d size zero\n", count); @@ -134,6 +144,8 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, (void *)block + sizeof(*block), block->size); + /* minus body size of block */ + remaining -= block->size; /* next block */ block = (void *)block + sizeof(*block) + block->size; } @@ -176,6 +188,7 @@ static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw) int (*load_module)(struct snd_sof_dev *sof_dev, struct snd_sof_mod_hdr *hdr); int ret, count; + size_t remaining; header = (struct snd_sof_fw_header *)fw->data; load_module = sdev->ops->load_module; @@ -184,13 +197,22 @@ static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw) /* parse each module */ module = (void *)fw->data + sizeof(*header); + remaining = fw->size - sizeof(*header); for (count = 0; count < header->num_modules; count++) { + /* minus header size of module */ + remaining -= sizeof(*module); + if (remaining < module->size) { + dev_err(sdev->dev, "error: not enough data remaining\n"); + return -EINVAL; + } /* module */ ret = load_module(sdev, module); if (ret < 0) { dev_err(sdev->dev, "error: invalid module %d\n", count); return ret; } + /* minus body size of module */ + remaining -= module->size; module = (void *)module + sizeof(*module) + module->size; } From 9380affab591a30905c60f0bba4f267099b1a8f1 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 13 Dec 2018 13:00:07 -0800 Subject: [PATCH 0414/1995] ASoC: SOF: utils: use devm_kasprintf use devm_kasprintk() based on Andy's feedback. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/utils.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index 93ac71483ef6e0..863c5a1f186250 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -18,7 +18,6 @@ int sof_bes_setup(struct device *dev, const struct snd_sof_dsp_ops *ops, struct snd_soc_dai_link *links, int link_num, struct snd_soc_card *card) { - char name[32]; int i; if (!ops || !links || !card) @@ -26,8 +25,8 @@ int sof_bes_setup(struct device *dev, const struct snd_sof_dsp_ops *ops, /* set up BE dai_links */ for (i = 0; i < link_num; i++) { - snprintf(name, 32, "NoCodec-%d", i); - links[i].name = devm_kstrdup(dev, name, GFP_KERNEL); + links[i].name = devm_kasprintf(dev, GFP_KERNEL, + "NoCodec-%d", i); if (!links[i].name) return -ENOMEM; From a988c108e9219027006887d8fa0071e4922df228 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 15:18:09 -0600 Subject: [PATCH 0415/1995] ASoC: SOF: nocodec: don't free memory allocated with devm_kzalloc Detected with Coccinelle sound/soc/sof/nocodec.c:46:2-7: WARNING: invalid free of devm_ allocated data Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/nocodec.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index e8b28b12051a00..4bb6a74093336d 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -23,7 +23,7 @@ int sof_nocodec_setup(struct device *dev, const struct snd_sof_dsp_ops *ops) { struct snd_soc_dai_link *links; - int ret; + int ret = 0; if (!mach) return -EINVAL; @@ -42,12 +42,7 @@ int sof_nocodec_setup(struct device *dev, ret = sof_bes_setup(dev, ops, links, ops->num_drv, &sof_nocodec_card); - if (ret) { - kfree(links); - return ret; - } - - return 0; + return ret; } EXPORT_SYMBOL(sof_nocodec_setup); From f73f3330975f83f101f143e7e30bc3510cb421ba Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 15:22:31 -0600 Subject: [PATCH 0416/1995] ASoC: SOF: debug: use simple_open() Detected with Coccinelle sound/soc/sof/debug.c:19:11-28: WARNING opportunity for simple_open, see also structure on line 82 Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/debug.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 5722346f954d8d..375a8e3d04cfe9 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -16,13 +16,6 @@ #include #include "sof-priv.h" -static int sof_dfsentry_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - - return 0; -} - static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { @@ -79,7 +72,7 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, } static const struct file_operations sof_dfs_fops = { - .open = sof_dfsentry_open, + .open = simple_open, .read = sof_dfsentry_read, .llseek = default_llseek, }; From 5dc432f07ab5c69d1e0e9e61009ff7eec43aa0ad Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 14 Dec 2018 21:49:11 -0600 Subject: [PATCH 0417/1995] ASoC: SOF: Add missing headers back, fix cross-compilation Missing linux/io.h and linux/modules.h Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-bus.c | 1 + sound/soc/sof/intel/hda-codec.c | 1 + sound/soc/sof/xtensa/core.c | 1 + 3 files changed, 3 insertions(+) diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index cadf559f5a82fd..62cc9921bb5597 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -7,6 +7,7 @@ // // Authors: Keyon Jie +#include #include #include "../sof-priv.h" #include "hda.h" diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 8d0fe7b7554efc..3cb5dc05e64a43 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -8,6 +8,7 @@ // Authors: Keyon Jie // +#include #include #include #include diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c index 8bc3b782c16e0f..5be713871c6af6 100644 --- a/sound/soc/sof/xtensa/core.c +++ b/sound/soc/sof/xtensa/core.c @@ -8,6 +8,7 @@ // Author: Pan Xiuli // +#include #include #include #include "../sof-priv.h" From 364cc07c196d4469e892c315f6c6f7b557811f7b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 14 Dec 2018 21:51:22 -0600 Subject: [PATCH 0418/1995] ASoC: SOF: acpi: fix cross-compilation issues asm/iosf-mbi.h only exists for X86, add dependency TODO: move is_byt_cr() to common helper Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-acpi-dev.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 03d45c5ce2224b..f6dda04444663e 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -8,7 +8,6 @@ // Author: Liam Girdwood // -#include #include #include #include @@ -16,6 +15,9 @@ #include #include #include +#ifdef CONFIG_X86 +#include +#endif #include "ops.h" @@ -69,12 +71,13 @@ static struct sof_dev_desc sof_acpi_baytrail_desc = { .nocodec_tplg_filename = "intel/sof-byt-nocodec.tplg" }; +#ifdef CONFIG_X86 /* TODO: move this to common helper */ static int is_byt_cr(struct device *dev) { u32 bios_status; int status; - if (!IS_ENABLED(CONFIG_IOSF_MBI) || !iosf_mbi_available()) { + if (!iosf_mbi_available()) { dev_info(dev, "IOSF_MBI not enabled - can't determine CPU variant\n"); return -EIO; } @@ -100,6 +103,12 @@ static int is_byt_cr(struct device *dev) dev_info(dev, "BYT-CR not detected\n"); return 0; } +#else +static int is_byt_cr(struct device *dev) +{ + return 0; +} +#endif static struct sof_dev_desc sof_acpi_cherrytrail_desc = { .machines = snd_soc_acpi_intel_cherrytrail_machines, From 1e9cb6f7b455e1a4ce003c377b9234a96a5c5b0c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 14 Dec 2018 21:53:01 -0600 Subject: [PATCH 0419/1995] ASoC: SOF: pci: add back missing header linux/pci.h is needed Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-pci-dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 65dd7be78655b1..c288c49e34b6e9 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include From b03a1b18419f10260a55985836196fbfea219921 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 14 Dec 2018 15:38:43 -0600 Subject: [PATCH 0420/1995] ASoC: SOF: fix Kconfig dependencies The existing module dependencies are handled in the wrong way. We need to select first acpi/pci, then platforms and last the core. Doing otherwise would result in broken configurations where acpi/pci stuff is compiled as built-in and platforms or SOF core as a module. Rebuild Kconfig to use 'select' statements in the right order. The platform selections are now exposed with booleans only. The choice of module or built-in can now happen only at the pci/acpi/spi level, the dependencies will be compiled accordingly. As a result, "make menuconfig" does not expose how dependencies are handled. Corner cases: PCI is required for sof-pci-dev, devm_pci_enable is not defined otherwise. ACPI and SOF_INTEL_TOPLEVEL can be enabled for COMPILE_TEST Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/Kconfig | 82 +++++++++++++---- sound/soc/sof/Makefile | 2 +- sound/soc/sof/intel/Kconfig | 170 +++++++++++++++++++++++++++--------- 3 files changed, 194 insertions(+), 60 deletions(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index bd6ca5b0c342f5..e4ed5582217357 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -1,23 +1,61 @@ +config SND_SOC_SOF_TOPLEVEL + bool "Sound Open Firmware Support" + help + This adds support for Sound Open Firmware (SOF). SOF is a free and + generic open source audio DSP firmware for multiple devices. + Say Y if you have such a device that is supported by SOF. + If unsure select "N". + +if SND_SOC_SOF_TOPLEVEL + config SND_SOC_SOF_PCI - tristate + tristate "SOF PCI enumeration support" + depends on PCI + select SND_SOC_SOF_OPTIONS + select SND_SOC_SOF_INTEL_PCI if SND_SOC_SOF_INTEL_TOPLEVEL + help + This adds support for PCI enumeration. This option is + required to enable Intel Skylake+ devices + Say Y if you need this option + If unsure select "N". config SND_SOC_SOF_ACPI - tristate + tristate "SOF ACPI enumeration support" + depends on ACPI || COMPILE_TEST + select SND_SOC_SOF_OPTIONS + select SND_SOC_SOF_INTEL_ACPI if SND_SOC_SOF_INTEL_TOPLEVEL + select IOSF_MBI if X86 + help + This adds support for ACPI enumeration. This option is required + to enable Intel Haswell/Broadwell/Baytrail/Cherrytrail devices + Say Y if you need this option + If unsure select "N". config SND_SOC_SOF_SPI + tristate "SOF SPI support" + select SPI + select SPI_MASTER + select SND_SOC_SOF_OPTIONS + select SND_SOC_SOF_SPIDSP + help + This adds support for Sound Open Firmware over SPI for Device + Tree based systems. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_SPIDSP tristate + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level -config SND_SOC_SOF - tristate "Sound Open Firmware Support" - select SND_SOC_TOPOLOGY - select SND_SOC_COMPRESS if SND_SOC_SOF_COMPRESS=y +config SND_SOC_SOF_OPTIONS + tristate help - This adds support for Sound Open Firmware (SOF). SOF is a free and - generic open source audio DSP firmware for multiple devices. - Say Y if you have such a device that is supported by SOF. - If unsure select "N". + This option is not user-selectable but automagically handled by + 'select' statements at a higher level -if SND_SOC_SOF +if SND_SOC_SOF_OPTIONS config SND_SOC_SOF_COMPRESS bool "SOF ALSA Compressed API support" @@ -38,17 +76,17 @@ config SND_SOC_SOF_NOCODEC config SND_SOC_SOF_DEBUG bool "SOF debugging features" - depends on SND_SOC_SOF help This option can be used to enable or disable individual SOF firmware and driver debugging options. Say Y if you are debugging SOF FW or drivers. If unsure select "N". +if SND_SOC_SOF_DEBUG + config SND_SOC_SOF_FORCE_NOCODEC_MODE bool "SOF force nocodec Mode" depends on SND_SOC_SOF_NOCODEC - depends on SND_SOC_SOF_DEBUG help This forces SOF to use dummy/nocodec as machine driver, even though there is a codec detected on the real platform. This is @@ -60,7 +98,6 @@ config SND_SOC_SOF_FORCE_NOCODEC_MODE config SND_SOC_SOF_DEBUG_XRUN_STOP bool "SOF stop on XRUN" - depends on SND_SOC_SOF_DEBUG help This option forces PCMs to stop on any XRUN event. This is useful to preserve any trace data ond pipeline status prior to the XRUN. @@ -69,7 +106,6 @@ config SND_SOC_SOF_DEBUG_XRUN_STOP config SND_SOC_SOF_DEBUG_VERBOSE_IPC bool "SOF verbose IPC logs" - depends on SND_SOC_SOF_DEBUG help This option enables more verbose IPC logs, with command types in human-readable form instead of just 32-bit hex dumps. This is useful @@ -78,8 +114,6 @@ config SND_SOC_SOF_DEBUG_VERBOSE_IPC config SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION bool "SOF force to use IPC for position update on SKL+" - depends on SND_SOC_SOF_DEBUG - default n help This option force to handle stream position update IPCs and run pcm elapse to inform ALSA about that, on platforms (e.g. Intel SKL+) that @@ -90,6 +124,20 @@ config SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION DPIB/posbuf is not ready, select "Y". If unsure select "N". +endif ## SND_SOC_SOF_DEBUG + +endif ## SND_SOC_SOF_OPTIONS + +config SND_SOC_SOF + tristate + select SND_SOC_TOPOLOGY + select SND_SOC_COMPRESS if SND_SOC_SOF_COMPRESS=y + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + Due to module dependencies this option needs to be selected + at the lowest level for each platform + source "sound/soc/sof/intel/Kconfig" source "sound/soc/sof/xtensa/Kconfig" diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 035ee0c7268394..b3d6defe6c39e6 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -21,5 +21,5 @@ obj-$(CONFIG_SND_SOC_SOF_SPI) += sof-spi-dev.o obj-$(CONFIG_SND_SOC_SOF_SPIDSP) += snd-sof-spi.o -obj-$(CONFIG_SND_SOC_SOF_INTEL) += intel/ +obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/ obj-$(CONFIG_SND_SOC_SOF_XTENSA) += xtensa/ diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index acc31134481fcf..cf751377e4e76c 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -1,114 +1,192 @@ -config SND_SOC_SOF_SPIDSP - tristate "SOF support over the SPI bus" - depends on SPI - select SND_SOC_SOF_SPI - help - This adds support for Sound Open Firmware over SPI for Device - Tree based systems. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_SOF_INTEL - tristate "SOF support for Intel audio DSPs" - depends on SND_DMA_SGBUF - select SND_SOC_INTEL_MACH - select SND_SOC_SOF_XTENSA +config SND_SOC_SOF_INTEL_TOPLEVEL + bool "SOF support for Intel audio DSPs" + depends on SND_DMA_SGBUF || COMPILE_TEST help This adds support for Sound Open Firmware for Intel(R) platforms. Say Y if you have such a device. If unsure select "N". -if SND_SOC_SOF_INTEL +if SND_SOC_SOF_INTEL_TOPLEVEL -config SND_SOC_SOF_BAYTRAIL - tristate "SOF support for Baytrail, Braswell and Cherrytrail" - select SND_SOC_SOF_ACPI +config SND_SOC_SOF_INTEL_ACPI + tristate + select SND_SOC_SOF_BAYTRAIL if SND_SOC_SOF_BAYTRAIL_SUPPORT + select SND_SOC_SOF_HASWELL if SND_SOC_SOF_HASWELL_SUPPORT + select SND_SOC_SOF_BROADWELL if SND_SOC_SOF_BROADWELL_SUPPORT + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_INTEL_PCI + tristate + select SND_SOC_SOF_APOLLOLAKE if SND_SOC_SOF_APOLLOLAKE_SUPPORT + select SND_SOC_SOF_GEMINILAKE if SND_SOC_SOF_GEMINILAKE_SUPPORT + select SND_SOC_SOF_CANNONLAKE if SND_SOC_SOF_CANNONLAKE_SUPPORT + select SND_SOC_SOF_KABYLAKE if SND_SOC_SOF_KABYLAKE_SUPPORT + select SND_SOC_SOF_SKYLAKE if SND_SOC_SOF_SKYLAKE_SUPPORT + select SND_SOC_SOF_ICELAKE if SND_SOC_SOF_ICELAKE_SUPPORT + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_INTEL_COMMON + tristate select SND_SOC_ACPI_INTEL_MATCH + select SND_SOC_SOF_XTENSA + select SND_SOC_SOF + select SND_SOC_INTEL_MACH + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +if SND_SOC_SOF_INTEL_ACPI + +config SND_SOC_SOF_BAYTRAIL_SUPPORT + bool "SOF support for Baytrail, Braswell and Cherrytrail" help This adds support for Sound Open Firmware for Intel(R) platforms using the Baytrail, Braswell or Cherrytrail processors. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_HASWELL - tristate "SOF support for Haswell" - select SND_SOC_SOF_ACPI - select SND_SOC_ACPI_INTEL_MATCH +config SND_SOC_SOF_BAYTRAIL + tristate + select SND_SOC_INTEL_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_HASWELL_SUPPORT + bool "SOF support for Haswell" help This adds support for Sound Open Firmware for Intel(R) platforms using the Haswell processors. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_BROADWELL - tristate "SOF support for Broadwell" - select SND_SOC_SOF_ACPI - select SND_SOC_ACPI_INTEL_MATCH +config SND_SOC_SOF_HASWELL + tristate + select SND_SOC_SOF_INTEL_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_BROADWELL_SUPPORT + bool "SOF support for Broadwell" help This adds support for Sound Open Firmware for Intel(R) platforms using the Broadwell processors. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_APOLLOLAKE - tristate "SOF support for Apollolake" - select SND_SOC_SOF_HDA_COMMON +config SND_SOC_SOF_BROADWELL + tristate + select SND_SOC_SOF_INTEL_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +endif ## SND_SOC_SOF_INTEL_ACPI + +if SND_SOC_SOF_INTEL_PCI + +config SND_SOC_SOF_APOLLOLAKE_SUPPORT + bool "SOF support for Apollolake" help This adds support for Sound Open Firmware for Intel(R) platforms using the Apollolake processors. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_GEMINILAKE - tristate "SOF support for GeminiLake" +config SND_SOC_SOF_APOLLOLAKE + tristate select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_GEMINILAKE_SUPPORT + bool "SOF support for GeminiLake" help This adds support for Sound Open Firmware for Intel(R) platforms using the Geminilake processors. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_CANNONLAKE - tristate "SOF support for Cannonlake" +config SND_SOC_SOF_GEMINILAKE + tristate select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_CANNONLAKE_SUPPORT + bool "SOF support for Cannonlake" help This adds support for Sound Open Firmware for Intel(R) platforms using the Cannonlake processors. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_KABYLAKE - tristate "SOF support for Kabylake" +config SND_SOC_SOF_CANNONLAKE + tristate select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_KABYLAKE_SUPPORT + bool "SOF support for Kabylake" help This adds support for Sound Open Firmware for Intel(R) platforms using the Kabylake processors. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_SKYLAKE - tristate "SOF support for Skylake" +config SND_SOC_SOF_KABYLAKE + tristate select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_SKYLAKE_SUPPORT + bool "SOF support for Skylake" help This adds support for Sound Open Firmware for Intel(R) platforms using the Skylake processors. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_ICELAKE - tristate "SOF support for Icelake" +config SND_SOC_SOF_SKYLAKE + tristate select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_ICELAKE_SUPPORT + bool "SOF support for Icelake" help This adds support for Sound Open Firmware for Intel(R) platforms using the Icelake processors. Say Y if you have such a device. If unsure select "N". +config SND_SOC_SOF_ICELAKE + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + config SND_SOC_SOF_HDA_COMMON tristate - select SND_SOC_SOF_PCI - select SND_SOC_ACPI_INTEL_MATCH + select SND_SOC_SOF_INTEL_COMMON select SND_SOC_SOF_HDA_LINK_BASELINE + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level if SND_SOC_SOF_HDA_COMMON @@ -134,10 +212,18 @@ endif ## SND_SOC_SOF_HDA_COMMON config SND_SOC_SOF_HDA_LINK_BASELINE tristate select SND_SOC_SOF_HDA if SND_SOC_SOF_HDA_LINK + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level config SND_SOC_SOF_HDA tristate select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +endif ## SND_SOC_SOF_INTEL_PCI endif ## SND_SOC_SOF_INTEL From 88bae3d6e0e6f507eefd9492e767cd3775efa901 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 14 Dec 2018 15:51:18 -0600 Subject: [PATCH 0421/1995] ASoC: Intel: Fix if statements for SOF in Kconfigs s/SND_SOF_SOC_INTEL/SND_SOC_SOF_INTEL_TOPLEVEL Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/Kconfig | 4 ++-- sound/soc/intel/boards/Kconfig | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index a8e33188b30ad3..d4d7ef5daf4bc0 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -139,7 +139,7 @@ endif ## SND_SOC_INTEL_SKYLAKE endif ## SND_SOC_INTEL_SST_TOPLEVEL -if SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL +if SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL config SND_SOC_ACPI_INTEL_MATCH tristate @@ -147,7 +147,7 @@ config SND_SOC_ACPI_INTEL_MATCH # this option controls the compilation of ACPI matching tables and # helpers and is not meant to be selected by the user. -endif ## SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL +endif ## SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL # ASoC codec drivers diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 2582146bf97651..3490bfd6af2869 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -1,6 +1,6 @@ menuconfig SND_SOC_INTEL_MACH bool "Intel Machine drivers" - depends on SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL + depends on SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL help Intel ASoC Machine Drivers. If you have a Intel machine that has an audio controller with a DSP and I2S or DMIC port, then From 2cb12efbf97fa51a8962ac5e4186dd0690cc5fe1 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Thu, 13 Dec 2018 21:49:58 +0800 Subject: [PATCH 0422/1995] ASoC: SOF: control: check value before waking DSP up We don't need to wake DSP up if the _put value is invalid. So move the value checking before waking DSP up. Signed-off-by: Bard liao --- sound/soc/sof/control.c | 50 +++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 6163948975ac64..cc589c65c7bc9b 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -162,6 +162,12 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, struct sof_abi_hdr *data = cdata->data; int ret, err; + if (data->size > be->max) { + dev_err_ratelimited(sdev->dev, "error: size too big %d bytes max is %d\n", + data->size, be->max); + return -EINVAL; + } + ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { dev_err_ratelimited(sdev->dev, "error: bytes put failed to resume %d\n", @@ -169,13 +175,6 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, return ret; } - if (data->size > be->max) { - dev_err_ratelimited(sdev->dev, "error: size too big %d bytes max is %d\n", - data->size, be->max); - ret = -EINVAL; - goto out; - } - /* copy from kcontrol */ memcpy(data, ucontrol->value.bytes.data, data->size); @@ -183,7 +182,6 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_DATA, SOF_CTRL_TYPE_DATA_SET, scontrol->cmd); -out: pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) @@ -209,20 +207,12 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, int max_size = SOF_IPC_MSG_MAX_SIZE - sizeof(const struct sof_ipc_ctrl_data); - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, "error: bytes_ext put failed to resume %d\n", - ret); - return ret; - } - /* The beginning of bytes data contains a header from where * the length (as bytes) is needed to know the correct copy * length of data from tlvd->tlv. */ if (copy_from_user(&header, tlvd, sizeof(const struct snd_ctl_tlv))) { - ret = -EFAULT; - goto out; + return -EFAULT; } /* The maximum length that can be copied is limited by IPC max * length and topology defined length for ext bytes control. @@ -232,48 +222,48 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, if (header.length > max_size) { dev_err_ratelimited(sdev->dev, "error: Bytes data size %d exceeds max %d.\n", header.length, max_size); - ret = -EINVAL; - goto out; + return -EINVAL; } /* Check that header id matches the command */ if (header.numid != scontrol->cmd) { dev_err_ratelimited(sdev->dev, "error: incorrect numid %d\n", header.numid); - ret = -EINVAL; - goto out; + return -EINVAL; } if (copy_from_user(cdata->data, tlvd->tlv, header.length)) { - ret = -EFAULT; - goto out; + return -EFAULT; } if (cdata->data->magic != SOF_ABI_MAGIC) { dev_err_ratelimited(sdev->dev, "error: Wrong ABI magic 0x%08x.\n", cdata->data->magic); - ret = -EINVAL; - goto out; + return -EINVAL; } if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { dev_err_ratelimited(sdev->dev, "error: Incompatible ABI version 0x%08x.\n", cdata->data->abi); - ret = -EINVAL; - goto out; + return -EINVAL; } if (cdata->data->size + sizeof(const struct sof_abi_hdr) > max_size) { dev_err_ratelimited(sdev->dev, "error: Mismatch in ABI data size (truncated?).\n"); - ret = -EINVAL; - goto out; + return -EINVAL; + } + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err_ratelimited(sdev->dev, "error: bytes_ext put failed to resume %d\n", + ret); + return ret; } /* notify DSP of mixer updates */ snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_DATA, SOF_CTRL_TYPE_DATA_SET, scontrol->cmd); -out: pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) From 3071bfcec75e356de4e9dc62a1c736a35705d7a2 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 14 Dec 2018 00:58:19 +0800 Subject: [PATCH 0423/1995] ASoC: SOF: control: add check of max data size be->max should not to exceed ucontrol data array size. Signed-off-by: Bard liao --- sound/soc/sof/control.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index cc589c65c7bc9b..bedfcee47125fa 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -121,6 +121,12 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, size_t size; int ret, err; + if (be->max > sizeof(ucontrol->value.bytes.data)) { + dev_err_ratelimited(sdev->dev, "error: data max %d exceeds ucontrol data array size\n", + be->max); + return -EINVAL; + } + ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { dev_err_ratelimited(sdev->dev, "error: bytes get failed to resume %d\n", @@ -162,6 +168,12 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, struct sof_abi_hdr *data = cdata->data; int ret, err; + if (be->max > sizeof(ucontrol->value.bytes.data)) { + dev_err_ratelimited(sdev->dev, "error: data max %d exceeds ucontrol data array size\n", + be->max); + return -EINVAL; + } + if (data->size > be->max) { dev_err_ratelimited(sdev->dev, "error: size too big %d bytes max is %d\n", data->size, be->max); From f9b2f986c3653f4dd996d2e53146b0acf0be1549 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 17 Dec 2018 09:03:22 -0800 Subject: [PATCH 0424/1995] ASoC: SOF: hda: remove stale comment The comment looks stale. Should be removed. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 14942829ff16aa..1b2db25c3c8e3e 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -410,11 +410,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) #endif -/* - * We don't need to do a full HDA codec probe as external HDA codec mode is - * considered legacy and will not be supported under SOF. HDMI/DP HDA will - * be supported in the DSP. - */ int hda_dsp_probe(struct snd_sof_dev *sdev) { struct pci_dev *pci = sdev->pci; From 151d59b0a50734b634b3a7c306d56d5d7618cd00 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 17 Dec 2018 18:56:14 -0600 Subject: [PATCH 0425/1995] ASoC: soc-acpi: add static inline fallbacks when CONFIG_ACPI=n Fix compilation issues reported by 0day-Kbuild with sparc64 w/ SOF. Signed-off-by: Pierre-Louis Bossart --- include/sound/soc-acpi.h | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 266e64e3c24c4f..6cbbeed9cdd0c8 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -22,20 +22,37 @@ struct snd_soc_acpi_package_context { #define SND_ACPI_I2C_ID_LEN (4 + ACPI_ID_LEN + 3 + 1) #if IS_ENABLED(CONFIG_ACPI) +/* acpi match */ +struct snd_soc_acpi_mach * +snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines); + bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], struct snd_soc_acpi_package_context *ctx); + +/* check all codecs */ +struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg); + #else +/* acpi match */ +static inline struct snd_soc_acpi_mach * +snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines) +{ + return NULL; +} + static inline bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], struct snd_soc_acpi_package_context *ctx) { return false; } -#endif -/* acpi match */ -struct snd_soc_acpi_mach * -snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines); +/* check all codecs */ +static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) +{ + return NULL; +} +#endif /** * snd_soc_acpi_mach_params: interface for machine driver configuration @@ -105,7 +122,4 @@ struct snd_soc_acpi_codecs { u8 codecs[SND_SOC_ACPI_MAX_CODECS][ACPI_ID_LEN]; }; -/* check all codecs */ -struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg); - #endif From 3e26e53c38c9012340f2a6cc47a2b04370577c34 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 17 Dec 2018 18:12:59 -0600 Subject: [PATCH 0426/1995] ASoC: SOF: cleanup Kconfig further Simplify selection of SND_SOC_SOF. It used to be selected following the module dependencies but since the module/buit-in selection is only done at the top-level it can be selected from the top-level. Also add dependency on SOC_SOC_ACPI This fixes compilation issues with sparc64 allyesconfig reported by 0day/kbuild Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/Kconfig | 8 ++++++-- sound/soc/sof/intel/Kconfig | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index e4ed5582217357..627b3c2c5edabe 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -11,6 +11,7 @@ if SND_SOC_SOF_TOPLEVEL config SND_SOC_SOF_PCI tristate "SOF PCI enumeration support" depends on PCI + select SND_SOC_SOF select SND_SOC_SOF_OPTIONS select SND_SOC_SOF_INTEL_PCI if SND_SOC_SOF_INTEL_TOPLEVEL help @@ -22,6 +23,7 @@ config SND_SOC_SOF_PCI config SND_SOC_SOF_ACPI tristate "SOF ACPI enumeration support" depends on ACPI || COMPILE_TEST + select SND_SOC_SOF select SND_SOC_SOF_OPTIONS select SND_SOC_SOF_INTEL_ACPI if SND_SOC_SOF_INTEL_TOPLEVEL select IOSF_MBI if X86 @@ -35,6 +37,7 @@ config SND_SOC_SOF_SPI tristate "SOF SPI support" select SPI select SPI_MASTER + select SND_SOC_SOF select SND_SOC_SOF_OPTIONS select SND_SOC_SOF_SPIDSP help @@ -135,8 +138,9 @@ config SND_SOC_SOF help This option is not user-selectable but automagically handled by 'select' statements at a higher level - Due to module dependencies this option needs to be selected - at the lowest level for each platform + The selection is made at the top level and does not exactly follow + module dependencies but since the module or built-in type is decided + at the top level it doesn't matter. source "sound/soc/sof/intel/Kconfig" source "sound/soc/sof/xtensa/Kconfig" diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index cf751377e4e76c..46edc9dc3cc365 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -33,8 +33,8 @@ config SND_SOC_SOF_INTEL_COMMON tristate select SND_SOC_ACPI_INTEL_MATCH select SND_SOC_SOF_XTENSA - select SND_SOC_SOF select SND_SOC_INTEL_MACH + select SND_SOC_ACPI if ACPI help This option is not user-selectable but automagically handled by 'select' statements at a higher level From f70ec08144c8b47125ff19c63252a72281ae63f1 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Mon, 17 Dec 2018 20:07:17 +0800 Subject: [PATCH 0427/1995] ASoC: SOF: use const for snd_sof_dsp_ops f91b468d751 ('ASoC: SOF: make ops constant') missed a couple of places when const can be used. Fix. Signed-off-by: Libin Yang Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/hw-spi.c | 2 +- sound/soc/sof/hw-spi.h | 2 +- sound/soc/sof/virtio-fe.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index 2d5f34e66f7487..a9a53c957163c0 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -275,7 +275,7 @@ static int spi_cmd_done(struct snd_sof_dev *sof_dev __maybe_unused, int dir __ma } /* SPI SOF ops */ -struct snd_sof_dsp_ops snd_sof_spi_ops = { +const struct snd_sof_dsp_ops snd_sof_spi_ops = { /* device init */ .probe = spi_sof_probe, .remove = spi_sof_remove, diff --git a/sound/soc/sof/hw-spi.h b/sound/soc/sof/hw-spi.h index 1929856eabec90..69ba896a1076fd 100644 --- a/sound/soc/sof/hw-spi.h +++ b/sound/soc/sof/hw-spi.h @@ -1,6 +1,6 @@ #ifndef HW_SPI_H #define HW_SPI_H -extern struct snd_sof_dsp_ops snd_sof_spi_ops; +extern const struct snd_sof_dsp_ops snd_sof_spi_ops; #endif diff --git a/sound/soc/sof/virtio-fe.c b/sound/soc/sof/virtio-fe.c index 6e9de114c2384c..3af6f37bd897ae 100644 --- a/sound/soc/sof/virtio-fe.c +++ b/sound/soc/sof/virtio-fe.c @@ -100,7 +100,7 @@ static int virtio_fe_remove(struct snd_sof_dev *sdev) } /* baytrail ops */ -struct snd_sof_dsp_ops snd_sof_virtio_fe_ops = { +const struct snd_sof_dsp_ops snd_sof_virtio_fe_ops = { /* device init */ .probe = virtio_fe_probe, .remove = virtio_fe_remove, From 21b203fc51427a1577f43da25f535794b0ac10be Mon Sep 17 00:00:00 2001 From: Bard liao Date: Mon, 17 Dec 2018 06:48:16 +0800 Subject: [PATCH 0428/1995] ASoC: SOF: pcm: remove unnecessary sdev->hda check People should be able to define their own pcm_pointer function even they don't use hda. We can just set sdev->ops->pcm_pointer = null if we want to use the default pointer function of SOF. Signed-off-by: Bard liao --- sound/soc/sof/pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 1e0914a49265c1..d62bb052c62788 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -339,7 +339,7 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) return 0; /* if have dsp ops pointer callback, use that directly */ - if (sdev->hda && sdev->ops->pcm_pointer) + if (sdev->ops->pcm_pointer) return sdev->ops->pcm_pointer(sdev, substream); /* read position from DSP */ From 007f8fedb909b46c64c324b5cd130e634f4f86e1 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 17 Dec 2018 14:20:55 -0800 Subject: [PATCH 0429/1995] ASoC: SOF: pm: don't return error when CTX_SAVE ipc fails CTX_SAVE ipc is sent right before the DSP is powered off. Returning an error if this ipc fails causes the resume sequence to fail as well. Instead just report the error and continue to power off the DSP. This is only a temporary workaround until the real issue with CTX_SAVE ipc's timing out is root caused. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index e34b2a5bd0f358..77388a36434bed 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -318,10 +318,17 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) /* notify DSP of upcoming power down */ ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_SAVE); if (ret < 0) { + + /* + * FIXME: CTX_SAVE ipc should not time-out. + * But if it happens, just report the error + * and continue powering off the DSP for now. + * This will allow the DSP to power up + * normally upon system resume. + */ dev_err(sdev->dev, "error: ctx_save ipc error during suspend %d\n", ret); - return ret; } /* drop all ipc */ From c702fdd998fa10359dc191cd54d75c9a60afd68e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 14 Dec 2018 18:30:51 -0600 Subject: [PATCH 0430/1995] ASoC: SOF: Intel: Baytrail: prepare Edison cleanup Move code around so that the probe code is more local Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/byt.c | 98 +++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 1442c47840024d..0380dc44019f70 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -455,6 +455,55 @@ static int byt_reset(struct snd_sof_dev *sdev) return 0; } +#define BYT_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +/* Baytrail DAIs */ +static struct snd_soc_dai_driver byt_dai[] = { +{ + .name = "ssp0-port", + .playback = SOF_DAI_STREAM("ssp0 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), + .capture = SOF_DAI_STREAM("ssp0 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), +}, +{ + .name = "ssp1-port", + .playback = SOF_DAI_STREAM("ssp1 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), + .capture = SOF_DAI_STREAM("ssp1 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), +}, +{ + .name = "ssp2-port", + .playback = SOF_DAI_STREAM("ssp2 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), + .capture = SOF_DAI_STREAM("ssp2 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), +}, +{ + .name = "ssp3-port", + .playback = SOF_DAI_STREAM("ssp3 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), + .capture = SOF_DAI_STREAM("ssp3 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), +}, +{ + .name = "ssp4-port", + .playback = SOF_DAI_STREAM("ssp4 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), + .capture = SOF_DAI_STREAM("ssp4 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), +}, +{ + .name = "ssp5-port", + .playback = SOF_DAI_STREAM("ssp5 Tx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), + .capture = SOF_DAI_STREAM("ssp5 Rx", 1, 8, + SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), +}, +}; + /* * Probe and remove. */ @@ -650,55 +699,6 @@ static int byt_probe(struct snd_sof_dev *sdev) return byt_acpi_probe(sdev); } -#define BYT_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE) - -/* Baytrail DAIs */ -static struct snd_soc_dai_driver byt_dai[] = { -{ - .name = "ssp0-port", - .playback = SOF_DAI_STREAM("ssp0 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), - .capture = SOF_DAI_STREAM("ssp0 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), -}, -{ - .name = "ssp1-port", - .playback = SOF_DAI_STREAM("ssp1 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), - .capture = SOF_DAI_STREAM("ssp1 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), -}, -{ - .name = "ssp2-port", - .playback = SOF_DAI_STREAM("ssp2 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), - .capture = SOF_DAI_STREAM("ssp2 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), -}, -{ - .name = "ssp3-port", - .playback = SOF_DAI_STREAM("ssp3 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), - .capture = SOF_DAI_STREAM("ssp3 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), -}, -{ - .name = "ssp4-port", - .playback = SOF_DAI_STREAM("ssp4 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), - .capture = SOF_DAI_STREAM("ssp4 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), -}, -{ - .name = "ssp5-port", - .playback = SOF_DAI_STREAM("ssp5 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), - .capture = SOF_DAI_STREAM("ssp5 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), -}, -}; - /* baytrail ops */ const struct snd_sof_dsp_ops sof_byt_ops = { /* device init */ From f5fac679095e2ff0268323216c3f13073de20f03 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 14 Dec 2018 18:32:38 -0600 Subject: [PATCH 0431/1995] ASoC: SOF: Intel: add Edison support Edison is based on PCI, need to split Baytrail in two No code change, only new Kconfig added Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/Kconfig | 25 ++++++++++++++++++++++++- sound/soc/sof/intel/Makefile | 2 +- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 46edc9dc3cc365..6670fc3a43c2cc 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -19,6 +19,7 @@ config SND_SOC_SOF_INTEL_ACPI config SND_SOC_SOF_INTEL_PCI tristate + select SND_SOC_SOF_EDISON if SND_SOC_SOF_EDISON_SUPPORT select SND_SOC_SOF_APOLLOLAKE if SND_SOC_SOF_APOLLOLAKE_SUPPORT select SND_SOC_SOF_GEMINILAKE if SND_SOC_SOF_GEMINILAKE_SUPPORT select SND_SOC_SOF_CANNONLAKE if SND_SOC_SOF_CANNONLAKE_SUPPORT @@ -29,6 +30,13 @@ config SND_SOC_SOF_INTEL_PCI This option is not user-selectable but automagically handled by 'select' statements at a higher level +config SND_SOC_SOF_INTEL_ATOM_HIFI_EP + tristate + select SND_SOC_INTEL_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + config SND_SOC_SOF_INTEL_COMMON tristate select SND_SOC_ACPI_INTEL_MATCH @@ -51,7 +59,7 @@ config SND_SOC_SOF_BAYTRAIL_SUPPORT config SND_SOC_SOF_BAYTRAIL tristate - select SND_SOC_INTEL_COMMON + select SND_SOC_SOF_INTEL_ATOM_HIFI_EP help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -90,6 +98,21 @@ endif ## SND_SOC_SOF_INTEL_ACPI if SND_SOC_SOF_INTEL_PCI +config SND_SOC_SOF_EDISON_SUPPORT + bool "SOF support for Tangier/Edison" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Baytrail, Braswell or Cherrytrail processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_EDISON + tristate + select SND_SOC_SOF_INTEL_ATOM_HIFI_EP + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + config SND_SOC_SOF_APOLLOLAKE_SUPPORT bool "SOF support for Apollolake" help diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index a7a7c0cf7663aa..7a52b89eea863a 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -12,7 +12,7 @@ snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ snd-sof-intel-hda-objs := hda-codec.o -obj-$(CONFIG_SND_SOC_SOF_BAYTRAIL) += snd-sof-intel-byt.o +obj-$(CONFIG_SND_SOC_SOF_INTEL_ATOM_HIFI_EP) += snd-sof-intel-byt.o obj-$(CONFIG_SND_SOC_SOF_HASWELL) += snd-sof-intel-hsw.o obj-$(CONFIG_SND_SOC_SOF_BROADWELL) += snd-sof-intel-bdw.o obj-$(CONFIG_SND_SOC_SOF_HDA_COMMON) += snd-sof-intel-hda-common.o From 3c3e8ea26568ba19bea72d35624e45f3723aae40 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 14 Dec 2018 18:42:15 -0600 Subject: [PATCH 0432/1995] ASoC: SOF: Intel: prepare Edison support without BAYTRAIL move code around to reduce diffs in future patches Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/byt.c | 160 +++++++++++++++++++++++------------- sound/soc/sof/intel/shim.h | 1 + sound/soc/sof/sof-pci-dev.c | 23 +++--- 3 files changed, 113 insertions(+), 71 deletions(-) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 0380dc44019f70..2af7f0ac098b75 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -508,37 +508,24 @@ static struct snd_soc_dai_driver byt_dai[] = { * Probe and remove. */ -static int byt_acpi_probe(struct snd_sof_dev *sdev) +static int byt_pci_probe(struct snd_sof_dev *sdev) { struct snd_sof_pdata *pdata = sdev->pdata; const struct sof_dev_desc *desc = pdata->desc; - struct platform_device *pdev = - container_of(sdev->parent, struct platform_device, dev); - struct resource *mmio; + struct pci_dev *pci = sdev->pci; u32 base, size; int ret = 0; - /* set DSP arch ops */ - sdev->arch_ops = &sof_xtensa_arch_ops; - /* DSP DMA can only access low 31 bits of host memory */ - ret = dma_coerce_mask_and_coherent(sdev->dev, DMA_BIT_MASK(31)); + ret = dma_coerce_mask_and_coherent(&pci->dev, DMA_BIT_MASK(31)); if (ret < 0) { dev_err(sdev->dev, "error: failed to set DMA mask %d\n", ret); return ret; } /* LPE base */ - mmio = platform_get_resource(pdev, IORESOURCE_MEM, - desc->resindex_lpe_base); - if (mmio) { - base = mmio->start; - size = resource_size(mmio); - } else { - dev_err(sdev->dev, "error: failed to get LPE base at idx %d\n", - desc->resindex_lpe_base); - return -EINVAL; - } + base = pci_resource_start(pci, desc->resindex_lpe_base) - IRAM_OFFSET; + size = BYT_PCI_BAR_SIZE; dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); sdev->bar[BYT_DSP_BAR] = devm_ioremap(sdev->dev, base, size); @@ -549,24 +536,12 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) } dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[BYT_DSP_BAR]); - /* TODO: add offsets */ - sdev->mmio_bar = BYT_DSP_BAR; - sdev->mailbox_bar = BYT_DSP_BAR; - /* IMR base - optional */ if (desc->resindex_imr_base == -1) goto irq; - mmio = platform_get_resource(pdev, IORESOURCE_MEM, - desc->resindex_imr_base); - if (mmio) { - base = mmio->start; - size = resource_size(mmio); - } else { - dev_err(sdev->dev, "error: failed to get IMR base at idx %d\n", - desc->resindex_imr_base); - return -ENODEV; - } + base = pci_resource_start(pci, desc->resindex_imr_base); + size = pci_resource_len(pci, desc->resindex_imr_base); /* some BIOSes don't map IMR */ if (base == 0x55aa55aa || base == 0x0) { @@ -585,17 +560,11 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) irq: /* register our IRQ */ - sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc); - if (sdev->ipc_irq < 0) { - dev_err(sdev->dev, "error: failed to get IRQ at index %d\n", - desc->irqindex_host_ipc); - return sdev->ipc_irq; - } - + sdev->ipc_irq = pci->irq; dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, byt_irq_handler, byt_irq_thread, - IRQF_SHARED, "AudioDSP", sdev); + 0, "AudioDSP", sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to register IRQ %d\n", sdev->ipc_irq); @@ -615,24 +584,87 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) return ret; } -static int byt_pci_probe(struct snd_sof_dev *sdev) +const struct snd_sof_dsp_ops sof_tng_ops = { + /* device init */ + .probe = byt_pci_probe, + + /* DSP core boot / reset */ + .run = byt_run, + .reset = byt_reset, + + /* Register IO */ + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* doorbell */ + .irq_handler = byt_irq_handler, + .irq_thread = byt_irq_thread, + + /* mailbox */ + .mailbox_read = sof_mailbox_read, + .mailbox_write = sof_mailbox_write, + + /* ipc */ + .send_msg = byt_send_msg, + .get_reply = byt_get_reply, + .fw_ready = byt_fw_ready, + .is_ready = byt_is_ready, + .cmd_done = byt_cmd_done, + + /* debug */ + .debug_map = byt_debugfs, + .debug_map_count = ARRAY_SIZE(byt_debugfs), + .dbg_dump = byt_dump, + + /* module loading */ + .load_module = snd_sof_parse_module_memcpy, + + /*Firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + + /* DAI drivers */ + .drv = byt_dai, + .num_drv = 3, /* we have only 3 SSPs on byt*/ +}; +EXPORT_SYMBOL(sof_tng_ops); + +static int byt_acpi_probe(struct snd_sof_dev *sdev) { struct snd_sof_pdata *pdata = sdev->pdata; const struct sof_dev_desc *desc = pdata->desc; - struct pci_dev *pci = sdev->pci; + struct platform_device *pdev = + container_of(sdev->parent, struct platform_device, dev); + struct resource *mmio; u32 base, size; int ret = 0; + /* set DSP arch ops */ + sdev->arch_ops = &sof_xtensa_arch_ops; + /* DSP DMA can only access low 31 bits of host memory */ - ret = dma_coerce_mask_and_coherent(&pci->dev, DMA_BIT_MASK(31)); + ret = dma_coerce_mask_and_coherent(sdev->dev, DMA_BIT_MASK(31)); if (ret < 0) { dev_err(sdev->dev, "error: failed to set DMA mask %d\n", ret); return ret; } /* LPE base */ - base = pci_resource_start(pci, desc->resindex_lpe_base) - IRAM_OFFSET; - size = BYT_PCI_BAR_SIZE; + mmio = platform_get_resource(pdev, IORESOURCE_MEM, + desc->resindex_lpe_base); + if (mmio) { + base = mmio->start; + size = resource_size(mmio); + } else { + dev_err(sdev->dev, "error: failed to get LPE base at idx %d\n", + desc->resindex_lpe_base); + return -EINVAL; + } dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); sdev->bar[BYT_DSP_BAR] = devm_ioremap(sdev->dev, base, size); @@ -643,12 +675,24 @@ static int byt_pci_probe(struct snd_sof_dev *sdev) } dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[BYT_DSP_BAR]); + /* TODO: add offsets */ + sdev->mmio_bar = BYT_DSP_BAR; + sdev->mailbox_bar = BYT_DSP_BAR; + /* IMR base - optional */ if (desc->resindex_imr_base == -1) goto irq; - base = pci_resource_start(pci, desc->resindex_imr_base); - size = pci_resource_len(pci, desc->resindex_imr_base); + mmio = platform_get_resource(pdev, IORESOURCE_MEM, + desc->resindex_imr_base); + if (mmio) { + base = mmio->start; + size = resource_size(mmio); + } else { + dev_err(sdev->dev, "error: failed to get IMR base at idx %d\n", + desc->resindex_imr_base); + return -ENODEV; + } /* some BIOSes don't map IMR */ if (base == 0x55aa55aa || base == 0x0) { @@ -667,11 +711,17 @@ static int byt_pci_probe(struct snd_sof_dev *sdev) irq: /* register our IRQ */ - sdev->ipc_irq = pci->irq; + sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc); + if (sdev->ipc_irq < 0) { + dev_err(sdev->dev, "error: failed to get IRQ at index %d\n", + desc->irqindex_host_ipc); + return sdev->ipc_irq; + } + dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, byt_irq_handler, byt_irq_thread, - 0, "AudioDSP", sdev); + IRQF_SHARED, "AudioDSP", sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to register IRQ %d\n", sdev->ipc_irq); @@ -691,18 +741,10 @@ static int byt_pci_probe(struct snd_sof_dev *sdev) return ret; } -static int byt_probe(struct snd_sof_dev *sdev) -{ - if (sdev->pci) - return byt_pci_probe(sdev); - - return byt_acpi_probe(sdev); -} - /* baytrail ops */ const struct snd_sof_dsp_ops sof_byt_ops = { /* device init */ - .probe = byt_probe, + .probe = byt_acpi_probe, /* DSP core boot / reset */ .run = byt_run, @@ -753,7 +795,7 @@ EXPORT_SYMBOL(sof_byt_ops); /* cherrytrail and braswell ops */ const struct snd_sof_dsp_ops sof_cht_ops = { /* device init */ - .probe = byt_probe, + .probe = byt_acpi_probe, /* DSP core boot / reset */ .run = byt_run, diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 06fc3df26c50ad..5d85fd579bfa8b 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -151,6 +151,7 @@ #define PCI_PMCS 0x84 #define PCI_PMCS_PS_MASK 0x3 +extern const struct snd_sof_dsp_ops sof_tng_ops; extern const struct snd_sof_dsp_ops sof_byt_ops; extern const struct snd_sof_dsp_ops sof_cht_ops; extern const struct snd_sof_dsp_ops sof_hsw_ops; diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index c288c49e34b6e9..df57f7855336db 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -47,8 +47,8 @@ static struct sof_dev_desc glk_desc = { }; #endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) -static struct snd_soc_acpi_mach sof_byt_machines[] = { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_EDISON) +static struct snd_soc_acpi_mach sof_tng_machines[] = { { .id = "INT343A", .drv_name = "edison", @@ -59,8 +59,8 @@ static struct snd_soc_acpi_mach sof_byt_machines[] = { {} }; -static const struct sof_dev_desc byt_desc = { - .machines = sof_byt_machines, +static const struct sof_dev_desc tng_desc = { + .machines = sof_tng_machines, .resindex_lpe_base = 3, /* IRAM, but subtract IRAM offset */ .resindex_pcicfg_base = -1, .resindex_imr_base = 0, @@ -133,15 +133,15 @@ static const struct dev_pm_ops sof_pci_pm = { }; static const struct sof_ops_table pci_mach_ops[] = { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_EDISON) + {&tng_desc, &sof_tng_ops}, +#endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) {&bxt_desc, &sof_apl_ops}, #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) {&glk_desc, &sof_apl_ops}, #endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - {&byt_desc, &sof_byt_ops}, -#endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) {&cnl_desc, &sof_cnl_ops}, #endif @@ -310,6 +310,10 @@ static void sof_pci_remove(struct pci_dev *pci) /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_EDISON) + { PCI_DEVICE(0x8086, 0x119a), + .driver_data = (unsigned long)&tng_desc}, +#endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) /* BXT-P & Apollolake */ { PCI_DEVICE(0x8086, 0x5a98), @@ -321,11 +325,6 @@ static const struct pci_device_id sof_pci_ids[] = { { PCI_DEVICE(0x8086, 0x3198), .driver_data = (unsigned long)&glk_desc}, #endif - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - { PCI_DEVICE(0x8086, 0x119a), - .driver_data = (unsigned long)&byt_desc}, -#endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) { PCI_DEVICE(0x8086, 0x9dc8), .driver_data = (unsigned long)&cnl_desc}, From 8a3368f05f38300632f7510361d0d4dd56ad6330 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 14 Dec 2018 19:39:43 -0600 Subject: [PATCH 0433/1995] ASoC: SOF: Intel: compile out EDISON or BAYTRAIL if needed Only compile what is selected Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/byt.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 2af7f0ac098b75..cef099406006e6 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -508,6 +508,8 @@ static struct snd_soc_dai_driver byt_dai[] = { * Probe and remove. */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_EDISON) + static int byt_pci_probe(struct snd_sof_dev *sdev) { struct snd_sof_pdata *pdata = sdev->pdata; @@ -634,6 +636,10 @@ const struct snd_sof_dsp_ops sof_tng_ops = { }; EXPORT_SYMBOL(sof_tng_ops); +#endif /* CONFIG_SND_SOC_SOF_EDISON */ + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) + static int byt_acpi_probe(struct snd_sof_dev *sdev) { struct snd_sof_pdata *pdata = sdev->pdata; @@ -844,4 +850,6 @@ const struct snd_sof_dsp_ops sof_cht_ops = { }; EXPORT_SYMBOL(sof_cht_ops); +#endif /* CONFIG_SND_SOC_SOF_BAYTRAIL */ + MODULE_LICENSE("Dual BSD/GPL"); From a6a1981656a8a802c3ead145a411bf615623870e Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 14 Dec 2018 16:57:39 +0800 Subject: [PATCH 0434/1995] ASoC: SOF: use spin_lock_irq to protect resource Ipc_lock is used to protect ipc message list shared by user contexts and a workqueue. So there is no need to save interrupt status with spin_lock_irqsave, just use spin_lock_irq. Signed-off-by: Rander Wang --- sound/soc/sof/ipc.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 0fdd72a801f73f..1dc4f9881efef8 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -197,14 +197,17 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, { struct snd_sof_dev *sdev = ipc->sdev; struct sof_ipc_cmd_hdr *hdr = (struct sof_ipc_cmd_hdr *)msg->msg_data; - unsigned long flags; int ret; /* wait for DSP IPC completion */ ret = wait_event_timeout(msg->waitq, msg->ipc_complete, msecs_to_jiffies(IPC_TIMEOUT_MS)); - spin_lock_irqsave(&sdev->ipc_lock, flags); + /* ipc_lock is used to protect ipc message list shared by user + * contexts and a workqueue. There is no need to save interrupt + * status with spin_lock_irqsave. + */ + spin_lock_irq(&sdev->ipc_lock); if (ret == 0) { dev_err(sdev->dev, "error: ipc timed out for 0x%x size 0x%x\n", @@ -227,7 +230,7 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, /* return message body to empty list */ list_move(&msg->list, &ipc->empty_list); - spin_unlock_irqrestore(&sdev->ipc_lock, flags); + spin_unlock_irq(&sdev->ipc_lock); snd_sof_dsp_cmd_done(sdev, SOF_IPC_DSP_REPLY); @@ -244,14 +247,13 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, { struct snd_sof_dev *sdev = ipc->sdev; struct snd_sof_ipc_msg *msg; - unsigned long flags; - spin_lock_irqsave(&sdev->ipc_lock, flags); + spin_lock_irq(&sdev->ipc_lock); /* get an empty message */ msg = msg_get_empty(ipc); if (!msg) { - spin_unlock_irqrestore(&sdev->ipc_lock, flags); + spin_unlock_irq(&sdev->ipc_lock); return -EBUSY; } @@ -271,7 +273,7 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, if (snd_sof_dsp_is_ready(sdev)) schedule_work(&ipc->tx_kwork); - spin_unlock_irqrestore(&sdev->ipc_lock, flags); + spin_unlock_irq(&sdev->ipc_lock); /* now wait for completion */ return tx_wait_done(ipc, msg, reply_data); @@ -285,9 +287,8 @@ static void ipc_tx_next_msg(struct work_struct *work) container_of(work, struct snd_sof_ipc, tx_kwork); struct snd_sof_dev *sdev = ipc->sdev; struct snd_sof_ipc_msg *msg; - unsigned long flags; - spin_lock_irqsave(&sdev->ipc_lock, flags); + spin_lock_irq(&sdev->ipc_lock); /* send message if HW read and message in TX list */ if (list_empty(&ipc->tx_list) || !snd_sof_dsp_is_ready(sdev)) @@ -300,7 +301,7 @@ static void ipc_tx_next_msg(struct work_struct *work) ipc_log_header(sdev->dev, "ipc tx", msg->header); out: - spin_unlock_irqrestore(&sdev->ipc_lock, flags); + spin_unlock_irq(&sdev->ipc_lock); } /* find original TX message from DSP reply */ @@ -335,10 +336,9 @@ void sof_ipc_drop_all(struct snd_sof_ipc *ipc) { struct snd_sof_dev *sdev = ipc->sdev; struct snd_sof_ipc_msg *msg, *tmp; - unsigned long flags; /* drop all TX and Rx messages before we stall + reset DSP */ - spin_lock_irqsave(&sdev->ipc_lock, flags); + spin_lock_irq(&sdev->ipc_lock); list_for_each_entry_safe(msg, tmp, &ipc->tx_list, list) { list_move(&msg->list, &ipc->empty_list); @@ -350,7 +350,7 @@ void sof_ipc_drop_all(struct snd_sof_ipc *ipc) dev_err(sdev->dev, "error: dropped reply %d\n", msg->header); } - spin_unlock_irqrestore(&sdev->ipc_lock, flags); + spin_unlock_irq(&sdev->ipc_lock); } EXPORT_SYMBOL(sof_ipc_drop_all); From 7f67e221f7adb257b2f790531df8968d73898fe7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Dec 2018 15:11:09 +0100 Subject: [PATCH 0435/1995] ALSA: hda/intel: Refactoring PM code Make unified suspend / resume helpers and call them from both the runtime- and the system-PM callbacks for simplifying code. There are slight changes of call orders, but there shouldn't be any functional difference after refactoring. Signed-off-by: Takashi Iwai (cherry picked from commit 3baffc4a84d759ba54c461e8e4583bd8890c749a) --- sound/pci/hda/hda_intel.c | 160 ++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 91 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 4b7666e0374cb2..6bf3067b246029 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -985,35 +985,82 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) mutex_unlock(&card_list_lock); return 0; } -#else -#define azx_add_card_list(chip) /* NOP */ -#define azx_del_card_list(chip) /* NOP */ -#endif /* CONFIG_PM */ -#ifdef CONFIG_PM_SLEEP /* * power management */ -static int azx_suspend(struct device *dev) +static bool azx_is_pm_ready(struct snd_card *card) { - struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; struct hda_intel *hda; - struct hdac_bus *bus; if (!card) - return 0; - + return false; chip = card->private_data; hda = container_of(chip, struct hda_intel, chip); if (chip->disabled || hda->init_failed || !chip->running) + return false; + return true; +} + +static void __azx_runtime_suspend(struct azx *chip) +{ + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + + azx_stop_chip(chip); + azx_enter_link_reset(chip); + azx_clear_irq_pending(chip); + if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && + hda->need_i915_power) + snd_hdac_display_power(azx_bus(chip), false); +} + +static void __azx_runtime_resume(struct azx *chip) +{ + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct hdac_bus *bus = azx_bus(chip); + struct hda_codec *codec; + int status; + + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { + snd_hdac_display_power(bus, true); + if (hda->need_i915_power) + snd_hdac_i915_set_bclk(bus); + } + + /* Read STATESTS before controller reset */ + status = azx_readw(chip, STATESTS); + + azx_init_pci(chip); + hda_intel_init_chip(chip, true); + + if (status) { + list_for_each_codec(codec, &chip->bus) + if (status & (1 << codec->addr)) + schedule_delayed_work(&codec->jackpoll_work, + codec->jackpoll_interval); + } + + /* power down again for link-controlled chips */ + if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && + !hda->need_i915_power) + snd_hdac_display_power(bus, false); +} + +#ifdef CONFIG_PM_SLEEP +static int azx_suspend(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip; + struct hdac_bus *bus; + + if (!azx_is_pm_ready(card)) return 0; + chip = card->private_data; bus = azx_bus(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - azx_clear_irq_pending(chip); - azx_stop_chip(chip); - azx_enter_link_reset(chip); + __azx_runtime_suspend(chip); if (bus->irq >= 0) { free_irq(bus->irq, chip); bus->irq = -1; @@ -1021,9 +1068,6 @@ static int azx_suspend(struct device *dev) if (chip->msi) pci_disable_msi(chip->pci); - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - && hda->need_i915_power) - snd_hdac_display_power(bus, false); trace_azx_suspend(chip); return 0; @@ -1031,41 +1075,19 @@ static int azx_suspend(struct device *dev) static int azx_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; - struct hda_intel *hda; - struct hdac_bus *bus; - if (!card) + if (!azx_is_pm_ready(card)) return 0; chip = card->private_data; - hda = container_of(chip, struct hda_intel, chip); - bus = azx_bus(chip); - if (chip->disabled || hda->init_failed || !chip->running) - return 0; - - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - snd_hdac_display_power(bus, true); - if (hda->need_i915_power) - snd_hdac_i915_set_bclk(bus); - } - if (chip->msi) - if (pci_enable_msi(pci) < 0) + if (pci_enable_msi(chip->pci) < 0) chip->msi = 0; if (azx_acquire_irq(chip, 1) < 0) return -EIO; - azx_init_pci(chip); - - hda_intel_init_chip(chip, true); - - /* power down again for link-controlled chips */ - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && - !hda->need_i915_power) - snd_hdac_display_power(bus, false); - + __azx_runtime_resume(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D0); trace_azx_resume(chip); @@ -1100,21 +1122,14 @@ static int azx_thaw_noirq(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -#ifdef CONFIG_PM static int azx_runtime_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; - struct hda_intel *hda; - if (!card) + if (!azx_is_pm_ready(card)) return 0; - chip = card->private_data; - hda = container_of(chip, struct hda_intel, chip); - if (chip->disabled || hda->init_failed) - return 0; - if (!azx_has_pm_runtime(chip)) return 0; @@ -1122,13 +1137,7 @@ static int azx_runtime_suspend(struct device *dev) azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) | STATESTS_INT_MASK); - azx_stop_chip(chip); - azx_enter_link_reset(chip); - azx_clear_irq_pending(chip); - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - && hda->need_i915_power) - snd_hdac_display_power(azx_bus(chip), false); - + __azx_runtime_suspend(chip); trace_azx_runtime_suspend(chip); return 0; } @@ -1137,51 +1146,18 @@ static int azx_runtime_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; - struct hda_intel *hda; - struct hdac_bus *bus; - struct hda_codec *codec; - int status; - if (!card) + if (!azx_is_pm_ready(card)) return 0; - chip = card->private_data; - hda = container_of(chip, struct hda_intel, chip); - bus = azx_bus(chip); - if (chip->disabled || hda->init_failed) - return 0; - if (!azx_has_pm_runtime(chip)) return 0; - - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - snd_hdac_display_power(bus, true); - if (hda->need_i915_power) - snd_hdac_i915_set_bclk(bus); - } - - /* Read STATESTS before controller reset */ - status = azx_readw(chip, STATESTS); - - azx_init_pci(chip); - hda_intel_init_chip(chip, true); - - if (status) { - list_for_each_codec(codec, &chip->bus) - if (status & (1 << codec->addr)) - schedule_delayed_work(&codec->jackpoll_work, - codec->jackpoll_interval); - } + __azx_runtime_resume(chip); /* disable controller Wake Up event*/ azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & ~STATESTS_INT_MASK); - /* power down again for link-controlled chips */ - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && - !hda->need_i915_power) - snd_hdac_display_power(bus, false); - trace_azx_runtime_resume(chip); return 0; } @@ -1222,6 +1198,8 @@ static const struct dev_pm_ops azx_pm = { #define AZX_PM_OPS &azx_pm #else +#define azx_add_card_list(chip) /* NOP */ +#define azx_del_card_list(chip) /* NOP */ #define AZX_PM_OPS NULL #endif /* CONFIG_PM */ From 43243e59678049b8b4ad9d2c567142e6115c908f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 8 Dec 2018 17:31:49 +0100 Subject: [PATCH 0436/1995] ALSA: hda: Refactor display power management The current HD-audio code manages the DRM audio power via too complex redirections, and this seems even still unbalanced in a corner case as Intel DRM CI has been intermittently reporting. This patch is a big surgery for addressing the complexity and the possible unbalance. Basically the patch changes the display PM in the following ways: - Both HD-audio controller and codec drivers call a single helper, snd_hdac_display_power(). (Formerly, the display power control from a codec was done indirectly via link_power bus ops.) - snd_hdac_display_power() receives the codec address index. For turning on/off from the controller, pass HDA_CODEC_IDX_CONTROLLER. - snd_hdac_display_power() doesn't manage refcounts any longer, but keeps the power status in bitmap. If any of controller or codecs is turned on, the function updates the DRM power state via get_power() or put_power(). Also this refactor allows us more cleanup: - The link_power bus ops is dropped, so there is no longer indirect management, as mentioned in the above. - hdac_device link_power_control flag is moved to hda_codec display_power_control flag, as it's only for HDA legacy. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106525 Signed-off-by: Takashi Iwai (cherry picked from commit 029d92c289bdad08ed08e61bf31b17cdc9ee61cf) --- include/sound/hda_codec.h | 1 + include/sound/hda_component.h | 10 ++++++++-- include/sound/hdaudio.h | 7 ++----- sound/hda/hdac_component.c | 35 +++++++++++++++++++++------------- sound/hda/hdac_device.c | 17 ----------------- sound/pci/hda/hda_codec.c | 16 ++++++++++++---- sound/pci/hda/hda_controller.c | 11 ----------- sound/pci/hda/hda_intel.c | 22 ++++++++------------- sound/pci/hda/patch_hdmi.c | 4 ++-- sound/soc/codecs/hdac_hdmi.c | 7 +++---- sound/soc/intel/skylake/skl.c | 10 +++++----- 11 files changed, 63 insertions(+), 77 deletions(-) diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index 0d98bb9068b178..7fa48b10093618 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -236,6 +236,7 @@ struct hda_codec { /* misc flags */ unsigned int in_freeing:1; /* being released */ unsigned int registered:1; /* codec was registered */ + unsigned int display_power_control:1; /* needs display power */ unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each * status change * (e.g. Realtek codecs) diff --git a/include/sound/hda_component.h b/include/sound/hda_component.h index 78626cde70811a..767c8d8a0230ba 100644 --- a/include/sound/hda_component.h +++ b/include/sound/hda_component.h @@ -5,10 +5,15 @@ #define __SOUND_HDA_COMPONENT_H #include +#include + +/* virtual idx for controller */ +#define HDA_CODEC_IDX_CONTROLLER HDA_MAX_CODECS #ifdef CONFIG_SND_HDA_COMPONENT int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable); -int snd_hdac_display_power(struct hdac_bus *bus, bool enable); +int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, + bool enable); int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int dev_id, int rate); int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id, @@ -25,7 +30,8 @@ static inline int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) { return 0; } -static inline int snd_hdac_display_power(struct hdac_bus *bus, bool enable) +static inline int snd_hdac_display_power(struct hdac_bus *bus, + unsigned int idx, bool enable) { return 0; } diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 2ee9eccf8d5405..f9b2b6330d27a1 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -79,7 +79,6 @@ struct hdac_device { /* misc flags */ atomic_t in_pm; /* suspend/resume being performed */ - bool link_power_control:1; /* sysfs */ struct hdac_widget_tree *widgets; @@ -237,8 +236,6 @@ struct hdac_bus_ops { /* get a response from the last command */ int (*get_response)(struct hdac_bus *bus, unsigned int addr, unsigned int *res); - /* control the link power */ - int (*link_power)(struct hdac_bus *bus, bool enable); }; /* @@ -363,7 +360,8 @@ struct hdac_bus { /* DRM component interface */ struct drm_audio_component *audio_component; - int drm_power_refcount; + long display_power_status; + bool display_power_active; /* parameters required for enhanced capabilities */ int num_streams; @@ -405,7 +403,6 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val); int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr, unsigned int *res); int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus); -int snd_hdac_link_power(struct hdac_device *codec, bool enable); bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset); void snd_hdac_bus_stop_chip(struct hdac_bus *bus); diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c index 6e46a9c73aed46..dd766414436be3 100644 --- a/sound/hda/hdac_component.c +++ b/sound/hda/hdac_component.c @@ -54,38 +54,45 @@ EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup); /** * snd_hdac_display_power - Power up / down the power refcount * @bus: HDA core bus + * @idx: HDA codec address, pass HDA_CODEC_IDX_CONTROLLER for controller * @enable: power up or down * - * This function is supposed to be used only by a HD-audio controller - * driver that needs the interaction with graphics driver. + * This function is used by either HD-audio controller or codec driver that + * needs the interaction with graphics driver. * - * This function manages a refcount and calls the get_power() and + * This function updates the power status, and calls the get_power() and * put_power() ops accordingly, toggling the codec wakeup, too. * * Returns zero for success or a negative error code. */ -int snd_hdac_display_power(struct hdac_bus *bus, bool enable) +int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) { struct drm_audio_component *acomp = bus->audio_component; - if (!acomp || !acomp->ops) - return -ENODEV; - dev_dbg(bus->dev, "display power %s\n", enable ? "enable" : "disable"); + if (enable) + set_bit(idx, &bus->display_power_status); + else + clear_bit(idx, &bus->display_power_status); - if (enable) { - if (!bus->drm_power_refcount++) { + if (!acomp || !acomp->ops) + return 0; + + if (bus->display_power_status) { + if (!bus->display_power_active) { if (acomp->ops->get_power) acomp->ops->get_power(acomp->dev); snd_hdac_set_codec_wakeup(bus, true); snd_hdac_set_codec_wakeup(bus, false); + bus->display_power_active = true; } } else { - WARN_ON(!bus->drm_power_refcount); - if (!--bus->drm_power_refcount) + if (bus->display_power_active) { if (acomp->ops->put_power) acomp->ops->put_power(acomp->dev); + bus->display_power_active = false; + } } return 0; @@ -321,10 +328,12 @@ int snd_hdac_acomp_exit(struct hdac_bus *bus) if (!acomp) return 0; - WARN_ON(bus->drm_power_refcount); - if (bus->drm_power_refcount > 0 && acomp->ops) + if (WARN_ON(bus->display_power_active) && acomp->ops) acomp->ops->put_power(acomp->dev); + bus->display_power_active = false; + bus->display_power_status = 0; + component_master_del(dev, &hdac_component_master_ops); bus->audio_component = NULL; diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index dbf02a3a8d2f28..95b073ee4b32bb 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -622,23 +622,6 @@ int snd_hdac_power_down_pm(struct hdac_device *codec) EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm); #endif -/** - * snd_hdac_link_power - Enable/disable the link power for a codec - * @codec: the codec object - * @bool: enable or disable the link power - */ -int snd_hdac_link_power(struct hdac_device *codec, bool enable) -{ - if (!codec->link_power_control) - return 0; - - if (codec->bus->ops->link_power) - return codec->bus->ops->link_power(codec->bus, enable); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_hdac_link_power); - /* codec vendor labels */ struct hda_vendor_id { unsigned int id; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0957813939e5cf..9f8d59e7e89f46 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -36,6 +36,7 @@ #include "hda_beep.h" #include "hda_jack.h" #include +#include #define codec_in_pm(codec) snd_hdac_is_in_pm(&codec->core) #define hda_codec_is_power_on(codec) snd_hdac_is_power_on(&codec->core) @@ -799,6 +800,13 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec) static unsigned int hda_set_power_state(struct hda_codec *codec, unsigned int power_state); +/* enable/disable display power per codec */ +static void codec_display_power(struct hda_codec *codec, bool enable) +{ + if (codec->display_power_control) + snd_hdac_display_power(&codec->bus->core, codec->addr, enable); +} + /* also called from hda_bind.c */ void snd_hda_codec_register(struct hda_codec *codec) { @@ -806,7 +814,7 @@ void snd_hda_codec_register(struct hda_codec *codec) return; if (device_is_registered(hda_codec_dev(codec))) { snd_hda_register_beep_device(codec); - snd_hdac_link_power(&codec->core, true); + codec_display_power(codec, true); pm_runtime_enable(hda_codec_dev(codec)); /* it was powered up in snd_hda_codec_new(), now all done */ snd_hda_power_down(codec); @@ -834,7 +842,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device) codec->in_freeing = 1; snd_hdac_device_unregister(&codec->core); - snd_hdac_link_power(&codec->core, false); + codec_display_power(codec, false); put_device(hda_codec_dev(codec)); return 0; } @@ -2926,7 +2934,7 @@ static int hda_codec_runtime_suspend(struct device *dev) (codec_has_clkstop(codec) && codec_has_epss(codec) && (state & AC_PWRST_CLK_STOP_OK))) snd_hdac_codec_link_down(&codec->core); - snd_hdac_link_power(&codec->core, false); + codec_display_power(codec, false); return 0; } @@ -2934,7 +2942,7 @@ static int hda_codec_runtime_resume(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); - snd_hdac_link_power(&codec->core, true); + codec_display_power(codec, true); snd_hdac_codec_link_up(&codec->core); hda_call_codec_resume(codec); pm_runtime_mark_last_busy(dev); diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index a12e594d4e3b3a..358e3a70c5d3f8 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -986,20 +986,9 @@ static int azx_get_response(struct hdac_bus *bus, unsigned int addr, return azx_rirb_get_response(bus, addr, res); } -static int azx_link_power(struct hdac_bus *bus, bool enable) -{ - struct azx *chip = bus_to_azx(bus); - - if (chip->ops->link_power) - return chip->ops->link_power(chip, enable); - else - return -EINVAL; -} - static const struct hdac_bus_ops bus_core_ops = { .command = azx_send_cmd, .get_response = azx_get_response, - .link_power = azx_link_power, }; #ifdef CONFIG_SND_HDA_DSP_LOADER diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 6bf3067b246029..3d00e7463a7121 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -722,13 +722,8 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) return 0; } -/* Enable/disable i915 display power for the link */ -static int azx_intel_link_power(struct azx *chip, bool enable) -{ - struct hdac_bus *bus = azx_bus(chip); - - return snd_hdac_display_power(bus, enable); -} +#define display_power(chip, enable) \ + snd_hdac_display_power(azx_bus(chip), HDA_CODEC_IDX_CONTROLLER, enable) /* * Check whether the current DMA position is acceptable for updating @@ -1012,7 +1007,7 @@ static void __azx_runtime_suspend(struct azx *chip) azx_clear_irq_pending(chip); if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && hda->need_i915_power) - snd_hdac_display_power(azx_bus(chip), false); + display_power(chip, false); } static void __azx_runtime_resume(struct azx *chip) @@ -1023,7 +1018,7 @@ static void __azx_runtime_resume(struct azx *chip) int status; if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - snd_hdac_display_power(bus, true); + display_power(chip, true); if (hda->need_i915_power) snd_hdac_i915_set_bclk(bus); } @@ -1044,7 +1039,7 @@ static void __azx_runtime_resume(struct azx *chip) /* power down again for link-controlled chips */ if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && !hda->need_i915_power) - snd_hdac_display_power(bus, false); + display_power(chip, false); } #ifdef CONFIG_PM_SLEEP @@ -1410,7 +1405,7 @@ static int azx_free(struct azx *chip) if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { if (hda->need_i915_power) - snd_hdac_display_power(bus, false); + display_power(chip, false); } if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT) snd_hdac_i915_exit(bus); @@ -2138,7 +2133,6 @@ static const struct hda_controller_ops pci_hda_ops = { .substream_free_pages = substream_free_pages, .pcm_mmap_prepare = pcm_mmap_prepare, .position_check = azx_position_check, - .link_power = azx_intel_link_power, }; static int azx_probe(struct pci_dev *pci, @@ -2315,7 +2309,7 @@ static int azx_probe_continue(struct azx *chip) if (CONTROLLER_IN_GPU(pci)) hda->need_i915_power = 1; - err = snd_hdac_display_power(bus, true); + err = display_power(chip, true); if (err < 0) { dev_err(chip->card->dev, "Cannot turn on display power on i915\n"); @@ -2371,7 +2365,7 @@ static int azx_probe_continue(struct azx *chip) out_free: if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && !hda->need_i915_power) - snd_hdac_display_power(bus, false); + display_power(chip, false); i915_power_fail: if (err < 0) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 67099cbb6be2f2..30fe4dbdb0ae9b 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2620,7 +2620,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid) * can cover the codec power request, and so need not set this flag. */ if (!is_haswell(codec) && !is_broadwell(codec)) - codec->core.link_power_control = 1; + codec->display_power_control = 1; codec->patch_ops.set_power_state = haswell_set_power_state; codec->depop_delay = 0; @@ -2656,7 +2656,7 @@ static int patch_i915_byt_hdmi(struct hda_codec *codec) /* For Valleyview/Cherryview, only the display codec is in the display * power well and can use link_power ops to request/release the power. */ - codec->core.link_power_control = 1; + codec->display_power_control = 1; codec->depop_delay = 0; codec->auto_runtime_pm = 1; diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index db709eeb019c78..6ef0cdc0ed7dd9 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2074,14 +2074,13 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) * Turned off in the runtime_suspend during the first explicit * pm_runtime_suspend call. */ - ret = snd_hdac_display_power(hdev->bus, true); + ret = snd_hdac_display_power(hdev->bus, hdev->addr, true); if (ret < 0) { dev_err(&hdev->dev, "Cannot turn on display power on i915 err: %d\n", ret); return ret; } - ret = hdac_hdmi_parse_and_map_nid(hdev, &hdmi_dais, &num_dais); if (ret < 0) { dev_err(&hdev->dev, @@ -2239,7 +2238,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) snd_hdac_ext_bus_link_put(bus, hlink); - err = snd_hdac_display_power(bus, false); + err = snd_hdac_display_power(bus, hdev->addr, false); if (err < 0) dev_err(dev, "Cannot turn off display power on i915\n"); @@ -2267,7 +2266,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev) snd_hdac_ext_bus_link_get(bus, hlink); - err = snd_hdac_display_power(bus, true); + err = snd_hdac_display_power(bus, hdev->addr, true); if (err < 0) { dev_err(dev, "Cannot turn on display power on i915\n"); return err; diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 3f0ac13129829e..f8fc7019006373 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -334,7 +334,7 @@ static int skl_suspend(struct device *dev) } if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, false); + ret = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); if (ret < 0) dev_err(bus->dev, "Cannot turn OFF display power on i915\n"); @@ -353,7 +353,7 @@ static int skl_resume(struct device *dev) /* Turned OFF in HDMI codec driver after codec reconfiguration */ if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, true); + ret = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); if (ret < 0) { dev_err(bus->dev, "Cannot turn on display power on i915\n"); @@ -786,7 +786,7 @@ static int skl_i915_init(struct hdac_bus *bus) if (err < 0) return err; - err = snd_hdac_display_power(bus, true); + err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); if (err < 0) dev_err(bus->dev, "Cannot turn on display power on i915\n"); @@ -841,7 +841,7 @@ static void skl_probe_work(struct work_struct *work) snd_hdac_ext_bus_link_put(bus, hlink); if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - err = snd_hdac_display_power(bus, false); + err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); if (err < 0) { dev_err(bus->dev, "Cannot turn off display power on i915\n"); skl_machine_device_unregister(skl); @@ -858,7 +858,7 @@ static void skl_probe_work(struct work_struct *work) out_err: if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - err = snd_hdac_display_power(bus, false); + err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); } /* From 67f294892ee2d96c1fd0e46c4bad2f01e3b2252d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 09:57:37 +0100 Subject: [PATCH 0437/1995] ALSA: hda/intel: Drop superfluous AZX_DCAPS_I915_POWERWELL checks snd_hdac_display_power() can be called even for a HDA controller without DRM binding. The same is true for other helpers, snd_hdac_i915_set_bclk() and snd_hdac_set_codec_wakeup(). So all superfluous AZX_DCAPS_I915_POWERWELL checks in hda_intel.c can be dropped, and the definition of AZX_DCAPS_I915_POWERWELL itself can be removed as well. This simplifies the code a lot. Signed-off-by: Takashi Iwai (cherry picked from commit e454ff8e89b6db0a2054260d48635fbc781e94ce) --- sound/pci/hda/hda_controller.h | 6 +-- sound/pci/hda/hda_intel.c | 73 +++++++++++++--------------------- 2 files changed, 28 insertions(+), 51 deletions(-) diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 55760e5231e62b..f099f8452dcfca 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -50,11 +50,7 @@ /* 24 unused */ #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ -#ifdef CONFIG_SND_HDA_I915 -#define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ -#else -#define AZX_DCAPS_I915_POWERWELL 0 /* NOP */ -#endif +/* 27 unused */ #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ #define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */ #define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3d00e7463a7121..f465b97486f837 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -310,31 +310,28 @@ enum { #define AZX_DCAPS_INTEL_HASWELL \ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\ AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL | AZX_DCAPS_SNOOP_TYPE(SCH)) + AZX_DCAPS_SNOOP_TYPE(SCH)) /* Broadwell HDMI can't use position buffer reliably, force to use LPIB */ #define AZX_DCAPS_INTEL_BROADWELL \ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_POSFIX_LPIB |\ AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL | AZX_DCAPS_SNOOP_TYPE(SCH)) + AZX_DCAPS_SNOOP_TYPE(SCH)) #define AZX_DCAPS_INTEL_BAYTRAIL \ - (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL) + (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT) #define AZX_DCAPS_INTEL_BRASWELL \ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ - AZX_DCAPS_I915_COMPONENT | AZX_DCAPS_I915_POWERWELL) + AZX_DCAPS_I915_COMPONENT) #define AZX_DCAPS_INTEL_SKYLAKE \ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ - AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL) + AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT) #define AZX_DCAPS_INTEL_BROXTON \ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ - AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL) + AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT) /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ @@ -646,8 +643,7 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) struct pci_dev *pci = chip->pci; u32 val; - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - snd_hdac_set_codec_wakeup(bus, true); + snd_hdac_set_codec_wakeup(bus, true); if (chip->driver_type == AZX_DRIVER_SKL) { pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val); val = val & ~INTEL_HDA_CGCTL_MISCBDCGE; @@ -659,8 +655,8 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) val = val | INTEL_HDA_CGCTL_MISCBDCGE; pci_write_config_dword(pci, INTEL_HDA_CGCTL, val); } - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - snd_hdac_set_codec_wakeup(bus, false); + + snd_hdac_set_codec_wakeup(bus, false); /* reduce dma latency to avoid noise */ if (IS_BXT(pci)) @@ -1000,14 +996,10 @@ static bool azx_is_pm_ready(struct snd_card *card) static void __azx_runtime_suspend(struct azx *chip) { - struct hda_intel *hda = container_of(chip, struct hda_intel, chip); - azx_stop_chip(chip); azx_enter_link_reset(chip); azx_clear_irq_pending(chip); - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && - hda->need_i915_power) - display_power(chip, false); + display_power(chip, false); } static void __azx_runtime_resume(struct azx *chip) @@ -1017,11 +1009,9 @@ static void __azx_runtime_resume(struct azx *chip) struct hda_codec *codec; int status; - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - display_power(chip, true); - if (hda->need_i915_power) - snd_hdac_i915_set_bclk(bus); - } + display_power(chip, true); + if (hda->need_i915_power) + snd_hdac_i915_set_bclk(bus); /* Read STATESTS before controller reset */ status = azx_readw(chip, STATESTS); @@ -1037,8 +1027,7 @@ static void __azx_runtime_resume(struct azx *chip) } /* power down again for link-controlled chips */ - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && - !hda->need_i915_power) + if (!hda->need_i915_power) display_power(chip, false); } @@ -1402,11 +1391,8 @@ static int azx_free(struct azx *chip) #ifdef CONFIG_SND_HDA_PATCH_LOADER release_firmware(chip->fw); #endif + display_power(chip, false); - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - if (hda->need_i915_power) - display_power(chip, false); - } if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT) snd_hdac_i915_exit(bus); kfree(hda); @@ -1957,8 +1943,7 @@ static int azx_first_init(struct azx *chip) /* initialize chip */ azx_init_pci(chip); - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - snd_hdac_i915_set_bclk(bus); + snd_hdac_i915_set_bclk(bus); hda_intel_init_chip(chip, (probe_only[dev] & 2) == 0); @@ -2293,10 +2278,13 @@ static int azx_probe_continue(struct azx *chip) goto out_free; } else { /* don't bother any longer */ - chip->driver_caps &= - ~(AZX_DCAPS_I915_COMPONENT | AZX_DCAPS_I915_POWERWELL); + chip->driver_caps &= ~AZX_DCAPS_I915_COMPONENT; } } + + /* HSW/BDW controllers need this power */ + if (CONTROLLER_IN_GPU(pci)) + hda->need_i915_power = 1; } /* Request display power well for the HDA controller or codec. For @@ -2304,17 +2292,11 @@ static int azx_probe_continue(struct azx *chip) * this power. For other platforms, like Baytrail/Braswell, only the * display codec needs the power and it can be released after probe. */ - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - /* HSW/BDW controllers need this power */ - if (CONTROLLER_IN_GPU(pci)) - hda->need_i915_power = 1; - - err = display_power(chip, true); - if (err < 0) { - dev_err(chip->card->dev, - "Cannot turn on display power on i915\n"); - goto i915_power_fail; - } + err = display_power(chip, true); + if (err < 0) { + dev_err(chip->card->dev, + "Cannot turn on display power on i915\n"); + goto i915_power_fail; } err = azx_first_init(chip); @@ -2363,8 +2345,7 @@ static int azx_probe_continue(struct azx *chip) pm_runtime_put_autosuspend(&pci->dev); out_free: - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - && !hda->need_i915_power) + if (!hda->need_i915_power) display_power(chip, false); i915_power_fail: From 036db3dc831af1bd5721faa64e55c4c6e863f503 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 09:59:03 +0100 Subject: [PATCH 0438/1995] ALSA: hda/intel: Properly free the display power at error path When an error occurs in azx_probe_continue(), we should release the display power. However, the current code ignores it and releases the display power only for HSW/BDW cases. Fix it. Signed-off-by: Takashi Iwai (cherry picked from commit 457f3c86d3358beb0ae19774fef8a9035dedd88f) --- sound/pci/hda/hda_intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f465b97486f837..cc4ae289bcdfbc 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2345,7 +2345,7 @@ static int azx_probe_continue(struct azx *chip) pm_runtime_put_autosuspend(&pci->dev); out_free: - if (!hda->need_i915_power) + if (err < 0 || !hda->need_i915_power) display_power(chip, false); i915_power_fail: From 952e181405004485e3285114e9b796a961759ae0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 10:04:25 +0100 Subject: [PATCH 0439/1995] ALSA: hda: Make snd_hdac_display_power() void function After the recent refactoring, snd_hdac_display_power() doesn't return any error, hence it can be defined to return void. This makes many error checks redundant and allows us to reduce them gracefully. Signed-off-by: Takashi Iwai (cherry picked from commit 4f799e734094f09feaae89ee75982fac84742c56) --- include/sound/hda_component.h | 9 ++++---- sound/hda/hdac_component.c | 8 ++----- sound/pci/hda/hda_intel.c | 9 +------- sound/soc/codecs/hdac_hdmi.c | 23 +++++--------------- sound/soc/intel/skylake/skl.c | 40 ++++++++++------------------------- 5 files changed, 23 insertions(+), 66 deletions(-) diff --git a/include/sound/hda_component.h b/include/sound/hda_component.h index 767c8d8a0230ba..2ec31b35895045 100644 --- a/include/sound/hda_component.h +++ b/include/sound/hda_component.h @@ -12,8 +12,8 @@ #ifdef CONFIG_SND_HDA_COMPONENT int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable); -int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, - bool enable); +void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, + bool enable); int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int dev_id, int rate); int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id, @@ -30,10 +30,9 @@ static inline int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) { return 0; } -static inline int snd_hdac_display_power(struct hdac_bus *bus, - unsigned int idx, bool enable) +static inline void snd_hdac_display_power(struct hdac_bus *bus, + unsigned int idx, bool enable) { - return 0; } static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int dev_id, int rate) diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c index dd766414436be3..a6d37b9d6413f5 100644 --- a/sound/hda/hdac_component.c +++ b/sound/hda/hdac_component.c @@ -62,10 +62,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup); * * This function updates the power status, and calls the get_power() and * put_power() ops accordingly, toggling the codec wakeup, too. - * - * Returns zero for success or a negative error code. */ -int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) +void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) { struct drm_audio_component *acomp = bus->audio_component; @@ -77,7 +75,7 @@ int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) clear_bit(idx, &bus->display_power_status); if (!acomp || !acomp->ops) - return 0; + return; if (bus->display_power_status) { if (!bus->display_power_active) { @@ -94,8 +92,6 @@ int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) bus->display_power_active = false; } } - - return 0; } EXPORT_SYMBOL_GPL(snd_hdac_display_power); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cc4ae289bcdfbc..d0feeaa7bee4dc 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2292,12 +2292,7 @@ static int azx_probe_continue(struct azx *chip) * this power. For other platforms, like Baytrail/Braswell, only the * display codec needs the power and it can be released after probe. */ - err = display_power(chip, true); - if (err < 0) { - dev_err(chip->card->dev, - "Cannot turn on display power on i915\n"); - goto i915_power_fail; - } + display_power(chip, true); err = azx_first_init(chip); if (err < 0) @@ -2347,8 +2342,6 @@ static int azx_probe_continue(struct azx *chip) out_free: if (err < 0 || !hda->need_i915_power) display_power(chip, false); - -i915_power_fail: if (err < 0) hda->init_failed = 1; complete_all(&hda->probe_wait); diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 6ef0cdc0ed7dd9..3fc1b312fc4391 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2074,13 +2074,8 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) * Turned off in the runtime_suspend during the first explicit * pm_runtime_suspend call. */ - ret = snd_hdac_display_power(hdev->bus, hdev->addr, true); - if (ret < 0) { - dev_err(&hdev->dev, - "Cannot turn on display power on i915 err: %d\n", - ret); - return ret; - } + snd_hdac_display_power(hdev->bus, hdev->addr, true); + ret = hdac_hdmi_parse_and_map_nid(hdev, &hdmi_dais, &num_dais); if (ret < 0) { dev_err(&hdev->dev, @@ -2212,7 +2207,6 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) struct hdac_device *hdev = dev_to_hdac_dev(dev); struct hdac_bus *bus = hdev->bus; struct hdac_ext_link *hlink = NULL; - int err; dev_dbg(dev, "Enter: %s\n", __func__); @@ -2238,11 +2232,9 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) snd_hdac_ext_bus_link_put(bus, hlink); - err = snd_hdac_display_power(bus, hdev->addr, false); - if (err < 0) - dev_err(dev, "Cannot turn off display power on i915\n"); + snd_hdac_display_power(bus, hdev->addr, false); - return err; + return 0; } static int hdac_hdmi_runtime_resume(struct device *dev) @@ -2250,7 +2242,6 @@ static int hdac_hdmi_runtime_resume(struct device *dev) struct hdac_device *hdev = dev_to_hdac_dev(dev); struct hdac_bus *bus = hdev->bus; struct hdac_ext_link *hlink = NULL; - int err; dev_dbg(dev, "Enter: %s\n", __func__); @@ -2266,11 +2257,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev) snd_hdac_ext_bus_link_get(bus, hlink); - err = snd_hdac_display_power(bus, hdev->addr, true); - if (err < 0) { - dev_err(dev, "Cannot turn on display power on i915\n"); - return err; - } + snd_hdac_display_power(bus, hdev->addr, true); hdac_hdmi_skl_enable_all_pins(hdev); hdac_hdmi_skl_enable_dp12(hdev); diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index f8fc7019006373..780daace11cdd6 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -311,7 +311,7 @@ static int skl_suspend(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct hdac_bus *bus = pci_get_drvdata(pci); struct skl *skl = bus_to_skl(bus); - int ret = 0; + int ret; /* * Do not suspend if streams which are marked ignore suspend are @@ -333,14 +333,10 @@ static int skl_suspend(struct device *dev) skl->skl_sst->fw_loaded = false; } - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - if (ret < 0) - dev_err(bus->dev, - "Cannot turn OFF display power on i915\n"); - } + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - return ret; + return 0; } static int skl_resume(struct device *dev) @@ -352,14 +348,8 @@ static int skl_resume(struct device *dev) int ret; /* Turned OFF in HDMI codec driver after codec reconfiguration */ - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - if (ret < 0) { - dev_err(bus->dev, - "Cannot turn on display power on i915\n"); - return ret; - } - } + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); /* * resume only when we are not in suspend active, otherwise need to @@ -786,11 +776,9 @@ static int skl_i915_init(struct hdac_bus *bus) if (err < 0) return err; - err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - if (err < 0) - dev_err(bus->dev, "Cannot turn on display power on i915\n"); + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - return err; + return 0; } static void skl_probe_work(struct work_struct *work) @@ -840,14 +828,8 @@ static void skl_probe_work(struct work_struct *work) list_for_each_entry(hlink, &bus->hlink_list, list) snd_hdac_ext_bus_link_put(bus, hlink); - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - if (err < 0) { - dev_err(bus->dev, "Cannot turn off display power on i915\n"); - skl_machine_device_unregister(skl); - return; - } - } + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); /* configure PM */ pm_runtime_put_noidle(bus->dev); @@ -858,7 +840,7 @@ static void skl_probe_work(struct work_struct *work) out_err: if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); } /* From 725f52c419e11e718bca59f29321936775660a47 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 10:06:59 +0100 Subject: [PATCH 0440/1995] ASoC: hdac_hdmi: Add missing display power-off at driver removal The display power is in unbalance at removing the driver since it misses the snd_hdac_display_power(OFF) call. Acked-by: Mark Brown Signed-off-by: Takashi Iwai (cherry picked from commit 77a49672aae384125942ce621365b11d42cefa32) --- sound/soc/codecs/hdac_hdmi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 3fc1b312fc4391..3ab2949c1dfa45 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2102,6 +2102,8 @@ static int hdac_hdmi_dev_remove(struct hdac_device *hdev) struct hdac_hdmi_port *port, *port_next; int i; + snd_hdac_display_power(hdev->bus, hdev->addr, false); + list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { pcm->cvt = NULL; if (list_empty(&pcm->port_list)) From dbaebae30b15e3c6099e617e1a9e9f6244722852 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 10:10:19 +0100 Subject: [PATCH 0441/1995] ALSA: hda/hdmi: Always set display_power_control for Intel HSW+ codecs We've excluded the display_power_control flag for Intel HSW and BDW codecs as the HD-audio controllers of the corresponding platforms take care of the display power as well. But the recent refactoring separates the controller and the codec power accounting, so it's fine to call the display PM even for HSW/BDW codecs. This is less confusing since we can avoid this well-hidden condition. Signed-off-by: Takashi Iwai (cherry picked from commit 46594d3345f0432ddc83b9f3c1b04492fdfafd07) --- sound/pci/hda/patch_hdmi.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 30fe4dbdb0ae9b..15290e4706e001 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2616,11 +2616,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid) intel_haswell_enable_all_pins(codec, true); intel_haswell_fixup_enable_dp12(codec); - /* For Haswell/Broadwell, the controller is also in the power well and - * can cover the codec power request, and so need not set this flag. - */ - if (!is_haswell(codec) && !is_broadwell(codec)) - codec->display_power_control = 1; + codec->display_power_control = 1; codec->patch_ops.set_power_state = haswell_set_power_state; codec->depop_delay = 0; From 5feeef554782d91774f2d8d8582f4a2730c8d3c1 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Sun, 16 Dec 2018 22:56:40 +0800 Subject: [PATCH 0442/1995] ASoC: SOF: intel: update the using of snd_hdac_display_power() The prototype of snd_hdac_display_power() has changed. pass HDA_CODEC_IDX_CONTROLLER since i915 is controller. Signed-off-by: Bard liao --- sound/soc/sof/intel/hda-codec.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 3cb5dc05e64a43..a8e360a9631ecd 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -123,28 +123,22 @@ EXPORT_SYMBOL(hda_codec_probe_bus); int hda_codec_i915_get(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); - int ret; dev_dbg(bus->dev, "Turning i915 HDAC power on\n"); - ret = snd_hdac_display_power(bus, true); - if (ret < 0) - dev_err(bus->dev, "error: i915 HDAC power on failed %d\n", ret); + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - return ret; + return 0; } EXPORT_SYMBOL(hda_codec_i915_get); int hda_codec_i915_put(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); - int ret; dev_dbg(bus->dev, "Turning i915 HDAC power off\n"); - ret = snd_hdac_display_power(bus, false); - if (ret < 0) - dev_err(bus->dev, "error: i915 HDAC power off failed %d\n", ret); + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - return ret; + return 0; } EXPORT_SYMBOL(hda_codec_i915_put); From a991c2dccd14fb8d654a6b8d622187e4c7544542 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Mon, 17 Dec 2018 02:00:21 +0800 Subject: [PATCH 0443/1995] ASoC: SOF: intel: Make hda_codec_i915_get()/put() void function snd_hdac_display_power() is already a void function therefore we don't need to return any value from hda_codec_i915_get() nor hda_codec_i915_put(). Signed-off-by: Bard liao --- sound/soc/sof/intel/hda-codec.c | 18 +++++------------- sound/soc/sof/intel/hda-dsp.c | 15 ++------------- sound/soc/sof/intel/hda.c | 9 ++------- sound/soc/sof/intel/hda.h | 8 ++++---- 4 files changed, 13 insertions(+), 37 deletions(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index a8e360a9631ecd..a633575647d9e7 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -120,25 +120,21 @@ EXPORT_SYMBOL(hda_codec_probe_bus); #if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) -int hda_codec_i915_get(struct snd_sof_dev *sdev) +void hda_codec_i915_get(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); dev_dbg(bus->dev, "Turning i915 HDAC power on\n"); snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - - return 0; } EXPORT_SYMBOL(hda_codec_i915_get); -int hda_codec_i915_put(struct snd_sof_dev *sdev) +void hda_codec_i915_put(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); dev_dbg(bus->dev, "Turning i915 HDAC power off\n"); snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - - return 0; } EXPORT_SYMBOL(hda_codec_i915_put); @@ -152,9 +148,9 @@ int hda_codec_i915_init(struct snd_sof_dev *sdev) if (ret < 0) return ret; - ret = hda_codec_i915_get(sdev); + hda_codec_i915_get(sdev); - return ret; + return 0; } EXPORT_SYMBOL(hda_codec_i915_init); @@ -163,11 +159,7 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev) struct hdac_bus *bus = sof_to_bus(sdev); int ret; - /* - * we don't need to decrease the refcount with - * hda_codec_i915_put() on exit since the device cannot be - * active - */ + hda_codec_i915_put(sdev); ret = snd_hdac_i915_exit(bus); diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 1471aa3834811d..6b67246a8b37f1 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -359,15 +359,8 @@ static int hda_resume(struct snd_sof_dev *sdev) int hda_dsp_resume(struct snd_sof_dev *sdev) { - struct hdac_bus *bus = sof_to_bus(sdev); - int ret; - /* turn display power on */ - ret = hda_codec_i915_get(sdev); - if (ret < 0) { - dev_err(bus->dev, "error: cannot turn on display power on i915 after resume\n"); - return ret; - } + hda_codec_i915_get(sdev); /* init hda controller. DSP cores will be powered up during fw boot */ return hda_resume(sdev); @@ -398,11 +391,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state) } /* turn display power off */ - ret = hda_codec_i915_put(sdev); - if (ret < 0) { - dev_err(bus->dev, "error: cannot turn OFF display power on i915 during suspend\n"); - return ret; - } + hda_codec_i915_put(sdev); return 0; } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 1b2db25c3c8e3e..1cd64d8b69be9a 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -335,7 +335,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) struct hdac_ext_link *hlink = NULL; struct snd_soc_acpi_mach_params *mach_params; int ret = 0; - int err; device_disable_async_suspend(bus->dev); @@ -356,9 +355,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) ret = hda_dsp_ctrl_init_chip(sdev, true); if (ret < 0) { dev_err(bus->dev, "error: init chip failed with ret: %d\n", ret); - err = hda_codec_i915_put(sdev); - if (err < 0) - return err; + hda_codec_i915_put(sdev); return ret; } @@ -376,9 +373,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) /* create codec instances */ hda_codec_probe_bus(sdev); - ret = hda_codec_i915_put(sdev); - if (ret < 0) - return ret; + hda_codec_i915_put(sdev); /* * we are done probing so decrement link counts diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index c11999e1cae3fa..05ece54e1dba91 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -503,15 +503,15 @@ int hda_codec_probe_bus(struct snd_sof_dev *sdev); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) && IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) -int hda_codec_i915_get(struct snd_sof_dev *sdev); -int hda_codec_i915_put(struct snd_sof_dev *sdev); +void hda_codec_i915_get(struct snd_sof_dev *sdev); +void hda_codec_i915_put(struct snd_sof_dev *sdev); int hda_codec_i915_init(struct snd_sof_dev *sdev); int hda_codec_i915_exit(struct snd_sof_dev *sdev); #else -static inline int hda_codec_i915_get(struct snd_sof_dev *sdev) { return 0; } -static inline int hda_codec_i915_put(struct snd_sof_dev *sdev) { return 0; } +static inline void hda_codec_i915_get(struct snd_sof_dev *sdev) { } +static inline void hda_codec_i915_put(struct snd_sof_dev *sdev) { } static inline int hda_codec_i915_init(struct snd_sof_dev *sdev) { return 0; } static inline int hda_codec_i915_exit(struct snd_sof_dev *sdev) { return 0; } From 6e6dfa20e776c6d1b4855b493e8339b004d5337a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Nov 2018 14:36:17 +0100 Subject: [PATCH 0444/1995] ALSA: control: Fix race between adding and removing a user element The procedure for adding a user control element has some window opened for race against the concurrent removal of a user element. This was caught by syzkaller, hitting a KASAN use-after-free error. This patch addresses the bug by wrapping the whole procedure to add a user control element with the card->controls_rwsem, instead of only around the increment of card->user_ctl_count. This required a slight code refactoring, too. The function snd_ctl_add() is split to two parts: a core function to add the control element and a part calling it. The former is called from the function for adding a user control element inside the controls_rwsem. One change to be noted is that snd_ctl_notify() for adding a control element gets called inside the controls_rwsem as well while it was called outside the rwsem. But this should be OK, as snd_ctl_notify() takes another (finer) rwlock instead of rwsem, and the call of snd_ctl_notify() inside rwsem is already done in another code path. Reported-by: syzbot+dc09047bce3820621ba2@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai (cherry picked from commit e1a7bfe3807974e66f971f2589d4e0197ec0fced) --- sound/core/control.c | 80 +++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/sound/core/control.c b/sound/core/control.c index 9aa15bfc79369a..649d3217590ed4 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -348,6 +348,40 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count) return 0; } +/* add a new kcontrol object; call with card->controls_rwsem locked */ +static int __snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) +{ + struct snd_ctl_elem_id id; + unsigned int idx; + unsigned int count; + + id = kcontrol->id; + if (id.index > UINT_MAX - kcontrol->count) + return -EINVAL; + + if (snd_ctl_find_id(card, &id)) { + dev_err(card->dev, + "control %i:%i:%i:%s:%i is already present\n", + id.iface, id.device, id.subdevice, id.name, id.index); + return -EBUSY; + } + + if (snd_ctl_find_hole(card, kcontrol->count) < 0) + return -ENOMEM; + + list_add_tail(&kcontrol->list, &card->controls); + card->controls_count += kcontrol->count; + kcontrol->id.numid = card->last_numid + 1; + card->last_numid += kcontrol->count; + + id = kcontrol->id; + count = kcontrol->count; + for (idx = 0; idx < count; idx++, id.index++, id.numid++) + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); + + return 0; +} + /** * snd_ctl_add - add the control instance to the card * @card: the card instance @@ -364,45 +398,18 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count) */ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) { - struct snd_ctl_elem_id id; - unsigned int idx; - unsigned int count; int err = -EINVAL; if (! kcontrol) return err; if (snd_BUG_ON(!card || !kcontrol->info)) goto error; - id = kcontrol->id; - if (id.index > UINT_MAX - kcontrol->count) - goto error; down_write(&card->controls_rwsem); - if (snd_ctl_find_id(card, &id)) { - up_write(&card->controls_rwsem); - dev_err(card->dev, "control %i:%i:%i:%s:%i is already present\n", - id.iface, - id.device, - id.subdevice, - id.name, - id.index); - err = -EBUSY; - goto error; - } - if (snd_ctl_find_hole(card, kcontrol->count) < 0) { - up_write(&card->controls_rwsem); - err = -ENOMEM; - goto error; - } - list_add_tail(&kcontrol->list, &card->controls); - card->controls_count += kcontrol->count; - kcontrol->id.numid = card->last_numid + 1; - card->last_numid += kcontrol->count; - id = kcontrol->id; - count = kcontrol->count; + err = __snd_ctl_add(card, kcontrol); up_write(&card->controls_rwsem); - for (idx = 0; idx < count; idx++, id.index++, id.numid++) - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); + if (err < 0) + goto error; return 0; error: @@ -1361,9 +1368,12 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, kctl->tlv.c = snd_ctl_elem_user_tlv; /* This function manage to free the instance on failure. */ - err = snd_ctl_add(card, kctl); - if (err < 0) - return err; + down_write(&card->controls_rwsem); + err = __snd_ctl_add(card, kctl); + if (err < 0) { + snd_ctl_free_one(kctl); + goto unlock; + } offset = snd_ctl_get_ioff(kctl, &info->id); snd_ctl_build_ioff(&info->id, kctl, offset); /* @@ -1374,10 +1384,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, * which locks the element. */ - down_write(&card->controls_rwsem); card->user_ctl_count++; - up_write(&card->controls_rwsem); + unlock: + up_write(&card->controls_rwsem); return 0; } From 692f505cfda85b2c90dbaaf0b2548b320d0cad56 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Mon, 29 Jan 2018 21:45:59 +0530 Subject: [PATCH 0445/1995] ASoC: Intel: Skylake: Make DSP replies more human readable Add more meaning to the IPC replies for easy debugging. Replace the switch case with a lookup table to lookup for the IPC replies and print in human readable form. Signed-off-by: Subhransu S. Prusty Signed-off-by: Sriram Periyasamy Signed-off-by: Vinod Koul Signed-off-by: Mark Brown (cherry picked from commit aa15679b2dc898049e9117fbe3ddda0b50fa52d2) --- sound/soc/intel/skylake/skl-sst-ipc.c | 44 ++++++++++++++++++++------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 5234fafb758a0e..8708755a8f9a0a 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -392,18 +392,43 @@ int skl_ipc_process_notification(struct sst_generic_ipc *ipc, return 0; } -static int skl_ipc_set_reply_error_code(u32 reply) +struct skl_ipc_err_map { + const char *msg; + enum skl_ipc_glb_reply reply; + int err; +}; + +static struct skl_ipc_err_map skl_err_map[] = { + {"DSP out of memory", IPC_GLB_REPLY_OUT_OF_MEMORY, -ENOMEM}, + {"DSP busy", IPC_GLB_REPLY_BUSY, -EBUSY}, +}; + +static int skl_ipc_set_reply_error_code(struct sst_generic_ipc *ipc, u32 reply) { - switch (reply) { - case IPC_GLB_REPLY_OUT_OF_MEMORY: - return -ENOMEM; + int i; - case IPC_GLB_REPLY_BUSY: - return -EBUSY; + for (i = 0; i < ARRAY_SIZE(skl_err_map); i++) { + if (skl_err_map[i].reply == reply) + break; + } - default: + if (i == ARRAY_SIZE(skl_err_map)) { + dev_err(ipc->dev, "ipc FW reply: %d FW Error Code: %u\n", + reply, + ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); return -EINVAL; } + + if (skl_err_map[i].err < 0) + dev_err(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n", + skl_err_map[i].msg, + ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); + else + dev_info(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n", + skl_err_map[i].msg, + ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); + + return skl_err_map[i].err; } void skl_ipc_process_reply(struct sst_generic_ipc *ipc, @@ -441,10 +466,7 @@ void skl_ipc_process_reply(struct sst_generic_ipc *ipc, } } else { - msg->errno = skl_ipc_set_reply_error_code(reply); - dev_err(ipc->dev, "ipc FW reply: reply=%d\n", reply); - dev_err(ipc->dev, "FW Error Code: %u\n", - ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); + msg->errno = skl_ipc_set_reply_error_code(ipc, reply); switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { case IPC_GLB_LOAD_MULTIPLE_MODS: case IPC_GLB_LOAD_LIBRARY: From 6cbcc195021cf7930ee2af0439acfce1066e0df9 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Mon, 29 Jan 2018 21:46:00 +0530 Subject: [PATCH 0446/1995] ASoC: Intel: Skylake: Add FW reply for MCLK/SCLK IPC If mclk/sclk is already running, FW responds with IPC reply MCLK/SCLK already running. Add these to the IPC reply lookup table. Signed-off-by: Subhransu S. Prusty Signed-off-by: Sriram Periyasamy Signed-off-by: Vinod Koul Signed-off-by: Mark Brown (cherry picked from commit 61f94ee4a7435c35d78b22e4ae6e0551908000ae) --- sound/soc/intel/skylake/skl-sst-ipc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 8708755a8f9a0a..9f3ce73593aec4 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -249,6 +249,8 @@ enum skl_ipc_glb_reply { IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121, IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140, IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141, + IPC_GLB_REPLY_SCLK_ALREADY_RUNNING = 150, + IPC_GLB_REPLY_MCLK_ALREADY_RUNNING = 151, IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160, IPC_GLB_REPLY_PPL_NOT_EXIST = 161, @@ -401,6 +403,10 @@ struct skl_ipc_err_map { static struct skl_ipc_err_map skl_err_map[] = { {"DSP out of memory", IPC_GLB_REPLY_OUT_OF_MEMORY, -ENOMEM}, {"DSP busy", IPC_GLB_REPLY_BUSY, -EBUSY}, + {"SCLK already running", IPC_GLB_REPLY_SCLK_ALREADY_RUNNING, + IPC_GLB_REPLY_SCLK_ALREADY_RUNNING}, + {"MCLK already running", IPC_GLB_REPLY_MCLK_ALREADY_RUNNING, + IPC_GLB_REPLY_MCLK_ALREADY_RUNNING}, }; static int skl_ipc_set_reply_error_code(struct sst_generic_ipc *ipc, u32 reply) From 77beedce3fa90e2c362f6782d40c872411c6bf69 Mon Sep 17 00:00:00 2001 From: Jenny TC Date: Wed, 28 Nov 2018 12:22:45 +0530 Subject: [PATCH 0447/1995] ASoC: dmic: introduce mode switch delay On startup, applications such as PulseAudio or CRAS enable playback or capture on all PCM devices to verify that configurations are correct, and close them immediately. For DMICs, this can result in the clock being turned off very quickly, which may not compatible with internal state machine transition requirements. This patch add a mode-switch delay which will prevent the clock from being turned off without complying with manufacturer timing specifications. While the DMIC clock may be controlled at a lower level, be it with hardware or firmware, applying the delay during the STOP_TRIGGER phase ensures that there is no race condition, e.g. with the hardware/firmware turning off the clock earlier Signed-off-by: Sathyanarayana Nujella Signed-off-by: Jairaj Arava Signed-off-by: Harsha Priya Signed-off-by: Jenny TC Signed-off-by: Mark Brown (cherry picked from commit bc0a7dbc5a54a06b925064adba8b07d65acf8718) --- .../devicetree/bindings/sound/dmic.txt | 2 ++ sound/soc/codecs/dmic.c | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/dmic.txt b/Documentation/devicetree/bindings/sound/dmic.txt index e957b41367160b..32e8710372696d 100644 --- a/Documentation/devicetree/bindings/sound/dmic.txt +++ b/Documentation/devicetree/bindings/sound/dmic.txt @@ -9,6 +9,7 @@ Optional properties: - dmicen-gpios: GPIO specifier for dmic to control start and stop - num-channels: Number of microphones on this DAI - wakeup-delay-ms: Delay (in ms) after enabling the DMIC + - modeswitch-delay-ms: Delay (in ms) to complete DMIC mode switch Example node: @@ -17,4 +18,5 @@ Example node: dmicen-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>; num-channels = <1>; wakeup-delay-ms <50>; + modeswitch-delay-ms <35>; }; diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index 71322e0410ee76..f4eb0a438a3add 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -30,9 +30,36 @@ #include #include +#define MAX_MODESWITCH_DELAY 70 +static int modeswitch_delay; +module_param(modeswitch_delay, uint, 0644); + struct dmic { struct gpio_desc *gpio_en; int wakeup_delay; + /* Delay after DMIC mode switch */ + int modeswitch_delay; +}; + +int dmic_daiops_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct dmic *dmic = snd_soc_component_get_drvdata(component); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_STOP: + if (dmic->modeswitch_delay) + mdelay(dmic->modeswitch_delay); + + break; + } + + return 0; +} + +static const struct snd_soc_dai_ops dmic_dai_ops = { + .trigger = dmic_daiops_trigger, }; static int dmic_aif_event(struct snd_soc_dapm_widget *w, @@ -68,6 +95,7 @@ static struct snd_soc_dai_driver dmic_dai = { | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, }, + .ops = &dmic_dai_ops, }; static int dmic_component_probe(struct snd_soc_component *component) @@ -85,6 +113,13 @@ static int dmic_component_probe(struct snd_soc_component *component) device_property_read_u32(component->dev, "wakeup-delay-ms", &dmic->wakeup_delay); + device_property_read_u32(component->dev, "modeswitch-delay-ms", + &dmic->modeswitch_delay); + if (modeswitch_delay) + dmic->modeswitch_delay = modeswitch_delay; + + if (dmic->modeswitch_delay > MAX_MODESWITCH_DELAY) + dmic->modeswitch_delay = MAX_MODESWITCH_DELAY; snd_soc_component_set_drvdata(component, dmic); From fab1b23584604c26a1fe2da9159561c70d38e584 Mon Sep 17 00:00:00 2001 From: Jenny TC Date: Wed, 28 Nov 2018 12:22:46 +0530 Subject: [PATCH 0448/1995] ASoC: dmic: introduce module_param wakeup_delay Introducing a module param for wakeup_delay in order to align with modeswitch_delay parameter. With this change, both wakeup_delay and modeswitch_delay parameters can be passed as module parameters. Signed-off-by: Jenny TC Signed-off-by: Mark Brown (cherry picked from commit f6f30a609c526dbf6d59490a8c85adaf6ac9b0fa) --- sound/soc/codecs/dmic.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index f4eb0a438a3add..da921da50ef0fc 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -34,6 +34,9 @@ static int modeswitch_delay; module_param(modeswitch_delay, uint, 0644); +static int wakeup_delay; +module_param(wakeup_delay, uint, 0644); + struct dmic { struct gpio_desc *gpio_en; int wakeup_delay; @@ -115,6 +118,8 @@ static int dmic_component_probe(struct snd_soc_component *component) &dmic->wakeup_delay); device_property_read_u32(component->dev, "modeswitch-delay-ms", &dmic->modeswitch_delay); + if (wakeup_delay) + dmic->wakeup_delay = wakeup_delay; if (modeswitch_delay) dmic->modeswitch_delay = modeswitch_delay; From 6a07499c93441829c8788ffc6e957362f9ea7543 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 29 Nov 2018 08:02:49 +0100 Subject: [PATCH 0449/1995] ALSA: pcm: Call snd_pcm_unlink() conditionally at closing Currently the PCM core calls snd_pcm_unlink() always unconditionally at closing a stream. However, since snd_pcm_unlink() invokes the global rwsem down, the lock can be easily contended. More badly, when a thread runs in a high priority RT-FIFO, it may stall at spinning. Basically the call of snd_pcm_unlink() is required only for the linked streams that are already rare occasion. For normal use cases, this code path is fairly superfluous. As an optimization (and also as a workaround for the RT problem above in normal situations without linked streams), this patch adds a check before calling snd_pcm_unlink() and calls it only when needed. Reported-by: Chanho Min Cc: Signed-off-by: Takashi Iwai (cherry picked from commit b51abed8355e5556886623b2772fa6b7598d2282) --- sound/core/pcm_native.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 66c90f486af913..6afcc393113a9c 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2369,7 +2369,8 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) static void pcm_release_private(struct snd_pcm_substream *substream) { - snd_pcm_unlink(substream); + if (snd_pcm_stream_linked(substream)) + snd_pcm_unlink(substream); } void snd_pcm_release_substream(struct snd_pcm_substream *substream) From f75c893879dfb19ad5c6ec419eab519d5953744e Mon Sep 17 00:00:00 2001 From: Chanho Min Date: Mon, 26 Nov 2018 14:36:37 +0900 Subject: [PATCH 0450/1995] ALSA: pcm: Fix starvation on down_write_nonblock() Commit 67ec1072b053 ("ALSA: pcm: Fix rwsem deadlock for non-atomic PCM stream") fixes deadlock for non-atomic PCM stream. But, This patch causes antother stuck. If writer is RT thread and reader is a normal thread, the reader thread will be difficult to get scheduled. It may not give chance to release readlocks and writer gets stuck for a long time if they are pinned to single cpu. The deadlock described in the previous commit is because the linux rwsem queues like a FIFO. So, we might need non-FIFO writelock, not non-block one. My suggestion is that the writer gives reader a chance to be scheduled by using the minimum msleep() instaed of spinning without blocking by writer. Also, The *_nonblock may be changed to *_nonfifo appropriately to this concept. In terms of performance, when trylock is failed, this minimum periodic msleep will have the same performance as the tick-based schedule()/wake_up_q(). [ Although this has a fairly high performance penalty, the relevant code path became already rare due to the previous commit ("ALSA: pcm: Call snd_pcm_unlink() conditionally at closing"). That is, now this unconditional msleep appears only when using linked streams, and this must be a rare case. So we accept this as a quick workaround until finding a more suitable one -- tiwai ] Fixes: 67ec1072b053 ("ALSA: pcm: Fix rwsem deadlock for non-atomic PCM stream") Suggested-by: Wonmin Jung Signed-off-by: Chanho Min Cc: Signed-off-by: Takashi Iwai (cherry picked from commit b888a5f713e4d17faaaff24316585a4eb07f35b7) --- sound/core/pcm_native.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 6afcc393113a9c..818dff1de545fa 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "pcm_local.h" @@ -91,12 +92,12 @@ static DECLARE_RWSEM(snd_pcm_link_rwsem); * and this may lead to a deadlock when the code path takes read sem * twice (e.g. one in snd_pcm_action_nonatomic() and another in * snd_pcm_stream_lock()). As a (suboptimal) workaround, let writer to - * spin until it gets the lock. + * sleep until all the readers are completed without blocking by writer. */ -static inline void down_write_nonblock(struct rw_semaphore *lock) +static inline void down_write_nonfifo(struct rw_semaphore *lock) { while (!down_write_trylock(lock)) - cond_resched(); + msleep(1); } #define PCM_LOCK_DEFAULT 0 @@ -1967,7 +1968,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) res = -ENOMEM; goto _nolock; } - down_write_nonblock(&snd_pcm_link_rwsem); + down_write_nonfifo(&snd_pcm_link_rwsem); write_lock_irq(&snd_pcm_link_rwlock); if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || substream->runtime->status->state != substream1->runtime->status->state || @@ -2014,7 +2015,7 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream) struct snd_pcm_substream *s; int res = 0; - down_write_nonblock(&snd_pcm_link_rwsem); + down_write_nonfifo(&snd_pcm_link_rwsem); write_lock_irq(&snd_pcm_link_rwlock); if (!snd_pcm_stream_linked(substream)) { res = -EALREADY; From fb2545967e6d369ed1689e6cda9418bd6a52cd92 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 29 Nov 2018 12:05:19 +0100 Subject: [PATCH 0451/1995] ALSA: pcm: Fix interval evaluation with openmin/max As addressed in alsa-lib (commit b420056604f0), we need to fix the case where the evaluation of PCM interval "(x x+1]" leading to -EINVAL. After applying rules, such an interval may be translated as "(x x+1)". Fixes: ff2d6acdf6f1 ("ALSA: pcm: Fix snd_interval_refine first/last with open min/max") Cc: Signed-off-by: Takashi Iwai (cherry picked from commit 5363857b916c1f48027e9b96ee8be8376bf20811) --- include/sound/pcm_params.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h index 2dd37cada7c088..888a833d3b003f 100644 --- a/include/sound/pcm_params.h +++ b/include/sound/pcm_params.h @@ -254,11 +254,13 @@ static inline int snd_interval_empty(const struct snd_interval *i) static inline int snd_interval_single(const struct snd_interval *i) { return (i->min == i->max || - (i->min + 1 == i->max && i->openmax)); + (i->min + 1 == i->max && (i->openmin || i->openmax))); } static inline int snd_interval_value(const struct snd_interval *i) { + if (i->openmin && !i->openmax) + return i->max; return i->min; } From 9d11f4b67c7b6b127747b9a9811de464b5cb8416 Mon Sep 17 00:00:00 2001 From: Young_X Date: Tue, 27 Nov 2018 06:33:16 +0000 Subject: [PATCH 0452/1995] ASoC: au8540: use 64-bit arithmetic instead of 32-bit Add suffix ULL to constant 256 in order to give the compiler complete information about the proper arithmetic to use. Notice that such constant is used in a context that expects an expression of type u64 (64 bits, unsigned) and the following expression is currently being evaluated using 32-bit arithmetic: 256 * fs * 2 * mclk_src_scaling[i].param Signed-off-by: Young_X Signed-off-by: Mark Brown (cherry picked from commit cd7fdc45bc69a62b4e22c6e875f1f1aea566256d) --- sound/soc/codecs/nau8540.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c index e3c8cd17daf2da..4dd1a609756be6 100644 --- a/sound/soc/codecs/nau8540.c +++ b/sound/soc/codecs/nau8540.c @@ -585,7 +585,7 @@ static int nau8540_calc_fll_param(unsigned int fll_in, fvco_max = 0; fvco_sel = ARRAY_SIZE(mclk_src_scaling); for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) { - fvco = 256 * fs * 2 * mclk_src_scaling[i].param; + fvco = 256ULL * fs * 2 * mclk_src_scaling[i].param; if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX && fvco_max < fvco) { fvco_max = fvco; From 13df4d08e9dceb0e7e005f90b78ff32af4f04924 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 30 Nov 2018 18:54:37 -0600 Subject: [PATCH 0453/1995] ASoC: Intel: common: add ACPI matching tables for ICL Entry needed for ICL RVP w/ RT274 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 9923e9072d813e2efa591d01e6971e0833c38815) --- include/sound/soc-acpi-intel-match.h | 1 + sound/soc/intel/common/Makefile | 2 +- .../intel/common/soc-acpi-intel-icl-match.c | 32 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/common/soc-acpi-intel-icl-match.c diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index f48f59e5b7b02b..bb5e1e4ce8bf91 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -24,6 +24,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[]; /* * generic table used for HDA codec-based platforms, possibly with diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index c1f50a079d34aa..56c81e20b5bf8d 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -7,7 +7,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-hsw-bdw-match.o \ soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ - soc-acpi-intel-cnl-match.o \ + soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \ soc-acpi-intel-hda-match.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c new file mode 100644 index 00000000000000..33b441dca4d308 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-apci-intel-icl-match.c - tables and support for ICL ACPI enumeration. + * + * Copyright (c) 2018, Intel Corporation. + * + */ + +#include +#include +#include "../skylake/skl.h" + +static struct skl_machine_pdata icl_pdata = { + .use_tplg_pcm = true, +}; + +struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { + { + .id = "INT34C2", + .drv_name = "icl_rt274", + .fw_filename = "intel/dsp_fw_icl.bin", + .pdata = &icl_pdata, + .sof_fw_filename = "intel/sof-icl.ri", + .sof_tplg_filename = "intel/sof-icl-rt274.tplg", + .asoc_plat_name = "0000:00:1f.3", + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_icl_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); From 3a6a067a3e0e0633f8261834a26c76ddd8cafd7d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 2 Dec 2018 13:21:22 +0100 Subject: [PATCH 0454/1995] ASoC: intel: cht_bsw_max98090_ti: Add pmc_plt_clk_0 quirk for Chromebook Clapper The Clapper model Chromebook uses pmc_plt_clk_0 instead of pmc_plt_clk_3 for the mclk, just like the Swanky model. This commit adds a DMI based quirk for this. This fixing audio no longer working on these devices after commit 648e921888ad ("clk: x86: Stop marking clocks as CLK_IS_CRITICAL") that commit fixes us unnecessary keeping unused clocks on, but in case of the Clapper that was breaking audio support since we were not using the right clock in the cht_bsw_max98090_ti machine driver. Cc: stable@vger.kernel.org Fixes: 648e921888ad ("clk: x86: Stop marking clocks as CLK_IS_CRITICAL") Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 984bfb398a3af6fa9b7e80165e524933b0616686) --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 9d9f6e41d81c07..ad0c9838385366 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -389,6 +389,13 @@ static struct snd_soc_card snd_soc_card_cht = { }; static const struct dmi_system_id cht_max98090_quirk_table[] = { + { + /* Clapper model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Clapper"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, { /* Swanky model Chromebook (Toshiba Chromebook 2) */ .matches = { From f470f56799280bb59847557f879d31fe979fcc6e Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Fri, 30 Nov 2018 03:21:09 +0000 Subject: [PATCH 0455/1995] ASoC: max98373: Added max98373_reset for stable amp reset This patch added max98373_reset function to avoid amp software reset failure and code duplication. Reset verification step has been added for stable amp reset and it repeats verification maximum 3 times when it is failed. Chip revision ID is available when the amp is in the idle state which means software reset is completed well. Additional 10ms delay was added for every retrial and maximum 30ms delay can be applied. Signed-off-by: Ryan Lee Signed-off-by: Mark Brown (cherry picked from commit 20f2ab247d3b787af91c1aa5eb27c5061744c154) --- sound/soc/codecs/max98373.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index a09d01318f793d..9c8616a7b61c9d 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -724,14 +724,39 @@ static struct snd_soc_dai_driver max98373_dai[] = { } }; +static void max98373_reset(struct max98373_priv *max98373, struct device *dev) +{ + int ret, reg, count; + + /* Software Reset */ + ret = regmap_update_bits(max98373->regmap, + MAX98373_R2000_SW_RESET, + MAX98373_SOFT_RESET, + MAX98373_SOFT_RESET); + if (ret) + dev_err(dev, "Reset command failed. (ret:%d)\n", ret); + + count = 0; + while (count < 3) { + usleep_range(10000, 11000); + /* Software Reset Verification */ + ret = regmap_read(max98373->regmap, + MAX98373_R21FF_REV_ID, ®); + if (!ret) { + dev_info(dev, "Reset completed (retry:%d)\n", count); + return; + } + count++; + } + dev_err(dev, "Reset failed. (ret:%d)\n", ret); +} + static int max98373_probe(struct snd_soc_component *component) { struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component); /* Software Reset */ - regmap_write(max98373->regmap, - MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET); - usleep_range(10000, 11000); + max98373_reset(max98373, component->dev); /* IV default slot configuration */ regmap_write(max98373->regmap, @@ -818,9 +843,7 @@ static int max98373_resume(struct device *dev) { struct max98373_priv *max98373 = dev_get_drvdata(dev); - regmap_write(max98373->regmap, - MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET); - usleep_range(10000, 11000); + max98373_reset(max98373, dev); regcache_cache_only(max98373->regmap, false); regcache_sync(max98373->regmap); return 0; From cd473427b6f309ced23d638ea76564eabeb299bf Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 3 Dec 2018 21:45:14 +0100 Subject: [PATCH 0456/1995] ASoC: intel: cht_bsw_max98090_ti: Add pmc_plt_clk_0 quirk for Chromebook Gnawty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Gnawty model Chromebook uses pmc_plt_clk_0 instead of pmc_plt_clk_3 for the mclk, just like the Clapper and Swanky models. This commit adds a DMI based quirk for this. This fixing audio no longer working on these devices after commit 648e921888ad ("clk: x86: Stop marking clocks as CLK_IS_CRITICAL") that commit fixes us unnecessary keeping unused clocks on, but in case of the Gnawty that was breaking audio support since we were not using the right clock in the cht_bsw_max98090_ti machine driver. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=201787 Cc: stable@vger.kernel.org Fixes: 648e921888ad ("clk: x86: Stop marking clocks as CLK_IS_CRITICAL") Reported-and-tested-by: Jaime Pérez <19.jaime.91@gmail.com> Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 94ea56cff506c769a509c5dd87904c7fe3806a81) --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index ad0c9838385366..08a5152e635ac8 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -396,6 +396,13 @@ static const struct dmi_system_id cht_max98090_quirk_table[] = { }, .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, }, + { + /* Gnawty model Chromebook (Acer Chromebook CB3-111) */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Gnawty"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, { /* Swanky model Chromebook (Toshiba Chromebook 2) */ .matches = { From 2da88f22daa54818ab69a8707b6c124c5f330670 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Thu, 6 Dec 2018 22:52:05 +0800 Subject: [PATCH 0457/1995] ASoC: rt5660: Add a new ACPI match ID The Realtek codec ALC3277 is 100% compatible with the codec RT5660 in I2S mode. And on the Dell IoT platform, the codec is ALC3277, and the HID of the codec in the BIOS is 10EC3277, so adding this ID to the ACPI match table. Signed-off-by: Hui Wang Signed-off-by: Mark Brown (cherry picked from commit a01b8d1d24451bfc00d3a975d107f9b1590bf826) --- sound/soc/codecs/rt5660.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index 27f7445b243200..e74b2e8cd423e3 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -1246,6 +1246,7 @@ MODULE_DEVICE_TABLE(of, rt5660_of_match); static const struct acpi_device_id rt5660_acpi_match[] = { { "10EC5660", 0 }, + { "10EC3277", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, rt5660_acpi_match); From a6c73a9fe7eae4c36884abfe980ef0fccd699085 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 8 Dec 2018 14:01:13 +0100 Subject: [PATCH 0458/1995] ASoC: Intel: bytcr_rt5640: Add quirk for the Prowise PT301 tablet Add a quirk for the Prowise PT301 tablet, this BYTCR tablet has no CHAN package in its ACPI tables and uses SSP0-AIF1 rather then SSP0-AIF2 which is the default for BYTCR devices. Also it uses IN1 for its MIC and JD2 for jack-detect, rather then the default IN3 and JD1. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 271248f4c2bf56dc6b3582e37c7ac19dd483d989) --- sound/soc/intel/boards/bytcr_rt5640.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 09591144ea7d2e..a48ea8ef21ce31 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -673,6 +673,20 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF2 | BYT_RT5640_MCLK_EN), }, + { + /* Prowise PT301 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Prowise"), + DMI_MATCH(DMI_PRODUCT_NAME, "PT301"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"), From 0a0482d7b34e17d1e9058d42b13f34f5ef7cb9ee Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 8 Dec 2018 14:01:14 +0100 Subject: [PATCH 0459/1995] ASoC: Intel: bytcr_rt5640: Add quirk for the Point of View Mobii TAB-P1005W-232 Add a quirk for the Point of View Mobii TAB-P1005W-232 v2.0 tablet, this BYTCR device uses IN1 for its MIC and JD2 for jack-detect, rather then the default IN3 and JD1. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 02e5af6575627ca0692d5b93e7c3fc3b86f62f40) --- sound/soc/intel/boards/bytcr_rt5640.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index a48ea8ef21ce31..a22366ce33c403 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -673,6 +673,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF2 | BYT_RT5640_MCLK_EN), }, + { /* Point of View Mobii TAB-P1005W-232 (V2.0) */ + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "POV"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "I102A"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { /* Prowise PT301 */ .matches = { From 471197429a4b21fb2a3b09f40ced090672dfe367 Mon Sep 17 00:00:00 2001 From: Zhuohao Lee Date: Mon, 10 Dec 2018 12:32:13 +0800 Subject: [PATCH 0460/1995] ASoC: Intel: kbl_da7219_max98927: fix the audio jack button remapping From the da7219 spec, the button A, B, C and D are remapped to 0, 1, 2 and 3 respectively where button A is KEY_PLAYPAUSE, B is KEY_VOLUMEUP, C is KEY_VOLUMEDOWN and D is KEY_VOICECOMMAND. Signed-off-by: Zhuohao Lee Signed-off-by: Max Chang Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7f63196eaa83e033de523602324ff91288390a67) --- sound/soc/intel/boards/kbl_da7219_max98927.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 58eb0fe69978bd..723a4935ed76ed 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -262,9 +262,9 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) jack = &ctx->kabylake_headset; snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); da7219_aad_jack_det(component, &ctx->kabylake_headset); From 8eaf38d13139d38c0ce1db6a0253f28f3bd83170 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Thu, 13 Dec 2018 21:02:16 +0800 Subject: [PATCH 0461/1995] ASoC: Intel: kbl_rt5660: Add a new machine driver for kbl with rt5660 The new Dell IoT platform uses kabylake + alc3277 codec, and alc3277 shares the driver with the codec rt5660, here we generate a new machine driver based on kbl_da7219_max98357a. The audio design on this IoT platform is as below: - Intel kabylake platform - connect the codec ALC3277 via SSP0 - line-out and line-in with Micbias jacks - line-out mute control and jack detection of line-out and line-in - two HDMI ports with audio capability Signed-off-by: Hui Wang Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 8625db9416923b2941ef68776f55062555f7ce65) --- sound/soc/intel/boards/Kconfig | 10 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/kbl_rt5660.c | 543 ++++++++++++++++++ .../intel/common/soc-acpi-intel-kbl-match.c | 10 + 4 files changed, 565 insertions(+) create mode 100644 sound/soc/intel/boards/kbl_rt5660.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index b177db2a0dbb2a..3839d6205fcf42 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -293,6 +293,16 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH Say Y if you have such a device. If unsure select "N". +config SND_SOC_INTEL_KBL_RT5660_MACH + tristate "KBL with RT5660 in I2S Mode" + depends on MFD_INTEL_LPSS && I2C && ACPI + select SND_SOC_RT5660 + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC Onboard Codec I2S machine driver. This will + create an alsa sound card for RT5660 I2S audio codec. + Say Y if you have such a device. + config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH tristate "GLK with RT5682 and MAX98357A in I2S Mode" depends on MFD_INTEL_LPSS && I2C && ACPI diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 5381e27df9cc76..bf072ea299b709 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -20,6 +20,7 @@ snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o +snd-soc-kbl_rt5660-objs := kbl_rt5660.o snd-soc-skl_rt286-objs := skl_rt286.o snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o @@ -46,6 +47,7 @@ obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max9 obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o +obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5660_MACH) += snd-soc-kbl_rt5660.o obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c new file mode 100644 index 00000000000000..3255e00292764e --- /dev/null +++ b/sound/soc/intel/boards/kbl_rt5660.c @@ -0,0 +1,543 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2018-19 Canonical Corporation. + +/* + * Intel Kabylake I2S Machine Driver with RT5660 Codec + * + * Modified from: + * Intel Kabylake I2S Machine driver supporting MAXIM98357a and + * DA7219 codecs + * Also referred to: + * Intel Broadwell I2S Machine driver supporting RT5677 codec + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../codecs/hdac_hdmi.h" +#include "../../codecs/rt5660.h" + +#define KBL_RT5660_CODEC_DAI "rt5660-aif1" +#define DUAL_CHANNEL 2 + +static struct snd_soc_card *kabylake_audio_card; +static struct snd_soc_jack skylake_hdmi[3]; +static struct snd_soc_jack lineout_jack; +static struct snd_soc_jack mic_jack; + +struct kbl_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct kbl_codec_private { + struct gpio_desc *gpio_lo_mute; + struct list_head hdmi_pcm_list; +}; + +enum { + KBL_DPCM_AUDIO_PB = 0, + KBL_DPCM_AUDIO_CP, + KBL_DPCM_AUDIO_HDMI1_PB, + KBL_DPCM_AUDIO_HDMI2_PB, + KBL_DPCM_AUDIO_HDMI3_PB, +}; + +#define GPIO_LINEOUT_MUTE_INDEX 0 +#define GPIO_LINEOUT_DET_INDEX 3 +#define GPIO_LINEIN_DET_INDEX 4 + +static const struct acpi_gpio_params lineout_mute_gpio = { GPIO_LINEOUT_MUTE_INDEX, 0, true }; +static const struct acpi_gpio_params lineout_det_gpio = { GPIO_LINEOUT_DET_INDEX, 0, false }; +static const struct acpi_gpio_params mic_det_gpio = { GPIO_LINEIN_DET_INDEX, 0, false }; + + +static const struct acpi_gpio_mapping acpi_rt5660_gpios[] = { + { "lineout-mute-gpios", &lineout_mute_gpio, 1 }, + { "lineout-det-gpios", &lineout_det_gpio, 1 }, + { "mic-det-gpios", &mic_det_gpio, 1 }, + { NULL }, +}; + +static struct snd_soc_jack_pin lineout_jack_pin = { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, +}; + +static struct snd_soc_jack_pin mic_jack_pin = { + .pin = "Line In", + .mask = SND_JACK_MICROPHONE, +}; + +static struct snd_soc_jack_gpio lineout_jack_gpio = { + .name = "lineout-det", + .report = SND_JACK_LINEOUT, + .debounce_time = 200, +}; + +static struct snd_soc_jack_gpio mic_jack_gpio = { + .name = "mic-det", + .report = SND_JACK_MICROPHONE, + .debounce_time = 200, +}; + +static int kabylake_5660_event_lineout(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct kbl_codec_private *priv = snd_soc_card_get_drvdata(dapm->card); + + gpiod_set_value_cansleep(priv->gpio_lo_mute, + !(SND_SOC_DAPM_EVENT_ON(event))); + + return 0; +} + +static const struct snd_kcontrol_new kabylake_rt5660_controls[] = { + SOC_DAPM_PIN_SWITCH("Line In"), + SOC_DAPM_PIN_SWITCH("Line Out"), +}; + +static const struct snd_soc_dapm_widget kabylake_rt5660_widgets[] = { + SND_SOC_DAPM_MIC("Line In", NULL), + SND_SOC_DAPM_LINE("Line Out", kabylake_5660_event_lineout), +}; + +static const struct snd_soc_dapm_route kabylake_rt5660_map[] = { + /* other jacks */ + {"IN1P", NULL, "Line In"}, + {"IN2P", NULL, "Line In"}, + {"Line Out", NULL, "LOUTR"}, + {"Line Out", NULL, "LOUTL"}, + + /* CODEC BE connections */ + { "AIF1 Playback", NULL, "ssp0 Tx"}, + { "ssp0 Tx", NULL, "codec0_out"}, + + { "codec0_in", NULL, "ssp0 Rx" }, + { "ssp0 Rx", NULL, "AIF1 Capture" }, + + { "hifi1", NULL, "iDisp1 Tx"}, + { "iDisp1 Tx", NULL, "iDisp1_out"}, + { "hifi2", NULL, "iDisp2 Tx"}, + { "iDisp2 Tx", NULL, "iDisp2_out"}, + { "hifi3", NULL, "iDisp3 Tx"}, + { "iDisp3 Tx", NULL, "iDisp3_out"}, +}; + +static int kabylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = DUAL_CHANNEL; + + /* set SSP0 to 24 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +static int kabylake_rt5660_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_component *component = rtd->codec_dai->component; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + ret = devm_acpi_dev_add_driver_gpios(component->dev, acpi_rt5660_gpios); + if (ret) + dev_warn(component->dev, "Failed to add driver gpios\n"); + + /* Request rt5660 GPIO for lineout mute control, return if fails */ + ctx->gpio_lo_mute = devm_gpiod_get(component->dev, "lineout-mute", + GPIOD_OUT_HIGH); + if (IS_ERR(ctx->gpio_lo_mute)) { + dev_err(component->dev, "Can't find GPIO_MUTE# gpio\n"); + return PTR_ERR(ctx->gpio_lo_mute); + } + + /* Create and initialize headphone jack, this jack is not mandatory, don't return if fails */ + ret = snd_soc_card_jack_new(rtd->card, "Lineout Jack", + SND_JACK_LINEOUT, &lineout_jack, + &lineout_jack_pin, 1); + if (ret) + dev_warn(component->dev, "Can't create Lineout jack\n"); + else { + lineout_jack_gpio.gpiod_dev = component->dev; + ret = snd_soc_jack_add_gpios(&lineout_jack, 1, + &lineout_jack_gpio); + if (ret) + dev_warn(component->dev, "Can't add Lineout jack gpio\n"); + } + + /* Create and initialize mic jack, this jack is not mandatory, don't return if fails */ + ret = snd_soc_card_jack_new(rtd->card, "Mic Jack", + SND_JACK_MICROPHONE, &mic_jack, + &mic_jack_pin, 1); + if (ret) + dev_warn(component->dev, "Can't create mic jack\n"); + else { + mic_jack_gpio.gpiod_dev = component->dev; + ret = snd_soc_jack_add_gpios(&mic_jack, 1, &mic_jack_gpio); + if (ret) + dev_warn(component->dev, "Can't add mic jack gpio\n"); + } + + /* Here we enable some dapms in advance to reduce the pop noise for recording via line-in */ + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_force_enable_pin(dapm, "BST1"); + snd_soc_dapm_force_enable_pin(dapm, "BST2"); + + return 0; +} + +static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) +{ + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct kbl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = device; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); +} + +static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); +} + +static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); +} + +static int kabylake_rt5660_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, + RT5660_SCLK_S_PLL1, params_rate(params) * 512, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_pll(codec_dai, 0, + RT5660_PLL1_S_BCLK, + params_rate(params) * 50, + params_rate(params) * 512); + if (ret < 0) + dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret); + + return ret; +} + +static struct snd_soc_ops kabylake_rt5660_ops = { + .hw_params = kabylake_rt5660_hw_params, +}; + +static const unsigned int rates[] = { + 48000, +}; + +static const struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; + +static const unsigned int channels[] = { + DUAL_CHANNEL, +}; + +static const struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, +}; + +static int kbl_fe_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + /* + * On this platform for PCM device we support, + * 48Khz + * stereo + * 16 bit audio + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + + return 0; +} + +static const struct snd_soc_ops kabylake_rt5660_fe_ops = { + .startup = kbl_fe_startup, +}; + +/* kabylake digital audio interface glue - connects rt5660 codec <--> CPU */ +static struct snd_soc_dai_link kabylake_rt5660_dais[] = { + /* Front End DAI links */ + [KBL_DPCM_AUDIO_PB] = { + .name = "Kbl Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &kabylake_rt5660_fe_ops, + }, + [KBL_DPCM_AUDIO_CP] = { + .name = "Kbl Audio Capture Port", + .stream_name = "Audio Record", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_capture = 1, + .ops = &kabylake_rt5660_fe_ops, + }, + [KBL_DPCM_AUDIO_HDMI1_PB] = { + .name = "Kbl HDMI Port1", + .stream_name = "Hdmi1", + .cpu_dai_name = "HDMI1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI2_PB] = { + .name = "Kbl HDMI Port2", + .stream_name = "Hdmi2", + .cpu_dai_name = "HDMI2 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI3_PB] = { + .name = "Kbl HDMI Port3", + .stream_name = "Hdmi3", + .cpu_dai_name = "HDMI3 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .init = NULL, + .nonatomic = 1, + .dynamic = 1, + }, + + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .id = 0, + .cpu_dai_name = "SSP0 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codec_name = "i2c-10EC3277:00", + .codec_dai_name = KBL_RT5660_CODEC_DAI, + .init = kabylake_rt5660_codec_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp0_fixup, + .ops = &kabylake_rt5660_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + { + .name = "iDisp1", + .id = 1, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = kabylake_hdmi1_init, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .id = 2, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi2_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .id = 3, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi3_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + + +#define NAME_SIZE 32 +static int kabylake_card_late_probe(struct snd_soc_card *card) +{ + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); + struct kbl_hdmi_pcm *pcm; + struct snd_soc_component *component = NULL; + int err, i = 0; + char jack_name[NAME_SIZE]; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &skylake_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &skylake_hdmi[i]); + if (err < 0) + return err; + + i++; + + } + + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); +} + +/* kabylake audio machine driver for rt5660 */ +static struct snd_soc_card kabylake_audio_card_rt5660 = { + .name = "kblrt5660", + .owner = THIS_MODULE, + .dai_link = kabylake_rt5660_dais, + .num_links = ARRAY_SIZE(kabylake_rt5660_dais), + .controls = kabylake_rt5660_controls, + .num_controls = ARRAY_SIZE(kabylake_rt5660_controls), + .dapm_widgets = kabylake_rt5660_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_rt5660_widgets), + .dapm_routes = kabylake_rt5660_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_rt5660_map), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + +static int kabylake_audio_probe(struct platform_device *pdev) +{ + struct kbl_codec_private *ctx; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + kabylake_audio_card = + (struct snd_soc_card *)pdev->id_entry->driver_data; + + kabylake_audio_card->dev = &pdev->dev; + snd_soc_card_set_drvdata(kabylake_audio_card, ctx); + return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); +} + +static const struct platform_device_id kbl_board_ids[] = { + { + .name = "kbl_rt5660", + .driver_data = + (kernel_ulong_t)&kabylake_audio_card_rt5660, + }, + { } +}; + +static struct platform_driver kabylake_audio = { + .probe = kabylake_audio_probe, + .driver = { + .name = "kbl_rt5660", + .pm = &snd_soc_pm_ops, + }, + .id_table = kbl_board_ids, +}; + +module_platform_driver(kabylake_audio) + +/* Module information */ +MODULE_DESCRIPTION("Audio Machine driver-RT5660 in I2S mode"); +MODULE_AUTHOR("Hui Wang "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:kbl_rt5660"); diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c index a317b7790fcecf..e6fa6f470526dc 100644 --- a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c @@ -96,6 +96,16 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .quirk_data = &kbl_7219_98927_codecs, .pdata = &skl_dmic_data }, + { + .id = "10EC5660", + .drv_name = "kbl_rt5660", + .fw_filename = "intel/dsp_fw_kbl.bin", + }, + { + .id = "10EC3277", + .drv_name = "kbl_rt5660", + .fw_filename = "intel/dsp_fw_kbl.bin", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines); From f96a52016d98b08d4927c1432f87f3fc767263ae Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Dec 2018 17:50:03 -0600 Subject: [PATCH 0462/1995] ASoC: Intel: Skylake: Add CFL-S support It's with CNP, supposed to be equivalent with CNL entry. Keep the existing declaration style for now, at a later point we may transition and use PCI_DEVICE_DATA(). Signed-off-by: Takashi Iwai Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit e6b98db945124987b1ecec3f5f030877627e01a9) --- sound/soc/intel/skylake/skl-messages.c | 8 ++++++++ sound/soc/intel/skylake/skl.c | 3 +++ 2 files changed, 11 insertions(+) diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 8bfb8b0fa3d595..b0e6fb93eaf83c 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -247,6 +247,14 @@ static const struct skl_dsp_ops dsp_ops[] = { .init_fw = cnl_sst_init_fw, .cleanup = cnl_sst_dsp_cleanup }, + { + .id = 0xa348, + .num_cores = 4, + .loader_ops = bxt_get_loader_ops, + .init = cnl_sst_dsp_init, + .init_fw = cnl_sst_init_fw, + .cleanup = cnl_sst_dsp_cleanup + }, }; const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 3f0ac13129829e..df36b8fe6d5e38 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -1121,6 +1121,9 @@ static const struct pci_device_id skl_ids[] = { /* CNL */ { PCI_DEVICE(0x8086, 0x9dc8), .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, + /* CFL */ + { PCI_DEVICE(0x8086, 0xa348), + .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, { 0, } }; MODULE_DEVICE_TABLE(pci, skl_ids); From 72952b4ef4657db662179422a2a11f3409915168 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 7 Dec 2018 17:50:04 -0600 Subject: [PATCH 0463/1995] ASoC: Intel: Skylake: Harden DSP detection with PCI class/subclass info The existing PPCAP and GCAP fields cannot be used reliably to determine if the DSP is enabled by the BIOS. Instead rely on the class/subclass information to find out if this driver can run or not. The values in the code don't seem to be documented in publicly available documents but are part of recommendations made to BIOS writers and have been verified to be accurate on a number of platforms. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit c746de8dbc7b0ae9df491f7a99a6dab34203b51b) --- sound/soc/intel/skylake/skl.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index df36b8fe6d5e38..41a084b3d48fdc 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -916,6 +916,21 @@ static int skl_first_init(struct hdac_bus *bus) unsigned short gcap; int cp_streams, pb_streams, start_idx; + /* + * detect DSP by checking class/subclass/prog-id information + * class=04 subclass 03 prog-if 00: no DSP, legacy driver needs to be used + * class=04 subclass 01 prog-if 00: DSP is present (and may be required e.g. for DMIC or SSP support) + * class=04 subclass 03 prog-if 80: either of DSP or legacy mode can be used + */ + if (pci->class == 0x040300) { + dev_err(bus->dev, "The DSP is not enabled on this platform, aborting probe\n"); + return -ENODEV; + } else if (pci->class != 0x040100 && pci->class != 0x040380) { + dev_err(bus->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, aborting probe\n", pci->class); + return -ENODEV; + } + dev_info(bus->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class); + err = pci_request_regions(pci, "Skylake HD audio"); if (err < 0) return err; From 2b898ab4dbffbc395ad7b03cf81445bef2ded1eb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 7 Dec 2018 17:50:05 -0600 Subject: [PATCH 0464/1995] ASoC: Intel: Skylake: stop probe if HDaudio capabilities don't exist Check immediately if required HDaudio capabilities can't be found (no PPCAP or no streams exposed in GCAP), and move all DMA inits after the error tests. PPCAP and GCAP are not reliable indicators of DSP presence, but if they don't exist then the driver will not work. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit fa11ab5688f744bc868356f3f14c3bb9f283a780) --- sound/soc/intel/skylake/skl.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 41a084b3d48fdc..72e366bbba3399 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -946,6 +946,12 @@ static int skl_first_init(struct hdac_bus *bus) snd_hdac_bus_parse_capabilities(bus); + /* check if PPCAP exists */ + if (!bus->ppcap) { + dev_err(bus->dev, "bus ppcap not set, HDaudio or DSP not present?\n"); + return -ENODEV; + } + if (skl_acquire_irq(bus, 0) < 0) return -EBUSY; @@ -955,23 +961,25 @@ static int skl_first_init(struct hdac_bus *bus) gcap = snd_hdac_chip_readw(bus, GCAP); dev_dbg(bus->dev, "chipset global capabilities = 0x%x\n", gcap); - /* allow 64bit DMA address if supported by H/W */ - if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) { - dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64)); - } else { - dma_set_mask(bus->dev, DMA_BIT_MASK(32)); - dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32)); - } - /* read number of streams from GCAP register */ cp_streams = (gcap >> 8) & 0x0f; pb_streams = (gcap >> 12) & 0x0f; - if (!pb_streams && !cp_streams) + if (!pb_streams && !cp_streams) { + dev_err(bus->dev, "no streams found in GCAP definitions?\n"); return -EIO; + } bus->num_streams = cp_streams + pb_streams; + /* allow 64bit DMA address if supported by H/W */ + if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) { + dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64)); + } else { + dma_set_mask(bus->dev, DMA_BIT_MASK(32)); + dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32)); + } + /* initialize streams */ snd_hdac_ext_stream_init_all (bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE); From d23bce7a45f52644e88ead89cf357475f7d01ed0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 7 Dec 2018 17:50:06 -0600 Subject: [PATCH 0465/1995] ASoC: Intel: Skylake: remove useless tests on HDaudio capabilities bus->ppcap is now tested upfront, there is no need to re-check if the hardware is exposed as needed. Remove tests and remove indentation. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7f981bdcf55fda28a9a70c9e8151dd200771a0a8) --- sound/soc/intel/skylake/skl.c | 40 ++++++++++++++++------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 72e366bbba3399..f04e9ec4432bd2 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -826,12 +826,10 @@ static void skl_probe_work(struct work_struct *work) return; } - if (bus->ppcap) { - err = skl_machine_device_register(skl); - if (err < 0) { - dev_err(bus->dev, "machine register failed: %d\n", err); - goto out_err; - } + err = skl_machine_device_register(skl); + if (err < 0) { + dev_err(bus->dev, "machine register failed: %d\n", err); + goto out_err; } /* @@ -1034,25 +1032,23 @@ static int skl_probe(struct pci_dev *pci, pci_set_drvdata(skl->pci, bus); - /* check if dsp is there */ - if (bus->ppcap) { - /* create device for dsp clk */ - err = skl_clock_device_register(skl); - if (err < 0) - goto out_clk_free; + /* create device for dsp clk */ + err = skl_clock_device_register(skl); + if (err < 0) + goto out_clk_free; - err = skl_find_machine(skl, (void *)pci_id->driver_data); - if (err < 0) - goto out_nhlt_free; + err = skl_find_machine(skl, (void *)pci_id->driver_data); + if (err < 0) + goto out_nhlt_free; - err = skl_init_dsp(skl); - if (err < 0) { - dev_dbg(bus->dev, "error failed to register dsp\n"); - goto out_nhlt_free; - } - skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge; - skl->skl_sst->clock_power_gating = skl_clock_power_gating; + err = skl_init_dsp(skl); + if (err < 0) { + dev_dbg(bus->dev, "error failed to register dsp\n"); + goto out_nhlt_free; } + skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge; + skl->skl_sst->clock_power_gating = skl_clock_power_gating; + if (bus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(bus); From ca360bd258fb50cdfe6fbb81241b5c5f00a202ec Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 7 Dec 2018 17:50:07 -0600 Subject: [PATCH 0466/1995] ASoC: Intel: Skylake: add error logs on probe, remove dependency on NHLT Add error logs to make probe debug easier. Also remove hard-coded dependency on NHLT. NHLT literally stands for NonHdaudioLinkTable and is only required for SSP/DMIC interfaces. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit f231c34ca9772f0b0e2d1b781e9c415847aff522) --- sound/soc/intel/skylake/skl-nhlt.c | 3 +++ sound/soc/intel/skylake/skl.c | 41 +++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 01a050cf877537..5d125a3df52792 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -180,6 +180,9 @@ int skl_get_dmic_geo(struct skl *skl) unsigned int dmic_geo = 0; u8 j; + if (!nhlt) + return 0; + epnt = (struct nhlt_endpoint *)nhlt->desc; for (j = 0; j < nhlt->endpoint_count; j++) { diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index f04e9ec4432bd2..f9888b1d552182 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -1010,8 +1010,10 @@ static int skl_probe(struct pci_dev *pci, bus = skl_to_bus(skl); err = skl_first_init(bus); - if (err < 0) + if (err < 0) { + dev_err(bus->dev, "skl_first_init failed with err: %d\n", err); goto out_free; + } skl->pci_id = pci->device; @@ -1020,26 +1022,39 @@ static int skl_probe(struct pci_dev *pci, skl->nhlt = skl_nhlt_init(bus->dev); if (skl->nhlt == NULL) { +#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) + dev_err(bus->dev, "no nhlt info found\n"); err = -ENODEV; goto out_free; - } +#else + dev_warn(bus->dev, "no nhlt info found, continuing to try to enable HDaudio codec\n"); +#endif + } else { - err = skl_nhlt_create_sysfs(skl); - if (err < 0) - goto out_nhlt_free; + err = skl_nhlt_create_sysfs(skl); + if (err < 0) { + dev_err(bus->dev, "skl_nhlt_create_sysfs failed with err: %d\n", err); + goto out_nhlt_free; + } - skl_nhlt_update_topology_bin(skl); + skl_nhlt_update_topology_bin(skl); + + /* create device for dsp clk */ + err = skl_clock_device_register(skl); + if (err < 0) { + dev_err(bus->dev, "skl_clock_device_register failed with err: %d\n", err); + goto out_clk_free; + } + } pci_set_drvdata(skl->pci, bus); - /* create device for dsp clk */ - err = skl_clock_device_register(skl); - if (err < 0) - goto out_clk_free; err = skl_find_machine(skl, (void *)pci_id->driver_data); - if (err < 0) + if (err < 0) { + dev_err(bus->dev, "skl_find_machine failed with err: %d\n", err); goto out_nhlt_free; + } err = skl_init_dsp(skl); if (err < 0) { @@ -1056,8 +1071,10 @@ static int skl_probe(struct pci_dev *pci, /* create device for soc dmic */ err = skl_dmic_device_register(skl); - if (err < 0) + if (err < 0) { + dev_err(bus->dev, "skl_dmic_device_register failed with err: %d\n", err); goto out_dsp_free; + } schedule_work(&skl->probe_work); From 9947b4ff521e84b2697246061ca84f9e6ec7cc68 Mon Sep 17 00:00:00 2001 From: Dimitris Papavasiliou Date: Sat, 24 Nov 2018 22:05:42 +0200 Subject: [PATCH 0467/1995] ASoC: pcm512x: Implement the digital_mute interface Clicks and pops of various volumes can be produced while the device is opened, closed, put into and taken out of standby, or reconfigured. Fix this, by implementing the digital_mute interface, so that the output is muted during such operations. Signed-off-by: Dimitris Papavasiliou Signed-off-by: Mark Brown (cherry picked from commit 3500f1c589e92e0b6b1f8d31b4084fbde08d49cb) --- sound/soc/codecs/pcm512x.c | 121 ++++++++++++++++++++++++++++++++++++- sound/soc/codecs/pcm512x.h | 2 + 2 files changed, 121 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index f0f2d4fd3769f5..6cb1653be80417 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -53,6 +53,8 @@ struct pcm512x_priv { unsigned long overclock_pll; unsigned long overclock_dac; unsigned long overclock_dsp; + int mute; + struct mutex mutex; }; /* @@ -384,6 +386,61 @@ static const struct soc_enum pcm512x_veds = SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4, pcm512x_ramp_step_text); +static int pcm512x_update_mute(struct pcm512x_priv *pcm512x) +{ + return regmap_update_bits( + pcm512x->regmap, PCM512x_MUTE, PCM512x_RQML | PCM512x_RQMR, + (!!(pcm512x->mute & 0x5) << PCM512x_RQML_SHIFT) + | (!!(pcm512x->mute & 0x3) << PCM512x_RQMR_SHIFT)); +} + +static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + + mutex_lock(&pcm512x->mutex); + ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4); + ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2); + mutex_unlock(&pcm512x->mutex); + + return 0; +} + +static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + int ret, changed = 0; + + mutex_lock(&pcm512x->mutex); + + if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) { + pcm512x->mute ^= 0x4; + changed = 1; + } + if ((pcm512x->mute & 0x2) == (ucontrol->value.integer.value[1] << 1)) { + pcm512x->mute ^= 0x2; + changed = 1; + } + + if (changed) { + ret = pcm512x_update_mute(pcm512x); + if (ret != 0) { + dev_err(component->dev, + "Failed to update digital mute: %d\n", ret); + mutex_unlock(&pcm512x->mutex); + return ret; + } + } + + mutex_unlock(&pcm512x->mutex); + + return changed; +} + static const struct snd_kcontrol_new pcm512x_controls[] = { SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2, PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), @@ -391,8 +448,15 @@ SOC_DOUBLE_TLV("Analogue Playback Volume", PCM512x_ANALOG_GAIN_CTRL, PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), -SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, - PCM512x_RQMR_SHIFT, 1, 1), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Digital Playback Switch", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_ctl_boolean_stereo_info, + .get = pcm512x_digital_playback_switch_get, + .put = pcm512x_digital_playback_switch_put +}, SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), SOC_ENUM("DSP Program", pcm512x_dsp_program), @@ -1319,10 +1383,61 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_component *component = dai->component; + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + int ret; + unsigned int mute_det; + + mutex_lock(&pcm512x->mutex); + + if (mute) { + pcm512x->mute |= 0x1; + ret = regmap_update_bits(pcm512x->regmap, PCM512x_MUTE, + PCM512x_RQML | PCM512x_RQMR, + PCM512x_RQML | PCM512x_RQMR); + if (ret != 0) { + dev_err(component->dev, + "Failed to set digital mute: %d\n", ret); + mutex_unlock(&pcm512x->mutex); + return ret; + } + + regmap_read_poll_timeout(pcm512x->regmap, + PCM512x_ANALOG_MUTE_DET, + mute_det, (mute_det & 0x3) == 0, + 200, 10000); + + mutex_unlock(&pcm512x->mutex); + } else { + pcm512x->mute &= ~0x1; + ret = pcm512x_update_mute(pcm512x); + if (ret != 0) { + dev_err(component->dev, + "Failed to update digital mute: %d\n", ret); + mutex_unlock(&pcm512x->mutex); + return ret; + } + + regmap_read_poll_timeout(pcm512x->regmap, + PCM512x_ANALOG_MUTE_DET, + mute_det, + (mute_det & 0x3) + == ((~pcm512x->mute >> 1) & 0x3), + 200, 10000); + } + + mutex_unlock(&pcm512x->mutex); + + return 0; +} + static const struct snd_soc_dai_ops pcm512x_dai_ops = { .startup = pcm512x_dai_startup, .hw_params = pcm512x_hw_params, .set_fmt = pcm512x_set_fmt, + .digital_mute = pcm512x_digital_mute, }; static struct snd_soc_dai_driver pcm512x_dai = { @@ -1388,6 +1503,8 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap) if (!pcm512x) return -ENOMEM; + mutex_init(&pcm512x->mutex); + dev_set_drvdata(dev, pcm512x); pcm512x->regmap = regmap; diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h index d70d9c0c2088c5..9dda8693498ef6 100644 --- a/sound/soc/codecs/pcm512x.h +++ b/sound/soc/codecs/pcm512x.h @@ -112,7 +112,9 @@ #define PCM512x_RQST_SHIFT 4 /* Page 0, Register 3 - mute */ +#define PCM512x_RQMR (1 << 0) #define PCM512x_RQMR_SHIFT 0 +#define PCM512x_RQML (1 << 4) #define PCM512x_RQML_SHIFT 4 /* Page 0, Register 4 - PLL */ From d1804b23f0d35199458eda4bc975684ceea02c47 Mon Sep 17 00:00:00 2001 From: Rohit kumar Date: Thu, 1 Nov 2018 18:08:49 +0530 Subject: [PATCH 0468/1995] ASoC: core: Invoke pcm_new() for all DAI-link Remove no_pcm check to invoke pcm_new() for backend dai-links too. This fixes crash in hdmi codec driver during hdmi_codec_startup() while accessing chmap_info struct. chmap_info struct memory is allocated in pcm_new() of hdmi codec driver which is not invoked in case of DPCM when hdmi codec driver is part of backend dai-link. Below is the crash stack: [ 61.635493] Unable to handle kernel NULL pointer dereference at virtual address 00000018 .. [ 61.666696] CM = 0, WnR = 1 [ 61.669778] user pgtable: 4k pages, 39-bit VAs, pgd = ffffffc0d6633000 [ 61.676526] [0000000000000018] *pgd=0000000153fc8003, *pud=0000000153fc8003, *pmd=0000000000000000 [ 61.685793] Internal error: Oops: 96000046 [#1] PREEMPT SMP [ 61.722955] CPU: 7 PID: 2238 Comm: aplay Not tainted 4.14.72 #21 .. [ 61.740269] PC is at hdmi_codec_startup+0x124/0x164 [ 61.745308] LR is at hdmi_codec_startup+0xe4/0x164 Signed-off-by: Rohit kumar Signed-off-by: Mark Brown (cherry picked from commit de17f14ea576d8a0f2932404467fa916542da94d) --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b0db59e6339d97..0462b3ec977a22 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1467,7 +1467,7 @@ static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, for (i = 0; i < num_dais; ++i) { struct snd_soc_dai_driver *drv = dais[i]->driver; - if (!rtd->dai_link->no_pcm && drv->pcm_new) + if (drv->pcm_new) ret = drv->pcm_new(rtd, dais[i]); if (ret < 0) { dev_err(dais[i]->dev, From d8044c96385f9c9ee53fb289197c4b94554f7da1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 13 Dec 2018 13:03:00 -0600 Subject: [PATCH 0469/1995] ASoC: Intel: Skylake: Add more platform granularity The current SKYLAKE kconfig is a all-you-can-eat selection that will support all known plaforms. This is however not necessarily a good thing: most platforms for SKL and KBL don't support the DSP, but a number of CNL/WHL ones do. Selecting this driver in all cases isn't really smart and will require users to muck with blacklists. Partition the configs to allow distributions to select on which platform this driver is used. Keep the existing SND_SOC_INTEL_SKYLAKE config to select everything for backwards compatibility. This patch does not provide new functionality, only finer-grained choices in supported platforms. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 35bc99aaa1a3af23cf78b6b56f14230b5da3993b) --- sound/soc/intel/Kconfig | 73 ++++++++++++++++++++++++++++++---- sound/soc/intel/boards/Kconfig | 16 +++++++- sound/soc/intel/skylake/skl.c | 12 ++++++ 3 files changed, 92 insertions(+), 9 deletions(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 18e71770368550..99a62ba409df83 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -102,15 +102,74 @@ config SND_SST_ATOM_HIFI2_PLATFORM_ACPI recommended option config SND_SOC_INTEL_SKYLAKE - tristate "SKL/BXT/KBL/GLK/CNL... Platforms" + tristate "All Skylake/SST Platforms" depends on PCI && ACPI - select SND_SOC_INTEL_SKYLAKE_COMMON + select SND_SOC_INTEL_SKL + select SND_SOC_INTEL_APL + select SND_SOC_INTEL_KBL + select SND_SOC_INTEL_GLK + select SND_SOC_INTEL_CNL + select SND_SOC_INTEL_CFL help - If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/ - GeminiLake or CannonLake platform with the DSP enabled in the BIOS - then enable this option by saying Y or m. + This is a backwards-compatible option to select all devices + supported by the Intel SST/Skylake driver. This option is no + longer recommended and will be deprecated when the SOF + driver is introduced. Distributions should explicitly + select which platform uses this driver. + +config SND_SOC_INTEL_SKL + tristate "Skylake Platforms" + depends on PCI && ACPI + select SND_SOC_INTEL_SKYLAKE_FAMILY + help + If you have a Intel Skylake platform with the DSP enabled + in the BIOS then enable this option by saying Y or m. + +config SND_SOC_INTEL_APL + tristate "Broxton/ApolloLake Platforms" + depends on PCI && ACPI + select SND_SOC_INTEL_SKYLAKE_FAMILY + help + If you have a Intel Broxton/ApolloLake platform with the DSP + enabled in the BIOS then enable this option by saying Y or m. + +config SND_SOC_INTEL_KBL + tristate "Kabylake Platforms" + depends on PCI && ACPI + select SND_SOC_INTEL_SKYLAKE_FAMILY + help + If you have a Intel Kabylake platform with the DSP + enabled in the BIOS then enable this option by saying Y or m. + +config SND_SOC_INTEL_GLK + tristate "GeminiLake Platforms" + depends on PCI && ACPI + select SND_SOC_INTEL_SKYLAKE_FAMILY + help + If you have a Intel GeminiLake platform with the DSP + enabled in the BIOS then enable this option by saying Y or m. + +config SND_SOC_INTEL_CNL + tristate "CannonLake/WhiskyLake Platforms" + depends on PCI && ACPI + select SND_SOC_INTEL_SKYLAKE_FAMILY + help + If you have a Intel CNL/WHL platform with the DSP + enabled in the BIOS then enable this option by saying Y or m. + +config SND_SOC_INTEL_CFL + tristate "CoffeeLake Platforms" + depends on PCI && ACPI + select SND_SOC_INTEL_SKYLAKE_FAMILY + help + If you have a Intel CoffeeLake platform with the DSP + enabled in the BIOS then enable this option by saying Y or m. + +config SND_SOC_INTEL_SKYLAKE_FAMILY + tristate + select SND_SOC_INTEL_SKYLAKE_COMMON -if SND_SOC_INTEL_SKYLAKE +if SND_SOC_INTEL_SKYLAKE_FAMILY config SND_SOC_INTEL_SKYLAKE_SSP_CLK tristate @@ -135,7 +194,7 @@ config SND_SOC_INTEL_SKYLAKE_COMMON GeminiLake or CannonLake platform with the DSP enabled in the BIOS then enable this option by saying Y or m. -endif ## SND_SOC_INTEL_SKYLAKE +endif ## SND_SOC_INTEL_SKYLAKE_FAMILY config SND_SOC_ACPI_INTEL_MATCH tristate diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 3839d6205fcf42..0a7e40d0639572 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -172,7 +172,7 @@ config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH endif ## SND_SST_ATOM_HIFI2_PLATFORM -if SND_SOC_INTEL_SKYLAKE +if SND_SOC_INTEL_SKL config SND_SOC_INTEL_SKL_RT286_MACH tristate "SKL with RT286 I2S mode" @@ -212,6 +212,10 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +endif ## SND_SOC_INTEL_SKL + +if SND_SOC_INTEL_APL + config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH tristate "Broxton with DA7219 and MAX98357A in I2S Mode" depends on MFD_INTEL_LPSS && I2C && ACPI @@ -239,6 +243,10 @@ config SND_SOC_INTEL_BXT_RT298_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +endif ## SND_SOC_INTEL_APL + +if SND_SOC_INTEL_KBL + config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH tristate "KBL with RT5663 and MAX98927 in I2S Mode" depends on MFD_INTEL_LPSS && I2C && ACPI @@ -303,6 +311,10 @@ config SND_SOC_INTEL_KBL_RT5660_MACH create an alsa sound card for RT5660 I2S audio codec. Say Y if you have such a device. +endif ## SND_SOC_INTEL_KBL + +if SND_SOC_INTEL_GLK + config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH tristate "GLK with RT5682 and MAX98357A in I2S Mode" depends on MFD_INTEL_LPSS && I2C && ACPI @@ -317,7 +329,7 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH Say Y if you have such a device. If unsure select "N". -endif ## SND_SOC_INTEL_SKYLAKE +endif ## SND_SOC_INTEL_GLK if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index f9888b1d552182..5abd35ca4e4173 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -1142,24 +1142,36 @@ static void skl_remove(struct pci_dev *pci) /* PCI IDs */ static const struct pci_device_id skl_ids[] = { +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL) /* Sunrise Point-LP */ { PCI_DEVICE(0x8086, 0x9d70), .driver_data = (unsigned long)&snd_soc_acpi_intel_skl_machines}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) /* BXT-P */ { PCI_DEVICE(0x8086, 0x5a98), .driver_data = (unsigned long)&snd_soc_acpi_intel_bxt_machines}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) /* KBL */ { PCI_DEVICE(0x8086, 0x9D71), .driver_data = (unsigned long)&snd_soc_acpi_intel_kbl_machines}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK) /* GLK */ { PCI_DEVICE(0x8086, 0x3198), .driver_data = (unsigned long)&snd_soc_acpi_intel_glk_machines}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL) /* CNL */ { PCI_DEVICE(0x8086, 0x9dc8), .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CFL) /* CFL */ { PCI_DEVICE(0x8086, 0xa348), .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, +#endif { 0, } }; MODULE_DEVICE_TABLE(pci, skl_ids); From 3b3b3942657d7900aecce484e2dae7882ee96681 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 15 Nov 2018 18:13:20 +0000 Subject: [PATCH 0470/1995] ALSA: soc-compress: add support to snd_compr_set_runtime_buffer() Existing compress offload code allocates data buffers using simple kmalloc, however there are situations where these buffers have to be mapped in smmu. So provide a way to set the runtime buffer by the driver itself, simillar to what we do with pcm. This patch adds support to set runtime dma buffer on compressed stream. Signed-off-by: Srinivas Kandagatla Acked-by: Vinod Koul Signed-off-by: Mark Brown (cherry picked from commit ba02eed9f300b6512181d526311d4e11aaa9714f) --- include/sound/compress_driver.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index ea8c93bbb0e054..0cdc3999ecfa84 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -23,6 +23,7 @@ struct snd_compr_ops; * struct snd_compr_runtime: runtime stream description * @state: stream state * @ops: pointer to DSP callbacks + * @dma_buffer_p: runtime dma buffer pointer * @buffer: pointer to kernel buffer, valid only when not in mmap mode or * DSP doesn't implement copy * @buffer_size: size of the above buffer @@ -37,6 +38,7 @@ struct snd_compr_ops; struct snd_compr_runtime { snd_pcm_state_t state; struct snd_compr_ops *ops; + struct snd_dma_buffer *dma_buffer_p; void *buffer; u64 buffer_size; u32 fragment_size; @@ -175,6 +177,23 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream) wake_up(&stream->runtime->sleep); } +/** + * snd_compr_set_runtime_buffer - Set the Compress runtime buffer + * @substream: compress substream to set + * @bufp: the buffer information, NULL to clear + * + * Copy the buffer information to runtime buffer when @bufp is non-NULL. + * Otherwise it clears the current buffer information. + */ +static inline void snd_compr_set_runtime_buffer( + struct snd_compr_stream *substream, + struct snd_dma_buffer *bufp) +{ + struct snd_compr_runtime *runtime = substream->runtime; + + runtime->dma_buffer_p = bufp; +} + int snd_compr_stop_error(struct snd_compr_stream *stream, snd_pcm_state_t state); From 1a6726b7dc590ec1c7760c7ef632fc0cc84bc8e6 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 15 Nov 2018 18:13:21 +0000 Subject: [PATCH 0471/1995] ALSA: compress: make use of runtime buffer for copy Default copy function uses kmalloc to allocate buffers, lets check if the runtime buffers are setup before making this allocations. This can be useful if the buffers are dma buffers. Signed-off-by: Srinivas Kandagatla Acked-by: Vinod Koul Signed-off-by: Mark Brown (cherry picked from commit d00f749b00f7802bf944688ad2971455f84fdacb) --- sound/core/compress_offload.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 26b5e245b0747d..a5b09e75e7874b 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -171,7 +171,8 @@ static int snd_compr_free(struct inode *inode, struct file *f) } data->stream.ops->free(&data->stream); - kfree(data->stream.runtime->buffer); + if (!data->stream.runtime->dma_buffer_p) + kfree(data->stream.runtime->buffer); kfree(data->stream.runtime); kfree(data); return 0; @@ -505,7 +506,7 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream, struct snd_compr_params *params) { unsigned int buffer_size; - void *buffer; + void *buffer = NULL; buffer_size = params->buffer.fragment_size * params->buffer.fragments; if (stream->ops->copy) { @@ -514,7 +515,18 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream, * the data from core */ } else { - buffer = kmalloc(buffer_size, GFP_KERNEL); + if (stream->runtime->dma_buffer_p) { + + if (buffer_size > stream->runtime->dma_buffer_p->bytes) + dev_err(&stream->device->dev, + "Not enough DMA buffer"); + else + buffer = stream->runtime->dma_buffer_p->area; + + } else { + buffer = kmalloc(buffer_size, GFP_KERNEL); + } + if (!buffer) return -ENOMEM; } From f3f0ea1687db8980d0c447707969489d799cf59e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Dec 2018 15:11:09 +0100 Subject: [PATCH 0472/1995] ALSA: hda/intel: Refactoring PM code Make unified suspend / resume helpers and call them from both the runtime- and the system-PM callbacks for simplifying code. There are slight changes of call orders, but there shouldn't be any functional difference after refactoring. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 160 ++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 91 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 4b7666e0374cb2..6bf3067b246029 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -985,35 +985,82 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) mutex_unlock(&card_list_lock); return 0; } -#else -#define azx_add_card_list(chip) /* NOP */ -#define azx_del_card_list(chip) /* NOP */ -#endif /* CONFIG_PM */ -#ifdef CONFIG_PM_SLEEP /* * power management */ -static int azx_suspend(struct device *dev) +static bool azx_is_pm_ready(struct snd_card *card) { - struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; struct hda_intel *hda; - struct hdac_bus *bus; if (!card) - return 0; - + return false; chip = card->private_data; hda = container_of(chip, struct hda_intel, chip); if (chip->disabled || hda->init_failed || !chip->running) + return false; + return true; +} + +static void __azx_runtime_suspend(struct azx *chip) +{ + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + + azx_stop_chip(chip); + azx_enter_link_reset(chip); + azx_clear_irq_pending(chip); + if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && + hda->need_i915_power) + snd_hdac_display_power(azx_bus(chip), false); +} + +static void __azx_runtime_resume(struct azx *chip) +{ + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct hdac_bus *bus = azx_bus(chip); + struct hda_codec *codec; + int status; + + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { + snd_hdac_display_power(bus, true); + if (hda->need_i915_power) + snd_hdac_i915_set_bclk(bus); + } + + /* Read STATESTS before controller reset */ + status = azx_readw(chip, STATESTS); + + azx_init_pci(chip); + hda_intel_init_chip(chip, true); + + if (status) { + list_for_each_codec(codec, &chip->bus) + if (status & (1 << codec->addr)) + schedule_delayed_work(&codec->jackpoll_work, + codec->jackpoll_interval); + } + + /* power down again for link-controlled chips */ + if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && + !hda->need_i915_power) + snd_hdac_display_power(bus, false); +} + +#ifdef CONFIG_PM_SLEEP +static int azx_suspend(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip; + struct hdac_bus *bus; + + if (!azx_is_pm_ready(card)) return 0; + chip = card->private_data; bus = azx_bus(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - azx_clear_irq_pending(chip); - azx_stop_chip(chip); - azx_enter_link_reset(chip); + __azx_runtime_suspend(chip); if (bus->irq >= 0) { free_irq(bus->irq, chip); bus->irq = -1; @@ -1021,9 +1068,6 @@ static int azx_suspend(struct device *dev) if (chip->msi) pci_disable_msi(chip->pci); - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - && hda->need_i915_power) - snd_hdac_display_power(bus, false); trace_azx_suspend(chip); return 0; @@ -1031,41 +1075,19 @@ static int azx_suspend(struct device *dev) static int azx_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; - struct hda_intel *hda; - struct hdac_bus *bus; - if (!card) + if (!azx_is_pm_ready(card)) return 0; chip = card->private_data; - hda = container_of(chip, struct hda_intel, chip); - bus = azx_bus(chip); - if (chip->disabled || hda->init_failed || !chip->running) - return 0; - - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - snd_hdac_display_power(bus, true); - if (hda->need_i915_power) - snd_hdac_i915_set_bclk(bus); - } - if (chip->msi) - if (pci_enable_msi(pci) < 0) + if (pci_enable_msi(chip->pci) < 0) chip->msi = 0; if (azx_acquire_irq(chip, 1) < 0) return -EIO; - azx_init_pci(chip); - - hda_intel_init_chip(chip, true); - - /* power down again for link-controlled chips */ - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && - !hda->need_i915_power) - snd_hdac_display_power(bus, false); - + __azx_runtime_resume(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D0); trace_azx_resume(chip); @@ -1100,21 +1122,14 @@ static int azx_thaw_noirq(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -#ifdef CONFIG_PM static int azx_runtime_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; - struct hda_intel *hda; - if (!card) + if (!azx_is_pm_ready(card)) return 0; - chip = card->private_data; - hda = container_of(chip, struct hda_intel, chip); - if (chip->disabled || hda->init_failed) - return 0; - if (!azx_has_pm_runtime(chip)) return 0; @@ -1122,13 +1137,7 @@ static int azx_runtime_suspend(struct device *dev) azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) | STATESTS_INT_MASK); - azx_stop_chip(chip); - azx_enter_link_reset(chip); - azx_clear_irq_pending(chip); - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - && hda->need_i915_power) - snd_hdac_display_power(azx_bus(chip), false); - + __azx_runtime_suspend(chip); trace_azx_runtime_suspend(chip); return 0; } @@ -1137,51 +1146,18 @@ static int azx_runtime_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; - struct hda_intel *hda; - struct hdac_bus *bus; - struct hda_codec *codec; - int status; - if (!card) + if (!azx_is_pm_ready(card)) return 0; - chip = card->private_data; - hda = container_of(chip, struct hda_intel, chip); - bus = azx_bus(chip); - if (chip->disabled || hda->init_failed) - return 0; - if (!azx_has_pm_runtime(chip)) return 0; - - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - snd_hdac_display_power(bus, true); - if (hda->need_i915_power) - snd_hdac_i915_set_bclk(bus); - } - - /* Read STATESTS before controller reset */ - status = azx_readw(chip, STATESTS); - - azx_init_pci(chip); - hda_intel_init_chip(chip, true); - - if (status) { - list_for_each_codec(codec, &chip->bus) - if (status & (1 << codec->addr)) - schedule_delayed_work(&codec->jackpoll_work, - codec->jackpoll_interval); - } + __azx_runtime_resume(chip); /* disable controller Wake Up event*/ azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & ~STATESTS_INT_MASK); - /* power down again for link-controlled chips */ - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && - !hda->need_i915_power) - snd_hdac_display_power(bus, false); - trace_azx_runtime_resume(chip); return 0; } @@ -1222,6 +1198,8 @@ static const struct dev_pm_ops azx_pm = { #define AZX_PM_OPS &azx_pm #else +#define azx_add_card_list(chip) /* NOP */ +#define azx_del_card_list(chip) /* NOP */ #define AZX_PM_OPS NULL #endif /* CONFIG_PM */ From 44b39a5aaee16f1c595e82f119d324de509ecd1d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 8 Dec 2018 17:31:49 +0100 Subject: [PATCH 0473/1995] ALSA: hda: Refactor display power management The current HD-audio code manages the DRM audio power via too complex redirections, and this seems even still unbalanced in a corner case as Intel DRM CI has been intermittently reporting. This patch is a big surgery for addressing the complexity and the possible unbalance. Basically the patch changes the display PM in the following ways: - Both HD-audio controller and codec drivers call a single helper, snd_hdac_display_power(). (Formerly, the display power control from a codec was done indirectly via link_power bus ops.) - snd_hdac_display_power() receives the codec address index. For turning on/off from the controller, pass HDA_CODEC_IDX_CONTROLLER. - snd_hdac_display_power() doesn't manage refcounts any longer, but keeps the power status in bitmap. If any of controller or codecs is turned on, the function updates the DRM power state via get_power() or put_power(). Also this refactor allows us more cleanup: - The link_power bus ops is dropped, so there is no longer indirect management, as mentioned in the above. - hdac_device link_power_control flag is moved to hda_codec display_power_control flag, as it's only for HDA legacy. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106525 Signed-off-by: Takashi Iwai --- include/sound/hda_codec.h | 1 + include/sound/hda_component.h | 10 ++++++++-- include/sound/hdaudio.h | 7 ++----- sound/hda/hdac_component.c | 35 +++++++++++++++++++++------------- sound/hda/hdac_device.c | 17 ----------------- sound/pci/hda/hda_codec.c | 16 ++++++++++++---- sound/pci/hda/hda_controller.c | 11 ----------- sound/pci/hda/hda_intel.c | 22 ++++++++------------- sound/pci/hda/patch_hdmi.c | 4 ++-- sound/soc/codecs/hdac_hdmi.c | 7 +++---- sound/soc/intel/skylake/skl.c | 10 +++++----- 11 files changed, 63 insertions(+), 77 deletions(-) diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index 0d98bb9068b178..7fa48b10093618 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -236,6 +236,7 @@ struct hda_codec { /* misc flags */ unsigned int in_freeing:1; /* being released */ unsigned int registered:1; /* codec was registered */ + unsigned int display_power_control:1; /* needs display power */ unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each * status change * (e.g. Realtek codecs) diff --git a/include/sound/hda_component.h b/include/sound/hda_component.h index 78626cde70811a..767c8d8a0230ba 100644 --- a/include/sound/hda_component.h +++ b/include/sound/hda_component.h @@ -5,10 +5,15 @@ #define __SOUND_HDA_COMPONENT_H #include +#include + +/* virtual idx for controller */ +#define HDA_CODEC_IDX_CONTROLLER HDA_MAX_CODECS #ifdef CONFIG_SND_HDA_COMPONENT int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable); -int snd_hdac_display_power(struct hdac_bus *bus, bool enable); +int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, + bool enable); int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int dev_id, int rate); int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id, @@ -25,7 +30,8 @@ static inline int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) { return 0; } -static inline int snd_hdac_display_power(struct hdac_bus *bus, bool enable) +static inline int snd_hdac_display_power(struct hdac_bus *bus, + unsigned int idx, bool enable) { return 0; } diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index cd1773d0e08f07..940e2b28213358 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -79,7 +79,6 @@ struct hdac_device { /* misc flags */ atomic_t in_pm; /* suspend/resume being performed */ - bool link_power_control:1; /* sysfs */ struct hdac_widget_tree *widgets; @@ -237,8 +236,6 @@ struct hdac_bus_ops { /* get a response from the last command */ int (*get_response)(struct hdac_bus *bus, unsigned int addr, unsigned int *res); - /* control the link power */ - int (*link_power)(struct hdac_bus *bus, bool enable); }; /* @@ -363,7 +360,8 @@ struct hdac_bus { /* DRM component interface */ struct drm_audio_component *audio_component; - int drm_power_refcount; + long display_power_status; + bool display_power_active; /* parameters required for enhanced capabilities */ int num_streams; @@ -404,7 +402,6 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val); int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr, unsigned int *res); int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus); -int snd_hdac_link_power(struct hdac_device *codec, bool enable); bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset); void snd_hdac_bus_stop_chip(struct hdac_bus *bus); diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c index 6e46a9c73aed46..dd766414436be3 100644 --- a/sound/hda/hdac_component.c +++ b/sound/hda/hdac_component.c @@ -54,38 +54,45 @@ EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup); /** * snd_hdac_display_power - Power up / down the power refcount * @bus: HDA core bus + * @idx: HDA codec address, pass HDA_CODEC_IDX_CONTROLLER for controller * @enable: power up or down * - * This function is supposed to be used only by a HD-audio controller - * driver that needs the interaction with graphics driver. + * This function is used by either HD-audio controller or codec driver that + * needs the interaction with graphics driver. * - * This function manages a refcount and calls the get_power() and + * This function updates the power status, and calls the get_power() and * put_power() ops accordingly, toggling the codec wakeup, too. * * Returns zero for success or a negative error code. */ -int snd_hdac_display_power(struct hdac_bus *bus, bool enable) +int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) { struct drm_audio_component *acomp = bus->audio_component; - if (!acomp || !acomp->ops) - return -ENODEV; - dev_dbg(bus->dev, "display power %s\n", enable ? "enable" : "disable"); + if (enable) + set_bit(idx, &bus->display_power_status); + else + clear_bit(idx, &bus->display_power_status); - if (enable) { - if (!bus->drm_power_refcount++) { + if (!acomp || !acomp->ops) + return 0; + + if (bus->display_power_status) { + if (!bus->display_power_active) { if (acomp->ops->get_power) acomp->ops->get_power(acomp->dev); snd_hdac_set_codec_wakeup(bus, true); snd_hdac_set_codec_wakeup(bus, false); + bus->display_power_active = true; } } else { - WARN_ON(!bus->drm_power_refcount); - if (!--bus->drm_power_refcount) + if (bus->display_power_active) { if (acomp->ops->put_power) acomp->ops->put_power(acomp->dev); + bus->display_power_active = false; + } } return 0; @@ -321,10 +328,12 @@ int snd_hdac_acomp_exit(struct hdac_bus *bus) if (!acomp) return 0; - WARN_ON(bus->drm_power_refcount); - if (bus->drm_power_refcount > 0 && acomp->ops) + if (WARN_ON(bus->display_power_active) && acomp->ops) acomp->ops->put_power(acomp->dev); + bus->display_power_active = false; + bus->display_power_status = 0; + component_master_del(dev, &hdac_component_master_ops); bus->audio_component = NULL; diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index dbf02a3a8d2f28..95b073ee4b32bb 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -622,23 +622,6 @@ int snd_hdac_power_down_pm(struct hdac_device *codec) EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm); #endif -/** - * snd_hdac_link_power - Enable/disable the link power for a codec - * @codec: the codec object - * @bool: enable or disable the link power - */ -int snd_hdac_link_power(struct hdac_device *codec, bool enable) -{ - if (!codec->link_power_control) - return 0; - - if (codec->bus->ops->link_power) - return codec->bus->ops->link_power(codec->bus, enable); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_hdac_link_power); - /* codec vendor labels */ struct hda_vendor_id { unsigned int id; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0957813939e5cf..9f8d59e7e89f46 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -36,6 +36,7 @@ #include "hda_beep.h" #include "hda_jack.h" #include +#include #define codec_in_pm(codec) snd_hdac_is_in_pm(&codec->core) #define hda_codec_is_power_on(codec) snd_hdac_is_power_on(&codec->core) @@ -799,6 +800,13 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec) static unsigned int hda_set_power_state(struct hda_codec *codec, unsigned int power_state); +/* enable/disable display power per codec */ +static void codec_display_power(struct hda_codec *codec, bool enable) +{ + if (codec->display_power_control) + snd_hdac_display_power(&codec->bus->core, codec->addr, enable); +} + /* also called from hda_bind.c */ void snd_hda_codec_register(struct hda_codec *codec) { @@ -806,7 +814,7 @@ void snd_hda_codec_register(struct hda_codec *codec) return; if (device_is_registered(hda_codec_dev(codec))) { snd_hda_register_beep_device(codec); - snd_hdac_link_power(&codec->core, true); + codec_display_power(codec, true); pm_runtime_enable(hda_codec_dev(codec)); /* it was powered up in snd_hda_codec_new(), now all done */ snd_hda_power_down(codec); @@ -834,7 +842,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device) codec->in_freeing = 1; snd_hdac_device_unregister(&codec->core); - snd_hdac_link_power(&codec->core, false); + codec_display_power(codec, false); put_device(hda_codec_dev(codec)); return 0; } @@ -2926,7 +2934,7 @@ static int hda_codec_runtime_suspend(struct device *dev) (codec_has_clkstop(codec) && codec_has_epss(codec) && (state & AC_PWRST_CLK_STOP_OK))) snd_hdac_codec_link_down(&codec->core); - snd_hdac_link_power(&codec->core, false); + codec_display_power(codec, false); return 0; } @@ -2934,7 +2942,7 @@ static int hda_codec_runtime_resume(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); - snd_hdac_link_power(&codec->core, true); + codec_display_power(codec, true); snd_hdac_codec_link_up(&codec->core); hda_call_codec_resume(codec); pm_runtime_mark_last_busy(dev); diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index a12e594d4e3b3a..358e3a70c5d3f8 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -986,20 +986,9 @@ static int azx_get_response(struct hdac_bus *bus, unsigned int addr, return azx_rirb_get_response(bus, addr, res); } -static int azx_link_power(struct hdac_bus *bus, bool enable) -{ - struct azx *chip = bus_to_azx(bus); - - if (chip->ops->link_power) - return chip->ops->link_power(chip, enable); - else - return -EINVAL; -} - static const struct hdac_bus_ops bus_core_ops = { .command = azx_send_cmd, .get_response = azx_get_response, - .link_power = azx_link_power, }; #ifdef CONFIG_SND_HDA_DSP_LOADER diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 6bf3067b246029..3d00e7463a7121 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -722,13 +722,8 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) return 0; } -/* Enable/disable i915 display power for the link */ -static int azx_intel_link_power(struct azx *chip, bool enable) -{ - struct hdac_bus *bus = azx_bus(chip); - - return snd_hdac_display_power(bus, enable); -} +#define display_power(chip, enable) \ + snd_hdac_display_power(azx_bus(chip), HDA_CODEC_IDX_CONTROLLER, enable) /* * Check whether the current DMA position is acceptable for updating @@ -1012,7 +1007,7 @@ static void __azx_runtime_suspend(struct azx *chip) azx_clear_irq_pending(chip); if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && hda->need_i915_power) - snd_hdac_display_power(azx_bus(chip), false); + display_power(chip, false); } static void __azx_runtime_resume(struct azx *chip) @@ -1023,7 +1018,7 @@ static void __azx_runtime_resume(struct azx *chip) int status; if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - snd_hdac_display_power(bus, true); + display_power(chip, true); if (hda->need_i915_power) snd_hdac_i915_set_bclk(bus); } @@ -1044,7 +1039,7 @@ static void __azx_runtime_resume(struct azx *chip) /* power down again for link-controlled chips */ if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && !hda->need_i915_power) - snd_hdac_display_power(bus, false); + display_power(chip, false); } #ifdef CONFIG_PM_SLEEP @@ -1410,7 +1405,7 @@ static int azx_free(struct azx *chip) if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { if (hda->need_i915_power) - snd_hdac_display_power(bus, false); + display_power(chip, false); } if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT) snd_hdac_i915_exit(bus); @@ -2138,7 +2133,6 @@ static const struct hda_controller_ops pci_hda_ops = { .substream_free_pages = substream_free_pages, .pcm_mmap_prepare = pcm_mmap_prepare, .position_check = azx_position_check, - .link_power = azx_intel_link_power, }; static int azx_probe(struct pci_dev *pci, @@ -2315,7 +2309,7 @@ static int azx_probe_continue(struct azx *chip) if (CONTROLLER_IN_GPU(pci)) hda->need_i915_power = 1; - err = snd_hdac_display_power(bus, true); + err = display_power(chip, true); if (err < 0) { dev_err(chip->card->dev, "Cannot turn on display power on i915\n"); @@ -2371,7 +2365,7 @@ static int azx_probe_continue(struct azx *chip) out_free: if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && !hda->need_i915_power) - snd_hdac_display_power(bus, false); + display_power(chip, false); i915_power_fail: if (err < 0) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 67099cbb6be2f2..30fe4dbdb0ae9b 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2620,7 +2620,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid) * can cover the codec power request, and so need not set this flag. */ if (!is_haswell(codec) && !is_broadwell(codec)) - codec->core.link_power_control = 1; + codec->display_power_control = 1; codec->patch_ops.set_power_state = haswell_set_power_state; codec->depop_delay = 0; @@ -2656,7 +2656,7 @@ static int patch_i915_byt_hdmi(struct hda_codec *codec) /* For Valleyview/Cherryview, only the display codec is in the display * power well and can use link_power ops to request/release the power. */ - codec->core.link_power_control = 1; + codec->display_power_control = 1; codec->depop_delay = 0; codec->auto_runtime_pm = 1; diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index db709eeb019c78..6ef0cdc0ed7dd9 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2074,14 +2074,13 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) * Turned off in the runtime_suspend during the first explicit * pm_runtime_suspend call. */ - ret = snd_hdac_display_power(hdev->bus, true); + ret = snd_hdac_display_power(hdev->bus, hdev->addr, true); if (ret < 0) { dev_err(&hdev->dev, "Cannot turn on display power on i915 err: %d\n", ret); return ret; } - ret = hdac_hdmi_parse_and_map_nid(hdev, &hdmi_dais, &num_dais); if (ret < 0) { dev_err(&hdev->dev, @@ -2239,7 +2238,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) snd_hdac_ext_bus_link_put(bus, hlink); - err = snd_hdac_display_power(bus, false); + err = snd_hdac_display_power(bus, hdev->addr, false); if (err < 0) dev_err(dev, "Cannot turn off display power on i915\n"); @@ -2267,7 +2266,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev) snd_hdac_ext_bus_link_get(bus, hlink); - err = snd_hdac_display_power(bus, true); + err = snd_hdac_display_power(bus, hdev->addr, true); if (err < 0) { dev_err(dev, "Cannot turn on display power on i915\n"); return err; diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 5abd35ca4e4173..531182299c41c9 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -334,7 +334,7 @@ static int skl_suspend(struct device *dev) } if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, false); + ret = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); if (ret < 0) dev_err(bus->dev, "Cannot turn OFF display power on i915\n"); @@ -353,7 +353,7 @@ static int skl_resume(struct device *dev) /* Turned OFF in HDMI codec driver after codec reconfiguration */ if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, true); + ret = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); if (ret < 0) { dev_err(bus->dev, "Cannot turn on display power on i915\n"); @@ -786,7 +786,7 @@ static int skl_i915_init(struct hdac_bus *bus) if (err < 0) return err; - err = snd_hdac_display_power(bus, true); + err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); if (err < 0) dev_err(bus->dev, "Cannot turn on display power on i915\n"); @@ -839,7 +839,7 @@ static void skl_probe_work(struct work_struct *work) snd_hdac_ext_bus_link_put(bus, hlink); if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - err = snd_hdac_display_power(bus, false); + err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); if (err < 0) { dev_err(bus->dev, "Cannot turn off display power on i915\n"); skl_machine_device_unregister(skl); @@ -856,7 +856,7 @@ static void skl_probe_work(struct work_struct *work) out_err: if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - err = snd_hdac_display_power(bus, false); + err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); } /* From 03220678d40a8767de43c66dd0fa63112f3d73a3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 09:57:37 +0100 Subject: [PATCH 0474/1995] ALSA: hda/intel: Drop superfluous AZX_DCAPS_I915_POWERWELL checks snd_hdac_display_power() can be called even for a HDA controller without DRM binding. The same is true for other helpers, snd_hdac_i915_set_bclk() and snd_hdac_set_codec_wakeup(). So all superfluous AZX_DCAPS_I915_POWERWELL checks in hda_intel.c can be dropped, and the definition of AZX_DCAPS_I915_POWERWELL itself can be removed as well. This simplifies the code a lot. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.h | 6 +-- sound/pci/hda/hda_intel.c | 73 +++++++++++++--------------------- 2 files changed, 28 insertions(+), 51 deletions(-) diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 55760e5231e62b..f099f8452dcfca 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -50,11 +50,7 @@ /* 24 unused */ #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ -#ifdef CONFIG_SND_HDA_I915 -#define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ -#else -#define AZX_DCAPS_I915_POWERWELL 0 /* NOP */ -#endif +/* 27 unused */ #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ #define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */ #define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3d00e7463a7121..f465b97486f837 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -310,31 +310,28 @@ enum { #define AZX_DCAPS_INTEL_HASWELL \ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\ AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL | AZX_DCAPS_SNOOP_TYPE(SCH)) + AZX_DCAPS_SNOOP_TYPE(SCH)) /* Broadwell HDMI can't use position buffer reliably, force to use LPIB */ #define AZX_DCAPS_INTEL_BROADWELL \ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_POSFIX_LPIB |\ AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL | AZX_DCAPS_SNOOP_TYPE(SCH)) + AZX_DCAPS_SNOOP_TYPE(SCH)) #define AZX_DCAPS_INTEL_BAYTRAIL \ - (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL) + (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT) #define AZX_DCAPS_INTEL_BRASWELL \ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ - AZX_DCAPS_I915_COMPONENT | AZX_DCAPS_I915_POWERWELL) + AZX_DCAPS_I915_COMPONENT) #define AZX_DCAPS_INTEL_SKYLAKE \ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ - AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL) + AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT) #define AZX_DCAPS_INTEL_BROXTON \ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ - AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL) + AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT) /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ @@ -646,8 +643,7 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) struct pci_dev *pci = chip->pci; u32 val; - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - snd_hdac_set_codec_wakeup(bus, true); + snd_hdac_set_codec_wakeup(bus, true); if (chip->driver_type == AZX_DRIVER_SKL) { pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val); val = val & ~INTEL_HDA_CGCTL_MISCBDCGE; @@ -659,8 +655,8 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) val = val | INTEL_HDA_CGCTL_MISCBDCGE; pci_write_config_dword(pci, INTEL_HDA_CGCTL, val); } - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - snd_hdac_set_codec_wakeup(bus, false); + + snd_hdac_set_codec_wakeup(bus, false); /* reduce dma latency to avoid noise */ if (IS_BXT(pci)) @@ -1000,14 +996,10 @@ static bool azx_is_pm_ready(struct snd_card *card) static void __azx_runtime_suspend(struct azx *chip) { - struct hda_intel *hda = container_of(chip, struct hda_intel, chip); - azx_stop_chip(chip); azx_enter_link_reset(chip); azx_clear_irq_pending(chip); - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && - hda->need_i915_power) - display_power(chip, false); + display_power(chip, false); } static void __azx_runtime_resume(struct azx *chip) @@ -1017,11 +1009,9 @@ static void __azx_runtime_resume(struct azx *chip) struct hda_codec *codec; int status; - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - display_power(chip, true); - if (hda->need_i915_power) - snd_hdac_i915_set_bclk(bus); - } + display_power(chip, true); + if (hda->need_i915_power) + snd_hdac_i915_set_bclk(bus); /* Read STATESTS before controller reset */ status = azx_readw(chip, STATESTS); @@ -1037,8 +1027,7 @@ static void __azx_runtime_resume(struct azx *chip) } /* power down again for link-controlled chips */ - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && - !hda->need_i915_power) + if (!hda->need_i915_power) display_power(chip, false); } @@ -1402,11 +1391,8 @@ static int azx_free(struct azx *chip) #ifdef CONFIG_SND_HDA_PATCH_LOADER release_firmware(chip->fw); #endif + display_power(chip, false); - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - if (hda->need_i915_power) - display_power(chip, false); - } if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT) snd_hdac_i915_exit(bus); kfree(hda); @@ -1957,8 +1943,7 @@ static int azx_first_init(struct azx *chip) /* initialize chip */ azx_init_pci(chip); - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - snd_hdac_i915_set_bclk(bus); + snd_hdac_i915_set_bclk(bus); hda_intel_init_chip(chip, (probe_only[dev] & 2) == 0); @@ -2293,10 +2278,13 @@ static int azx_probe_continue(struct azx *chip) goto out_free; } else { /* don't bother any longer */ - chip->driver_caps &= - ~(AZX_DCAPS_I915_COMPONENT | AZX_DCAPS_I915_POWERWELL); + chip->driver_caps &= ~AZX_DCAPS_I915_COMPONENT; } } + + /* HSW/BDW controllers need this power */ + if (CONTROLLER_IN_GPU(pci)) + hda->need_i915_power = 1; } /* Request display power well for the HDA controller or codec. For @@ -2304,17 +2292,11 @@ static int azx_probe_continue(struct azx *chip) * this power. For other platforms, like Baytrail/Braswell, only the * display codec needs the power and it can be released after probe. */ - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - /* HSW/BDW controllers need this power */ - if (CONTROLLER_IN_GPU(pci)) - hda->need_i915_power = 1; - - err = display_power(chip, true); - if (err < 0) { - dev_err(chip->card->dev, - "Cannot turn on display power on i915\n"); - goto i915_power_fail; - } + err = display_power(chip, true); + if (err < 0) { + dev_err(chip->card->dev, + "Cannot turn on display power on i915\n"); + goto i915_power_fail; } err = azx_first_init(chip); @@ -2363,8 +2345,7 @@ static int azx_probe_continue(struct azx *chip) pm_runtime_put_autosuspend(&pci->dev); out_free: - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - && !hda->need_i915_power) + if (!hda->need_i915_power) display_power(chip, false); i915_power_fail: From 620575a906854390a46e38609b4d3f84ba94dfba Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 09:59:03 +0100 Subject: [PATCH 0475/1995] ALSA: hda/intel: Properly free the display power at error path When an error occurs in azx_probe_continue(), we should release the display power. However, the current code ignores it and releases the display power only for HSW/BDW cases. Fix it. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f465b97486f837..cc4ae289bcdfbc 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2345,7 +2345,7 @@ static int azx_probe_continue(struct azx *chip) pm_runtime_put_autosuspend(&pci->dev); out_free: - if (!hda->need_i915_power) + if (err < 0 || !hda->need_i915_power) display_power(chip, false); i915_power_fail: From bc2fd8189144bab6354f06aebdb15446dafdfa0b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 10:04:25 +0100 Subject: [PATCH 0476/1995] ALSA: hda: Make snd_hdac_display_power() void function After the recent refactoring, snd_hdac_display_power() doesn't return any error, hence it can be defined to return void. This makes many error checks redundant and allows us to reduce them gracefully. Signed-off-by: Takashi Iwai --- include/sound/hda_component.h | 9 ++++---- sound/hda/hdac_component.c | 8 ++----- sound/pci/hda/hda_intel.c | 9 +------- sound/soc/codecs/hdac_hdmi.c | 23 +++++--------------- sound/soc/intel/skylake/skl.c | 40 ++++++++++------------------------- 5 files changed, 23 insertions(+), 66 deletions(-) diff --git a/include/sound/hda_component.h b/include/sound/hda_component.h index 767c8d8a0230ba..2ec31b35895045 100644 --- a/include/sound/hda_component.h +++ b/include/sound/hda_component.h @@ -12,8 +12,8 @@ #ifdef CONFIG_SND_HDA_COMPONENT int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable); -int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, - bool enable); +void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, + bool enable); int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int dev_id, int rate); int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id, @@ -30,10 +30,9 @@ static inline int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) { return 0; } -static inline int snd_hdac_display_power(struct hdac_bus *bus, - unsigned int idx, bool enable) +static inline void snd_hdac_display_power(struct hdac_bus *bus, + unsigned int idx, bool enable) { - return 0; } static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int dev_id, int rate) diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c index dd766414436be3..a6d37b9d6413f5 100644 --- a/sound/hda/hdac_component.c +++ b/sound/hda/hdac_component.c @@ -62,10 +62,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup); * * This function updates the power status, and calls the get_power() and * put_power() ops accordingly, toggling the codec wakeup, too. - * - * Returns zero for success or a negative error code. */ -int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) +void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) { struct drm_audio_component *acomp = bus->audio_component; @@ -77,7 +75,7 @@ int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) clear_bit(idx, &bus->display_power_status); if (!acomp || !acomp->ops) - return 0; + return; if (bus->display_power_status) { if (!bus->display_power_active) { @@ -94,8 +92,6 @@ int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) bus->display_power_active = false; } } - - return 0; } EXPORT_SYMBOL_GPL(snd_hdac_display_power); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cc4ae289bcdfbc..d0feeaa7bee4dc 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2292,12 +2292,7 @@ static int azx_probe_continue(struct azx *chip) * this power. For other platforms, like Baytrail/Braswell, only the * display codec needs the power and it can be released after probe. */ - err = display_power(chip, true); - if (err < 0) { - dev_err(chip->card->dev, - "Cannot turn on display power on i915\n"); - goto i915_power_fail; - } + display_power(chip, true); err = azx_first_init(chip); if (err < 0) @@ -2347,8 +2342,6 @@ static int azx_probe_continue(struct azx *chip) out_free: if (err < 0 || !hda->need_i915_power) display_power(chip, false); - -i915_power_fail: if (err < 0) hda->init_failed = 1; complete_all(&hda->probe_wait); diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 6ef0cdc0ed7dd9..3fc1b312fc4391 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2074,13 +2074,8 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) * Turned off in the runtime_suspend during the first explicit * pm_runtime_suspend call. */ - ret = snd_hdac_display_power(hdev->bus, hdev->addr, true); - if (ret < 0) { - dev_err(&hdev->dev, - "Cannot turn on display power on i915 err: %d\n", - ret); - return ret; - } + snd_hdac_display_power(hdev->bus, hdev->addr, true); + ret = hdac_hdmi_parse_and_map_nid(hdev, &hdmi_dais, &num_dais); if (ret < 0) { dev_err(&hdev->dev, @@ -2212,7 +2207,6 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) struct hdac_device *hdev = dev_to_hdac_dev(dev); struct hdac_bus *bus = hdev->bus; struct hdac_ext_link *hlink = NULL; - int err; dev_dbg(dev, "Enter: %s\n", __func__); @@ -2238,11 +2232,9 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) snd_hdac_ext_bus_link_put(bus, hlink); - err = snd_hdac_display_power(bus, hdev->addr, false); - if (err < 0) - dev_err(dev, "Cannot turn off display power on i915\n"); + snd_hdac_display_power(bus, hdev->addr, false); - return err; + return 0; } static int hdac_hdmi_runtime_resume(struct device *dev) @@ -2250,7 +2242,6 @@ static int hdac_hdmi_runtime_resume(struct device *dev) struct hdac_device *hdev = dev_to_hdac_dev(dev); struct hdac_bus *bus = hdev->bus; struct hdac_ext_link *hlink = NULL; - int err; dev_dbg(dev, "Enter: %s\n", __func__); @@ -2266,11 +2257,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev) snd_hdac_ext_bus_link_get(bus, hlink); - err = snd_hdac_display_power(bus, hdev->addr, true); - if (err < 0) { - dev_err(dev, "Cannot turn on display power on i915\n"); - return err; - } + snd_hdac_display_power(bus, hdev->addr, true); hdac_hdmi_skl_enable_all_pins(hdev); hdac_hdmi_skl_enable_dp12(hdev); diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 531182299c41c9..29d9b0eb83ea15 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -311,7 +311,7 @@ static int skl_suspend(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct hdac_bus *bus = pci_get_drvdata(pci); struct skl *skl = bus_to_skl(bus); - int ret = 0; + int ret; /* * Do not suspend if streams which are marked ignore suspend are @@ -333,14 +333,10 @@ static int skl_suspend(struct device *dev) skl->skl_sst->fw_loaded = false; } - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - if (ret < 0) - dev_err(bus->dev, - "Cannot turn OFF display power on i915\n"); - } + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - return ret; + return 0; } static int skl_resume(struct device *dev) @@ -352,14 +348,8 @@ static int skl_resume(struct device *dev) int ret; /* Turned OFF in HDMI codec driver after codec reconfiguration */ - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - if (ret < 0) { - dev_err(bus->dev, - "Cannot turn on display power on i915\n"); - return ret; - } - } + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); /* * resume only when we are not in suspend active, otherwise need to @@ -786,11 +776,9 @@ static int skl_i915_init(struct hdac_bus *bus) if (err < 0) return err; - err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - if (err < 0) - dev_err(bus->dev, "Cannot turn on display power on i915\n"); + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - return err; + return 0; } static void skl_probe_work(struct work_struct *work) @@ -838,14 +826,8 @@ static void skl_probe_work(struct work_struct *work) list_for_each_entry(hlink, &bus->hlink_list, list) snd_hdac_ext_bus_link_put(bus, hlink); - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - if (err < 0) { - dev_err(bus->dev, "Cannot turn off display power on i915\n"); - skl_machine_device_unregister(skl); - return; - } - } + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); /* configure PM */ pm_runtime_put_noidle(bus->dev); @@ -856,7 +838,7 @@ static void skl_probe_work(struct work_struct *work) out_err: if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); } /* From 701f76eeb6e4b1b81343548c2a8336d95248c0e3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 10:06:59 +0100 Subject: [PATCH 0477/1995] ASoC: hdac_hdmi: Add missing display power-off at driver removal The display power is in unbalance at removing the driver since it misses the snd_hdac_display_power(OFF) call. Acked-by: Mark Brown Signed-off-by: Takashi Iwai --- sound/soc/codecs/hdac_hdmi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 3fc1b312fc4391..3ab2949c1dfa45 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2102,6 +2102,8 @@ static int hdac_hdmi_dev_remove(struct hdac_device *hdev) struct hdac_hdmi_port *port, *port_next; int i; + snd_hdac_display_power(hdev->bus, hdev->addr, false); + list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { pcm->cvt = NULL; if (list_empty(&pcm->port_list)) From c87bc73a3123cd78a58a300ed18d42b0a543674e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 10:10:19 +0100 Subject: [PATCH 0478/1995] ALSA: hda/hdmi: Always set display_power_control for Intel HSW+ codecs We've excluded the display_power_control flag for Intel HSW and BDW codecs as the HD-audio controllers of the corresponding platforms take care of the display power as well. But the recent refactoring separates the controller and the codec power accounting, so it's fine to call the display PM even for HSW/BDW codecs. This is less confusing since we can avoid this well-hidden condition. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 30fe4dbdb0ae9b..15290e4706e001 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2616,11 +2616,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid) intel_haswell_enable_all_pins(codec, true); intel_haswell_fixup_enable_dp12(codec); - /* For Haswell/Broadwell, the controller is also in the power well and - * can cover the codec power request, and so need not set this flag. - */ - if (!is_haswell(codec) && !is_broadwell(codec)) - codec->display_power_control = 1; + codec->display_power_control = 1; codec->patch_ops.set_power_state = haswell_set_power_state; codec->depop_delay = 0; From d0e3bb3836096459eb990e3f8880c931c75c1a41 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 18 Dec 2018 20:14:08 -0600 Subject: [PATCH 0479/1995] ASoC: Intel: bxt_pcm512x: fix SPDX license Make checkpatch happy Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bxt_pcm512x.c | 29 ++++++++++------------------ 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/sound/soc/intel/boards/bxt_pcm512x.c b/sound/soc/intel/boards/bxt_pcm512x.c index ae6a5feded18e9..32ada659c7afbe 100644 --- a/sound/soc/intel/boards/bxt_pcm512x.c +++ b/sound/soc/intel/boards/bxt_pcm512x.c @@ -1,23 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Pierre-Louis Bossart +// + /* - * bxt-pcm512x.c - ASoc Machine driver for Intel Baytrail and - * Cherrytrail-based platforms, with TI PCM512x codec - * - * Copyright (C) 2016 Intel Corporation - * Author: Pierre-Louis Bossart - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * 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. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * bxt-pcm512x.c - ASoc Machine driver for Intel platforms + * with TI PCM512x codec, e.g. Up or Up2 with Hifiberry DAC+ (PRO) HAT */ + #include #include #include @@ -229,7 +221,6 @@ static struct snd_soc_dai_link dailink[] = { #endif }; - /* SoC card */ static struct snd_soc_card bxt_pcm512x_card = { .name = "bxt-pcm512x", From 05d64bdeff065a40122c78e112de00d3e8e487ce Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 18 Dec 2018 20:14:38 -0600 Subject: [PATCH 0480/1995] ASoC: SOF: control: remove unneeded braces Make checkpatch happy Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/control.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index bedfcee47125fa..ab9ff937c3c3a1 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -223,9 +223,9 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, * the length (as bytes) is needed to know the correct copy * length of data from tlvd->tlv. */ - if (copy_from_user(&header, tlvd, sizeof(const struct snd_ctl_tlv))) { + if (copy_from_user(&header, tlvd, sizeof(const struct snd_ctl_tlv))) return -EFAULT; - } + /* The maximum length that can be copied is limited by IPC max * length and topology defined length for ext bytes control. */ @@ -244,9 +244,8 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, return -EINVAL; } - if (copy_from_user(cdata->data, tlvd->tlv, header.length)) { + if (copy_from_user(cdata->data, tlvd->tlv, header.length)) return -EFAULT; - } if (cdata->data->magic != SOF_ABI_MAGIC) { dev_err_ratelimited(sdev->dev, "error: Wrong ABI magic 0x%08x.\n", From e8e0db0c2c574ddca0f46ebff112e654037db08c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 18 Dec 2018 20:15:00 -0600 Subject: [PATCH 0481/1995] ASoC: SOF: Intel: hda-codec: remove double lines Make checkpatch happy Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-codec.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index a633575647d9e7..bcec7d58465cf0 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -19,7 +19,6 @@ #include "../../codecs/hdac_hda.h" #endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ - #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) #define IDISP_VID_INTEL 0x80860000 From e6b4d64f103bd2950222c8b64599a3213bdc0855 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 18 Dec 2018 20:15:34 -0600 Subject: [PATCH 0482/1995] ASoC: SOF: Intel: hda-loader: remove extra lines Make checkpatch happy Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-loader.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 9cadaaf246146f..4eca36c9f5f6c0 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -339,7 +339,6 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) continue; } - dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); return ret; } From cac0c10e905b805cbd8f80a989c51ea91d15de02 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 18 Dec 2018 20:37:45 -0600 Subject: [PATCH 0483/1995] acpi: blacklist: update quirk for Dell XPS13 w/ SOF Use CONFIG_SND_SOC_SOF_BROADWELL (CONFIG_SND_SOC_SOF_INTEL no longer exists) Signed-off-by: Pierre-Louis Bossart --- drivers/acpi/blacklist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index edf821bc582baa..c6e2666ed6c443 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -91,7 +91,7 @@ static int __init dmi_enable_rev_override(const struct dmi_system_id *d) static const struct dmi_system_id acpi_rev_dmi_table[] __initconst = { #ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) /* * DELL XPS 13 (2015) switches sound between HDA and I2S * depending on the ACPI _REV callback. If userspace supports From 43b4e383f85446a7f43f7fd19f382d344afb7d62 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Wed, 19 Dec 2018 17:27:52 +0800 Subject: [PATCH 0484/1995] ASoC: SOF: pm: do not use suspend_late suspend_late is used as some workaround to avoid suspend fail. Now we should use suspend directly. Signed-off-by: Pan Xiuli --- sound/soc/sof/pm.c | 8 +------- sound/soc/sof/sof-acpi-dev.c | 1 - sound/soc/sof/sof-pci-dev.c | 1 - 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 77388a36434bed..64833396a50d98 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -369,16 +369,10 @@ int snd_sof_resume(struct device *dev) EXPORT_SYMBOL(snd_sof_resume); int snd_sof_suspend(struct device *dev) -{ - return 0; -} -EXPORT_SYMBOL(snd_sof_suspend); - -int snd_sof_suspend_late(struct device *dev) { return sof_suspend(dev, false); } -EXPORT_SYMBOL(snd_sof_suspend_late); +EXPORT_SYMBOL(snd_sof_suspend); int snd_sof_prepare(struct device *dev) { diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index f6dda04444663e..8181170c3da214 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -126,7 +126,6 @@ static const struct dev_pm_ops sof_acpi_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, NULL) - .suspend_late = snd_sof_suspend_late, }; static const struct sof_ops_table acpi_mach_ops[] = { diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index df57f7855336db..18e6038abf4c84 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -127,7 +127,6 @@ static const struct dev_pm_ops sof_pci_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, NULL) - .suspend_late = snd_sof_suspend_late, .prepare = snd_sof_prepare, }; From cfcd5693f6142751bcbc6577be51c492f404ce6f Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Wed, 19 Dec 2018 17:24:21 +0800 Subject: [PATCH 0485/1995] [DEBUG][CI]travis: add W=1 build check Add W=1 check for SOF build Signed-off-by: Pan Xiuli --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cb349457aaff70..727dc28a5b3f6d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ git: before_install: - sudo apt-get update -qq - - sudo apt-get install python-ply python-git libelf-dev codespell sparse fakeroot + - sudo apt-get install -y python-ply python-git libelf-dev codespell sparse fakeroot - git clone https://github.com/thesofproject/kconfig.git jobs: @@ -28,6 +28,8 @@ jobs: - export ARCH=x86_64 - make defconfig - scripts/kconfig/merge_config.sh .config kconfig/base-defconfig kconfig/sof-defconfig + - make modules_prepare + - KCFLAGS="-Wall -Werror" make -j`getconf _NPROCESSORS_ONLN` SUBDIRS=sound/soc/sof W=1 - KCFLAGS="-Wall -Werror" make -j`getconf _NPROCESSORS_ONLN` - make bindeb-pkg -j`getconf _NPROCESSORS_ONLN` - name: "BUILD SST Kernel x86_64" From 19e351b0ba58a48944d39243704f4448d2d48240 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Thu, 13 Dec 2018 17:27:17 +0800 Subject: [PATCH 0486/1995] ASOC: SOF: merge chip info into dev descriptor Move each chip table to each chip file. And sof_intel_dsp_desc is moved from hda.h to shim.h because BYT, BDW and HSW is not a HDA platform and they should be supported. Signed-off-by: Rander Wang --- include/sound/sof.h | 3 + sound/soc/sof/intel/apl.c | 13 ++++ sound/soc/sof/intel/byt.c | 8 +++ sound/soc/sof/intel/cnl.c | 16 +++++ sound/soc/sof/intel/hda.c | 122 ++++-------------------------------- sound/soc/sof/intel/hda.h | 18 ++---- sound/soc/sof/intel/shim.h | 13 ++++ sound/soc/sof/intel/skl.c | 13 ++++ sound/soc/sof/sof-pci-dev.c | 33 ++++++---- 9 files changed, 103 insertions(+), 136 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index 87d6f8fd9c9a8e..2727abbcfe4cdd 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -66,6 +66,9 @@ struct sof_dev_desc { int ipc_timeout; int boot_timeout; + /* chip information for dsp */ + const void *chip_info; + /* defaults for no codec mode */ const char *nocodec_fw_filename; const char *nocodec_tplg_filename; diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 5de30087ded6d7..87ce880c698d21 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -97,3 +97,16 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .runtime_resume = hda_dsp_runtime_resume, }; EXPORT_SYMBOL(sof_apl_ops); + +const struct sof_intel_dsp_desc apl_chip_info = { + /* Apollolake */ + .cores_num = 2, + .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1), + .ipc_req = HDA_DSP_REG_HIPCI, + .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY, + .ipc_ack = HDA_DSP_REG_HIPCIE, + .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, + .ipc_ctl = HDA_DSP_REG_HIPCCTL, + .ops = &sof_apl_ops, +}; +EXPORT_SYMBOL(apl_chip_info); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index cef099406006e6..46cc2d1220db14 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -636,6 +636,14 @@ const struct snd_sof_dsp_ops sof_tng_ops = { }; EXPORT_SYMBOL(sof_tng_ops); +const struct sof_intel_dsp_desc tng_chip_info = { + /* Tng */ + .cores_num = 1, + .cores_mask = 1, + .ops = &sof_tng_ops, +}; +EXPORT_SYMBOL(tng_chip_info); + #endif /* CONFIG_SND_SOC_SOF_EDISON */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index a9cea84fa56ff1..134833bcf63e1c 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -246,3 +246,19 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .runtime_resume = hda_dsp_runtime_resume, }; EXPORT_SYMBOL(sof_cnl_ops); + +const struct sof_intel_dsp_desc cnl_chip_info = { + /* Cannonlake */ + .cores_num = 4, + .cores_mask = HDA_DSP_CORE_MASK(0) | + HDA_DSP_CORE_MASK(1) | + HDA_DSP_CORE_MASK(2) | + HDA_DSP_CORE_MASK(3), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .ops = &sof_cnl_ops, +}; +EXPORT_SYMBOL(cnl_chip_info); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 1cd64d8b69be9a..80735a9a807509 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -174,115 +174,6 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) } } -/* - * Supported devices. - */ - -static const struct sof_intel_dsp_desc chip_info[] = { -{ - /* Skylake */ - .id = 0x9d70, - .cores_num = 2, - .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1), - .ipc_req = HDA_DSP_REG_HIPCI, - .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY, - .ipc_ack = HDA_DSP_REG_HIPCIE, - .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, - .ipc_ctl = HDA_DSP_REG_HIPCCTL, - .ops = &sof_skl_ops, -}, -{ - /* Kabylake */ - .id = 0x9d71, - .cores_num = 2, - .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1), - .ipc_req = HDA_DSP_REG_HIPCI, - .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY, - .ipc_ack = HDA_DSP_REG_HIPCIE, - .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, - .ipc_ctl = HDA_DSP_REG_HIPCCTL, - .ops = &sof_skl_ops, -}, -{ - /* Apollolake - BXT-P */ - .id = 0x5a98, - .cores_num = 2, - .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1), - .ipc_req = HDA_DSP_REG_HIPCI, - .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY, - .ipc_ack = HDA_DSP_REG_HIPCIE, - .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, - .ipc_ctl = HDA_DSP_REG_HIPCCTL, - .ops = &sof_apl_ops, -}, -{ - /* BXT-M */ - .id = 0x1a98, - .cores_num = 2, - .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1), - .ipc_req = HDA_DSP_REG_HIPCI, - .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY, - .ipc_ack = HDA_DSP_REG_HIPCIE, - .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, - .ipc_ctl = HDA_DSP_REG_HIPCCTL, - .ops = &sof_apl_ops, -}, -{ - /* GeminiLake */ - .id = 0x3198, - .cores_num = 2, - .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1), - .ipc_req = HDA_DSP_REG_HIPCI, - .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY, - .ipc_ack = HDA_DSP_REG_HIPCIE, - .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, - .ipc_ctl = HDA_DSP_REG_HIPCCTL, - .ops = &sof_apl_ops, -}, -{ - /* Cannonlake */ - .id = 0x9dc8, - .cores_num = 4, - .cores_mask = HDA_DSP_CORE_MASK(0) | - HDA_DSP_CORE_MASK(1) | - HDA_DSP_CORE_MASK(2) | - HDA_DSP_CORE_MASK(3), - .ipc_req = CNL_DSP_REG_HIPCIDR, - .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, - .ipc_ack = CNL_DSP_REG_HIPCIDA, - .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, - .ipc_ctl = CNL_DSP_REG_HIPCCTL, - .ops = &sof_cnl_ops, -}, -{ - /* Icelake */ - .id = 0x34c8, - .cores_num = 4, - .cores_mask = HDA_DSP_CORE_MASK(0) | - HDA_DSP_CORE_MASK(1) | - HDA_DSP_CORE_MASK(2) | - HDA_DSP_CORE_MASK(3), - .ipc_req = CNL_DSP_REG_HIPCIDR, - .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, - .ipc_ack = CNL_DSP_REG_HIPCIDA, - .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, - .ipc_ctl = CNL_DSP_REG_HIPCCTL, - .ops = &sof_cnl_ops, -}, -}; - -static const struct sof_intel_dsp_desc *get_chip_info(int pci_id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(chip_info); i++) { - if (chip_info[i].id == pci_id) - return &chip_info[i]; - } - - return NULL; -} - static int hda_init(struct snd_sof_dev *sdev) { struct hda_bus *hbus; @@ -405,6 +296,17 @@ static int hda_init_caps(struct snd_sof_dev *sdev) #endif +static const struct sof_intel_dsp_desc + *get_chip_info(struct snd_sof_pdata *pdata) +{ + const struct sof_dev_desc *desc = pdata->desc; + const struct sof_intel_dsp_desc *chip_info; + + chip_info = (struct sof_intel_dsp_desc *)desc->chip_info; + + return chip_info; +} + int hda_dsp_probe(struct snd_sof_dev *sdev) { struct pci_dev *pci = sdev->pci; @@ -433,7 +335,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) /* set DSP arch ops */ sdev->arch_ops = &sof_xtensa_arch_ops; - chip = get_chip_info(pci->device); + chip = get_chip_info(sdev->pdata); if (!chip) { dev_err(sdev->dev, "error: no such device supported, chip id:%x\n", pci->device); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 05ece54e1dba91..02bae92201cdba 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -12,6 +12,7 @@ #define __SOF_INTEL_HDA_H #include +#include "shim.h" /* PCI registers */ #define PCI_TCSEL 0x44 @@ -343,19 +344,6 @@ struct sof_intel_dsp_bdl { __le32 ioc; } __attribute((packed)); -/* DSP hardware descriptor */ -struct sof_intel_dsp_desc { - int id; - int cores_num; - int cores_mask; - int ipc_req; - int ipc_req_mask; - int ipc_ack; - int ipc_ack_mask; - int ipc_ctl; - const struct snd_sof_dsp_ops *ops; -}; - #define SOF_HDA_PLAYBACK_STREAMS 16 #define SOF_HDA_CAPTURE_STREAMS 16 #define SOF_HDA_PLAYBACK 0 @@ -534,4 +522,8 @@ extern const struct snd_sof_dsp_ops sof_apl_ops; extern const struct snd_sof_dsp_ops sof_cnl_ops; extern const struct snd_sof_dsp_ops sof_skl_ops; +extern const struct sof_intel_dsp_desc apl_chip_info; +extern const struct sof_intel_dsp_desc cnl_chip_info; +extern const struct sof_intel_dsp_desc skl_chip_info; + #endif diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 5d85fd579bfa8b..07ccbd365b9374 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -151,10 +151,23 @@ #define PCI_PMCS 0x84 #define PCI_PMCS_PS_MASK 0x3 +/* DSP hardware descriptor */ +struct sof_intel_dsp_desc { + int cores_num; + int cores_mask; + int ipc_req; + int ipc_req_mask; + int ipc_ack; + int ipc_ack_mask; + int ipc_ctl; + const struct snd_sof_dsp_ops *ops; +}; + extern const struct snd_sof_dsp_ops sof_tng_ops; extern const struct snd_sof_dsp_ops sof_byt_ops; extern const struct snd_sof_dsp_ops sof_cht_ops; extern const struct snd_sof_dsp_ops sof_hsw_ops; extern const struct snd_sof_dsp_ops sof_bdw_ops; +extern const struct sof_intel_dsp_desc tng_chip_info; #endif diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 275000d7884070..55113d57486e59 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -90,3 +90,16 @@ const struct snd_sof_dsp_ops sof_skl_ops = { .num_drv = SOF_SKL_NUM_DAIS, }; EXPORT_SYMBOL(sof_skl_ops); + +const struct sof_intel_dsp_desc skl_chip_info = { + /* Apollolake */ + .cores_num = 2, + .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1), + .ipc_req = HDA_DSP_REG_HIPCI, + .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY, + .ipc_ack = HDA_DSP_REG_HIPCIE, + .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, + .ipc_ctl = HDA_DSP_REG_HIPCCTL, + .ops = &sof_skl_ops, +}; +EXPORT_SYMBOL(skl_chip_info); diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 18e6038abf4c84..55fad65799da96 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -29,6 +29,7 @@ static struct sof_dev_desc bxt_desc = { .resindex_imr_base = -1, .irqindex_host_ipc = -1, .resindex_dma_base = -1, + .chip_info = &apl_chip_info, .nocodec_fw_filename = "intel/sof-apl.ri", .nocodec_tplg_filename = "intel/sof-apl-nocodec.tplg" }; @@ -42,6 +43,7 @@ static struct sof_dev_desc glk_desc = { .resindex_imr_base = -1, .irqindex_host_ipc = -1, .resindex_dma_base = -1, + .chip_info = &apl_chip_info, .nocodec_fw_filename = "intel/sof-glk.ri", .nocodec_tplg_filename = "intel/sof-glk-nocodec.tplg" }; @@ -66,6 +68,7 @@ static const struct sof_dev_desc tng_desc = { .resindex_imr_base = 0, .irqindex_host_ipc = -1, .resindex_dma_base = -1, + .chip_info = &tng_chip_info, .nocodec_fw_filename = "intel/sof-byt.ri", .nocodec_tplg_filename = "intel/sof-byt.tplg" }; @@ -79,11 +82,26 @@ static const struct sof_dev_desc cnl_desc = { .resindex_imr_base = -1, .irqindex_host_ipc = -1, .resindex_dma_base = -1, + .chip_info = &cnl_chip_info, .nocodec_fw_filename = "intel/sof-cnl.ri", .nocodec_tplg_filename = "intel/sof-cnl.tplg" }; #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) +static const struct sof_dev_desc icl_desc = { + .machines = snd_soc_acpi_intel_icl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &cnl_chip_info, + .nocodec_fw_filename = "intel/sof-icl.ri", + .nocodec_tplg_filename = "intel/sof-icl-nocodec.tplg" +}; +#endif + #if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) static struct sof_dev_desc skl_desc = { .machines = snd_soc_acpi_intel_skl_machines, @@ -92,6 +110,7 @@ static struct sof_dev_desc skl_desc = { .resindex_imr_base = -1, .irqindex_host_ipc = -1, .resindex_dma_base = -1, + .chip_info = &skl_chip_info, .nocodec_fw_filename = "intel/sof-skl.ri", .nocodec_tplg_filename = "intel/sof-skl-nocodec.tplg" }; @@ -105,24 +124,12 @@ static struct sof_dev_desc kbl_desc = { .resindex_imr_base = -1, .irqindex_host_ipc = -1, .resindex_dma_base = -1, + .chip_info = &skl_chip_info, .nocodec_fw_filename = "intel/sof-kbl.ri", .nocodec_tplg_filename = "intel/sof-kbl-nocodec.tplg" }; #endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) -static const struct sof_dev_desc icl_desc = { - .machines = snd_soc_acpi_intel_icl_machines, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = -1, - .resindex_imr_base = -1, - .irqindex_host_ipc = -1, - .resindex_dma_base = -1, - .nocodec_fw_filename = "intel/sof-icl.ri", - .nocodec_tplg_filename = "intel/sof-icl-nocodec.tplg" -}; -#endif - static const struct dev_pm_ops sof_pci_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, From 94bd6947acac718a2a5ec81133fb75c126300e25 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Thu, 20 Dec 2018 13:35:49 +0800 Subject: [PATCH 0487/1995] ASoC: SOF: remove redundant ops table on pci platform Get ops from sof_intel_dsp_desc directly Signed-off-by: Rander Wang --- sound/soc/sof/sof-pci-dev.c | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 55fad65799da96..47c27d55b593e7 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -138,30 +138,6 @@ static const struct dev_pm_ops sof_pci_pm = { }; -static const struct sof_ops_table pci_mach_ops[] = { -#if IS_ENABLED(CONFIG_SND_SOC_SOF_EDISON) - {&tng_desc, &sof_tng_ops}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) - {&bxt_desc, &sof_apl_ops}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) - {&glk_desc, &sof_apl_ops}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) - {&cnl_desc, &sof_cnl_ops}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) - {&skl_desc, &sof_skl_ops}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) - {&kbl_desc, &sof_skl_ops}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) - {&icl_desc, &sof_cnl_ops}, -#endif -}; - static int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -177,7 +153,7 @@ static int sof_pci_probe(struct pci_dev *pci, dev_dbg(&pci->dev, "PCI DSP detected"); /* get ops for platform */ - ops = sof_get_ops(desc, pci_mach_ops, ARRAY_SIZE(pci_mach_ops)); + ops = ((const struct sof_intel_dsp_desc *)desc->chip_info)->ops; if (!ops) { dev_err(dev, "error: no matching PCI descriptor ops\n"); return -ENODEV; From 5701d92f90a4b04a87e95e4a950184eb88d02a89 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Thu, 20 Dec 2018 11:11:13 +0800 Subject: [PATCH 0488/1995] ASoC: SOF: remove redundant ops table on spi platform Now on intel platform, chip info would be stored in sof_dev_desc, and ops is gotten from chim info directly. Signed-off-by: Rander Wang --- sound/soc/sof/hw-spi.c | 8 ++++++++ sound/soc/sof/hw-spi.h | 1 + sound/soc/sof/sof-spi-dev.c | 12 +++++------- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index a9a53c957163c0..cb4f1f4e1291e6 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -27,6 +27,7 @@ #include #include #include +#include "intel/shim.h" #include "sof-priv.h" #include "hw-spi.h" #include "ops.h" @@ -312,4 +313,11 @@ const struct snd_sof_dsp_ops snd_sof_spi_ops = { }; EXPORT_SYMBOL(snd_sof_spi_ops); +const struct sof_intel_dsp_desc spi_chip_info = { + .cores_num = 2, + .cores_mask = 0x3, + .ops = &snd_sof_spi_ops, +}; +EXPORT_SYMBOL(spi_chip_info); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/hw-spi.h b/sound/soc/sof/hw-spi.h index 69ba896a1076fd..c751d0f0795c9d 100644 --- a/sound/soc/sof/hw-spi.h +++ b/sound/soc/sof/hw-spi.h @@ -2,5 +2,6 @@ #define HW_SPI_H extern const struct snd_sof_dsp_ops snd_sof_spi_ops; +extern const struct sof_intel_dsp_desc spi_chip_info; #endif diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index cee4ef517a94fd..79bd7b4842890a 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -18,6 +18,7 @@ #include #include #include +#include "intel/shim.h" #include "sof-priv.h" #include "hw-spi.h" #include "ops.h" @@ -42,10 +43,7 @@ static const struct sof_dev_desc spi_desc = { .resindex_imr_base = -1, .irqindex_host_ipc = -1, .resindex_dma_base = -1, -}; - -static const struct sof_ops_table spi_mach_ops[] = { - {&spi_desc, &snd_sof_spi_ops}, + .chip_info = &spi_chip_info, }; static int sof_spi_probe(struct spi_device *spi) @@ -53,6 +51,7 @@ static int sof_spi_probe(struct spi_device *spi) struct device *dev = &spi->dev; const struct sof_dev_desc *desc = of_device_get_match_data(dev); struct snd_soc_acpi_mach *machines, *mach; + const struct sof_intel_dsp_desc *chip_info; struct snd_sof_pdata *sof_pdata; struct sof_platform_priv *priv; const char *tplg, *fw; @@ -123,9 +122,8 @@ static int sof_spi_probe(struct spi_device *spi) * to add a dedicated ops field in the generic soc-acpi structure * to avoid such issues */ - - mach->pdata = (void *)sof_get_ops(desc, spi_mach_ops, - ARRAY_SIZE(spi_mach_ops)); + chip_info = (const struct sof_intel_dsp_desc *)desc->chip_info; + mach->pdata = (void *)chip_info->ops; if (!mach->pdata) { dev_err(dev, "error: no matching SPI descriptor ops\n"); return -ENODEV; From 598ee6d12fb53db502b4bb47e1ebae63e4f03f40 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Thu, 20 Dec 2018 11:21:49 +0800 Subject: [PATCH 0489/1995] ASoC: SOF: remove redundant ops table on acpi platform Get ops from sof_intel_dsp_desc directly Signed-off-by: Rander Wang --- sound/soc/sof/intel/bdw.c | 7 +++++++ sound/soc/sof/intel/byt.c | 15 ++++++++++++++- sound/soc/sof/intel/hsw.c | 7 +++++++ sound/soc/sof/intel/shim.h | 5 +++++ sound/soc/sof/sof-acpi-dev.c | 21 ++++++--------------- 5 files changed, 39 insertions(+), 16 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index b1876cc025804b..29048d3094cec8 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -697,4 +697,11 @@ const struct snd_sof_dsp_ops sof_bdw_ops = { }; EXPORT_SYMBOL(sof_bdw_ops); +const struct sof_intel_dsp_desc bdw_chip_info = { + .cores_num = 1, + .cores_mask = 1, + .ops = &sof_bdw_ops, +}; +EXPORT_SYMBOL(bdw_chip_info); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 46cc2d1220db14..168b8d31735473 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -637,7 +637,6 @@ const struct snd_sof_dsp_ops sof_tng_ops = { EXPORT_SYMBOL(sof_tng_ops); const struct sof_intel_dsp_desc tng_chip_info = { - /* Tng */ .cores_num = 1, .cores_mask = 1, .ops = &sof_tng_ops, @@ -806,6 +805,13 @@ const struct snd_sof_dsp_ops sof_byt_ops = { }; EXPORT_SYMBOL(sof_byt_ops); +const struct sof_intel_dsp_desc byt_chip_info = { + .cores_num = 1, + .cores_mask = 1, + .ops = &sof_byt_ops, +}; +EXPORT_SYMBOL(byt_chip_info); + /* cherrytrail and braswell ops */ const struct snd_sof_dsp_ops sof_cht_ops = { /* device init */ @@ -858,6 +864,13 @@ const struct snd_sof_dsp_ops sof_cht_ops = { }; EXPORT_SYMBOL(sof_cht_ops); +const struct sof_intel_dsp_desc cht_chip_info = { + .cores_num = 1, + .cores_mask = 1, + .ops = &sof_cht_ops, +}; +EXPORT_SYMBOL(cht_chip_info); + #endif /* CONFIG_SND_SOC_SOF_BAYTRAIL */ MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index b64f84a92bf5a4..9903a68b857a26 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -698,4 +698,11 @@ const struct snd_sof_dsp_ops sof_hsw_ops = { }; EXPORT_SYMBOL(sof_hsw_ops); +const struct sof_intel_dsp_desc hsw_chip_info = { + .cores_num = 1, + .cores_mask = 1, + .ops = &sof_hsw_ops, +}; +EXPORT_SYMBOL(hsw_chip_info); + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 07ccbd365b9374..f43b70d9d1c1df 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -169,5 +169,10 @@ extern const struct snd_sof_dsp_ops sof_cht_ops; extern const struct snd_sof_dsp_ops sof_hsw_ops; extern const struct snd_sof_dsp_ops sof_bdw_ops; +extern const struct sof_intel_dsp_desc byt_chip_info; +extern const struct sof_intel_dsp_desc cht_chip_info; +extern const struct sof_intel_dsp_desc bdw_chip_info; +extern const struct sof_intel_dsp_desc hsw_chip_info; extern const struct sof_intel_dsp_desc tng_chip_info; + #endif diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 8181170c3da214..b9f87d1c44c747 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -31,6 +31,7 @@ static struct sof_dev_desc sof_acpi_haswell_desc = { .resindex_pcicfg_base = 1, .resindex_imr_base = -1, .irqindex_host_ipc = 0, + .chip_info = &hsw_chip_info, .nocodec_fw_filename = "intel/sof-hsw.ri", .nocodec_tplg_filename = "intel/sof-hsw-nocodec.tplg" }; @@ -43,6 +44,7 @@ static struct sof_dev_desc sof_acpi_broadwell_desc = { .resindex_pcicfg_base = 1, .resindex_imr_base = -1, .irqindex_host_ipc = 0, + .chip_info = &bdw_chip_info, .nocodec_fw_filename = "intel/sof-bdw.ri", .nocodec_tplg_filename = "intel/sof-bdw-nocodec.tplg" }; @@ -57,6 +59,7 @@ static struct sof_dev_desc sof_acpi_baytrailcr_desc = { .resindex_pcicfg_base = 1, .resindex_imr_base = 2, .irqindex_host_ipc = 0, + .chip_info = &byt_chip_info, .nocodec_fw_filename = "intel/sof-byt.ri", .nocodec_tplg_filename = "intel/sof-byt-nocodec.tplg" }; @@ -67,6 +70,7 @@ static struct sof_dev_desc sof_acpi_baytrail_desc = { .resindex_pcicfg_base = 1, .resindex_imr_base = 2, .irqindex_host_ipc = 5, + .chip_info = &byt_chip_info, .nocodec_fw_filename = "intel/sof-byt.ri", .nocodec_tplg_filename = "intel/sof-byt-nocodec.tplg" }; @@ -116,6 +120,7 @@ static struct sof_dev_desc sof_acpi_cherrytrail_desc = { .resindex_pcicfg_base = 1, .resindex_imr_base = 2, .irqindex_host_ipc = 5, + .chip_info = &cht_chip_info, .nocodec_fw_filename = "intel/sof-cht.ri", .nocodec_tplg_filename = "intel/sof-cht-nocodec.tplg" }; @@ -128,20 +133,6 @@ static const struct dev_pm_ops sof_acpi_pm = { NULL) }; -static const struct sof_ops_table acpi_mach_ops[] = { -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL) - {&sof_acpi_haswell_desc, &sof_hsw_ops}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) - {&sof_acpi_broadwell_desc, &sof_bdw_ops}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - {&sof_acpi_baytrail_desc, &sof_byt_ops}, - {&sof_acpi_baytrailcr_desc, &sof_byt_ops}, - {&sof_acpi_cherrytrail_desc, &sof_cht_ops}, -#endif -}; - static int sof_acpi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -172,7 +163,7 @@ static int sof_acpi_probe(struct platform_device *pdev) #endif /* get ops for platform */ - ops = sof_get_ops(desc, acpi_mach_ops, ARRAY_SIZE(acpi_mach_ops)); + ops = ((const struct sof_intel_dsp_desc *)desc->chip_info)->ops; if (!ops) { dev_err(dev, "error: no matching ACPI descriptor ops\n"); return -ENODEV; From f395dd273254cd66d28ae0b24e54ec0871d435ff Mon Sep 17 00:00:00 2001 From: Bard liao Date: Wed, 19 Dec 2018 07:41:20 +0800 Subject: [PATCH 0490/1995] ASoC: SOF: remove intel-specific field from snd_sof_dev{} We don't want to keep intel-specific data in struct snd_sof_dev{} which is on the top level of SOF. This patch do the following 1. remove "struct sof_intel_hda_dev *hda;" from snd_sof_dev{} struct 2. remove spi-specific fields from snd_sof_dev{} struct 3. add struct sof_spi_dev{} to store spi-specific data 4. add "void *hw_pdata;" into snd_sof_pdata{}. It will be converted to struct sof_intel_hda_dev or struct sof_spi_dev The *hw_pdata can be used to store SoC or hardware-stuff. Signed-off-by: Bard liao --- include/sound/sof.h | 6 ++---- sound/soc/sof/hw-spi.c | 10 +++++++--- sound/soc/sof/hw-spi.h | 5 +++++ sound/soc/sof/intel/hda-dsp.c | 4 +++- sound/soc/sof/intel/hda-loader-skl.c | 4 +++- sound/soc/sof/intel/hda-loader.c | 4 +++- sound/soc/sof/intel/hda-pcm.c | 8 ++++++-- sound/soc/sof/intel/hda-stream.c | 4 +++- sound/soc/sof/intel/hda-trace.c | 28 +++++++++++++++++++--------- sound/soc/sof/intel/hda.c | 28 +++++++++++++++------------- sound/soc/sof/intel/hda.h | 14 ++++++++++++++ sound/soc/sof/sof-priv.h | 6 +----- sound/soc/sof/sof-spi-dev.c | 8 +++++++- 13 files changed, 88 insertions(+), 41 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index 2727abbcfe4cdd..65665aaabdc005 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -33,13 +33,11 @@ struct snd_sof_pdata { /* descriptor */ const struct sof_dev_desc *desc; - /* SPI data */ - int gpio; - unsigned int active; - /* machine */ struct platform_device *pdev_mach; const struct snd_soc_acpi_mach *machine; + + void *hw_pdata; }; /* diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index cb4f1f4e1291e6..e32ab3d669c267 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -155,12 +155,14 @@ static irqreturn_t spi_irq_handler(int irq __maybe_unused, void *context) const struct platform_device *pdev = container_of(sdev->parent, struct platform_device, dev); struct snd_sof_pdata *sof_pdata = dev_get_platdata(&pdev->dev); + struct sof_spi_dev *sof_spi = + (struct sof_spi_dev *)sof_pdata->hw_pdata; // on SPI based devices this will likely come via a SoC GPIO IRQ // check if GPIO is assetred and if so run thread. - if (sof_pdata->gpio >= 0 && - gpio_get_value(sof_pdata->gpio) == sof_pdata->active) + if (sof_spi->gpio >= 0 && + gpio_get_value(sof_spi->gpio) == sof_spi->active) return IRQ_WAKE_THREAD; return IRQ_NONE; @@ -237,6 +239,8 @@ static int spi_sof_probe(struct snd_sof_dev *sdev) struct platform_device *pdev = container_of(sdev->parent, struct platform_device, dev); struct snd_sof_pdata *sof_pdata = dev_get_platdata(&pdev->dev); + struct sof_spi_dev *sof_spi = + (struct sof_spi_dev *)sof_pdata->hw_pdata; /* get IRQ from Device tree or ACPI - register our IRQ */ struct irq_data *irqd; struct spi_device *spi = to_spi_device(pdev->dev.parent); @@ -251,7 +255,7 @@ static int spi_sof_probe(struct snd_sof_dev *sdev) irq_trigger = irqd_get_trigger_type(irqd); irq_sense = irq_trigger & IRQ_TYPE_SENSE_MASK; - sof_pdata->active = irq_sense == IRQ_TYPE_EDGE_RISING || + sof_spi->active = irq_sense == IRQ_TYPE_EDGE_RISING || irq_sense == IRQ_TYPE_LEVEL_HIGH; ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, diff --git a/sound/soc/sof/hw-spi.h b/sound/soc/sof/hw-spi.h index c751d0f0795c9d..5348f38b393160 100644 --- a/sound/soc/sof/hw-spi.h +++ b/sound/soc/sof/hw-spi.h @@ -4,4 +4,9 @@ extern const struct snd_sof_dsp_ops snd_sof_spi_ops; extern const struct sof_intel_dsp_desc spi_chip_info; +struct sof_spi_dev { + int gpio; + unsigned int active; +}; + #endif diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 6b67246a8b37f1..b79e6a12b75b7a 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -246,7 +246,9 @@ int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, static int hda_suspend(struct snd_sof_dev *sdev, int state) { - const struct sof_intel_dsp_desc *chip = sdev->hda->desc; + struct sof_intel_hda_dev *hda = + (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_bus *bus = sof_to_bus(sdev); #endif diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 8437ce7201c735..b58773cd5e15ee 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -308,7 +308,9 @@ static void cl_cleanup_skl(struct snd_sof_dev *sdev) static int cl_dsp_init_skl(struct snd_sof_dev *sdev) { - const struct sof_intel_dsp_desc *chip = sdev->hda->desc; + struct sof_intel_hda_dev *hda = + (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; int ret; /* check if the core is already enabled, if yes, reset and make it run, diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 4eca36c9f5f6c0..236a8a1bb11839 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -82,7 +82,9 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, { int tag, ret, i; u32 hipcie; - const struct sof_intel_dsp_desc *chip = sdev->hda->desc; + struct sof_intel_hda_dev *hda = + (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; /* prepare DMA for code loader stream */ tag = cl_stream_prepare(sdev, 0x40, fwsize, &sdev->dmab, diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 862283ff02a2bc..1e91d42e700da7 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -88,6 +88,8 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, { struct hdac_stream *hstream = substream->runtime->private_data; struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream); + struct sof_intel_hda_dev *hda = + (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; struct snd_dma_buffer *dmab; int ret; u32 size, rate, bits; @@ -117,7 +119,7 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); /* set host_period_bytes to 0 if no IPC position */ - if (sdev->hda && sdev->hda->no_ipc_position) + if (hda && hda->no_ipc_position) ipc_params->host_period_bytes = 0; ipc_params->stream_tag = hstream->stream_tag; @@ -139,10 +141,12 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, { struct hdac_stream *hstream = substream->runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sof_intel_hda_dev *hda = + (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; struct snd_sof_pcm *spcm = rtd->private; snd_pcm_uframes_t pos = 0; - if (!sdev->hda->no_ipc_position) { + if (hda && !hda->no_ipc_position) { /* read position from IPC position */ pos = spcm->stream[substream->stream].posn.host_posn; goto found; diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 815a74994bbc49..0fbcda92395d9f 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -80,6 +80,8 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, struct hdac_stream *stream) { + struct sof_intel_hda_dev *hda = + (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; struct sof_intel_dsp_bdl *bdl; int i, offset, period_bytes, periods; int remain, ioc; @@ -106,7 +108,7 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, * set IOC if don't use position IPC * and period_wakeup needed. */ - ioc = sdev->hda->no_ipc_position ? + ioc = hda->no_ipc_position ? !stream->no_period_wakeup : 0; for (i = 0; i < periods; i++) { diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c index 5e9f73f0954469..3481d47e04a00c 100644 --- a/sound/soc/sof/intel/hda-trace.c +++ b/sound/soc/sof/intel/hda-trace.c @@ -21,7 +21,9 @@ static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev) { - struct hdac_ext_stream *stream = sdev->hda->dtrace_stream; + struct sof_intel_hda_dev *hda = + (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + struct hdac_ext_stream *stream = hda->dtrace_stream; struct hdac_stream *hstream = &stream->hstream; struct snd_dma_buffer *dmab = &sdev->dmatb; int ret; @@ -38,16 +40,19 @@ static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev) int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *tag) { - sdev->hda->dtrace_stream = hda_dsp_stream_get(sdev, - SNDRV_PCM_STREAM_CAPTURE); + struct sof_intel_hda_dev *hda = + (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; - if (!sdev->hda->dtrace_stream) { + hda->dtrace_stream = hda_dsp_stream_get(sdev, + SNDRV_PCM_STREAM_CAPTURE); + + if (hda && !hda->dtrace_stream) { dev_err(sdev->dev, "error: no available capture stream for DMA trace\n"); return -ENODEV; } - *tag = sdev->hda->dtrace_stream->hstream.stream_tag; + *tag = hda->dtrace_stream->hstream.stream_tag; /* * initialize capture stream, set BDL address and return corresponding @@ -58,14 +63,16 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *tag) int hda_dsp_trace_release(struct snd_sof_dev *sdev) { + struct sof_intel_hda_dev *hda = + (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; struct hdac_stream *hstream; - if (sdev->hda->dtrace_stream) { - hstream = &sdev->hda->dtrace_stream->hstream; + if (hda->dtrace_stream) { + hstream = &hda->dtrace_stream->hstream; hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_CAPTURE, hstream->stream_tag); - sdev->hda->dtrace_stream = NULL; + hda->dtrace_stream = NULL; return 0; } @@ -75,5 +82,8 @@ int hda_dsp_trace_release(struct snd_sof_dev *sdev) int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd) { - return hda_dsp_stream_trigger(sdev, sdev->hda->dtrace_stream, cmd); + struct sof_intel_hda_dev *hda = + (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + + return hda_dsp_stream_trigger(sdev, hda->dtrace_stream, cmd); } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 80735a9a807509..93541fe3f4b40a 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -346,7 +346,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) hdev = devm_kzalloc(&pci->dev, sizeof(*hdev), GFP_KERNEL); if (!hdev) return -ENOMEM; - sdev->hda = hdev; + sdev->pdata->hw_pdata = hdev; hdev->desc = chip; hdev->dmic_dev = platform_device_register_data(&pci->dev, "dmic-codec", @@ -419,24 +419,24 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) * in IO-APIC mode, hda->irq and ipc_irq are using the same * irq number of pci->irq */ - sdev->hda->irq = pci->irq; + hdev->irq = pci->irq; sdev->ipc_irq = pci->irq; sdev->msi_enabled = 0; } else { dev_info(sdev->dev, "use msi interrupt mode\n"); - sdev->hda->irq = pci_irq_vector(pci, 0); + hdev->irq = pci_irq_vector(pci, 0); /* ipc irq number is the same of hda irq */ - sdev->ipc_irq = sdev->hda->irq; + sdev->ipc_irq = hdev->irq; sdev->msi_enabled = 1; } - dev_dbg(sdev->dev, "using HDA IRQ %d\n", sdev->hda->irq); - ret = request_threaded_irq(sdev->hda->irq, hda_dsp_stream_interrupt, + dev_dbg(sdev->dev, "using HDA IRQ %d\n", hdev->irq); + ret = request_threaded_irq(hdev->irq, hda_dsp_stream_interrupt, hda_dsp_stream_threaded_handler, IRQF_SHARED, "AudioHDA", bus); if (ret < 0) { dev_err(sdev->dev, "error: failed to register HDA IRQ %d\n", - sdev->hda->irq); + hdev->irq); goto free_irq_vector; } @@ -526,7 +526,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) free_ipc_irq: free_irq(sdev->ipc_irq, sdev); free_hda_irq: - free_irq(sdev->hda->irq, bus); + free_irq(hdev->irq, bus); free_irq_vector: if (sdev->msi_enabled) pci_free_irq_vectors(pci); @@ -542,20 +542,22 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) int hda_dsp_remove(struct snd_sof_dev *sdev) { + struct sof_intel_hda_dev *hda = + (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; struct hdac_bus *bus = sof_to_bus(sdev); struct pci_dev *pci = sdev->pci; const struct sof_intel_dsp_desc *chip = NULL; - if (sdev->hda) - chip = sdev->hda->desc; + if (hda) + chip = hda->desc; #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* codec removal, invoke bus_device_remove */ snd_hdac_ext_bus_device_remove(bus); #endif - if (sdev->hda && (!IS_ERR_OR_NULL(sdev->hda->dmic_dev))) - platform_device_unregister(sdev->hda->dmic_dev); + if (hda && (!IS_ERR_OR_NULL(hda->dmic_dev))) + platform_device_unregister(hda->dmic_dev); /* disable DSP IRQ */ snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, @@ -574,7 +576,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) SOF_HDA_PPCTL_GPROCEN, 0); free_irq(sdev->ipc_irq, sdev); - free_irq(sdev->hda->irq, bus); + free_irq(hda->irq, bus); if (sdev->msi_enabled) pci_free_irq_vectors(pci); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 02bae92201cdba..e09b83d0bb7203 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -369,6 +369,20 @@ struct sof_intel_hda_dev { struct platform_device *dmic_dev; }; +static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s) +{ + struct sof_intel_hda_dev *hda = + (struct sof_intel_hda_dev *)s->pdata->hw_pdata; + return &hda->hbus.core; +} + +static inline struct hda_bus *sof_to_hbus(struct snd_sof_dev *s) +{ + struct sof_intel_hda_dev *hda = + (struct sof_intel_hda_dev *)s->pdata->hw_pdata; + return &hda->hbus; +} + #define bus_to_sof_hda(bus) \ container_of(bus, struct sof_intel_hda_dev, hbus.core) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 1ada7eab46c887..a5e8ce54338282 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -21,6 +21,7 @@ #include #include #include +#include #include /* debug flags */ @@ -58,7 +59,6 @@ struct snd_sof_ipc; struct snd_sof_debugfs_map; struct snd_soc_tplg_ops; struct snd_soc_component; -struct sof_intel_hda_dev; struct snd_sof_pdata; /* @@ -315,7 +315,6 @@ struct snd_sof_dev { /* DSP HW differentiation */ struct snd_sof_pdata *pdata; const struct snd_sof_dsp_ops *ops; - struct sof_intel_hda_dev *hda; /* for HDA based DSP HW */ const struct sof_arch_ops *arch_ops; /* IPC */ @@ -381,9 +380,6 @@ struct snd_sof_dev { void *private; /* core does not touch this */ }; -#define sof_to_bus(s) (&(s)->hda->hbus.core) -#define sof_to_hbus(s) (&(s)->hda->hbus) - /* * SOF platform private struct used as drvdata of * platform dev (e.g. pci/acpi/spi...) drvdata. diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index 79bd7b4842890a..73fe5e266dd4d8 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -54,6 +54,7 @@ static int sof_spi_probe(struct spi_device *spi) const struct sof_intel_dsp_desc *chip_info; struct snd_sof_pdata *sof_pdata; struct sof_platform_priv *priv; + struct sof_spi_dev *sof_spi; const char *tplg, *fw; struct gpio_desc *gpiod; int ret, irq; @@ -92,7 +93,12 @@ static int sof_spi_probe(struct spi_device *spi) if (IS_ERR(gpiod)) return PTR_ERR(gpiod); - sof_pdata->gpio = desc_to_gpio(gpiod); + sof_spi = devm_kzalloc(dev, sizeof(*sof_spi), GFP_KERNEL); + if (!sof_spi) + return -ENOMEM; + + sof_spi->gpio = desc_to_gpio(gpiod); + sof_pdata->hw_pdata = sof_spi; irq = gpiod_to_irq(gpiod); if (irq < 0) From 695380ff5c3e79aa553de46edb8f50b415b4cde7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 21 Dec 2018 09:35:05 -0600 Subject: [PATCH 0491/1995] ASoc: SOF: spi: s/whitespaces/tab Make checkpatch happy Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/hw-spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index e32ab3d669c267..16315f555737b9 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -240,7 +240,7 @@ static int spi_sof_probe(struct snd_sof_dev *sdev) container_of(sdev->parent, struct platform_device, dev); struct snd_sof_pdata *sof_pdata = dev_get_platdata(&pdev->dev); struct sof_spi_dev *sof_spi = - (struct sof_spi_dev *)sof_pdata->hw_pdata; + (struct sof_spi_dev *)sof_pdata->hw_pdata; /* get IRQ from Device tree or ACPI - register our IRQ */ struct irq_data *irqd; struct spi_device *spi = to_spi_device(pdev->dev.parent); From cba58eed2c8a3df78b6bd39ea7c39d3dd5bc4974 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 18 Dec 2018 15:02:12 +0800 Subject: [PATCH 0492/1995] ASoC: SOF: use hex_dump_to_buffer to dump call stack It is simpler to use hex_dump_to_buffer than dumping stack by ourself. Don't check whether the value of stack_words is multiple of 4 because the value of stack_words is always multiple of 4 in driver and it makes no sense to dump stack with value of 4*x + y Signed-off-by: Rander Wang --- sound/soc/sof/xtensa/core.c | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c index 5be713871c6af6..930d6749a560ed 100644 --- a/sound/soc/sof/xtensa/core.c +++ b/sound/soc/sof/xtensa/core.c @@ -110,36 +110,19 @@ static void xtensa_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack, { struct sof_ipc_dsp_oops_xtensa *xoops = oops; u32 stack_ptr = xoops->stack; + /* 4 * 8chars + 3 ws + 1 terminating NUL */ + unsigned char buf[4 * 8 + 3 + 1]; int i; dev_err(sdev->dev, "stack dump from 0x%8.8x\n", stack_ptr); - for (i = 0; i <= stack_words - 4; i += 4) { - dev_err(sdev->dev, "0x%8.8x: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n", - stack_ptr + i, stack[i], stack[i + 1], stack[i + 2], - stack[i + 3]); - } - - /* deal with any remaining words */ - switch (stack_words - i) { - case 0: - break; - case 1: - dev_err(sdev->dev, "0x%8.8x: 0x%8.8x\n", - stack_ptr + stack_words - 1, stack[stack_words - 1]); - break; - case 2: - dev_err(sdev->dev, "0x%8.8x: 0x%8.8x 0x%8.8x\n", - stack_ptr + stack_words - 2, stack[stack_words - 2], - stack[stack_words - 1]); - break; - case 3: - dev_err(sdev->dev, "0x%8.8x: 0x%8.8x 0x%8.8x 0x%8.8x\n", - stack_ptr + stack_words - 3, stack[stack_words - 3], - stack[stack_words - 2], stack[stack_words - 1]); - break; - default: - break; + /* example output: + * 0x0049fbb0: 8000f2d0 0049fc00 6f6c6c61 00632e63 + */ + for (i = 0; i < stack_words; i += 4) { + hex_dump_to_buffer(stack + i * 4, 16, 16, 4, + buf, sizeof(buf), false); + dev_err(sdev->dev, "0x%08x: %s\n", stack_ptr + i, buf); } } From 62aa569818f49c7fa9ba326eda52b2eb785442bd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 21 Dec 2018 12:01:24 -0600 Subject: [PATCH 0493/1995] ASoC: SOF: fix Kconfig for ia64 Yet another build issue reported by kbuild/0day Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 627b3c2c5edabe..e8382eb8e1bb35 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -12,6 +12,7 @@ config SND_SOC_SOF_PCI tristate "SOF PCI enumeration support" depends on PCI select SND_SOC_SOF + select SND_SOC_ACPI if ACPI select SND_SOC_SOF_OPTIONS select SND_SOC_SOF_INTEL_PCI if SND_SOC_SOF_INTEL_TOPLEVEL help @@ -24,6 +25,7 @@ config SND_SOC_SOF_ACPI tristate "SOF ACPI enumeration support" depends on ACPI || COMPILE_TEST select SND_SOC_SOF + select SND_SOC_ACPI if ACPI select SND_SOC_SOF_OPTIONS select SND_SOC_SOF_INTEL_ACPI if SND_SOC_SOF_INTEL_TOPLEVEL select IOSF_MBI if X86 From a466431aace07b19ddf4f4ea50f08a14fade2e12 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Wed, 26 Dec 2018 10:56:07 +0800 Subject: [PATCH 0494/1995] ASoC: SOF: loader: checking block size to avoid unaligned accesses All elements in struct snd_sof_blk_hdr{} are 4 bytes length. So, let block size divisible by 4 can avoid unaligned accesses. We need to make sure that firmware adds padding in the block which is not divisible by 4. Otherwise, the firmware will not be loaded. Signed-off-by: Bard liao --- sound/soc/sof/loader.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 61cedeb2c4c887..134cca656e51c1 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -140,6 +140,12 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, "block %d type 0x%x size 0x%x ==> offset 0x%x\n", count, block->type, block->size, offset); + /* checking block->size to avoid unaligned access */ + if (block->size % sizeof(u32)) { + dev_err(sdev->dev, "error: invalid block size 0x%x\n", + block->size); + return -EINVAL; + } snd_sof_dsp_block_write(sdev, offset, (void *)block + sizeof(*block), block->size); From 6d1ebb712cd444dbc0ed9d8670cc9a59e94496ea Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Sat, 29 Dec 2018 13:59:02 +0800 Subject: [PATCH 0495/1995] ASoC: SOF: trace: release dma trace at fails We need to release dma trace at trace initialization fails, e.g. put stream, otherwise, we will see error like "no free capture streams" after fails several times. Signed-off-by: Keyon Jie --- sound/soc/sof/trace.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 40b6396b9b5ef7..c2be44a39f63b0 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -166,19 +166,23 @@ int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "error: can't set params for DMA for trace %d\n", ret); - return ret; + goto trace_release; } ret = snd_sof_dma_trace_trigger(sdev, SNDRV_PCM_TRIGGER_START); if (ret < 0) { dev_err(sdev->dev, "error: snd_sof_dma_trace_trigger: start: %d\n", ret); - return ret; + goto trace_release; } sdev->dtrace_is_enabled = true; return 0; + +trace_release: + snd_sof_dma_trace_release(sdev); + return ret; } int snd_sof_init_trace(struct snd_sof_dev *sdev) From 04fff958932943b9ae01f5f570f9d2ccafe7f0d3 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Thu, 3 Jan 2019 09:56:24 +0800 Subject: [PATCH 0496/1995] ASoC: SOF: hda-trace: cleanup for hda_dsp_trace_init() We need add error handling for hda_dsp_trace_prepare(), put stream at prepare fail. Here also remove the hda NULL check, we assume hda is available for those hda-xxx.c drivers. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-trace.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c index 3481d47e04a00c..dc0d1a091854cb 100644 --- a/sound/soc/sof/intel/hda-trace.c +++ b/sound/soc/sof/intel/hda-trace.c @@ -42,11 +42,12 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *tag) { struct sof_intel_hda_dev *hda = (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + int ret; hda->dtrace_stream = hda_dsp_stream_get(sdev, SNDRV_PCM_STREAM_CAPTURE); - if (hda && !hda->dtrace_stream) { + if (!hda->dtrace_stream) { dev_err(sdev->dev, "error: no available capture stream for DMA trace\n"); return -ENODEV; @@ -58,7 +59,15 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *tag) * initialize capture stream, set BDL address and return corresponding * stream tag which will be sent to the firmware by IPC message. */ - return hda_dsp_trace_prepare(sdev); + ret = hda_dsp_trace_prepare(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: hdac trace init failed: %x\n", ret); + hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_CAPTURE, *tag); + hda->dtrace_stream = NULL; + *tag = 0; + } + + return ret; } int hda_dsp_trace_release(struct snd_sof_dev *sdev) From 5931a304f36ce35cea40e690454d213de771a6ab Mon Sep 17 00:00:00 2001 From: Bard liao Date: Mon, 24 Dec 2018 21:00:04 +0800 Subject: [PATCH 0497/1995] ASoC: SOF: move ops to sof_dev_desc snd_sof_dsp_ops and sof_arch_ops are hardware specific stuff, so move them from snd_sof_dev to sof_dev_desc. Signed-off-by: Bard liao --- include/sound/sof.h | 3 + sound/soc/sof/core.c | 7 +- sound/soc/sof/debug.c | 3 +- sound/soc/sof/hw-spi.c | 1 - sound/soc/sof/intel/apl.c | 1 - sound/soc/sof/intel/bdw.c | 4 - sound/soc/sof/intel/byt.c | 6 -- sound/soc/sof/intel/cnl.c | 1 - sound/soc/sof/intel/hda.c | 7 +- sound/soc/sof/intel/hsw.c | 4 - sound/soc/sof/intel/shim.h | 1 - sound/soc/sof/intel/skl.c | 1 - sound/soc/sof/ipc.c | 4 +- sound/soc/sof/loader.c | 6 +- sound/soc/sof/ops.h | 145 ++++++++++++++++++----------------- sound/soc/sof/pcm.c | 4 +- sound/soc/sof/pm.c | 4 +- sound/soc/sof/sof-acpi-dev.c | 29 +++---- sound/soc/sof/sof-pci-dev.c | 38 +++++---- sound/soc/sof/sof-priv.h | 13 ++-- sound/soc/sof/sof-spi-dev.c | 15 +--- 21 files changed, 139 insertions(+), 158 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index 65665aaabdc005..7c11d16207e478 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -70,6 +70,9 @@ struct sof_dev_desc { /* defaults for no codec mode */ const char *nocodec_fw_filename; const char *nocodec_tplg_filename; + + const struct snd_sof_dsp_ops *ops; + const struct sof_arch_ops *arch_ops; }; int sof_nocodec_setup(struct device *dev, diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index c6f871cbf4f17e..e13d8dfad65b35 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -245,7 +245,6 @@ static int sof_probe(struct platform_device *pdev) sdev->parent = plat_data->dev; if dev_is_pci(plat_data->dev) sdev->pci = to_pci_dev(plat_data->dev); - sdev->ops = plat_data->machine->pdata; sdev->pdata = plat_data; sdev->first_boot = true; @@ -326,9 +325,9 @@ static int sof_probe(struct platform_device *pdev) sdev->first_boot = false; /* now register audio DSP platform driver and dai */ - ret = snd_soc_register_component(&pdev->dev, &sdev->plat_drv, - sdev->ops->drv, - sdev->ops->num_drv); + ret = snd_soc_register_component(&pdev->dev, &sdev->plat_drv, + sof_ops(sdev)->drv, + sof_ops(sdev)->num_drv); if (ret < 0) { dev_err(sdev->dev, "error: failed to register DSP DAI driver %d\n", ret); diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 375a8e3d04cfe9..5794e272fbaa79 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -15,6 +15,7 @@ #include #include #include "sof-priv.h" +#include "ops.h" static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) @@ -139,7 +140,7 @@ EXPORT_SYMBOL(snd_sof_debugfs_buf_create_item); int snd_sof_dbg_init(struct snd_sof_dev *sdev) { - const struct snd_sof_dsp_ops *ops = sdev->ops; + const struct snd_sof_dsp_ops *ops = sof_ops(sdev); const struct snd_sof_debugfs_map *map; int err = 0, i; diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index 16315f555737b9..920540356e6e77 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -320,7 +320,6 @@ EXPORT_SYMBOL(snd_sof_spi_ops); const struct sof_intel_dsp_desc spi_chip_info = { .cores_num = 2, .cores_mask = 0x3, - .ops = &snd_sof_spi_ops, }; EXPORT_SYMBOL(spi_chip_info); diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 87ce880c698d21..054baf27abc08b 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -107,6 +107,5 @@ const struct sof_intel_dsp_desc apl_chip_info = { .ipc_ack = HDA_DSP_REG_HIPCIE, .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, .ipc_ctl = HDA_DSP_REG_HIPCCTL, - .ops = &sof_apl_ops, }; EXPORT_SYMBOL(apl_chip_info); diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 29048d3094cec8..25e28bbef43590 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -537,9 +537,6 @@ static int bdw_probe(struct snd_sof_dev *sdev) u32 base, size; int ret = 0; - /* set DSP arch ops */ - sdev->arch_ops = &sof_xtensa_arch_ops; - /* LPE base */ mmio = platform_get_resource(pdev, IORESOURCE_MEM, desc->resindex_lpe_base); @@ -700,7 +697,6 @@ EXPORT_SYMBOL(sof_bdw_ops); const struct sof_intel_dsp_desc bdw_chip_info = { .cores_num = 1, .cores_mask = 1, - .ops = &sof_bdw_ops, }; EXPORT_SYMBOL(bdw_chip_info); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 168b8d31735473..4d0d11a10f3dc3 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -639,7 +639,6 @@ EXPORT_SYMBOL(sof_tng_ops); const struct sof_intel_dsp_desc tng_chip_info = { .cores_num = 1, .cores_mask = 1, - .ops = &sof_tng_ops, }; EXPORT_SYMBOL(tng_chip_info); @@ -657,9 +656,6 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) u32 base, size; int ret = 0; - /* set DSP arch ops */ - sdev->arch_ops = &sof_xtensa_arch_ops; - /* DSP DMA can only access low 31 bits of host memory */ ret = dma_coerce_mask_and_coherent(sdev->dev, DMA_BIT_MASK(31)); if (ret < 0) { @@ -808,7 +804,6 @@ EXPORT_SYMBOL(sof_byt_ops); const struct sof_intel_dsp_desc byt_chip_info = { .cores_num = 1, .cores_mask = 1, - .ops = &sof_byt_ops, }; EXPORT_SYMBOL(byt_chip_info); @@ -867,7 +862,6 @@ EXPORT_SYMBOL(sof_cht_ops); const struct sof_intel_dsp_desc cht_chip_info = { .cores_num = 1, .cores_mask = 1, - .ops = &sof_cht_ops, }; EXPORT_SYMBOL(cht_chip_info); diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 134833bcf63e1c..bcc9820d57968c 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -259,6 +259,5 @@ const struct sof_intel_dsp_desc cnl_chip_info = { .ipc_ack = CNL_DSP_REG_HIPCIDA, .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, .ipc_ctl = CNL_DSP_REG_HIPCCTL, - .ops = &sof_cnl_ops, }; EXPORT_SYMBOL(cnl_chip_info); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 93541fe3f4b40a..32ceeb110cb959 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -332,9 +332,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) } dev_info(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n", pci->class); - /* set DSP arch ops */ - sdev->arch_ops = &sof_xtensa_arch_ops; - chip = get_chip_info(sdev->pdata); if (!chip) { dev_err(sdev->dev, "error: no such device supported, chip id:%x\n", @@ -364,7 +361,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION) hdev->no_ipc_position = 0; #else - hdev->no_ipc_position = sdev->ops->pcm_pointer ? 1 : 0; + hdev->no_ipc_position = sof_ops(sdev)->pcm_pointer ? 1 : 0; #endif /* set up HDA base */ @@ -442,7 +439,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) dev_dbg(sdev->dev, "using IPC IRQ %d\n", sdev->ipc_irq); ret = request_threaded_irq(sdev->ipc_irq, hda_dsp_ipc_irq_handler, - chip->ops->irq_thread, IRQF_SHARED, + sof_ops(sdev)->irq_thread, IRQF_SHARED, "AudioDSP", sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to register IPC IRQ %d\n", diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 9903a68b857a26..cbffbdcf932c3e 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -537,9 +537,6 @@ static int hsw_probe(struct snd_sof_dev *sdev) u32 base, size; int ret = 0; - /* set DSP arch ops */ - sdev->arch_ops = &sof_xtensa_arch_ops; - /* LPE base */ mmio = platform_get_resource(pdev, IORESOURCE_MEM, desc->resindex_lpe_base); @@ -701,7 +698,6 @@ EXPORT_SYMBOL(sof_hsw_ops); const struct sof_intel_dsp_desc hsw_chip_info = { .cores_num = 1, .cores_mask = 1, - .ops = &sof_hsw_ops, }; EXPORT_SYMBOL(hsw_chip_info); diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index f43b70d9d1c1df..1a92b155af24c7 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -160,7 +160,6 @@ struct sof_intel_dsp_desc { int ipc_ack; int ipc_ack_mask; int ipc_ctl; - const struct snd_sof_dsp_ops *ops; }; extern const struct snd_sof_dsp_ops sof_tng_ops; diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 55113d57486e59..433b9ed0ffee51 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -100,6 +100,5 @@ const struct sof_intel_dsp_desc skl_chip_info = { .ipc_ack = HDA_DSP_REG_HIPCIE, .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, .ipc_ctl = HDA_DSP_REG_HIPCCTL, - .ops = &sof_skl_ops, }; EXPORT_SYMBOL(skl_chip_info); diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 1dc4f9881efef8..60bfa6a76ddc02 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -397,8 +397,8 @@ static void ipc_msgs_rx(struct work_struct *work) case SOF_IPC_FW_READY: /* check for FW boot completion */ if (!sdev->boot_complete) { - if (sdev->ops->fw_ready) - err = sdev->ops->fw_ready(sdev, cmd); + if (sof_ops(sdev)->fw_ready) + err = sof_ops(sdev)->fw_ready(sdev, cmd); if (err < 0) { dev_err(sdev->dev, "error: DSP firmware boot timeout %d\n", err); diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 134cca656e51c1..3362861f2795e8 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -197,7 +197,7 @@ static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw) size_t remaining; header = (struct snd_sof_fw_header *)fw->data; - load_module = sdev->ops->load_module; + load_module = sof_ops(sdev)->load_module; if (!load_module) return -EINVAL; @@ -277,8 +277,8 @@ int snd_sof_load_firmware(struct snd_sof_dev *sdev) { dev_dbg(sdev->dev, "loading firmware\n"); - if (sdev->ops->load_firmware) - return sdev->ops->load_firmware(sdev); + if (sof_ops(sdev)->load_firmware) + return sof_ops(sdev)->load_firmware(sdev); return 0; } EXPORT_SYMBOL(snd_sof_load_firmware); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index cf7438ce19eb20..68c340a3f3a153 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -18,19 +18,22 @@ #include #include "sof-priv.h" +#define sof_ops(sdev) \ + ((sdev)->pdata->desc->ops) + /* init */ static inline int snd_sof_probe(struct snd_sof_dev *sdev) { - if (sdev->ops->probe) - return sdev->ops->probe(sdev); + if (sof_ops(sdev)->probe) + return sof_ops(sdev)->probe(sdev); return 0; } static inline int snd_sof_remove(struct snd_sof_dev *sdev) { - if (sdev->ops->remove) - return sdev->ops->remove(sdev); + if (sof_ops(sdev)->remove) + return sof_ops(sdev)->remove(sdev); return 0; } @@ -38,24 +41,24 @@ static inline int snd_sof_remove(struct snd_sof_dev *sdev) /* control */ static inline int snd_sof_dsp_run(struct snd_sof_dev *sdev) { - if (sdev->ops->run) - return sdev->ops->run(sdev); + if (sof_ops(sdev)->run) + return sof_ops(sdev)->run(sdev); return 0; } static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev) { - if (sdev->ops->stall) - return sdev->ops->stall(sdev); + if (sof_ops(sdev)->stall) + return sof_ops(sdev)->stall(sdev); return 0; } static inline int snd_sof_dsp_reset(struct snd_sof_dev *sdev) { - if (sdev->ops->reset) - return sdev->ops->reset(sdev); + if (sof_ops(sdev)->reset) + return sof_ops(sdev)->reset(sdev); return 0; } @@ -64,8 +67,8 @@ static inline int snd_sof_dsp_reset(struct snd_sof_dev *sdev) static inline int snd_sof_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) { - if (sdev->ops->core_power_up) - return sdev->ops->core_power_up(sdev, core_mask); + if (sof_ops(sdev)->core_power_up) + return sof_ops(sdev)->core_power_up(sdev, core_mask); return 0; } @@ -73,8 +76,8 @@ static inline int snd_sof_dsp_core_power_up(struct snd_sof_dev *sdev, static inline int snd_sof_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask) { - if (sdev->ops->core_power_down) - return sdev->ops->core_power_down(sdev, core_mask); + if (sof_ops(sdev)->core_power_down) + return sof_ops(sdev)->core_power_down(sdev, core_mask); return 0; } @@ -82,16 +85,16 @@ static inline int snd_sof_dsp_core_power_down(struct snd_sof_dev *sdev, /* pre/post fw load */ static inline int snd_sof_dsp_pre_fw_run(struct snd_sof_dev *sdev) { - if (sdev->ops->pre_fw_run) - return sdev->ops->pre_fw_run(sdev); + if (sof_ops(sdev)->pre_fw_run) + return sof_ops(sdev)->pre_fw_run(sdev); return 0; } static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev) { - if (sdev->ops->post_fw_run) - return sdev->ops->post_fw_run(sdev); + if (sof_ops(sdev)->post_fw_run) + return sof_ops(sdev)->post_fw_run(sdev); return 0; } @@ -99,24 +102,24 @@ static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev) /* power management */ static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev) { - if (sdev->ops->resume) - return sdev->ops->resume(sdev); + if (sof_ops(sdev)->resume) + return sof_ops(sdev)->resume(sdev); return 0; } static inline int snd_sof_dsp_suspend(struct snd_sof_dev *sdev, int state) { - if (sdev->ops->suspend) - return sdev->ops->suspend(sdev, state); + if (sof_ops(sdev)->suspend) + return sof_ops(sdev)->suspend(sdev, state); return 0; } static inline int snd_sof_dsp_runtime_resume(struct snd_sof_dev *sdev) { - if (sdev->ops->runtime_resume) - return sdev->ops->runtime_resume(sdev); + if (sof_ops(sdev)->runtime_resume) + return sof_ops(sdev)->runtime_resume(sdev); return 0; } @@ -124,16 +127,16 @@ static inline int snd_sof_dsp_runtime_resume(struct snd_sof_dev *sdev) static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state) { - if (sdev->ops->runtime_suspend) - return sdev->ops->runtime_suspend(sdev, state); + if (sof_ops(sdev)->runtime_suspend) + return sof_ops(sdev)->runtime_suspend(sdev, state); return 0; } static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq) { - if (sdev->ops->set_clk) - return sdev->ops->set_clk(sdev, freq); + if (sof_ops(sdev)->set_clk) + return sof_ops(sdev)->set_clk(sdev, freq); return 0; } @@ -141,30 +144,30 @@ static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq) /* debug */ static inline void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, u32 flags) { - if (sdev->ops->dbg_dump) - return sdev->ops->dbg_dump(sdev, flags); + if (sof_ops(sdev)->dbg_dump) + return sof_ops(sdev)->dbg_dump(sdev, flags); } /* register IO */ static inline void snd_sof_dsp_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 value) { - if (sdev->ops->write) - sdev->ops->write(sdev, sdev->bar[bar] + offset, value); + if (sof_ops(sdev)->write) + sof_ops(sdev)->write(sdev, sdev->bar[bar] + offset, value); } static inline void snd_sof_dsp_write64(struct snd_sof_dev *sdev, u32 bar, u32 offset, u64 value) { - if (sdev->ops->write64) - sdev->ops->write64(sdev, sdev->bar[bar] + offset, value); + if (sof_ops(sdev)->write64) + sof_ops(sdev)->write64(sdev, sdev->bar[bar] + offset, value); } static inline u32 snd_sof_dsp_read(struct snd_sof_dev *sdev, u32 bar, u32 offset) { - if (sdev->ops->read) - return sdev->ops->read(sdev, sdev->bar[bar] + offset); + if (sof_ops(sdev)->read) + return sof_ops(sdev)->read(sdev, sdev->bar[bar] + offset); return 0; } @@ -172,8 +175,8 @@ static inline u32 snd_sof_dsp_read(struct snd_sof_dev *sdev, u32 bar, static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar, u32 offset) { - if (sdev->ops->read64) - return sdev->ops->read64(sdev, sdev->bar[bar] + offset); + if (sof_ops(sdev)->read64) + return sof_ops(sdev)->read64(sdev, sdev->bar[bar] + offset); return 0; } @@ -182,15 +185,15 @@ static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar, static inline void snd_sof_dsp_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, size_t bytes) { - if (sdev->ops->block_read) - sdev->ops->block_read(sdev, offset, dest, bytes); + if (sof_ops(sdev)->block_read) + sof_ops(sdev)->block_read(sdev, offset, dest, bytes); } static inline void snd_sof_dsp_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, size_t bytes) { - if (sdev->ops->block_write) - sdev->ops->block_write(sdev, offset, src, bytes); + if (sof_ops(sdev)->block_write) + sof_ops(sdev)->block_write(sdev, offset, src, bytes); } /* mailbox */ @@ -198,24 +201,24 @@ static inline void snd_sof_dsp_mailbox_read(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes) { - if (sdev->ops->mailbox_read) - sdev->ops->mailbox_read(sdev, offset, message, bytes); + if (sof_ops(sdev)->mailbox_read) + sof_ops(sdev)->mailbox_read(sdev, offset, message, bytes); } static inline void snd_sof_dsp_mailbox_write(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes) { - if (sdev->ops->mailbox_write) - sdev->ops->mailbox_write(sdev, offset, message, bytes); + if (sof_ops(sdev)->mailbox_write) + sof_ops(sdev)->mailbox_write(sdev, offset, message, bytes); } /* ipc */ static inline int snd_sof_dsp_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { - if (sdev->ops->send_msg) - return sdev->ops->send_msg(sdev, msg); + if (sof_ops(sdev)->send_msg) + return sof_ops(sdev)->send_msg(sdev, msg); return 0; } @@ -223,16 +226,16 @@ static inline int snd_sof_dsp_send_msg(struct snd_sof_dev *sdev, static inline int snd_sof_dsp_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { - if (sdev->ops->get_reply) - return sdev->ops->get_reply(sdev, msg); + if (sof_ops(sdev)->get_reply) + return sof_ops(sdev)->get_reply(sdev, msg); return 0; } static inline int snd_sof_dsp_is_ready(struct snd_sof_dev *sdev) { - if (sdev->ops->is_ready) - return sdev->ops->is_ready(sdev); + if (sof_ops(sdev)->is_ready) + return sof_ops(sdev)->is_ready(sdev); return 0; } @@ -240,8 +243,8 @@ static inline int snd_sof_dsp_is_ready(struct snd_sof_dev *sdev) static inline int snd_sof_dsp_cmd_done(struct snd_sof_dev *sdev, int dir) { - if (sdev->ops->cmd_done) - return sdev->ops->cmd_done(sdev, dir); + if (sof_ops(sdev)->cmd_done) + return sof_ops(sdev)->cmd_done(sdev, dir); return 0; } @@ -250,24 +253,24 @@ static inline int snd_sof_dsp_cmd_done(struct snd_sof_dev *sdev, static inline int snd_sof_dma_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag) { - if (sdev->ops->trace_init) - return sdev->ops->trace_init(sdev, stream_tag); + if (sof_ops(sdev)->trace_init) + return sof_ops(sdev)->trace_init(sdev, stream_tag); return 0; } static inline int snd_sof_dma_trace_release(struct snd_sof_dev *sdev) { - if (sdev->ops->trace_release) - return sdev->ops->trace_release(sdev); + if (sof_ops(sdev)->trace_release) + return sof_ops(sdev)->trace_release(sdev); return 0; } static inline int snd_sof_dma_trace_trigger(struct snd_sof_dev *sdev, int cmd) { - if (sdev->ops->trace_trigger) - return sdev->ops->trace_trigger(sdev, cmd); + if (sof_ops(sdev)->trace_trigger) + return sof_ops(sdev)->trace_trigger(sdev, cmd); return 0; } @@ -277,8 +280,8 @@ static inline int snd_sof_pcm_platform_open(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { - if (sdev->ops && sdev->ops->pcm_open) - return sdev->ops->pcm_open(sdev, substream); + if (sof_ops(sdev) && sof_ops(sdev)->pcm_open) + return sof_ops(sdev)->pcm_open(sdev, substream); return 0; } @@ -288,8 +291,8 @@ static inline int snd_sof_pcm_platform_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { - if (sdev->ops && sdev->ops->pcm_close) - return sdev->ops->pcm_close(sdev, substream); + if (sof_ops(sdev) && sof_ops(sdev)->pcm_close) + return sof_ops(sdev)->pcm_close(sdev, substream); return 0; } @@ -301,9 +304,9 @@ snd_sof_pcm_platform_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params, struct sof_ipc_stream_params *ipc_params) { - if (sdev->ops && sdev->ops->pcm_hw_params) - return sdev->ops->pcm_hw_params(sdev, substream, - params, ipc_params); + if (sof_ops(sdev) && sof_ops(sdev)->pcm_hw_params) + return sof_ops(sdev)->pcm_hw_params(sdev, substream, + params, ipc_params); return 0; } @@ -313,8 +316,8 @@ static inline int snd_sof_pcm_platform_trigger(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, int cmd) { - if (sdev->ops && sdev->ops->pcm_trigger) - return sdev->ops->pcm_trigger(sdev, substream, cmd); + if (sof_ops(sdev) && sof_ops(sdev)->pcm_trigger) + return sof_ops(sdev)->pcm_trigger(sdev, substream, cmd); return 0; } @@ -324,8 +327,8 @@ static inline snd_pcm_uframes_t snd_sof_pcm_platform_pointer(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { - if (sdev->ops && sdev->ops->pcm_pointer) - return sdev->ops->pcm_pointer(sdev, substream); + if (sof_ops(sdev) && sof_ops(sdev)->pcm_pointer) + return sof_ops(sdev)->pcm_pointer(sdev, substream); return 0; } diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index d62bb052c62788..e6fae94e4e84dc 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -339,8 +339,8 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) return 0; /* if have dsp ops pointer callback, use that directly */ - if (sdev->ops->pcm_pointer) - return sdev->ops->pcm_pointer(sdev, substream); + if (sof_ops(sdev)->pcm_pointer) + return sof_ops(sdev)->pcm_pointer(sdev, substream); /* read position from DSP */ host = bytes_to_frames(substream->runtime, diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 64833396a50d98..46efffc85ea3a1 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -233,7 +233,7 @@ static int sof_resume(struct device *dev, bool runtime_resume) int ret = 0; /* do nothing if dsp resume callbacks are not set */ - if (!sdev->ops->resume || !sdev->ops->runtime_resume) + if (!sof_ops(sdev)->resume || !sof_ops(sdev)->runtime_resume) return 0; /* @@ -303,7 +303,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) int ret = 0; /* do nothing if dsp suspend callback is not set */ - if (!sdev->ops->suspend) + if (!sof_ops(sdev)->suspend) return 0; /* release trace */ diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index b9f87d1c44c747..f85c7046120711 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -33,7 +33,9 @@ static struct sof_dev_desc sof_acpi_haswell_desc = { .irqindex_host_ipc = 0, .chip_info = &hsw_chip_info, .nocodec_fw_filename = "intel/sof-hsw.ri", - .nocodec_tplg_filename = "intel/sof-hsw-nocodec.tplg" + .nocodec_tplg_filename = "intel/sof-hsw-nocodec.tplg", + .ops = &sof_hsw_ops, + .arch_ops = &sof_xtensa_arch_ops }; #endif @@ -46,7 +48,9 @@ static struct sof_dev_desc sof_acpi_broadwell_desc = { .irqindex_host_ipc = 0, .chip_info = &bdw_chip_info, .nocodec_fw_filename = "intel/sof-bdw.ri", - .nocodec_tplg_filename = "intel/sof-bdw-nocodec.tplg" + .nocodec_tplg_filename = "intel/sof-bdw-nocodec.tplg", + .ops = &sof_bdw_ops, + .arch_ops = &sof_xtensa_arch_ops }; #endif @@ -61,7 +65,9 @@ static struct sof_dev_desc sof_acpi_baytrailcr_desc = { .irqindex_host_ipc = 0, .chip_info = &byt_chip_info, .nocodec_fw_filename = "intel/sof-byt.ri", - .nocodec_tplg_filename = "intel/sof-byt-nocodec.tplg" + .nocodec_tplg_filename = "intel/sof-byt-nocodec.tplg", + .ops = &sof_byt_ops, + .arch_ops = &sof_xtensa_arch_ops }; static struct sof_dev_desc sof_acpi_baytrail_desc = { @@ -72,7 +78,9 @@ static struct sof_dev_desc sof_acpi_baytrail_desc = { .irqindex_host_ipc = 5, .chip_info = &byt_chip_info, .nocodec_fw_filename = "intel/sof-byt.ri", - .nocodec_tplg_filename = "intel/sof-byt-nocodec.tplg" + .nocodec_tplg_filename = "intel/sof-byt-nocodec.tplg", + .ops = &sof_byt_ops, + .arch_ops = &sof_xtensa_arch_ops }; #ifdef CONFIG_X86 /* TODO: move this to common helper */ @@ -122,7 +130,9 @@ static struct sof_dev_desc sof_acpi_cherrytrail_desc = { .irqindex_host_ipc = 5, .chip_info = &cht_chip_info, .nocodec_fw_filename = "intel/sof-cht.ri", - .nocodec_tplg_filename = "intel/sof-cht-nocodec.tplg" + .nocodec_tplg_filename = "intel/sof-cht-nocodec.tplg", + .ops = &sof_cht_ops, + .arch_ops = &sof_xtensa_arch_ops }; #endif @@ -163,7 +173,7 @@ static int sof_acpi_probe(struct platform_device *pdev) #endif /* get ops for platform */ - ops = ((const struct sof_intel_dsp_desc *)desc->chip_info)->ops; + ops = desc->ops; if (!ops) { dev_err(dev, "error: no matching ACPI descriptor ops\n"); return -ENODEV; @@ -196,13 +206,6 @@ static int sof_acpi_probe(struct platform_device *pdev) } #endif - /* - * save ops in pdata. - * TODO: the explicit cast removes the const attribute, we'll need - * to add a dedicated ops field in the generic soc-acpi structure - * to avoid such issues - */ - mach->pdata = (void *)ops; sof_pdata->machine = mach; sof_pdata->desc = desc; priv->sof_pdata = sof_pdata; diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 47c27d55b593e7..881cac96f07a57 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -31,7 +31,9 @@ static struct sof_dev_desc bxt_desc = { .resindex_dma_base = -1, .chip_info = &apl_chip_info, .nocodec_fw_filename = "intel/sof-apl.ri", - .nocodec_tplg_filename = "intel/sof-apl-nocodec.tplg" + .nocodec_tplg_filename = "intel/sof-apl-nocodec.tplg", + .ops = &sof_apl_ops, + .arch_ops = &sof_xtensa_arch_ops }; #endif @@ -45,7 +47,9 @@ static struct sof_dev_desc glk_desc = { .resindex_dma_base = -1, .chip_info = &apl_chip_info, .nocodec_fw_filename = "intel/sof-glk.ri", - .nocodec_tplg_filename = "intel/sof-glk-nocodec.tplg" + .nocodec_tplg_filename = "intel/sof-glk-nocodec.tplg", + .ops = &sof_apl_ops, + .arch_ops = &sof_xtensa_arch_ops }; #endif @@ -70,7 +74,9 @@ static const struct sof_dev_desc tng_desc = { .resindex_dma_base = -1, .chip_info = &tng_chip_info, .nocodec_fw_filename = "intel/sof-byt.ri", - .nocodec_tplg_filename = "intel/sof-byt.tplg" + .nocodec_tplg_filename = "intel/sof-byt.tplg", + .ops = &sof_tng_ops, + .arch_ops = &sof_xtensa_arch_ops }; #endif @@ -84,7 +90,9 @@ static const struct sof_dev_desc cnl_desc = { .resindex_dma_base = -1, .chip_info = &cnl_chip_info, .nocodec_fw_filename = "intel/sof-cnl.ri", - .nocodec_tplg_filename = "intel/sof-cnl.tplg" + .nocodec_tplg_filename = "intel/sof-cnl.tplg", + .ops = &sof_cnl_ops, + .arch_ops = &sof_xtensa_arch_ops }; #endif @@ -98,7 +106,9 @@ static const struct sof_dev_desc icl_desc = { .resindex_dma_base = -1, .chip_info = &cnl_chip_info, .nocodec_fw_filename = "intel/sof-icl.ri", - .nocodec_tplg_filename = "intel/sof-icl-nocodec.tplg" + .nocodec_tplg_filename = "intel/sof-icl-nocodec.tplg", + .ops = &sof_cnl_ops, + .arch_ops = &sof_xtensa_arch_ops }; #endif @@ -112,7 +122,9 @@ static struct sof_dev_desc skl_desc = { .resindex_dma_base = -1, .chip_info = &skl_chip_info, .nocodec_fw_filename = "intel/sof-skl.ri", - .nocodec_tplg_filename = "intel/sof-skl-nocodec.tplg" + .nocodec_tplg_filename = "intel/sof-skl-nocodec.tplg", + .ops = &sof_skl_ops, + .arch_ops = &sof_xtensa_arch_ops }; #endif @@ -126,7 +138,9 @@ static struct sof_dev_desc kbl_desc = { .resindex_dma_base = -1, .chip_info = &skl_chip_info, .nocodec_fw_filename = "intel/sof-kbl.ri", - .nocodec_tplg_filename = "intel/sof-kbl-nocodec.tplg" + .nocodec_tplg_filename = "intel/sof-kbl-nocodec.tplg", + .ops = &sof_skl_ops, + .arch_ops = &sof_xtensa_arch_ops }; #endif @@ -153,7 +167,7 @@ static int sof_pci_probe(struct pci_dev *pci, dev_dbg(&pci->dev, "PCI DSP detected"); /* get ops for platform */ - ops = ((const struct sof_intel_dsp_desc *)desc->chip_info)->ops; + ops = desc->ops; if (!ops) { dev_err(dev, "error: no matching PCI descriptor ops\n"); return -ENODEV; @@ -227,14 +241,6 @@ static int sof_pci_probe(struct pci_dev *pci, goto release_regions; } - /* - * save ops in pdata. - * TODO: the explicit cast removes the const attribute, we'll need - * to add a dedicated ops field in the generic soc-acpi structure - * to avoid such issues - */ - mach->pdata = (void *)ops; - sof_pdata->id = pci_id->device; sof_pdata->name = pci_name(pci); sof_pdata->machine = mach; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index a5e8ce54338282..66f091ef9f4514 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -174,6 +174,9 @@ struct sof_arch_ops { u32 *stack, u32 stack_words); }; +#define sof_arch_ops(sdev) \ + ((sdev)->pdata->desc->arch_ops) + /* DSP device HW descriptor mapping between bus ID and ops */ struct sof_ops_table { const struct sof_dev_desc *desc; @@ -314,8 +317,6 @@ struct snd_sof_dev { /* DSP HW differentiation */ struct snd_sof_pdata *pdata; - const struct snd_sof_dsp_ops *ops; - const struct sof_arch_ops *arch_ops; /* IPC */ struct snd_sof_ipc *ipc; @@ -533,14 +534,14 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, static inline void sof_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack, u32 stack_words) { - if (sdev->arch_ops->dsp_stack) - sdev->arch_ops->dsp_stack(sdev, oops, stack, stack_words); + if (sof_arch_ops(sdev)->dsp_stack) + sof_arch_ops(sdev)->dsp_stack(sdev, oops, stack, stack_words); } static inline void sof_oops(struct snd_sof_dev *sdev, void *oops) { - if (sdev->arch_ops->dsp_oops) - sdev->arch_ops->dsp_oops(sdev, oops); + if (sof_arch_ops(sdev)->dsp_oops) + sof_arch_ops(sdev)->dsp_oops(sdev, oops); } extern const struct sof_arch_ops sof_xtensa_arch_ops; diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index 73fe5e266dd4d8..16fc3c8bd2dad2 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -44,6 +44,7 @@ static const struct sof_dev_desc spi_desc = { .irqindex_host_ipc = -1, .resindex_dma_base = -1, .chip_info = &spi_chip_info, + .ops = &snd_sof_spi_ops }; static int sof_spi_probe(struct spi_device *spi) @@ -51,7 +52,6 @@ static int sof_spi_probe(struct spi_device *spi) struct device *dev = &spi->dev; const struct sof_dev_desc *desc = of_device_get_match_data(dev); struct snd_soc_acpi_mach *machines, *mach; - const struct sof_intel_dsp_desc *chip_info; struct snd_sof_pdata *sof_pdata; struct sof_platform_priv *priv; struct sof_spi_dev *sof_spi; @@ -122,19 +122,6 @@ static int sof_spi_probe(struct spi_device *spi) mach->sof_tplg_filename = desc->nocodec_tplg_filename; mach->asoc_plat_name = "sof-platform"; - /* - * save ops in pdata. - * TODO: the explicit cast removes the const attribute, we'll need - * to add a dedicated ops field in the generic soc-acpi structure - * to avoid such issues - */ - chip_info = (const struct sof_intel_dsp_desc *)desc->chip_info; - mach->pdata = (void *)chip_info->ops; - if (!mach->pdata) { - dev_err(dev, "error: no matching SPI descriptor ops\n"); - return -ENODEV; - } - sof_pdata->id = -1; sof_pdata->name = dev_name(&spi->dev); sof_pdata->machine = mach; From abc41de54ba248df7af988725ce5db1148ac50dd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Dec 2018 15:11:09 +0100 Subject: [PATCH 0498/1995] ALSA: hda/intel: Refactoring PM code Make unified suspend / resume helpers and call them from both the runtime- and the system-PM callbacks for simplifying code. There are slight changes of call orders, but there shouldn't be any functional difference after refactoring. Signed-off-by: Takashi Iwai (cherry picked from commit 3baffc4a84d759ba54c461e8e4583bd8890c749a) --- sound/pci/hda/hda_intel.c | 160 ++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 91 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 76f03abd15ab76..cc06a323c81702 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -930,35 +930,82 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) mutex_unlock(&card_list_lock); return 0; } -#else -#define azx_add_card_list(chip) /* NOP */ -#define azx_del_card_list(chip) /* NOP */ -#endif /* CONFIG_PM */ -#ifdef CONFIG_PM_SLEEP /* * power management */ -static int azx_suspend(struct device *dev) +static bool azx_is_pm_ready(struct snd_card *card) { - struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; struct hda_intel *hda; - struct hdac_bus *bus; if (!card) - return 0; - + return false; chip = card->private_data; hda = container_of(chip, struct hda_intel, chip); if (chip->disabled || hda->init_failed || !chip->running) + return false; + return true; +} + +static void __azx_runtime_suspend(struct azx *chip) +{ + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + + azx_stop_chip(chip); + azx_enter_link_reset(chip); + azx_clear_irq_pending(chip); + if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && + hda->need_i915_power) + snd_hdac_display_power(azx_bus(chip), false); +} + +static void __azx_runtime_resume(struct azx *chip) +{ + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + struct hdac_bus *bus = azx_bus(chip); + struct hda_codec *codec; + int status; + + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { + snd_hdac_display_power(bus, true); + if (hda->need_i915_power) + snd_hdac_i915_set_bclk(bus); + } + + /* Read STATESTS before controller reset */ + status = azx_readw(chip, STATESTS); + + azx_init_pci(chip); + hda_intel_init_chip(chip, true); + + if (status) { + list_for_each_codec(codec, &chip->bus) + if (status & (1 << codec->addr)) + schedule_delayed_work(&codec->jackpoll_work, + codec->jackpoll_interval); + } + + /* power down again for link-controlled chips */ + if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && + !hda->need_i915_power) + snd_hdac_display_power(bus, false); +} + +#ifdef CONFIG_PM_SLEEP +static int azx_suspend(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip; + struct hdac_bus *bus; + + if (!azx_is_pm_ready(card)) return 0; + chip = card->private_data; bus = azx_bus(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - azx_clear_irq_pending(chip); - azx_stop_chip(chip); - azx_enter_link_reset(chip); + __azx_runtime_suspend(chip); if (bus->irq >= 0) { free_irq(bus->irq, chip); bus->irq = -1; @@ -966,9 +1013,6 @@ static int azx_suspend(struct device *dev) if (chip->msi) pci_disable_msi(chip->pci); - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - && hda->need_i915_power) - snd_hdac_display_power(bus, false); trace_azx_suspend(chip); return 0; @@ -976,41 +1020,19 @@ static int azx_suspend(struct device *dev) static int azx_resume(struct device *dev) { - struct pci_dev *pci = to_pci_dev(dev); struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; - struct hda_intel *hda; - struct hdac_bus *bus; - if (!card) + if (!azx_is_pm_ready(card)) return 0; chip = card->private_data; - hda = container_of(chip, struct hda_intel, chip); - bus = azx_bus(chip); - if (chip->disabled || hda->init_failed || !chip->running) - return 0; - - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - snd_hdac_display_power(bus, true); - if (hda->need_i915_power) - snd_hdac_i915_set_bclk(bus); - } - if (chip->msi) - if (pci_enable_msi(pci) < 0) + if (pci_enable_msi(chip->pci) < 0) chip->msi = 0; if (azx_acquire_irq(chip, 1) < 0) return -EIO; - azx_init_pci(chip); - - hda_intel_init_chip(chip, true); - - /* power down again for link-controlled chips */ - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && - !hda->need_i915_power) - snd_hdac_display_power(bus, false); - + __azx_runtime_resume(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D0); trace_azx_resume(chip); @@ -1045,21 +1067,14 @@ static int azx_thaw_noirq(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -#ifdef CONFIG_PM static int azx_runtime_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; - struct hda_intel *hda; - if (!card) + if (!azx_is_pm_ready(card)) return 0; - chip = card->private_data; - hda = container_of(chip, struct hda_intel, chip); - if (chip->disabled || hda->init_failed) - return 0; - if (!azx_has_pm_runtime(chip)) return 0; @@ -1067,13 +1082,7 @@ static int azx_runtime_suspend(struct device *dev) azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) | STATESTS_INT_MASK); - azx_stop_chip(chip); - azx_enter_link_reset(chip); - azx_clear_irq_pending(chip); - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - && hda->need_i915_power) - snd_hdac_display_power(azx_bus(chip), false); - + __azx_runtime_suspend(chip); trace_azx_runtime_suspend(chip); return 0; } @@ -1082,51 +1091,18 @@ static int azx_runtime_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; - struct hda_intel *hda; - struct hdac_bus *bus; - struct hda_codec *codec; - int status; - if (!card) + if (!azx_is_pm_ready(card)) return 0; - chip = card->private_data; - hda = container_of(chip, struct hda_intel, chip); - bus = azx_bus(chip); - if (chip->disabled || hda->init_failed) - return 0; - if (!azx_has_pm_runtime(chip)) return 0; - - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - snd_hdac_display_power(bus, true); - if (hda->need_i915_power) - snd_hdac_i915_set_bclk(bus); - } - - /* Read STATESTS before controller reset */ - status = azx_readw(chip, STATESTS); - - azx_init_pci(chip); - hda_intel_init_chip(chip, true); - - if (status) { - list_for_each_codec(codec, &chip->bus) - if (status & (1 << codec->addr)) - schedule_delayed_work(&codec->jackpoll_work, - codec->jackpoll_interval); - } + __azx_runtime_resume(chip); /* disable controller Wake Up event*/ azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & ~STATESTS_INT_MASK); - /* power down again for link-controlled chips */ - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && - !hda->need_i915_power) - snd_hdac_display_power(bus, false); - trace_azx_runtime_resume(chip); return 0; } @@ -1167,6 +1143,8 @@ static const struct dev_pm_ops azx_pm = { #define AZX_PM_OPS &azx_pm #else +#define azx_add_card_list(chip) /* NOP */ +#define azx_del_card_list(chip) /* NOP */ #define AZX_PM_OPS NULL #endif /* CONFIG_PM */ From df1ebad395167af44dc5172c0f8fe54eaae71be0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 8 Dec 2018 17:31:49 +0100 Subject: [PATCH 0499/1995] ALSA: hda: Refactor display power management The current HD-audio code manages the DRM audio power via too complex redirections, and this seems even still unbalanced in a corner case as Intel DRM CI has been intermittently reporting. This patch is a big surgery for addressing the complexity and the possible unbalance. Basically the patch changes the display PM in the following ways: - Both HD-audio controller and codec drivers call a single helper, snd_hdac_display_power(). (Formerly, the display power control from a codec was done indirectly via link_power bus ops.) - snd_hdac_display_power() receives the codec address index. For turning on/off from the controller, pass HDA_CODEC_IDX_CONTROLLER. - snd_hdac_display_power() doesn't manage refcounts any longer, but keeps the power status in bitmap. If any of controller or codecs is turned on, the function updates the DRM power state via get_power() or put_power(). Also this refactor allows us more cleanup: - The link_power bus ops is dropped, so there is no longer indirect management, as mentioned in the above. - hdac_device link_power_control flag is moved to hda_codec display_power_control flag, as it's only for HDA legacy. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106525 Signed-off-by: Takashi Iwai (cherry picked from commit 029d92c289bdad08ed08e61bf31b17cdc9ee61cf) --- include/sound/hda_codec.h | 1 + include/sound/hda_component.h | 10 ++++++++-- include/sound/hdaudio.h | 7 ++----- sound/hda/hdac_component.c | 35 +++++++++++++++++++++------------- sound/hda/hdac_device.c | 17 ----------------- sound/pci/hda/hda_codec.c | 16 ++++++++++++---- sound/pci/hda/hda_controller.c | 11 ----------- sound/pci/hda/hda_intel.c | 22 ++++++++------------- sound/pci/hda/patch_hdmi.c | 4 ++-- sound/soc/codecs/hdac_hdmi.c | 7 +++---- sound/soc/intel/skylake/skl.c | 10 +++++----- 11 files changed, 63 insertions(+), 77 deletions(-) diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index 0d98bb9068b178..7fa48b10093618 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -236,6 +236,7 @@ struct hda_codec { /* misc flags */ unsigned int in_freeing:1; /* being released */ unsigned int registered:1; /* codec was registered */ + unsigned int display_power_control:1; /* needs display power */ unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each * status change * (e.g. Realtek codecs) diff --git a/include/sound/hda_component.h b/include/sound/hda_component.h index 78626cde70811a..767c8d8a0230ba 100644 --- a/include/sound/hda_component.h +++ b/include/sound/hda_component.h @@ -5,10 +5,15 @@ #define __SOUND_HDA_COMPONENT_H #include +#include + +/* virtual idx for controller */ +#define HDA_CODEC_IDX_CONTROLLER HDA_MAX_CODECS #ifdef CONFIG_SND_HDA_COMPONENT int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable); -int snd_hdac_display_power(struct hdac_bus *bus, bool enable); +int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, + bool enable); int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int dev_id, int rate); int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id, @@ -25,7 +30,8 @@ static inline int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) { return 0; } -static inline int snd_hdac_display_power(struct hdac_bus *bus, bool enable) +static inline int snd_hdac_display_power(struct hdac_bus *bus, + unsigned int idx, bool enable) { return 0; } diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index cd1773d0e08f07..940e2b28213358 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -79,7 +79,6 @@ struct hdac_device { /* misc flags */ atomic_t in_pm; /* suspend/resume being performed */ - bool link_power_control:1; /* sysfs */ struct hdac_widget_tree *widgets; @@ -237,8 +236,6 @@ struct hdac_bus_ops { /* get a response from the last command */ int (*get_response)(struct hdac_bus *bus, unsigned int addr, unsigned int *res); - /* control the link power */ - int (*link_power)(struct hdac_bus *bus, bool enable); }; /* @@ -363,7 +360,8 @@ struct hdac_bus { /* DRM component interface */ struct drm_audio_component *audio_component; - int drm_power_refcount; + long display_power_status; + bool display_power_active; /* parameters required for enhanced capabilities */ int num_streams; @@ -404,7 +402,6 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val); int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr, unsigned int *res); int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus); -int snd_hdac_link_power(struct hdac_device *codec, bool enable); bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset); void snd_hdac_bus_stop_chip(struct hdac_bus *bus); diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c index 6e46a9c73aed46..dd766414436be3 100644 --- a/sound/hda/hdac_component.c +++ b/sound/hda/hdac_component.c @@ -54,38 +54,45 @@ EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup); /** * snd_hdac_display_power - Power up / down the power refcount * @bus: HDA core bus + * @idx: HDA codec address, pass HDA_CODEC_IDX_CONTROLLER for controller * @enable: power up or down * - * This function is supposed to be used only by a HD-audio controller - * driver that needs the interaction with graphics driver. + * This function is used by either HD-audio controller or codec driver that + * needs the interaction with graphics driver. * - * This function manages a refcount and calls the get_power() and + * This function updates the power status, and calls the get_power() and * put_power() ops accordingly, toggling the codec wakeup, too. * * Returns zero for success or a negative error code. */ -int snd_hdac_display_power(struct hdac_bus *bus, bool enable) +int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) { struct drm_audio_component *acomp = bus->audio_component; - if (!acomp || !acomp->ops) - return -ENODEV; - dev_dbg(bus->dev, "display power %s\n", enable ? "enable" : "disable"); + if (enable) + set_bit(idx, &bus->display_power_status); + else + clear_bit(idx, &bus->display_power_status); - if (enable) { - if (!bus->drm_power_refcount++) { + if (!acomp || !acomp->ops) + return 0; + + if (bus->display_power_status) { + if (!bus->display_power_active) { if (acomp->ops->get_power) acomp->ops->get_power(acomp->dev); snd_hdac_set_codec_wakeup(bus, true); snd_hdac_set_codec_wakeup(bus, false); + bus->display_power_active = true; } } else { - WARN_ON(!bus->drm_power_refcount); - if (!--bus->drm_power_refcount) + if (bus->display_power_active) { if (acomp->ops->put_power) acomp->ops->put_power(acomp->dev); + bus->display_power_active = false; + } } return 0; @@ -321,10 +328,12 @@ int snd_hdac_acomp_exit(struct hdac_bus *bus) if (!acomp) return 0; - WARN_ON(bus->drm_power_refcount); - if (bus->drm_power_refcount > 0 && acomp->ops) + if (WARN_ON(bus->display_power_active) && acomp->ops) acomp->ops->put_power(acomp->dev); + bus->display_power_active = false; + bus->display_power_status = 0; + component_master_del(dev, &hdac_component_master_ops); bus->audio_component = NULL; diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index dbf02a3a8d2f28..95b073ee4b32bb 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -622,23 +622,6 @@ int snd_hdac_power_down_pm(struct hdac_device *codec) EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm); #endif -/** - * snd_hdac_link_power - Enable/disable the link power for a codec - * @codec: the codec object - * @bool: enable or disable the link power - */ -int snd_hdac_link_power(struct hdac_device *codec, bool enable) -{ - if (!codec->link_power_control) - return 0; - - if (codec->bus->ops->link_power) - return codec->bus->ops->link_power(codec->bus, enable); - else - return -EINVAL; -} -EXPORT_SYMBOL_GPL(snd_hdac_link_power); - /* codec vendor labels */ struct hda_vendor_id { unsigned int id; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 0957813939e5cf..9f8d59e7e89f46 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -36,6 +36,7 @@ #include "hda_beep.h" #include "hda_jack.h" #include +#include #define codec_in_pm(codec) snd_hdac_is_in_pm(&codec->core) #define hda_codec_is_power_on(codec) snd_hdac_is_power_on(&codec->core) @@ -799,6 +800,13 @@ void snd_hda_codec_cleanup_for_unbind(struct hda_codec *codec) static unsigned int hda_set_power_state(struct hda_codec *codec, unsigned int power_state); +/* enable/disable display power per codec */ +static void codec_display_power(struct hda_codec *codec, bool enable) +{ + if (codec->display_power_control) + snd_hdac_display_power(&codec->bus->core, codec->addr, enable); +} + /* also called from hda_bind.c */ void snd_hda_codec_register(struct hda_codec *codec) { @@ -806,7 +814,7 @@ void snd_hda_codec_register(struct hda_codec *codec) return; if (device_is_registered(hda_codec_dev(codec))) { snd_hda_register_beep_device(codec); - snd_hdac_link_power(&codec->core, true); + codec_display_power(codec, true); pm_runtime_enable(hda_codec_dev(codec)); /* it was powered up in snd_hda_codec_new(), now all done */ snd_hda_power_down(codec); @@ -834,7 +842,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device) codec->in_freeing = 1; snd_hdac_device_unregister(&codec->core); - snd_hdac_link_power(&codec->core, false); + codec_display_power(codec, false); put_device(hda_codec_dev(codec)); return 0; } @@ -2926,7 +2934,7 @@ static int hda_codec_runtime_suspend(struct device *dev) (codec_has_clkstop(codec) && codec_has_epss(codec) && (state & AC_PWRST_CLK_STOP_OK))) snd_hdac_codec_link_down(&codec->core); - snd_hdac_link_power(&codec->core, false); + codec_display_power(codec, false); return 0; } @@ -2934,7 +2942,7 @@ static int hda_codec_runtime_resume(struct device *dev) { struct hda_codec *codec = dev_to_hda_codec(dev); - snd_hdac_link_power(&codec->core, true); + codec_display_power(codec, true); snd_hdac_codec_link_up(&codec->core); hda_call_codec_resume(codec); pm_runtime_mark_last_busy(dev); diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index fe2506672a7204..532e081f8b8a24 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -989,20 +989,9 @@ static int azx_get_response(struct hdac_bus *bus, unsigned int addr, return azx_rirb_get_response(bus, addr, res); } -static int azx_link_power(struct hdac_bus *bus, bool enable) -{ - struct azx *chip = bus_to_azx(bus); - - if (chip->ops->link_power) - return chip->ops->link_power(chip, enable); - else - return -EINVAL; -} - static const struct hdac_bus_ops bus_core_ops = { .command = azx_send_cmd, .get_response = azx_get_response, - .link_power = azx_link_power, }; #ifdef CONFIG_SND_HDA_DSP_LOADER diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index cc06a323c81702..9f67425d50390e 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -667,13 +667,8 @@ static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) return 0; } -/* Enable/disable i915 display power for the link */ -static int azx_intel_link_power(struct azx *chip, bool enable) -{ - struct hdac_bus *bus = azx_bus(chip); - - return snd_hdac_display_power(bus, enable); -} +#define display_power(chip, enable) \ + snd_hdac_display_power(azx_bus(chip), HDA_CODEC_IDX_CONTROLLER, enable) /* * Check whether the current DMA position is acceptable for updating @@ -957,7 +952,7 @@ static void __azx_runtime_suspend(struct azx *chip) azx_clear_irq_pending(chip); if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && hda->need_i915_power) - snd_hdac_display_power(azx_bus(chip), false); + display_power(chip, false); } static void __azx_runtime_resume(struct azx *chip) @@ -968,7 +963,7 @@ static void __azx_runtime_resume(struct azx *chip) int status; if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - snd_hdac_display_power(bus, true); + display_power(chip, true); if (hda->need_i915_power) snd_hdac_i915_set_bclk(bus); } @@ -989,7 +984,7 @@ static void __azx_runtime_resume(struct azx *chip) /* power down again for link-controlled chips */ if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && !hda->need_i915_power) - snd_hdac_display_power(bus, false); + display_power(chip, false); } #ifdef CONFIG_PM_SLEEP @@ -1355,7 +1350,7 @@ static int azx_free(struct azx *chip) if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { if (hda->need_i915_power) - snd_hdac_display_power(bus, false); + display_power(chip, false); } if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT) snd_hdac_i915_exit(bus); @@ -2056,7 +2051,6 @@ static const struct hda_controller_ops pci_hda_ops = { .disable_msi_reset_irq = disable_msi_reset_irq, .pcm_mmap_prepare = pcm_mmap_prepare, .position_check = azx_position_check, - .link_power = azx_intel_link_power, }; static int azx_probe(struct pci_dev *pci, @@ -2239,7 +2233,7 @@ static int azx_probe_continue(struct azx *chip) if (CONTROLLER_IN_GPU(pci)) hda->need_i915_power = 1; - err = snd_hdac_display_power(bus, true); + err = display_power(chip, true); if (err < 0) { dev_err(chip->card->dev, "Cannot turn on display power on i915\n"); @@ -2295,7 +2289,7 @@ static int azx_probe_continue(struct azx *chip) out_free: if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && !hda->need_i915_power) - snd_hdac_display_power(bus, false); + display_power(chip, false); i915_power_fail: if (err < 0) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 67099cbb6be2f2..30fe4dbdb0ae9b 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2620,7 +2620,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid) * can cover the codec power request, and so need not set this flag. */ if (!is_haswell(codec) && !is_broadwell(codec)) - codec->core.link_power_control = 1; + codec->display_power_control = 1; codec->patch_ops.set_power_state = haswell_set_power_state; codec->depop_delay = 0; @@ -2656,7 +2656,7 @@ static int patch_i915_byt_hdmi(struct hda_codec *codec) /* For Valleyview/Cherryview, only the display codec is in the display * power well and can use link_power ops to request/release the power. */ - codec->core.link_power_control = 1; + codec->display_power_control = 1; codec->depop_delay = 0; codec->auto_runtime_pm = 1; diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index e63d6e33df487d..c3d551d2af7f70 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2031,14 +2031,13 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) * Turned off in the runtime_suspend during the first explicit * pm_runtime_suspend call. */ - ret = snd_hdac_display_power(hdev->bus, true); + ret = snd_hdac_display_power(hdev->bus, hdev->addr, true); if (ret < 0) { dev_err(&hdev->dev, "Cannot turn on display power on i915 err: %d\n", ret); return ret; } - ret = hdac_hdmi_parse_and_map_nid(hdev, &hdmi_dais, &num_dais); if (ret < 0) { dev_err(&hdev->dev, @@ -2196,7 +2195,7 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) snd_hdac_ext_bus_link_put(bus, hlink); - err = snd_hdac_display_power(bus, false); + err = snd_hdac_display_power(bus, hdev->addr, false); if (err < 0) dev_err(dev, "Cannot turn off display power on i915\n"); @@ -2224,7 +2223,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev) snd_hdac_ext_bus_link_get(bus, hlink); - err = snd_hdac_display_power(bus, true); + err = snd_hdac_display_power(bus, hdev->addr, true); if (err < 0) { dev_err(dev, "Cannot turn on display power on i915\n"); return err; diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 7487f388e65d72..64f8433ae92123 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -334,7 +334,7 @@ static int skl_suspend(struct device *dev) } if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, false); + ret = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); if (ret < 0) dev_err(bus->dev, "Cannot turn OFF display power on i915\n"); @@ -353,7 +353,7 @@ static int skl_resume(struct device *dev) /* Turned OFF in HDMI codec driver after codec reconfiguration */ if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, true); + ret = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); if (ret < 0) { dev_err(bus->dev, "Cannot turn on display power on i915\n"); @@ -783,7 +783,7 @@ static int skl_i915_init(struct hdac_bus *bus) if (err < 0) return err; - err = snd_hdac_display_power(bus, true); + err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); if (err < 0) dev_err(bus->dev, "Cannot turn on display power on i915\n"); @@ -838,7 +838,7 @@ static void skl_probe_work(struct work_struct *work) snd_hdac_ext_bus_link_put(bus, hlink); if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - err = snd_hdac_display_power(bus, false); + err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); if (err < 0) { dev_err(bus->dev, "Cannot turn off display power on i915\n"); skl_machine_device_unregister(skl); @@ -855,7 +855,7 @@ static void skl_probe_work(struct work_struct *work) out_err: if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - err = snd_hdac_display_power(bus, false); + err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); } /* From 65e7f4bce31be0b5a16a0556d7e34146d87a1dcc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 09:57:37 +0100 Subject: [PATCH 0500/1995] ALSA: hda/intel: Drop superfluous AZX_DCAPS_I915_POWERWELL checks snd_hdac_display_power() can be called even for a HDA controller without DRM binding. The same is true for other helpers, snd_hdac_i915_set_bclk() and snd_hdac_set_codec_wakeup(). So all superfluous AZX_DCAPS_I915_POWERWELL checks in hda_intel.c can be dropped, and the definition of AZX_DCAPS_I915_POWERWELL itself can be removed as well. This simplifies the code a lot. Signed-off-by: Takashi Iwai (cherry picked from commit e454ff8e89b6db0a2054260d48635fbc781e94ce) --- sound/pci/hda/hda_controller.h | 6 +-- sound/pci/hda/hda_intel.c | 73 +++++++++++++--------------------- 2 files changed, 28 insertions(+), 51 deletions(-) diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index c95097bb5a0c03..7185ed574b412f 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -50,11 +50,7 @@ /* 24 unused */ #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ -#ifdef CONFIG_SND_HDA_I915 -#define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ -#else -#define AZX_DCAPS_I915_POWERWELL 0 /* NOP */ -#endif +/* 27 unused */ #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ #define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */ #define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 9f67425d50390e..663e86effa1f75 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -310,31 +310,28 @@ enum { #define AZX_DCAPS_INTEL_HASWELL \ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\ AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL | AZX_DCAPS_SNOOP_TYPE(SCH)) + AZX_DCAPS_SNOOP_TYPE(SCH)) /* Broadwell HDMI can't use position buffer reliably, force to use LPIB */ #define AZX_DCAPS_INTEL_BROADWELL \ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_POSFIX_LPIB |\ AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL | AZX_DCAPS_SNOOP_TYPE(SCH)) + AZX_DCAPS_SNOOP_TYPE(SCH)) #define AZX_DCAPS_INTEL_BAYTRAIL \ - (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL) + (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_I915_COMPONENT) #define AZX_DCAPS_INTEL_BRASWELL \ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ - AZX_DCAPS_I915_COMPONENT | AZX_DCAPS_I915_POWERWELL) + AZX_DCAPS_I915_COMPONENT) #define AZX_DCAPS_INTEL_SKYLAKE \ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ - AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL) + AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT) #define AZX_DCAPS_INTEL_BROXTON \ (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME |\ - AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT |\ - AZX_DCAPS_I915_POWERWELL) + AZX_DCAPS_SEPARATE_STREAM_TAG | AZX_DCAPS_I915_COMPONENT) /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ @@ -591,8 +588,7 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) struct pci_dev *pci = chip->pci; u32 val; - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - snd_hdac_set_codec_wakeup(bus, true); + snd_hdac_set_codec_wakeup(bus, true); if (chip->driver_type == AZX_DRIVER_SKL) { pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val); val = val & ~INTEL_HDA_CGCTL_MISCBDCGE; @@ -604,8 +600,8 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) val = val | INTEL_HDA_CGCTL_MISCBDCGE; pci_write_config_dword(pci, INTEL_HDA_CGCTL, val); } - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - snd_hdac_set_codec_wakeup(bus, false); + + snd_hdac_set_codec_wakeup(bus, false); /* reduce dma latency to avoid noise */ if (IS_BXT(pci)) @@ -945,14 +941,10 @@ static bool azx_is_pm_ready(struct snd_card *card) static void __azx_runtime_suspend(struct azx *chip) { - struct hda_intel *hda = container_of(chip, struct hda_intel, chip); - azx_stop_chip(chip); azx_enter_link_reset(chip); azx_clear_irq_pending(chip); - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && - hda->need_i915_power) - display_power(chip, false); + display_power(chip, false); } static void __azx_runtime_resume(struct azx *chip) @@ -962,11 +954,9 @@ static void __azx_runtime_resume(struct azx *chip) struct hda_codec *codec; int status; - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - display_power(chip, true); - if (hda->need_i915_power) - snd_hdac_i915_set_bclk(bus); - } + display_power(chip, true); + if (hda->need_i915_power) + snd_hdac_i915_set_bclk(bus); /* Read STATESTS before controller reset */ status = azx_readw(chip, STATESTS); @@ -982,8 +972,7 @@ static void __azx_runtime_resume(struct azx *chip) } /* power down again for link-controlled chips */ - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) && - !hda->need_i915_power) + if (!hda->need_i915_power) display_power(chip, false); } @@ -1347,11 +1336,8 @@ static int azx_free(struct azx *chip) #ifdef CONFIG_SND_HDA_PATCH_LOADER release_firmware(chip->fw); #endif + display_power(chip, false); - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - if (hda->need_i915_power) - display_power(chip, false); - } if (chip->driver_caps & AZX_DCAPS_I915_COMPONENT) snd_hdac_i915_exit(bus); kfree(hda); @@ -1908,8 +1894,7 @@ static int azx_first_init(struct azx *chip) /* initialize chip */ azx_init_pci(chip); - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - snd_hdac_i915_set_bclk(bus); + snd_hdac_i915_set_bclk(bus); hda_intel_init_chip(chip, (probe_only[dev] & 2) == 0); @@ -2217,10 +2202,13 @@ static int azx_probe_continue(struct azx *chip) goto out_free; } else { /* don't bother any longer */ - chip->driver_caps &= - ~(AZX_DCAPS_I915_COMPONENT | AZX_DCAPS_I915_POWERWELL); + chip->driver_caps &= ~AZX_DCAPS_I915_COMPONENT; } } + + /* HSW/BDW controllers need this power */ + if (CONTROLLER_IN_GPU(pci)) + hda->need_i915_power = 1; } /* Request display power well for the HDA controller or codec. For @@ -2228,17 +2216,11 @@ static int azx_probe_continue(struct azx *chip) * this power. For other platforms, like Baytrail/Braswell, only the * display codec needs the power and it can be released after probe. */ - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { - /* HSW/BDW controllers need this power */ - if (CONTROLLER_IN_GPU(pci)) - hda->need_i915_power = 1; - - err = display_power(chip, true); - if (err < 0) { - dev_err(chip->card->dev, - "Cannot turn on display power on i915\n"); - goto i915_power_fail; - } + err = display_power(chip, true); + if (err < 0) { + dev_err(chip->card->dev, + "Cannot turn on display power on i915\n"); + goto i915_power_fail; } err = azx_first_init(chip); @@ -2287,8 +2269,7 @@ static int azx_probe_continue(struct azx *chip) pm_runtime_put_autosuspend(&pci->dev); out_free: - if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - && !hda->need_i915_power) + if (!hda->need_i915_power) display_power(chip, false); i915_power_fail: From e95c7693535798942669f20e75a759831490e16f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 09:59:03 +0100 Subject: [PATCH 0501/1995] ALSA: hda/intel: Properly free the display power at error path When an error occurs in azx_probe_continue(), we should release the display power. However, the current code ignores it and releases the display power only for HSW/BDW cases. Fix it. Signed-off-by: Takashi Iwai (cherry picked from commit 457f3c86d3358beb0ae19774fef8a9035dedd88f) --- sound/pci/hda/hda_intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 663e86effa1f75..5399d0180434f2 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2269,7 +2269,7 @@ static int azx_probe_continue(struct azx *chip) pm_runtime_put_autosuspend(&pci->dev); out_free: - if (!hda->need_i915_power) + if (err < 0 || !hda->need_i915_power) display_power(chip, false); i915_power_fail: From a68658a75f2ef00030a21be67c2b97b070c377e1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 10:04:25 +0100 Subject: [PATCH 0502/1995] ALSA: hda: Make snd_hdac_display_power() void function After the recent refactoring, snd_hdac_display_power() doesn't return any error, hence it can be defined to return void. This makes many error checks redundant and allows us to reduce them gracefully. Signed-off-by: Takashi Iwai (cherry picked from commit 4f799e734094f09feaae89ee75982fac84742c56) --- include/sound/hda_component.h | 9 ++++---- sound/hda/hdac_component.c | 8 ++----- sound/pci/hda/hda_intel.c | 9 +------- sound/soc/codecs/hdac_hdmi.c | 23 +++++--------------- sound/soc/intel/skylake/skl.c | 40 ++++++++++------------------------- 5 files changed, 23 insertions(+), 66 deletions(-) diff --git a/include/sound/hda_component.h b/include/sound/hda_component.h index 767c8d8a0230ba..2ec31b35895045 100644 --- a/include/sound/hda_component.h +++ b/include/sound/hda_component.h @@ -12,8 +12,8 @@ #ifdef CONFIG_SND_HDA_COMPONENT int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable); -int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, - bool enable); +void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, + bool enable); int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int dev_id, int rate); int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id, @@ -30,10 +30,9 @@ static inline int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) { return 0; } -static inline int snd_hdac_display_power(struct hdac_bus *bus, - unsigned int idx, bool enable) +static inline void snd_hdac_display_power(struct hdac_bus *bus, + unsigned int idx, bool enable) { - return 0; } static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int dev_id, int rate) diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c index dd766414436be3..a6d37b9d6413f5 100644 --- a/sound/hda/hdac_component.c +++ b/sound/hda/hdac_component.c @@ -62,10 +62,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup); * * This function updates the power status, and calls the get_power() and * put_power() ops accordingly, toggling the codec wakeup, too. - * - * Returns zero for success or a negative error code. */ -int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) +void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) { struct drm_audio_component *acomp = bus->audio_component; @@ -77,7 +75,7 @@ int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) clear_bit(idx, &bus->display_power_status); if (!acomp || !acomp->ops) - return 0; + return; if (bus->display_power_status) { if (!bus->display_power_active) { @@ -94,8 +92,6 @@ int snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) bus->display_power_active = false; } } - - return 0; } EXPORT_SYMBOL_GPL(snd_hdac_display_power); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 5399d0180434f2..e784130ea4e0eb 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2216,12 +2216,7 @@ static int azx_probe_continue(struct azx *chip) * this power. For other platforms, like Baytrail/Braswell, only the * display codec needs the power and it can be released after probe. */ - err = display_power(chip, true); - if (err < 0) { - dev_err(chip->card->dev, - "Cannot turn on display power on i915\n"); - goto i915_power_fail; - } + display_power(chip, true); err = azx_first_init(chip); if (err < 0) @@ -2271,8 +2266,6 @@ static int azx_probe_continue(struct azx *chip) out_free: if (err < 0 || !hda->need_i915_power) display_power(chip, false); - -i915_power_fail: if (err < 0) hda->init_failed = 1; complete_all(&hda->probe_wait); diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index c3d551d2af7f70..552ed1968bc42a 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2031,13 +2031,8 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) * Turned off in the runtime_suspend during the first explicit * pm_runtime_suspend call. */ - ret = snd_hdac_display_power(hdev->bus, hdev->addr, true); - if (ret < 0) { - dev_err(&hdev->dev, - "Cannot turn on display power on i915 err: %d\n", - ret); - return ret; - } + snd_hdac_display_power(hdev->bus, hdev->addr, true); + ret = hdac_hdmi_parse_and_map_nid(hdev, &hdmi_dais, &num_dais); if (ret < 0) { dev_err(&hdev->dev, @@ -2169,7 +2164,6 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) struct hdac_device *hdev = dev_to_hdac_dev(dev); struct hdac_bus *bus = hdev->bus; struct hdac_ext_link *hlink = NULL; - int err; dev_dbg(dev, "Enter: %s\n", __func__); @@ -2195,11 +2189,9 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) snd_hdac_ext_bus_link_put(bus, hlink); - err = snd_hdac_display_power(bus, hdev->addr, false); - if (err < 0) - dev_err(dev, "Cannot turn off display power on i915\n"); + snd_hdac_display_power(bus, hdev->addr, false); - return err; + return 0; } static int hdac_hdmi_runtime_resume(struct device *dev) @@ -2207,7 +2199,6 @@ static int hdac_hdmi_runtime_resume(struct device *dev) struct hdac_device *hdev = dev_to_hdac_dev(dev); struct hdac_bus *bus = hdev->bus; struct hdac_ext_link *hlink = NULL; - int err; dev_dbg(dev, "Enter: %s\n", __func__); @@ -2223,11 +2214,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev) snd_hdac_ext_bus_link_get(bus, hlink); - err = snd_hdac_display_power(bus, hdev->addr, true); - if (err < 0) { - dev_err(dev, "Cannot turn on display power on i915\n"); - return err; - } + snd_hdac_display_power(bus, hdev->addr, true); hdac_hdmi_skl_enable_all_pins(hdev); hdac_hdmi_skl_enable_dp12(hdev); diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 64f8433ae92123..5c224a0e1c7a11 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -311,7 +311,7 @@ static int skl_suspend(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct hdac_bus *bus = pci_get_drvdata(pci); struct skl *skl = bus_to_skl(bus); - int ret = 0; + int ret; /* * Do not suspend if streams which are marked ignore suspend are @@ -333,14 +333,10 @@ static int skl_suspend(struct device *dev) skl->skl_sst->fw_loaded = false; } - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - if (ret < 0) - dev_err(bus->dev, - "Cannot turn OFF display power on i915\n"); - } + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - return ret; + return 0; } static int skl_resume(struct device *dev) @@ -352,14 +348,8 @@ static int skl_resume(struct device *dev) int ret; /* Turned OFF in HDMI codec driver after codec reconfiguration */ - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - ret = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - if (ret < 0) { - dev_err(bus->dev, - "Cannot turn on display power on i915\n"); - return ret; - } - } + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); /* * resume only when we are not in suspend active, otherwise need to @@ -783,11 +773,9 @@ static int skl_i915_init(struct hdac_bus *bus) if (err < 0) return err; - err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - if (err < 0) - dev_err(bus->dev, "Cannot turn on display power on i915\n"); + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - return err; + return 0; } static void skl_probe_work(struct work_struct *work) @@ -837,14 +825,8 @@ static void skl_probe_work(struct work_struct *work) list_for_each_entry(hlink, &bus->hlink_list, list) snd_hdac_ext_bus_link_put(bus, hlink); - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - if (err < 0) { - dev_err(bus->dev, "Cannot turn off display power on i915\n"); - skl_machine_device_unregister(skl); - return; - } - } + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); /* configure PM */ pm_runtime_put_noidle(bus->dev); @@ -855,7 +837,7 @@ static void skl_probe_work(struct work_struct *work) out_err: if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - err = snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); } /* From a186dcde9a40de2d3ecdc45b0b9ba1080dd18e7e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 10:06:59 +0100 Subject: [PATCH 0503/1995] ASoC: hdac_hdmi: Add missing display power-off at driver removal The display power is in unbalance at removing the driver since it misses the snd_hdac_display_power(OFF) call. Acked-by: Mark Brown Signed-off-by: Takashi Iwai (cherry picked from commit 77a49672aae384125942ce621365b11d42cefa32) --- sound/soc/codecs/hdac_hdmi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 552ed1968bc42a..6216e502cf7bde 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -2059,6 +2059,8 @@ static int hdac_hdmi_dev_remove(struct hdac_device *hdev) struct hdac_hdmi_port *port, *port_next; int i; + snd_hdac_display_power(hdev->bus, hdev->addr, false); + list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { pcm->cvt = NULL; if (list_empty(&pcm->port_list)) From 64b194baffa6c343696b198964712b6db41bd105 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 9 Dec 2018 10:10:19 +0100 Subject: [PATCH 0504/1995] ALSA: hda/hdmi: Always set display_power_control for Intel HSW+ codecs We've excluded the display_power_control flag for Intel HSW and BDW codecs as the HD-audio controllers of the corresponding platforms take care of the display power as well. But the recent refactoring separates the controller and the codec power accounting, so it's fine to call the display PM even for HSW/BDW codecs. This is less confusing since we can avoid this well-hidden condition. Signed-off-by: Takashi Iwai (cherry picked from commit 46594d3345f0432ddc83b9f3c1b04492fdfafd07) --- sound/pci/hda/patch_hdmi.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 30fe4dbdb0ae9b..15290e4706e001 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2616,11 +2616,7 @@ static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid) intel_haswell_enable_all_pins(codec, true); intel_haswell_fixup_enable_dp12(codec); - /* For Haswell/Broadwell, the controller is also in the power well and - * can cover the codec power request, and so need not set this flag. - */ - if (!is_haswell(codec) && !is_broadwell(codec)) - codec->display_power_control = 1; + codec->display_power_control = 1; codec->patch_ops.set_power_state = haswell_set_power_state; codec->depop_delay = 0; From 6dcb7e7a603fa12bd57ae86ef03fd8fb7f31af1e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 2 Nov 2018 16:18:21 +0100 Subject: [PATCH 0505/1995] ASoC: wm97xx: fix uninitialized regmap pointer problem gcc notices that without either the ac97 bus or the pdata, we never initialize the regmap pointer, which leads to an uninitialized variable access: sound/soc/codecs/wm9712.c: In function 'wm9712_soc_probe': sound/soc/codecs/wm9712.c:666:2: error: 'regmap' may be used uninitialized in this function [-Werror=maybe-uninitialized] Since that configuration is invalid, it's better to return an error here. I tried to avoid adding complexity to the conditions, and turned the #ifdef into a regular if(IS_ENABLED()) check for readability. This in turn requires moving some header file declarations out of an #ifdef. The same code is used in three drivers, all of which I'm changing the same way. Fixes: 2ed1a8e0ce8d ("ASoC: wm9712: add ac97 new bus support") Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown (cherry picked from commit 576ce4075bfa0f03e0e91a89eecc539b3b828b08) --- include/sound/soc.h | 2 +- sound/soc/codecs/wm9705.c | 10 ++++------ sound/soc/codecs/wm9712.c | 10 ++++------ sound/soc/codecs/wm9713.c | 10 ++++------ 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 70c10a8f3e90a7..3e0ac310a3df90 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -553,12 +553,12 @@ static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, } #endif -#ifdef CONFIG_SND_SOC_AC97_BUS struct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component); struct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component, unsigned int id, unsigned int id_mask); void snd_soc_free_ac97_component(struct snd_ac97 *ac97); +#ifdef CONFIG_SND_SOC_AC97_BUS int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops); int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops, struct platform_device *pdev); diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index ccdf088461b7f0..54c306707c02cc 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -325,8 +325,7 @@ static int wm9705_soc_probe(struct snd_soc_component *component) if (wm9705->mfd_pdata) { wm9705->ac97 = wm9705->mfd_pdata->ac97; regmap = wm9705->mfd_pdata->regmap; - } else { -#ifdef CONFIG_SND_SOC_AC97_BUS + } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) { wm9705->ac97 = snd_soc_new_ac97_component(component, WM9705_VENDOR_ID, WM9705_VENDOR_ID_MASK); if (IS_ERR(wm9705->ac97)) { @@ -339,7 +338,8 @@ static int wm9705_soc_probe(struct snd_soc_component *component) snd_soc_free_ac97_component(wm9705->ac97); return PTR_ERR(regmap); } -#endif + } else { + return -ENXIO; } snd_soc_component_set_drvdata(component, wm9705->ac97); @@ -350,14 +350,12 @@ static int wm9705_soc_probe(struct snd_soc_component *component) static void wm9705_soc_remove(struct snd_soc_component *component) { -#ifdef CONFIG_SND_SOC_AC97_BUS struct wm9705_priv *wm9705 = snd_soc_component_get_drvdata(component); - if (!wm9705->mfd_pdata) { + if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9705->mfd_pdata) { snd_soc_component_exit_regmap(component); snd_soc_free_ac97_component(wm9705->ac97); } -#endif } static const struct snd_soc_component_driver soc_component_dev_wm9705 = { diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index e873baa9e7780f..01949eaba4fd49 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -642,8 +642,7 @@ static int wm9712_soc_probe(struct snd_soc_component *component) if (wm9712->mfd_pdata) { wm9712->ac97 = wm9712->mfd_pdata->ac97; regmap = wm9712->mfd_pdata->regmap; - } else { -#ifdef CONFIG_SND_SOC_AC97_BUS + } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) { int ret; wm9712->ac97 = snd_soc_new_ac97_component(component, WM9712_VENDOR_ID, @@ -660,7 +659,8 @@ static int wm9712_soc_probe(struct snd_soc_component *component) snd_soc_free_ac97_component(wm9712->ac97); return PTR_ERR(regmap); } -#endif + } else { + return -ENXIO; } snd_soc_component_init_regmap(component, regmap); @@ -673,14 +673,12 @@ static int wm9712_soc_probe(struct snd_soc_component *component) static void wm9712_soc_remove(struct snd_soc_component *component) { -#ifdef CONFIG_SND_SOC_AC97_BUS struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component); - if (!wm9712->mfd_pdata) { + if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9712->mfd_pdata) { snd_soc_component_exit_regmap(component); snd_soc_free_ac97_component(wm9712->ac97); } -#endif } static const struct snd_soc_component_driver soc_component_dev_wm9712 = { diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 643863bb32e0d3..5a2fdf4f69bf3b 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1214,8 +1214,7 @@ static int wm9713_soc_probe(struct snd_soc_component *component) if (wm9713->mfd_pdata) { wm9713->ac97 = wm9713->mfd_pdata->ac97; regmap = wm9713->mfd_pdata->regmap; - } else { -#ifdef CONFIG_SND_SOC_AC97_BUS + } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) { wm9713->ac97 = snd_soc_new_ac97_component(component, WM9713_VENDOR_ID, WM9713_VENDOR_ID_MASK); if (IS_ERR(wm9713->ac97)) @@ -1225,7 +1224,8 @@ static int wm9713_soc_probe(struct snd_soc_component *component) snd_soc_free_ac97_component(wm9713->ac97); return PTR_ERR(regmap); } -#endif + } else { + return -ENXIO; } snd_soc_component_init_regmap(component, regmap); @@ -1238,14 +1238,12 @@ static int wm9713_soc_probe(struct snd_soc_component *component) static void wm9713_soc_remove(struct snd_soc_component *component) { -#ifdef CONFIG_SND_SOC_AC97_BUS struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component); - if (!wm9713->mfd_pdata) { + if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9713->mfd_pdata) { snd_soc_component_exit_regmap(component); snd_soc_free_ac97_component(wm9713->ac97); } -#endif } static const struct snd_soc_component_driver soc_component_dev_wm9713 = { From 79e8a021c3d80d14c90e94db9511efe99dcf8984 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sat, 3 Nov 2018 22:21:22 +0100 Subject: [PATCH 0506/1995] ASoC: Intel: mrfld: fix uninitialized variable access Randconfig testing revealed a very old bug, with gcc-8: sound/soc/intel/atom/sst/sst_loader.c: In function 'sst_load_fw': sound/soc/intel/atom/sst/sst_loader.c:357:5: error: 'fw' may be used uninitialized in this function [-Werror=maybe-uninitialized] if (fw == NULL) { ^ sound/soc/intel/atom/sst/sst_loader.c:354:25: note: 'fw' was declared here const struct firmware *fw; We must check the return code of request_firmware() before we look at the pointer result that may be uninitialized when the function fails. Fixes: 9012c9544eea ("ASoC: Intel: mrfld - Add DSP load and management") Signed-off-by: Arnd Bergmann Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 1539c7f23f256120f89f8b9ec53160790bce9ed2) --- sound/soc/intel/atom/sst/sst_loader.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c index 27413ebae9566e..b8c456753f015f 100644 --- a/sound/soc/intel/atom/sst/sst_loader.c +++ b/sound/soc/intel/atom/sst/sst_loader.c @@ -354,14 +354,14 @@ static int sst_request_fw(struct intel_sst_drv *sst) const struct firmware *fw; retval = request_firmware(&fw, sst->firmware_name, sst->dev); - if (fw == NULL) { - dev_err(sst->dev, "fw is returning as null\n"); - return -EINVAL; - } if (retval) { dev_err(sst->dev, "request fw failed %d\n", retval); return retval; } + if (fw == NULL) { + dev_err(sst->dev, "fw is returning as null\n"); + return -EINVAL; + } mutex_lock(&sst->sst_lock); retval = sst_cache_and_parse_fw(sst, fw); mutex_unlock(&sst->sst_lock); From 0bab00b3643c1650b1db937a14851abe48896e6f Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 4 Nov 2018 07:55:29 -0500 Subject: [PATCH 0507/1995] ASoC: nau8825: remove unnecessary unlikely() WARN_ON() already contains an unlikely(), so it's not necessary to use unlikely. Signed-off-by: Yangtao Li Signed-off-by: Mark Brown (cherry picked from commit 0b6277e6343e192aaa7d452ab933281eb0d420dc) --- sound/soc/codecs/nau8825.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index b9fed99d8b5ed3..7bbcbf5f05c887 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -424,10 +424,8 @@ static u32 nau8825_xtalk_sidetone(u32 sig_org, u32 sig_cros) { u32 gain, sidetone; - if (unlikely(sig_org == 0) || unlikely(sig_cros == 0)) { - WARN_ON(1); + if (WARN_ON(sig_org == 0 || sig_cros == 0)) return 0; - } sig_org = nau8825_intlog10_dec3(sig_org); sig_cros = nau8825_intlog10_dec3(sig_cros); From fd540f41bbb064f2a154f64b73440dcd420e1dcc Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 27 Oct 2018 15:34:44 +0200 Subject: [PATCH 0508/1995] ASoC: codecs: constify snd_soc_dai_ops structures The snd_soc_dai_ops structures are only stored in the ops field of a snd_soc_dai_driver structure, so make the snd_soc_dai_ops structures const as well. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Mark Brown (cherry picked from commit 704a9fc20b87f2929732cab0a1a04f28d4093085) --- sound/soc/codecs/ak4458.c | 2 +- sound/soc/codecs/ak5558.c | 2 +- sound/soc/codecs/hdac_hda.c | 2 +- sound/soc/codecs/tas6424.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index 299ada4dfaa009..70d4c89bd6fc38 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -456,7 +456,7 @@ static int ak4458_startup(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_dai_ops ak4458_dai_ops = { +static const struct snd_soc_dai_ops ak4458_dai_ops = { .startup = ak4458_startup, .hw_params = ak4458_hw_params, .set_fmt = ak4458_set_dai_fmt, diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index 448bb90c9c8e0a..60f1f12c81ea78 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -246,7 +246,7 @@ static int ak5558_startup(struct snd_pcm_substream *substream, &ak5558_rate_constraints); } -static struct snd_soc_dai_ops ak5558_dai_ops = { +static const struct snd_soc_dai_ops ak5558_dai_ops = { .startup = ak5558_startup, .hw_params = ak5558_hw_params, diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 2aaa83028e55f2..ffecdaaa8cf2bb 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -46,7 +46,7 @@ static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, struct snd_soc_dai *dai); -static struct snd_soc_dai_ops hdac_hda_dai_ops = { +static const struct snd_soc_dai_ops hdac_hda_dai_ops = { .startup = hdac_hda_dai_open, .shutdown = hdac_hda_dai_close, .prepare = hdac_hda_dai_prepare, diff --git a/sound/soc/codecs/tas6424.c b/sound/soc/codecs/tas6424.c index 36aebdb8f55c5b..aaba3929507993 100644 --- a/sound/soc/codecs/tas6424.c +++ b/sound/soc/codecs/tas6424.c @@ -378,7 +378,7 @@ static struct snd_soc_component_driver soc_codec_dev_tas6424 = { .non_legacy_dai_naming = 1, }; -static struct snd_soc_dai_ops tas6424_speaker_dai_ops = { +static const struct snd_soc_dai_ops tas6424_speaker_dai_ops = { .hw_params = tas6424_hw_params, .set_fmt = tas6424_set_dai_fmt, .set_tdm_slot = tas6424_set_dai_tdm_slot, From 88cd1f70f7ba79433dd83ff95cefc68085fe5a58 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 1 Nov 2018 16:34:48 -0500 Subject: [PATCH 0509/1995] ASoC: acpi: define common interface for machine driver configuration The machine drivers may need information provided by the platform driver. Currently the information is passed using pdata specific to each plaform driver. This prevents other drivers, such as SOF, from reusing machine drivers directly. Add a new structure which contains the required fields. This proposal requires a bit more work on the platform side but this generic interface helps reuse code directly. Reviewed-by: Andy Shevchenko Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 8679284b37e9e2d529d60d1acc4133af4aa5dd34) --- include/sound/soc-acpi.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index e45b2330d16a45..5154c6359609fc 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -37,6 +37,19 @@ snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], struct snd_soc_acpi_mach * snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines); +/** + * snd_soc_acpi_mach_params: interface for machine driver configuration + * + * @acpi_ipc_irq_index: used for BYT-CR detection + * @platform: string used for HDaudio codec support + * @codec_mask: used for HDAudio support + */ +struct snd_soc_acpi_mach_params { + u32 acpi_ipc_irq_index; + const char *platform; + u32 codec_mask; +}; + /** * snd_soc_acpi_mach: ACPI-based machine descriptor. Most of the fields are * related to the hardware, except for the firmware and topology file names. @@ -68,6 +81,7 @@ struct snd_soc_acpi_mach { struct snd_soc_acpi_mach * (*machine_quirk)(void *arg); const void *quirk_data; void *pdata; + struct snd_soc_acpi_mach_params mach_params; const char *sof_fw_filename; const char *sof_tplg_filename; const char *asoc_plat_name; From 0a51373cf48b6e6468acb638940b1e36e5e8f8e8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 1 Nov 2018 16:34:49 -0500 Subject: [PATCH 0510/1995] ASoC: Intel: use standard interface for Hdaudio machine driver Don't rely on internal Skylake-specific data structures, use generic interface to let other drivers use the same machine driver as is, e.g. SOF to support HDaudio codecs and HDMI outputs. Tested on LeafHill CRB board, no regression seen with this change. Reviewed-by: Andy Shevchenko Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 842bb5135f1016151235413726e4956210a79664) --- sound/soc/intel/boards/skl_hda_dsp_generic.c | 20 ++++++++++---------- sound/soc/intel/skylake/skl.c | 10 +++------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index b415dd4c85f5ac..b6f287fa950533 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -12,8 +12,8 @@ #include #include #include +#include #include "../../codecs/hdac_hdmi.h" -#include "../skylake/skl.h" #include "skl_hda_dsp_common.h" static const struct snd_soc_dapm_widget skl_hda_widgets[] = { @@ -101,17 +101,17 @@ static struct snd_soc_card hda_soc_card = { #define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2) #define IDISP_CODEC_MASK 0x4 -static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) +static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params) { struct snd_soc_card *card = &hda_soc_card; struct snd_soc_dai_link *dai_link; u32 codec_count, codec_mask; int i, num_links, num_route; - codec_mask = pdata->codec_mask; + codec_mask = mach_params->codec_mask; codec_count = hweight_long(codec_mask); - if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) { + if (codec_count == 1 && codec_mask & IDISP_CODEC_MASK) { num_links = IDISP_DAI_COUNT; num_route = IDISP_ROUTE_COUNT; } else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) { @@ -127,14 +127,14 @@ static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) card->num_dapm_routes = num_route; for_each_card_prelinks(card, i, dai_link) - dai_link->platform_name = pdata->platform; + dai_link->platform_name = mach_params->platform; return 0; } static int skl_hda_audio_probe(struct platform_device *pdev) { - struct skl_machine_pdata *pdata; + struct snd_soc_acpi_mach *mach; struct skl_hda_private *ctx; int ret; @@ -146,11 +146,11 @@ static int skl_hda_audio_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - pdata = dev_get_drvdata(&pdev->dev); - if (!pdata) + mach = dev_get_drvdata(&pdev->dev); + if (!mach) return -EINVAL; - ret = skl_hda_fill_card_info(pdata); + ret = skl_hda_fill_card_info(&mach->mach_params); if (ret < 0) { dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n"); return ret; @@ -158,7 +158,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev) ctx->pcm_count = hda_soc_card.num_links; ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */ - ctx->platform_name = pdata->platform; + ctx->platform_name = mach->mach_params.platform; hda_soc_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&hda_soc_card, ctx); diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 5c224a0e1c7a11..09addbe5647ebc 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -517,7 +517,6 @@ static int skl_machine_device_register(struct skl *skl) { struct snd_soc_acpi_mach *mach = skl->mach; struct hdac_bus *bus = skl_to_bus(skl); - struct skl_machine_pdata *pdata; struct platform_device *pdev; int ret; @@ -534,12 +533,9 @@ static int skl_machine_device_register(struct skl *skl) return -EIO; } - if (mach->pdata) { - pdata = (struct skl_machine_pdata *)mach->pdata; - pdata->platform = dev_name(bus->dev); - pdata->codec_mask = bus->codec_mask; - dev_set_drvdata(&pdev->dev, mach->pdata); - } + mach->mach_params.platform = dev_name(bus->dev); + mach->mach_params.codec_mask = bus->codec_mask; + dev_set_drvdata(&pdev->dev, mach); skl->i2s_dev = pdev; From 32bec2b1b41d08f27851d3308b7c095764d94901 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 1 Nov 2018 16:34:50 -0500 Subject: [PATCH 0511/1995] ASoC: Intel: use standard interface for Atom machine drivers Don't rely on internal Atom/SST-specific data structures, use generic interface to let other drivers use the same machine drivers as is, e.g. SOF to support BYT-CR devices Tested-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 3ee1cd4f81e15f51638db80fb9f1371b3bdf05ba) --- sound/soc/intel/atom/sst/sst_acpi.c | 4 ++++ sound/soc/intel/boards/bytcr_rt5640.c | 6 +----- sound/soc/intel/boards/bytcr_rt5651.c | 6 +----- sound/soc/intel/boards/cht_bsw_rt5645.c | 6 +----- 4 files changed, 7 insertions(+), 15 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index c90b04cc071dc2..ac542535b9d53f 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -341,6 +341,10 @@ static int sst_acpi_probe(struct platform_device *pdev) byt_rvp_platform_data.res_info = &bytcr_res_info; } + /* update machine parameters */ + mach->mach_params.acpi_ipc_irq_index = + pdata->res_info->acpi_ipc_irq_index; + plat_dev = platform_device_register_data(dev, pdata->platform, -1, NULL, 0); if (IS_ERR(plat_dev)) { diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 8587bd3d1cc17d..09591144ea7d2e 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -1152,10 +1151,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) * (will be overridden if DMI quirk is detected) */ if (is_valleyview()) { - struct sst_platform_info *p_info = mach->pdata; - const struct sst_res_info *res_info = p_info->res_info; - - if (res_info->acpi_ipc_irq_index == 0) + if (mach->mach_params.acpi_ipc_irq_index == 0) is_bytcr = true; } diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index c442981307208c..e528995668b78e 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -920,10 +919,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) * (will be overridden if DMI quirk is detected) */ if (x86_match_cpu(baytrail_cpu_ids)) { - struct sst_platform_info *p_info = mach->pdata; - const struct sst_res_info *res_info = p_info->res_info; - - if (res_info->acpi_ipc_irq_index == 0) + if (mach->mach_params.acpi_ipc_irq_index == 0) is_bytcr = true; } diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index f5a5ea6a093c71..250a356a0cbf08 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -585,10 +584,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) * (will be overridden if DMI quirk is detected) */ if (is_valleyview()) { - struct sst_platform_info *p_info = mach->pdata; - const struct sst_res_info *res_info = p_info->res_info; - - if (res_info->acpi_ipc_irq_index == 0) + if (mach->mach_params.acpi_ipc_irq_index == 0) is_bytcr = true; } From 60fd3604c64c2fd3f4369c3380c55663f0c5eba3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 1 Nov 2018 16:34:51 -0500 Subject: [PATCH 0512/1995] ASoC: Intel: boards: fix Skylake typo s/skylaye/skylake Reviewed-by: Andy Shevchenko Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 48bf41a2be51ef3f67b60f85bf75cecfb57884ba) --- sound/soc/intel/boards/kbl_da7219_max98927.c | 6 +++--- sound/soc/intel/boards/kbl_rt5663_max98927.c | 4 ++-- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 4 ++-- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 3fa1c3ca6d376f..3bc78e3a91ee5f 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -441,7 +441,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream) } -static struct snd_soc_ops skylaye_refcap_ops = { +static struct snd_soc_ops skylake_refcap_ops = { .startup = kabylake_refcap_startup, }; @@ -525,7 +525,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { .dpcm_capture = 1, .nonatomic = 1, .dynamic = 1, - .ops = &skylaye_refcap_ops, + .ops = &skylake_refcap_ops, }, [KBL_DPCM_AUDIO_DMIC_CP] = { .name = "Kbl Audio DMIC cap", @@ -736,7 +736,7 @@ static struct snd_soc_dai_link kabylake_max98927_dais[] = { .dpcm_capture = 1, .nonatomic = 1, .dynamic = 1, - .ops = &skylaye_refcap_ops, + .ops = &skylake_refcap_ops, }, [KBL_DPCM_AUDIO_DMIC_CP] = { .name = "Kbl Audio DMIC cap", diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index 99e1320c485ff2..6ea969c0a5fb8c 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -586,7 +586,7 @@ static int kabylake_refcap_startup(struct snd_pcm_substream *substream) &constraints_16000); } -static struct snd_soc_ops skylaye_refcap_ops = { +static struct snd_soc_ops skylake_refcap_ops = { .startup = kabylake_refcap_startup, }; @@ -655,7 +655,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { .dpcm_capture = 1, .nonatomic = 1, .dynamic = 1, - .ops = &skylaye_refcap_ops, + .ops = &skylake_refcap_ops, }, [KBL_DPCM_AUDIO_DMIC_CP] = { .name = "Kbl Audio DMIC cap", diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index d31482b8c9bbb0..552958ce736d1e 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -400,7 +400,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream) &constraints_16000); } -static const struct snd_soc_ops skylaye_refcap_ops = { +static const struct snd_soc_ops skylake_refcap_ops = { .startup = skylake_refcap_startup, }; @@ -447,7 +447,7 @@ static struct snd_soc_dai_link skylake_dais[] = { .dpcm_capture = 1, .nonatomic = 1, .dynamic = 1, - .ops = &skylaye_refcap_ops, + .ops = &skylake_refcap_ops, }, [SKL_DPCM_AUDIO_DMIC_CP] = { .name = "Skl Audio DMIC cap", diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index e877bb60beb10b..f985b30a1d0eaa 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -449,7 +449,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream) &constraints_16000); } -static const struct snd_soc_ops skylaye_refcap_ops = { +static const struct snd_soc_ops skylake_refcap_ops = { .startup = skylake_refcap_startup, }; @@ -496,7 +496,7 @@ static struct snd_soc_dai_link skylake_dais[] = { .dpcm_capture = 1, .nonatomic = 1, .dynamic = 1, - .ops = &skylaye_refcap_ops, + .ops = &skylake_refcap_ops, }, [SKL_DPCM_AUDIO_DMIC_CP] = { .name = "Skl Audio DMIC cap", From 5e45da1acc9193963735715e2d09c70b2831685e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 1 Nov 2018 16:34:52 -0500 Subject: [PATCH 0513/1995] ASoC: Intel: remove GFP_ATOMIC, use GFP_KERNEL GFP_ATOMIC is not required on any Intel drivers, use GFP_KERNEL instead. A first cleanup was merged in April but missed a number occurrences and new ones were added by copy/paste inertia. While we are at it, make checkpatch happy with a sizeof(*msg) Reviewed-by: Andy Shevchenko Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 972b0d456e645ea8fd3fdc70f95f0e41c27c0870) --- sound/soc/intel/atom/sst/sst_pvt.c | 4 ++-- sound/soc/intel/boards/cht_bsw_rt5672.c | 2 +- sound/soc/intel/boards/glk_rt5682_max98357a.c | 2 +- sound/soc/intel/boards/kbl_da7219_max98927.c | 2 +- sound/soc/intel/boards/skl_hda_dsp_generic.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c index af93244b48686f..00a37a09dc9b0f 100644 --- a/sound/soc/intel/atom/sst/sst_pvt.c +++ b/sound/soc/intel/atom/sst/sst_pvt.c @@ -166,11 +166,11 @@ int sst_create_ipc_msg(struct ipc_post **arg, bool large) { struct ipc_post *msg; - msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC); + msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (!msg) return -ENOMEM; if (large) { - msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC); + msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL); if (!msg->mailbox_data) { kfree(msg); return -ENOMEM; diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 51f0d45d6f8f9d..9de64f447e7bed 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -403,7 +403,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) const char *i2c_name; int i; - drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); + drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); if (!drv) return -ENOMEM; diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index c4b94e2617c59b..c74c4f17316fe8 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -603,7 +603,7 @@ static int geminilake_audio_probe(struct platform_device *pdev) { struct glk_card_private *ctx; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 3bc78e3a91ee5f..58eb0fe69978bd 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -935,7 +935,7 @@ static int kabylake_audio_probe(struct platform_device *pdev) { struct kbl_codec_private *ctx; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index b6f287fa950533..15c502d6774d08 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -140,7 +140,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s: entry\n", __func__); - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; From 51a1cb2249db7dcfa05ea6405d767b7701d719ba Mon Sep 17 00:00:00 2001 From: Bard liao Date: Thu, 1 Nov 2018 16:34:53 -0500 Subject: [PATCH 0514/1995] ASoC: Intel: common: add SOF information for APL RVP Add firmware/topology information for APL RVP Reviewed-by: Andy Shevchenko Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 97bb91ae2f3325fd06ea2c28fb8b5b4e023b4b5d) --- sound/soc/intel/common/soc-acpi-intel-bxt-match.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c index f39386e540d322..2756fa4ab55201 100644 --- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c @@ -19,6 +19,9 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .id = "INT343A", .drv_name = "bxt_alc298s_i2s", .fw_filename = "intel/dsp_fw_bxtn.bin", + .sof_fw_filename = "intel/sof-apl.ri", + .sof_tplg_filename = "intel/sof-apl-rt298.tplg", + .asoc_plat_name = "0000:00:0e.0", }, { .id = "DLGS7219", From f807faf57713304859807b6a4cf67cf965b3a82f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 1 Nov 2018 16:34:54 -0500 Subject: [PATCH 0515/1995] ASoC: Intel: common: add quirk for APL RVP boards For some reason the RVP/LeafHill SSDT exposes an INT34C3 ID which is used on other boards to point to the TDF8532 amplifier. Yay BIOS. Add a DMI-quirk to ignore this ID and check for other valid machine driver descriptors. Reviewed-by: Andy Shevchenko Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 935ff8007f5efd24e995d26ebf875ee2c787465e) --- .../intel/common/soc-acpi-intel-bxt-match.c | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c index 2756fa4ab55201..61dedc103b1966 100644 --- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c @@ -6,9 +6,41 @@ * */ +#include #include #include +enum { + APL_RVP, +}; + +static const struct dmi_system_id apl_table[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."), + DMI_MATCH(DMI_BOARD_NAME, "Apollolake RVP1A"), + }, + .driver_data = (void *)(APL_RVP), + }, + {} +}; + +static struct snd_soc_acpi_mach *apl_quirk(void *arg) +{ + struct snd_soc_acpi_mach *mach = arg; + const struct dmi_system_id *dmi_id; + unsigned long apl_machine_id; + + dmi_id = dmi_first_match(apl_table); + if (dmi_id) { + apl_machine_id = (unsigned long)dmi_id->driver_data; + if (apl_machine_id == APL_RVP) + return NULL; + } + + return mach; +} + static struct snd_soc_acpi_codecs bxt_codecs = { .num_codecs = 1, .codecs = {"MX98357A"} @@ -50,6 +82,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { { .id = "INT34C3", .drv_name = "bxt_tdf8532", + .machine_quirk = apl_quirk, .sof_fw_filename = "intel/sof-apl.ri", .sof_tplg_filename = "intel/sof-apl-tdf8532.tplg", .asoc_plat_name = "0000:00:0e.0", From 405b330750771e6d886a7b969eac6ff5185380b6 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Sun, 11 Nov 2018 05:18:46 +0800 Subject: [PATCH 0516/1995] ASoC: Intel: hdac_hdmi: add Icelake support Add Icelake device id. Also, Icelake's pin2port mapping table is complicated. So we use a mapping table to do the pin2port mapping. Signed-off-by: Bard liao Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 019033c854a20e10f691f6cc0e897df8817d9521) --- sound/soc/codecs/hdac_hdmi.c | 63 ++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 6216e502cf7bde..3ab2949c1dfa45 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -121,8 +121,16 @@ struct hdac_hdmi_dai_port_map { struct hdac_hdmi_cvt *cvt; }; +/* + * pin to port mapping table where the value indicate the pin number and + * the index indicate the port number with 1 base. + */ +static const int icl_pin2port_map[] = {0x4, 0x6, 0x8, 0xa, 0xb}; + struct hdac_hdmi_drv_data { unsigned int vendor_nid; + const int *port_map; /* pin to port mapping table */ + int port_num; }; struct hdac_hdmi_priv { @@ -1329,11 +1337,12 @@ static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid) return 0; } -#define INTEL_VENDOR_NID 0x08 -#define INTEL_GLK_VENDOR_NID 0x0b +#define INTEL_VENDOR_NID_0x2 0x02 +#define INTEL_VENDOR_NID_0x8 0x08 +#define INTEL_VENDOR_NID_0xb 0x0b #define INTEL_GET_VENDOR_VERB 0xf81 #define INTEL_SET_VENDOR_VERB 0x781 -#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ +#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ #define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdev) @@ -1538,7 +1547,26 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev, static int hdac_hdmi_pin2port(void *aptr, int pin) { - return pin - 4; /* map NID 0x05 -> port #1 */ + struct hdac_device *hdev = aptr; + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); + const int *map = hdmi->drv_data->port_map; + int i; + + if (!hdmi->drv_data->port_num) + return pin - 4; /* map NID 0x05 -> port #1 */ + + /* + * looking for the pin number in the mapping table and return + * the index which indicate the port number + */ + for (i = 0; i < hdmi->drv_data->port_num; i++) { + if (pin == map[i]) + return i + 1; + } + + /* return -1 if pin number exceeds our expectation */ + dev_err(&hdev->dev, "Can't find the port for pin %d\n", pin); + return -1; } static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) @@ -1549,9 +1577,18 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) struct hdac_hdmi_port *hport = NULL; struct snd_soc_component *component = hdmi->component; int i; - - /* Don't know how this mapping is derived */ - hda_nid_t pin_nid = port + 0x04; + hda_nid_t pin_nid; + + if (!hdmi->drv_data->port_num) { + /* for legacy platforms */ + pin_nid = port + 0x04; + } else if (port < hdmi->drv_data->port_num) { + /* get pin number from the pin2port mapping table */ + pin_nid = hdmi->drv_data->port_map[port - 1]; + } else { + dev_err(&hdev->dev, "Can't find the pin for port %d\n", port); + return; + } dev_dbg(&hdev->dev, "%s: for pin:%d port=%d\n", __func__, pin_nid, pipe); @@ -1973,12 +2010,18 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx) return port->eld.info.spk_alloc; } +static struct hdac_hdmi_drv_data intel_icl_drv_data = { + .vendor_nid = INTEL_VENDOR_NID_0x2, + .port_map = icl_pin2port_map, + .port_num = ARRAY_SIZE(icl_pin2port_map), +}; + static struct hdac_hdmi_drv_data intel_glk_drv_data = { - .vendor_nid = INTEL_GLK_VENDOR_NID, + .vendor_nid = INTEL_VENDOR_NID_0xb, }; static struct hdac_hdmi_drv_data intel_drv_data = { - .vendor_nid = INTEL_VENDOR_NID, + .vendor_nid = INTEL_VENDOR_NID_0x8, }; static int hdac_hdmi_dev_probe(struct hdac_device *hdev) @@ -2246,6 +2289,8 @@ static const struct hda_device_id hdmi_list[] = { &intel_glk_drv_data), HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI", &intel_glk_drv_data), + HDA_CODEC_EXT_ENTRY(0x8086280f, 0x100000, "Icelake HDMI", + &intel_icl_drv_data), {} }; From 4ed8ec66635a05e20a8a2f10849f2139a4b682e5 Mon Sep 17 00:00:00 2001 From: David Lin Date: Thu, 15 Nov 2018 17:14:47 +0800 Subject: [PATCH 0517/1995] ASoC: nau8822: convert to SPDX identifiers This patch updates license to SPDX-License-Identifier instead of verbose license text. Signed-off-by: David Lin Signed-off-by: Mark Brown (cherry picked from commit ba34f253711a8427d2ef29475afe406b2d6e5118) --- sound/soc/codecs/nau8822.c | 26 +++++++++++--------------- sound/soc/codecs/nau8822.h | 11 +++++------ 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c index 622ce947f13462..c6152a04441635 100644 --- a/sound/soc/codecs/nau8822.c +++ b/sound/soc/codecs/nau8822.c @@ -1,18 +1,14 @@ -/* - * nau8822.c -- NAU8822 ALSA Soc Audio Codec driver - * - * Copyright 2017 Nuvoton Technology Corp. - * - * Author: David Lin - * Co-author: John Hsu - * Co-author: Seven Li - * - * Based on WM8974.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// nau8822.c -- NAU8822 ALSA Soc Audio driver +// +// Copyright 2017 Nuvoton Technology Crop. +// +// Author: David Lin +// Co-author: John Hsu +// Co-author: Seven Li +// +// Based on WM8974.c #include #include diff --git a/sound/soc/codecs/nau8822.h b/sound/soc/codecs/nau8822.h index aa79c969cd44f5..d15afd78281543 100644 --- a/sound/soc/codecs/nau8822.h +++ b/sound/soc/codecs/nau8822.h @@ -1,13 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* - * nau8822.h -- NAU8822 Soc Audio Codec driver + * nau8822.h -- NAU8822 ALSA SoC Audio driver + * + * Copyright 2017 Nuvoton Technology Crop. * * Author: David Lin - * Co-author: John Hsu + * Co-author: John Hsu * Co-author: Seven Li - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __NAU8822_H__ From 93528dedc18e044acfae5bc36f4584ad96da587c Mon Sep 17 00:00:00 2001 From: David Lin Date: Thu, 15 Nov 2018 17:49:13 +0800 Subject: [PATCH 0518/1995] ASoC: nau8822: convert to SPDX identifiers This patch fixes typo in the comment. Signed-off-by: David Lin Signed-off-by: Mark Brown (cherry picked from commit 0c8224c34aa82901037e6c5921b692ea1b78fd24) --- sound/soc/codecs/nau8822.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/nau8822.h b/sound/soc/codecs/nau8822.h index d15afd78281543..9c552983a293e8 100644 --- a/sound/soc/codecs/nau8822.h +++ b/sound/soc/codecs/nau8822.h @@ -5,7 +5,7 @@ * Copyright 2017 Nuvoton Technology Crop. * * Author: David Lin - * Co-author: John Hsu + * Co-author: John Hsu * Co-author: Seven Li */ From 39152d464831aa384928512a9f97b884955d9295 Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Thu, 15 Nov 2018 12:13:34 +0800 Subject: [PATCH 0519/1995] ASoC: rt5663: Add regulator support Add regulator support to turn on cpvdd and avdd in probe. If a regulator is not given from device tree, a dummy regulator will be used. Signed-off-by: Cheng-Yi Chiang Signed-off-by: Mark Brown (cherry picked from commit e81a2a6d12e85fbd7b19e96ad72b82a3cc8a6b2d) --- sound/soc/codecs/rt5663.c | 68 +++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 7eb2cbd39d6e09..29c059ed06821d 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,9 @@ #define RT5663_DEVICE_ID_2 0x6451 #define RT5663_DEVICE_ID_1 0x6406 +#define RT5663_POWER_ON_DELAY_MS 300 +#define RT5663_SUPPLY_CURRENT_UA 500000 + enum { CODEC_VER_1, CODEC_VER_0, @@ -48,6 +52,11 @@ struct impedance_mapping_table { unsigned int dc_offset_r_manual_mic; }; +static const char *const rt5663_supply_names[] = { + "avdd", + "cpvdd", +}; + struct rt5663_priv { struct snd_soc_component *component; struct rt5663_platform_data pdata; @@ -56,6 +65,7 @@ struct rt5663_priv { struct snd_soc_jack *hs_jack; struct timer_list btn_check_timer; struct impedance_mapping_table *imp_table; + struct regulator_bulk_data supplies[ARRAY_SIZE(rt5663_supply_names)]; int codec_ver; int sysclk; @@ -3483,7 +3493,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, { struct rt5663_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5663_priv *rt5663; - int ret; + int ret, i; unsigned int val; struct regmap *regmap; @@ -3500,6 +3510,37 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, else rt5663_parse_dp(rt5663, &i2c->dev); + for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++) + rt5663->supplies[i].supply = rt5663_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, + ARRAY_SIZE(rt5663->supplies), + rt5663->supplies); + if (ret) { + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + /* Set load for regulator. */ + for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++) { + ret = regulator_set_load(rt5663->supplies[i].consumer, + RT5663_SUPPLY_CURRENT_UA); + if (ret) { + dev_err(&i2c->dev, + "Failed to set regulator %s, ret: %d\n", + rt5663->supplies[i].supply, ret); + } + } + + ret = regulator_bulk_enable(ARRAY_SIZE(rt5663->supplies), + rt5663->supplies); + + if (ret) { + dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + msleep(RT5663_POWER_ON_DELAY_MS); + regmap = devm_regmap_init_i2c(i2c, &temp_regmap); if (IS_ERR(regmap)) { ret = PTR_ERR(regmap); @@ -3530,7 +3571,8 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, dev_err(&i2c->dev, "Device with ID register %#x is not rt5663\n", val); - return -ENODEV; + ret = -ENODEV; + goto err_enable; } if (IS_ERR(rt5663->regmap)) { @@ -3635,20 +3677,30 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, ret = request_irq(i2c->irq, rt5663_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "rt5663", rt5663); - if (ret) + if (ret) { dev_err(&i2c->dev, "%s Failed to reguest IRQ: %d\n", __func__, ret); + goto err_enable; + } } ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_rt5663, rt5663_dai, ARRAY_SIZE(rt5663_dai)); - if (ret) { - if (i2c->irq) - free_irq(i2c->irq, rt5663); - } + if (ret) + goto err_irq; + return 0; + +err_irq: + if (i2c->irq) + free_irq(i2c->irq, rt5663); + +err_enable: + dev_err(&i2c->dev, + "%s: Disable regulator after probe error\n", __func__); + regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies); return ret; } @@ -3659,6 +3711,8 @@ static int rt5663_i2c_remove(struct i2c_client *i2c) if (i2c->irq) free_irq(i2c->irq, rt5663); + regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies); + return 0; } From 266b9ee8320ab471ae01bc56f2a3ce6ab8f74f7c Mon Sep 17 00:00:00 2001 From: Cheng-Yi Chiang Date: Fri, 16 Nov 2018 17:28:56 +0800 Subject: [PATCH 0520/1995] ASoC: rt5663: Fix error handling of regulator_set_load The default implementation of regulator_set_load returns REGULATOR_MODE_NORMAL, which is positive. [This was a bug which is being fixed but the change is valid anyway -- bronie] rt5663_i2c_probe should only do error handling when return value of regulator_set_load is negative. In this case, rt5663_i2c_probe should return error. Also, consolidate err_irq into err_enable. Fix the missing goto for temporary regmap and rt5663->regmap. Signed-off-by: Cheng-Yi Chiang Signed-off-by: Mark Brown (cherry picked from commit 746dca0aebd4d77adccb76c500a60028a900dabb) --- sound/soc/codecs/rt5663.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 29c059ed06821d..da664701570808 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -3525,10 +3525,11 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, for (i = 0; i < ARRAY_SIZE(rt5663->supplies); i++) { ret = regulator_set_load(rt5663->supplies[i].consumer, RT5663_SUPPLY_CURRENT_UA); - if (ret) { + if (ret < 0) { dev_err(&i2c->dev, - "Failed to set regulator %s, ret: %d\n", + "Failed to set regulator load on %s, ret: %d\n", rt5663->supplies[i].supply, ret); + return ret; } } @@ -3546,7 +3547,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, ret = PTR_ERR(regmap); dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n", ret); - return ret; + goto err_enable; } ret = regmap_read(regmap, RT5663_VENDOR_ID_2, &val); @@ -3579,7 +3580,7 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, ret = PTR_ERR(rt5663->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); - return ret; + goto err_enable; } /* reset and calibrate */ @@ -3689,17 +3690,19 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, rt5663_dai, ARRAY_SIZE(rt5663_dai)); if (ret) - goto err_irq; + goto err_enable; return 0; -err_irq: + + /* + * Error after enabling regulators should goto err_enable + * to disable regulators. + */ +err_enable: if (i2c->irq) free_irq(i2c->irq, rt5663); -err_enable: - dev_err(&i2c->dev, - "%s: Disable regulator after probe error\n", __func__); regulator_bulk_disable(ARRAY_SIZE(rt5663->supplies), rt5663->supplies); return ret; } From d581801339c105cc863c7191eaef1b8e7347be18 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 16 Nov 2018 18:47:05 -0600 Subject: [PATCH 0521/1995] ASoC: Intel: fix interface for Chromebook machine drivers The changes for HDaudio overlooked the fact that the machine drivers used for Chromebooks rely on the dmic number information passed as pdata. Add dmic_num field to standard interface and use standard interface instead of SKL-specific one. Also clean-up pdata definition to remove fields that are no longer used. Fixes: 842bb5135f10 ('ASoC: Intel: use standard interface for Hdaudio machine driver') Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit b92826fa8c5a423edf6c9e385b5d433c61375cc8) --- include/sound/soc-acpi.h | 1 + sound/soc/intel/boards/kbl_rt5663_max98927.c | 10 +++++----- sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c | 10 +++++----- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 10 +++++----- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 10 +++++----- sound/soc/intel/skylake/skl.c | 2 +- sound/soc/intel/skylake/skl.h | 3 --- 7 files changed, 22 insertions(+), 24 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 5154c6359609fc..266e64e3c24c4f 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -48,6 +48,7 @@ struct snd_soc_acpi_mach_params { u32 acpi_ipc_irq_index; const char *platform; u32 codec_mask; + u32 dmic_num; }; /** diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index 6ea969c0a5fb8c..c2a96940f9f296 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -25,9 +25,9 @@ #include #include #include +#include #include "../../codecs/rt5663.h" #include "../../codecs/hdac_hdmi.h" -#include "../skylake/skl.h" #include #include #include @@ -969,7 +969,7 @@ static struct snd_soc_card kabylake_audio_card_rt5663 = { static int kabylake_audio_probe(struct platform_device *pdev) { struct kbl_rt5663_private *ctx; - struct skl_machine_pdata *pdata; + struct snd_soc_acpi_mach *mach; int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); @@ -984,9 +984,9 @@ static int kabylake_audio_probe(struct platform_device *pdev) kabylake_audio_card->dev = &pdev->dev; snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - pdata = dev_get_drvdata(&pdev->dev); - if (pdata) - dmic_constraints = pdata->dmic_num == 2 ? + mach = dev_get_drvdata(&pdev->dev); + if (mach) + dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk"); diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index a737c915d46a83..d7df307b406f7a 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -26,10 +26,10 @@ #include #include #include +#include #include "../../codecs/rt5514.h" #include "../../codecs/rt5663.h" #include "../../codecs/hdac_hdmi.h" -#include "../skylake/skl.h" #define KBL_REALTEK_CODEC_DAI "rt5663-aif" #define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1" @@ -648,7 +648,7 @@ static struct snd_soc_card kabylake_audio_card = { static int kabylake_audio_probe(struct platform_device *pdev) { struct kbl_codec_private *ctx; - struct skl_machine_pdata *pdata; + struct snd_soc_acpi_mach *mach; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -659,9 +659,9 @@ static int kabylake_audio_probe(struct platform_device *pdev) kabylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&kabylake_audio_card, ctx); - pdata = dev_get_drvdata(&pdev->dev); - if (pdata) - dmic_constraints = pdata->dmic_num == 2 ? + mach = dev_get_drvdata(&pdev->dev); + if (mach) + dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card); diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 552958ce736d1e..931890f9aa742c 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -21,9 +21,9 @@ #include #include #include +#include #include "../../codecs/nau8825.h" #include "../../codecs/hdac_hdmi.h" -#include "../skylake/skl.h" #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" #define SKL_MAXIM_CODEC_DAI "HiFi" @@ -641,7 +641,7 @@ static struct snd_soc_card skylake_audio_card = { static int skylake_audio_probe(struct platform_device *pdev) { struct skl_nau8825_private *ctx; - struct skl_machine_pdata *pdata; + struct snd_soc_acpi_mach *mach; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -652,9 +652,9 @@ static int skylake_audio_probe(struct platform_device *pdev) skylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - pdata = dev_get_drvdata(&pdev->dev); - if (pdata) - dmic_constraints = pdata->dmic_num == 2 ? + mach = dev_get_drvdata(&pdev->dev); + if (mach) + dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index f985b30a1d0eaa..657c650766fc71 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -23,11 +23,11 @@ #include #include #include +#include #include #include #include "../../codecs/nau8825.h" #include "../../codecs/hdac_hdmi.h" -#include "../skylake/skl.h" #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" #define SKL_SSM_CODEC_DAI "ssm4567-hifi" @@ -694,7 +694,7 @@ static struct snd_soc_card skylake_audio_card = { static int skylake_audio_probe(struct platform_device *pdev) { struct skl_nau88125_private *ctx; - struct skl_machine_pdata *pdata; + struct snd_soc_acpi_mach *mach; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -705,9 +705,9 @@ static int skylake_audio_probe(struct platform_device *pdev) skylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - pdata = dev_get_drvdata(&pdev->dev); - if (pdata) - dmic_constraints = pdata->dmic_num == 2 ? + mach = dev_get_drvdata(&pdev->dev); + if (mach) + dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 09addbe5647ebc..19392922b4e778 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -507,7 +507,7 @@ static int skl_find_machine(struct skl *skl, void *driver_data) if (pdata) { skl->use_tplg_pcm = pdata->use_tplg_pcm; - pdata->dmic_num = skl_get_dmic_geo(skl); + mach->mach_params.dmic_num = skl_get_dmic_geo(skl); } return 0; diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 8d48cd7c56c835..85f8bb6687dcbd 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -119,10 +119,7 @@ struct skl_dma_params { }; struct skl_machine_pdata { - u32 dmic_num; bool use_tplg_pcm; /* use dais and dai links from topology */ - const char *platform; - u32 codec_mask; }; struct skl_dsp_ops { From 7b585ef7a6964dc74d04aef059247cbb86d50d6c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 16 Nov 2018 18:47:06 -0600 Subject: [PATCH 0522/1995] ASoC: Intel: use platform_data for machine drivers For some reason we have different mechanisms for passing data to machine drivers. Use the solution used by Atom/SST and SOF instead of using drv_data as done by Skylake. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 5a619b9e8883a0f9691964d001b8480df44df5b9) --- sound/soc/intel/boards/kbl_rt5663_max98927.c | 2 +- sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c | 2 +- sound/soc/intel/boards/skl_hda_dsp_generic.c | 2 +- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 2 +- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 2 +- sound/soc/intel/skylake/skl.c | 13 ++++++++++--- 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c index c2a96940f9f296..d71475200b08aa 100644 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c @@ -984,7 +984,7 @@ static int kabylake_audio_probe(struct platform_device *pdev) kabylake_audio_card->dev = &pdev->dev; snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - mach = dev_get_drvdata(&pdev->dev); + mach = (&pdev->dev)->platform_data; if (mach) dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index d7df307b406f7a..7044d8c2b18737 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -659,7 +659,7 @@ static int kabylake_audio_probe(struct platform_device *pdev) kabylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&kabylake_audio_card, ctx); - mach = dev_get_drvdata(&pdev->dev); + mach = (&pdev->dev)->platform_data; if (mach) dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 15c502d6774d08..b9a21e64ead2ec 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -146,7 +146,7 @@ static int skl_hda_audio_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - mach = dev_get_drvdata(&pdev->dev); + mach = (&pdev->dev)->platform_data; if (!mach) return -EINVAL; diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 931890f9aa742c..0922106bd323d7 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -652,7 +652,7 @@ static int skylake_audio_probe(struct platform_device *pdev) skylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - mach = dev_get_drvdata(&pdev->dev); + mach = (&pdev->dev)->platform_data; if (mach) dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 657c650766fc71..8433c521d39f21 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -705,7 +705,7 @@ static int skylake_audio_probe(struct platform_device *pdev) skylake_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - mach = dev_get_drvdata(&pdev->dev); + mach = (&pdev->dev)->platform_data; if (mach) dmic_constraints = mach->mach_params.dmic_num == 2 ? &constraints_dmic_2ch : &constraints_dmic_channels; diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 19392922b4e778..780daace11cdd6 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -526,6 +526,16 @@ static int skl_machine_device_register(struct skl *skl) return -EIO; } + mach->mach_params.platform = dev_name(bus->dev); + mach->mach_params.codec_mask = bus->codec_mask; + + ret = platform_device_add_data(pdev, (const void *)mach, sizeof(*mach)); + if (ret) { + dev_err(bus->dev, "failed to add machine device platform data\n"); + platform_device_put(pdev); + return ret; + } + ret = platform_device_add(pdev); if (ret) { dev_err(bus->dev, "failed to add machine device\n"); @@ -533,9 +543,6 @@ static int skl_machine_device_register(struct skl *skl) return -EIO; } - mach->mach_params.platform = dev_name(bus->dev); - mach->mach_params.codec_mask = bus->codec_mask; - dev_set_drvdata(&pdev->dev, mach); skl->i2s_dev = pdev; From 4796c23b063391ffb570daea49f49abf2d58891b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 22 Nov 2018 00:55:09 +0000 Subject: [PATCH 0523/1995] ASoC: soc-core: add snd_soc_of_parse_node_prefix() Current ASoC has snd_soc_of_parse_audio_prefix() to get codec_conf settings from DT which is used to avoid DAI naming conflict when CPU/Codec matching. Currently, it is parsing from "top node", but, we want to parse from "each sub node" if sound card had multi cpus/codecs. This patch adds new snd_soc_of_parse_node_prefix() to allow parsing settings from selected node. It is keeping existing snd_soc_of_parse_audio_prefix() by using macro. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 3b7103562c03cffb1a351f8c235b3bba2acd9e9b) --- include/sound/soc.h | 6 +++++- sound/soc/soc-core.c | 11 +++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 3e0ac310a3df90..37155f927415fb 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1477,10 +1477,14 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, unsigned int *rx_mask, unsigned int *slots, unsigned int *slot_width); -void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, +void snd_soc_of_parse_node_prefix(struct device_node *np, struct snd_soc_codec_conf *codec_conf, struct device_node *of_node, const char *propname); +#define snd_soc_of_parse_audio_prefix(card, conf, node, name) \ + snd_soc_of_parse_node_prefix((card)->dev->of_node, \ + (conf), (node), (name)) + int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname); unsigned int snd_soc_of_parse_daifmt(struct device_node *np, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b29d0f65611eb5..b0db59e6339d97 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3485,12 +3485,11 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); -void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, - struct snd_soc_codec_conf *codec_conf, - struct device_node *of_node, - const char *propname) +void snd_soc_of_parse_node_prefix(struct device_node *np, + struct snd_soc_codec_conf *codec_conf, + struct device_node *of_node, + const char *propname) { - struct device_node *np = card->dev->of_node; const char *str; int ret; @@ -3503,7 +3502,7 @@ void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, codec_conf->of_node = of_node; codec_conf->name_prefix = str; } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_node_prefix); int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname) From ee5ff613bd846dd26118865959ae1cc6fa5aa29e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 26 Nov 2018 01:21:22 +0000 Subject: [PATCH 0524/1995] ASoC: soc.h: makes snd_soc_of_parse_audio_prefix() inline commit 3b7103562c03c ("ASoC: soc-core: add snd_soc_of_parse_node_prefix()") maked snd_soc_of_parse_audio_prefix() as #define. But it'd be better to make this a static inline rather than a #define. It helps with error messages and type safety. This patch makes it inline. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 2708bccf9c6f142c3ef5a27f15d34febe751ce4c) --- include/sound/soc.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 37155f927415fb..8ec1de856ee7e1 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1481,9 +1481,15 @@ void snd_soc_of_parse_node_prefix(struct device_node *np, struct snd_soc_codec_conf *codec_conf, struct device_node *of_node, const char *propname); -#define snd_soc_of_parse_audio_prefix(card, conf, node, name) \ - snd_soc_of_parse_node_prefix((card)->dev->of_node, \ - (conf), (node), (name)) +static inline +void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, + struct snd_soc_codec_conf *codec_conf, + struct device_node *of_node, + const char *propname) +{ + snd_soc_of_parse_node_prefix(card->dev->of_node, + codec_conf, of_node, propname); +} int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname); From d24aab6bf7d42021a12e51ac5d2e3cdc7ab73d32 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Mon, 29 Jan 2018 21:45:59 +0530 Subject: [PATCH 0525/1995] ASoC: Intel: Skylake: Make DSP replies more human readable Add more meaning to the IPC replies for easy debugging. Replace the switch case with a lookup table to lookup for the IPC replies and print in human readable form. Signed-off-by: Subhransu S. Prusty Signed-off-by: Sriram Periyasamy Signed-off-by: Vinod Koul Signed-off-by: Mark Brown (cherry picked from commit aa15679b2dc898049e9117fbe3ddda0b50fa52d2) --- sound/soc/intel/skylake/skl-sst-ipc.c | 44 ++++++++++++++++++++------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 5234fafb758a0e..8708755a8f9a0a 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -392,18 +392,43 @@ int skl_ipc_process_notification(struct sst_generic_ipc *ipc, return 0; } -static int skl_ipc_set_reply_error_code(u32 reply) +struct skl_ipc_err_map { + const char *msg; + enum skl_ipc_glb_reply reply; + int err; +}; + +static struct skl_ipc_err_map skl_err_map[] = { + {"DSP out of memory", IPC_GLB_REPLY_OUT_OF_MEMORY, -ENOMEM}, + {"DSP busy", IPC_GLB_REPLY_BUSY, -EBUSY}, +}; + +static int skl_ipc_set_reply_error_code(struct sst_generic_ipc *ipc, u32 reply) { - switch (reply) { - case IPC_GLB_REPLY_OUT_OF_MEMORY: - return -ENOMEM; + int i; - case IPC_GLB_REPLY_BUSY: - return -EBUSY; + for (i = 0; i < ARRAY_SIZE(skl_err_map); i++) { + if (skl_err_map[i].reply == reply) + break; + } - default: + if (i == ARRAY_SIZE(skl_err_map)) { + dev_err(ipc->dev, "ipc FW reply: %d FW Error Code: %u\n", + reply, + ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); return -EINVAL; } + + if (skl_err_map[i].err < 0) + dev_err(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n", + skl_err_map[i].msg, + ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); + else + dev_info(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n", + skl_err_map[i].msg, + ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); + + return skl_err_map[i].err; } void skl_ipc_process_reply(struct sst_generic_ipc *ipc, @@ -441,10 +466,7 @@ void skl_ipc_process_reply(struct sst_generic_ipc *ipc, } } else { - msg->errno = skl_ipc_set_reply_error_code(reply); - dev_err(ipc->dev, "ipc FW reply: reply=%d\n", reply); - dev_err(ipc->dev, "FW Error Code: %u\n", - ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); + msg->errno = skl_ipc_set_reply_error_code(ipc, reply); switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { case IPC_GLB_LOAD_MULTIPLE_MODS: case IPC_GLB_LOAD_LIBRARY: From 9a6c41ecece58491ea2b9c8fee3ebf5324a4e539 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Mon, 29 Jan 2018 21:46:00 +0530 Subject: [PATCH 0526/1995] ASoC: Intel: Skylake: Add FW reply for MCLK/SCLK IPC If mclk/sclk is already running, FW responds with IPC reply MCLK/SCLK already running. Add these to the IPC reply lookup table. Signed-off-by: Subhransu S. Prusty Signed-off-by: Sriram Periyasamy Signed-off-by: Vinod Koul Signed-off-by: Mark Brown (cherry picked from commit 61f94ee4a7435c35d78b22e4ae6e0551908000ae) --- sound/soc/intel/skylake/skl-sst-ipc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 8708755a8f9a0a..9f3ce73593aec4 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -249,6 +249,8 @@ enum skl_ipc_glb_reply { IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121, IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140, IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141, + IPC_GLB_REPLY_SCLK_ALREADY_RUNNING = 150, + IPC_GLB_REPLY_MCLK_ALREADY_RUNNING = 151, IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160, IPC_GLB_REPLY_PPL_NOT_EXIST = 161, @@ -401,6 +403,10 @@ struct skl_ipc_err_map { static struct skl_ipc_err_map skl_err_map[] = { {"DSP out of memory", IPC_GLB_REPLY_OUT_OF_MEMORY, -ENOMEM}, {"DSP busy", IPC_GLB_REPLY_BUSY, -EBUSY}, + {"SCLK already running", IPC_GLB_REPLY_SCLK_ALREADY_RUNNING, + IPC_GLB_REPLY_SCLK_ALREADY_RUNNING}, + {"MCLK already running", IPC_GLB_REPLY_MCLK_ALREADY_RUNNING, + IPC_GLB_REPLY_MCLK_ALREADY_RUNNING}, }; static int skl_ipc_set_reply_error_code(struct sst_generic_ipc *ipc, u32 reply) From 44441c4c5f3859b19c514349b53937ac21d30031 Mon Sep 17 00:00:00 2001 From: Jenny TC Date: Wed, 28 Nov 2018 12:22:45 +0530 Subject: [PATCH 0527/1995] ASoC: dmic: introduce mode switch delay On startup, applications such as PulseAudio or CRAS enable playback or capture on all PCM devices to verify that configurations are correct, and close them immediately. For DMICs, this can result in the clock being turned off very quickly, which may not compatible with internal state machine transition requirements. This patch add a mode-switch delay which will prevent the clock from being turned off without complying with manufacturer timing specifications. While the DMIC clock may be controlled at a lower level, be it with hardware or firmware, applying the delay during the STOP_TRIGGER phase ensures that there is no race condition, e.g. with the hardware/firmware turning off the clock earlier Signed-off-by: Sathyanarayana Nujella Signed-off-by: Jairaj Arava Signed-off-by: Harsha Priya Signed-off-by: Jenny TC Signed-off-by: Mark Brown (cherry picked from commit bc0a7dbc5a54a06b925064adba8b07d65acf8718) --- .../devicetree/bindings/sound/dmic.txt | 2 ++ sound/soc/codecs/dmic.c | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/dmic.txt b/Documentation/devicetree/bindings/sound/dmic.txt index e957b41367160b..32e8710372696d 100644 --- a/Documentation/devicetree/bindings/sound/dmic.txt +++ b/Documentation/devicetree/bindings/sound/dmic.txt @@ -9,6 +9,7 @@ Optional properties: - dmicen-gpios: GPIO specifier for dmic to control start and stop - num-channels: Number of microphones on this DAI - wakeup-delay-ms: Delay (in ms) after enabling the DMIC + - modeswitch-delay-ms: Delay (in ms) to complete DMIC mode switch Example node: @@ -17,4 +18,5 @@ Example node: dmicen-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>; num-channels = <1>; wakeup-delay-ms <50>; + modeswitch-delay-ms <35>; }; diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index 71322e0410ee76..f4eb0a438a3add 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -30,9 +30,36 @@ #include #include +#define MAX_MODESWITCH_DELAY 70 +static int modeswitch_delay; +module_param(modeswitch_delay, uint, 0644); + struct dmic { struct gpio_desc *gpio_en; int wakeup_delay; + /* Delay after DMIC mode switch */ + int modeswitch_delay; +}; + +int dmic_daiops_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct dmic *dmic = snd_soc_component_get_drvdata(component); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_STOP: + if (dmic->modeswitch_delay) + mdelay(dmic->modeswitch_delay); + + break; + } + + return 0; +} + +static const struct snd_soc_dai_ops dmic_dai_ops = { + .trigger = dmic_daiops_trigger, }; static int dmic_aif_event(struct snd_soc_dapm_widget *w, @@ -68,6 +95,7 @@ static struct snd_soc_dai_driver dmic_dai = { | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, }, + .ops = &dmic_dai_ops, }; static int dmic_component_probe(struct snd_soc_component *component) @@ -85,6 +113,13 @@ static int dmic_component_probe(struct snd_soc_component *component) device_property_read_u32(component->dev, "wakeup-delay-ms", &dmic->wakeup_delay); + device_property_read_u32(component->dev, "modeswitch-delay-ms", + &dmic->modeswitch_delay); + if (modeswitch_delay) + dmic->modeswitch_delay = modeswitch_delay; + + if (dmic->modeswitch_delay > MAX_MODESWITCH_DELAY) + dmic->modeswitch_delay = MAX_MODESWITCH_DELAY; snd_soc_component_set_drvdata(component, dmic); From 334d0a29ea4ae40684810a4184bd927ac955e46c Mon Sep 17 00:00:00 2001 From: Jenny TC Date: Wed, 28 Nov 2018 12:22:46 +0530 Subject: [PATCH 0528/1995] ASoC: dmic: introduce module_param wakeup_delay Introducing a module param for wakeup_delay in order to align with modeswitch_delay parameter. With this change, both wakeup_delay and modeswitch_delay parameters can be passed as module parameters. Signed-off-by: Jenny TC Signed-off-by: Mark Brown (cherry picked from commit f6f30a609c526dbf6d59490a8c85adaf6ac9b0fa) --- sound/soc/codecs/dmic.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index f4eb0a438a3add..da921da50ef0fc 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -34,6 +34,9 @@ static int modeswitch_delay; module_param(modeswitch_delay, uint, 0644); +static int wakeup_delay; +module_param(wakeup_delay, uint, 0644); + struct dmic { struct gpio_desc *gpio_en; int wakeup_delay; @@ -115,6 +118,8 @@ static int dmic_component_probe(struct snd_soc_component *component) &dmic->wakeup_delay); device_property_read_u32(component->dev, "modeswitch-delay-ms", &dmic->modeswitch_delay); + if (wakeup_delay) + dmic->wakeup_delay = wakeup_delay; if (modeswitch_delay) dmic->modeswitch_delay = modeswitch_delay; From 2b78cf0ce7c97bff53e8c4adfd4d4acb23776d37 Mon Sep 17 00:00:00 2001 From: Young_X Date: Tue, 27 Nov 2018 06:33:16 +0000 Subject: [PATCH 0529/1995] ASoC: au8540: use 64-bit arithmetic instead of 32-bit Add suffix ULL to constant 256 in order to give the compiler complete information about the proper arithmetic to use. Notice that such constant is used in a context that expects an expression of type u64 (64 bits, unsigned) and the following expression is currently being evaluated using 32-bit arithmetic: 256 * fs * 2 * mclk_src_scaling[i].param Signed-off-by: Young_X Signed-off-by: Mark Brown (cherry picked from commit cd7fdc45bc69a62b4e22c6e875f1f1aea566256d) --- sound/soc/codecs/nau8540.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c index e3c8cd17daf2da..4dd1a609756be6 100644 --- a/sound/soc/codecs/nau8540.c +++ b/sound/soc/codecs/nau8540.c @@ -585,7 +585,7 @@ static int nau8540_calc_fll_param(unsigned int fll_in, fvco_max = 0; fvco_sel = ARRAY_SIZE(mclk_src_scaling); for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) { - fvco = 256 * fs * 2 * mclk_src_scaling[i].param; + fvco = 256ULL * fs * 2 * mclk_src_scaling[i].param; if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX && fvco_max < fvco) { fvco_max = fvco; From 4ffe79bc0094df160051c09c3c722f7edbf4cee7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 30 Nov 2018 18:54:37 -0600 Subject: [PATCH 0530/1995] ASoC: Intel: common: add ACPI matching tables for ICL Entry needed for ICL RVP w/ RT274 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 9923e9072d813e2efa591d01e6971e0833c38815) --- include/sound/soc-acpi-intel-match.h | 1 + sound/soc/intel/common/Makefile | 2 +- .../intel/common/soc-acpi-intel-icl-match.c | 32 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/common/soc-acpi-intel-icl-match.c diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index f48f59e5b7b02b..bb5e1e4ce8bf91 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -24,6 +24,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[]; /* * generic table used for HDA codec-based platforms, possibly with diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index c1f50a079d34aa..56c81e20b5bf8d 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -7,7 +7,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-hsw-bdw-match.o \ soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ - soc-acpi-intel-cnl-match.o \ + soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \ soc-acpi-intel-hda-match.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c new file mode 100644 index 00000000000000..33b441dca4d308 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-apci-intel-icl-match.c - tables and support for ICL ACPI enumeration. + * + * Copyright (c) 2018, Intel Corporation. + * + */ + +#include +#include +#include "../skylake/skl.h" + +static struct skl_machine_pdata icl_pdata = { + .use_tplg_pcm = true, +}; + +struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { + { + .id = "INT34C2", + .drv_name = "icl_rt274", + .fw_filename = "intel/dsp_fw_icl.bin", + .pdata = &icl_pdata, + .sof_fw_filename = "intel/sof-icl.ri", + .sof_tplg_filename = "intel/sof-icl-rt274.tplg", + .asoc_plat_name = "0000:00:1f.3", + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_icl_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); From d1a1e76cadb9c8746624dbe25487795963e1f1b7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 2 Dec 2018 13:21:22 +0100 Subject: [PATCH 0531/1995] ASoC: intel: cht_bsw_max98090_ti: Add pmc_plt_clk_0 quirk for Chromebook Clapper The Clapper model Chromebook uses pmc_plt_clk_0 instead of pmc_plt_clk_3 for the mclk, just like the Swanky model. This commit adds a DMI based quirk for this. This fixing audio no longer working on these devices after commit 648e921888ad ("clk: x86: Stop marking clocks as CLK_IS_CRITICAL") that commit fixes us unnecessary keeping unused clocks on, but in case of the Clapper that was breaking audio support since we were not using the right clock in the cht_bsw_max98090_ti machine driver. Cc: stable@vger.kernel.org Fixes: 648e921888ad ("clk: x86: Stop marking clocks as CLK_IS_CRITICAL") Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 984bfb398a3af6fa9b7e80165e524933b0616686) --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 9d9f6e41d81c07..ad0c9838385366 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -389,6 +389,13 @@ static struct snd_soc_card snd_soc_card_cht = { }; static const struct dmi_system_id cht_max98090_quirk_table[] = { + { + /* Clapper model Chromebook */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Clapper"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, { /* Swanky model Chromebook (Toshiba Chromebook 2) */ .matches = { From 93d0fd938fdf9550456b4da059a205dc9ebc8ee5 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Fri, 30 Nov 2018 03:21:09 +0000 Subject: [PATCH 0532/1995] ASoC: max98373: Added max98373_reset for stable amp reset This patch added max98373_reset function to avoid amp software reset failure and code duplication. Reset verification step has been added for stable amp reset and it repeats verification maximum 3 times when it is failed. Chip revision ID is available when the amp is in the idle state which means software reset is completed well. Additional 10ms delay was added for every retrial and maximum 30ms delay can be applied. Signed-off-by: Ryan Lee Signed-off-by: Mark Brown (cherry picked from commit 20f2ab247d3b787af91c1aa5eb27c5061744c154) --- sound/soc/codecs/max98373.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index a09d01318f793d..9c8616a7b61c9d 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -724,14 +724,39 @@ static struct snd_soc_dai_driver max98373_dai[] = { } }; +static void max98373_reset(struct max98373_priv *max98373, struct device *dev) +{ + int ret, reg, count; + + /* Software Reset */ + ret = regmap_update_bits(max98373->regmap, + MAX98373_R2000_SW_RESET, + MAX98373_SOFT_RESET, + MAX98373_SOFT_RESET); + if (ret) + dev_err(dev, "Reset command failed. (ret:%d)\n", ret); + + count = 0; + while (count < 3) { + usleep_range(10000, 11000); + /* Software Reset Verification */ + ret = regmap_read(max98373->regmap, + MAX98373_R21FF_REV_ID, ®); + if (!ret) { + dev_info(dev, "Reset completed (retry:%d)\n", count); + return; + } + count++; + } + dev_err(dev, "Reset failed. (ret:%d)\n", ret); +} + static int max98373_probe(struct snd_soc_component *component) { struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component); /* Software Reset */ - regmap_write(max98373->regmap, - MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET); - usleep_range(10000, 11000); + max98373_reset(max98373, component->dev); /* IV default slot configuration */ regmap_write(max98373->regmap, @@ -818,9 +843,7 @@ static int max98373_resume(struct device *dev) { struct max98373_priv *max98373 = dev_get_drvdata(dev); - regmap_write(max98373->regmap, - MAX98373_R2000_SW_RESET, MAX98373_SOFT_RESET); - usleep_range(10000, 11000); + max98373_reset(max98373, dev); regcache_cache_only(max98373->regmap, false); regcache_sync(max98373->regmap); return 0; From 13d7da707ea29ad7e7a31423c58fcaa3efe35761 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 3 Dec 2018 21:45:14 +0100 Subject: [PATCH 0533/1995] ASoC: intel: cht_bsw_max98090_ti: Add pmc_plt_clk_0 quirk for Chromebook Gnawty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Gnawty model Chromebook uses pmc_plt_clk_0 instead of pmc_plt_clk_3 for the mclk, just like the Clapper and Swanky models. This commit adds a DMI based quirk for this. This fixing audio no longer working on these devices after commit 648e921888ad ("clk: x86: Stop marking clocks as CLK_IS_CRITICAL") that commit fixes us unnecessary keeping unused clocks on, but in case of the Gnawty that was breaking audio support since we were not using the right clock in the cht_bsw_max98090_ti machine driver. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=201787 Cc: stable@vger.kernel.org Fixes: 648e921888ad ("clk: x86: Stop marking clocks as CLK_IS_CRITICAL") Reported-and-tested-by: Jaime Pérez <19.jaime.91@gmail.com> Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 94ea56cff506c769a509c5dd87904c7fe3806a81) --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index ad0c9838385366..08a5152e635ac8 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -396,6 +396,13 @@ static const struct dmi_system_id cht_max98090_quirk_table[] = { }, .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, }, + { + /* Gnawty model Chromebook (Acer Chromebook CB3-111) */ + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Gnawty"), + }, + .driver_data = (void *)QUIRK_PMC_PLT_CLK_0, + }, { /* Swanky model Chromebook (Toshiba Chromebook 2) */ .matches = { From 0dcfc1d1da83a1297764cafa28f37191625bb7cf Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Thu, 6 Dec 2018 22:52:05 +0800 Subject: [PATCH 0534/1995] ASoC: rt5660: Add a new ACPI match ID The Realtek codec ALC3277 is 100% compatible with the codec RT5660 in I2S mode. And on the Dell IoT platform, the codec is ALC3277, and the HID of the codec in the BIOS is 10EC3277, so adding this ID to the ACPI match table. Signed-off-by: Hui Wang Signed-off-by: Mark Brown (cherry picked from commit a01b8d1d24451bfc00d3a975d107f9b1590bf826) --- sound/soc/codecs/rt5660.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index 27f7445b243200..e74b2e8cd423e3 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -1246,6 +1246,7 @@ MODULE_DEVICE_TABLE(of, rt5660_of_match); static const struct acpi_device_id rt5660_acpi_match[] = { { "10EC5660", 0 }, + { "10EC3277", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, rt5660_acpi_match); From 7e2d8177c55da4a90c6076f2074866bd7a0cfaac Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 8 Dec 2018 14:01:13 +0100 Subject: [PATCH 0535/1995] ASoC: Intel: bytcr_rt5640: Add quirk for the Prowise PT301 tablet Add a quirk for the Prowise PT301 tablet, this BYTCR tablet has no CHAN package in its ACPI tables and uses SSP0-AIF1 rather then SSP0-AIF2 which is the default for BYTCR devices. Also it uses IN1 for its MIC and JD2 for jack-detect, rather then the default IN3 and JD1. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 271248f4c2bf56dc6b3582e37c7ac19dd483d989) --- sound/soc/intel/boards/bytcr_rt5640.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 09591144ea7d2e..a48ea8ef21ce31 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -673,6 +673,20 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF2 | BYT_RT5640_MCLK_EN), }, + { + /* Prowise PT301 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Prowise"), + DMI_MATCH(DMI_PRODUCT_NAME, "PT301"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"), From 8a729c41d380b636c085b5a4df1ea4edb4d09642 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 8 Dec 2018 14:01:14 +0100 Subject: [PATCH 0536/1995] ASoC: Intel: bytcr_rt5640: Add quirk for the Point of View Mobii TAB-P1005W-232 Add a quirk for the Point of View Mobii TAB-P1005W-232 v2.0 tablet, this BYTCR device uses IN1 for its MIC and JD2 for jack-detect, rather then the default IN3 and JD1. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 02e5af6575627ca0692d5b93e7c3fc3b86f62f40) --- sound/soc/intel/boards/bytcr_rt5640.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index a48ea8ef21ce31..a22366ce33c403 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -673,6 +673,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF2 | BYT_RT5640_MCLK_EN), }, + { /* Point of View Mobii TAB-P1005W-232 (V2.0) */ + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "POV"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "I102A"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { /* Prowise PT301 */ .matches = { From a90af727ca0b9aba9740a862a6edcec6ebb801b7 Mon Sep 17 00:00:00 2001 From: Zhuohao Lee Date: Mon, 10 Dec 2018 12:32:13 +0800 Subject: [PATCH 0537/1995] ASoC: Intel: kbl_da7219_max98927: fix the audio jack button remapping From the da7219 spec, the button A, B, C and D are remapped to 0, 1, 2 and 3 respectively where button A is KEY_PLAYPAUSE, B is KEY_VOLUMEUP, C is KEY_VOLUMEDOWN and D is KEY_VOICECOMMAND. Signed-off-by: Zhuohao Lee Signed-off-by: Max Chang Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7f63196eaa83e033de523602324ff91288390a67) --- sound/soc/intel/boards/kbl_da7219_max98927.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 58eb0fe69978bd..723a4935ed76ed 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -262,9 +262,9 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) jack = &ctx->kabylake_headset; snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); da7219_aad_jack_det(component, &ctx->kabylake_headset); From 2232943a98ffbd25a09078ec18d34c762c93fa68 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Thu, 13 Dec 2018 21:02:16 +0800 Subject: [PATCH 0538/1995] ASoC: Intel: kbl_rt5660: Add a new machine driver for kbl with rt5660 The new Dell IoT platform uses kabylake + alc3277 codec, and alc3277 shares the driver with the codec rt5660, here we generate a new machine driver based on kbl_da7219_max98357a. The audio design on this IoT platform is as below: - Intel kabylake platform - connect the codec ALC3277 via SSP0 - line-out and line-in with Micbias jacks - line-out mute control and jack detection of line-out and line-in - two HDMI ports with audio capability Signed-off-by: Hui Wang Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 8625db9416923b2941ef68776f55062555f7ce65) --- sound/soc/intel/boards/Kconfig | 10 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/kbl_rt5660.c | 543 ++++++++++++++++++ .../intel/common/soc-acpi-intel-kbl-match.c | 10 + 4 files changed, 565 insertions(+) create mode 100644 sound/soc/intel/boards/kbl_rt5660.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index b177db2a0dbb2a..3839d6205fcf42 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -293,6 +293,16 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH Say Y if you have such a device. If unsure select "N". +config SND_SOC_INTEL_KBL_RT5660_MACH + tristate "KBL with RT5660 in I2S Mode" + depends on MFD_INTEL_LPSS && I2C && ACPI + select SND_SOC_RT5660 + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC Onboard Codec I2S machine driver. This will + create an alsa sound card for RT5660 I2S audio codec. + Say Y if you have such a device. + config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH tristate "GLK with RT5682 and MAX98357A in I2S Mode" depends on MFD_INTEL_LPSS && I2C && ACPI diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 5381e27df9cc76..bf072ea299b709 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -20,6 +20,7 @@ snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o +snd-soc-kbl_rt5660-objs := kbl_rt5660.o snd-soc-skl_rt286-objs := skl_rt286.o snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o @@ -46,6 +47,7 @@ obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max9 obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o +obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5660_MACH) += snd-soc-kbl_rt5660.o obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c new file mode 100644 index 00000000000000..3255e00292764e --- /dev/null +++ b/sound/soc/intel/boards/kbl_rt5660.c @@ -0,0 +1,543 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2018-19 Canonical Corporation. + +/* + * Intel Kabylake I2S Machine Driver with RT5660 Codec + * + * Modified from: + * Intel Kabylake I2S Machine driver supporting MAXIM98357a and + * DA7219 codecs + * Also referred to: + * Intel Broadwell I2S Machine driver supporting RT5677 codec + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../codecs/hdac_hdmi.h" +#include "../../codecs/rt5660.h" + +#define KBL_RT5660_CODEC_DAI "rt5660-aif1" +#define DUAL_CHANNEL 2 + +static struct snd_soc_card *kabylake_audio_card; +static struct snd_soc_jack skylake_hdmi[3]; +static struct snd_soc_jack lineout_jack; +static struct snd_soc_jack mic_jack; + +struct kbl_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct kbl_codec_private { + struct gpio_desc *gpio_lo_mute; + struct list_head hdmi_pcm_list; +}; + +enum { + KBL_DPCM_AUDIO_PB = 0, + KBL_DPCM_AUDIO_CP, + KBL_DPCM_AUDIO_HDMI1_PB, + KBL_DPCM_AUDIO_HDMI2_PB, + KBL_DPCM_AUDIO_HDMI3_PB, +}; + +#define GPIO_LINEOUT_MUTE_INDEX 0 +#define GPIO_LINEOUT_DET_INDEX 3 +#define GPIO_LINEIN_DET_INDEX 4 + +static const struct acpi_gpio_params lineout_mute_gpio = { GPIO_LINEOUT_MUTE_INDEX, 0, true }; +static const struct acpi_gpio_params lineout_det_gpio = { GPIO_LINEOUT_DET_INDEX, 0, false }; +static const struct acpi_gpio_params mic_det_gpio = { GPIO_LINEIN_DET_INDEX, 0, false }; + + +static const struct acpi_gpio_mapping acpi_rt5660_gpios[] = { + { "lineout-mute-gpios", &lineout_mute_gpio, 1 }, + { "lineout-det-gpios", &lineout_det_gpio, 1 }, + { "mic-det-gpios", &mic_det_gpio, 1 }, + { NULL }, +}; + +static struct snd_soc_jack_pin lineout_jack_pin = { + .pin = "Line Out", + .mask = SND_JACK_LINEOUT, +}; + +static struct snd_soc_jack_pin mic_jack_pin = { + .pin = "Line In", + .mask = SND_JACK_MICROPHONE, +}; + +static struct snd_soc_jack_gpio lineout_jack_gpio = { + .name = "lineout-det", + .report = SND_JACK_LINEOUT, + .debounce_time = 200, +}; + +static struct snd_soc_jack_gpio mic_jack_gpio = { + .name = "mic-det", + .report = SND_JACK_MICROPHONE, + .debounce_time = 200, +}; + +static int kabylake_5660_event_lineout(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct kbl_codec_private *priv = snd_soc_card_get_drvdata(dapm->card); + + gpiod_set_value_cansleep(priv->gpio_lo_mute, + !(SND_SOC_DAPM_EVENT_ON(event))); + + return 0; +} + +static const struct snd_kcontrol_new kabylake_rt5660_controls[] = { + SOC_DAPM_PIN_SWITCH("Line In"), + SOC_DAPM_PIN_SWITCH("Line Out"), +}; + +static const struct snd_soc_dapm_widget kabylake_rt5660_widgets[] = { + SND_SOC_DAPM_MIC("Line In", NULL), + SND_SOC_DAPM_LINE("Line Out", kabylake_5660_event_lineout), +}; + +static const struct snd_soc_dapm_route kabylake_rt5660_map[] = { + /* other jacks */ + {"IN1P", NULL, "Line In"}, + {"IN2P", NULL, "Line In"}, + {"Line Out", NULL, "LOUTR"}, + {"Line Out", NULL, "LOUTL"}, + + /* CODEC BE connections */ + { "AIF1 Playback", NULL, "ssp0 Tx"}, + { "ssp0 Tx", NULL, "codec0_out"}, + + { "codec0_in", NULL, "ssp0 Rx" }, + { "ssp0 Rx", NULL, "AIF1 Capture" }, + + { "hifi1", NULL, "iDisp1 Tx"}, + { "iDisp1 Tx", NULL, "iDisp1_out"}, + { "hifi2", NULL, "iDisp2 Tx"}, + { "iDisp2 Tx", NULL, "iDisp2_out"}, + { "hifi3", NULL, "iDisp3 Tx"}, + { "iDisp3 Tx", NULL, "iDisp3_out"}, +}; + +static int kabylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = DUAL_CHANNEL; + + /* set SSP0 to 24 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +static int kabylake_rt5660_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_component *component = rtd->codec_dai->component; + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + ret = devm_acpi_dev_add_driver_gpios(component->dev, acpi_rt5660_gpios); + if (ret) + dev_warn(component->dev, "Failed to add driver gpios\n"); + + /* Request rt5660 GPIO for lineout mute control, return if fails */ + ctx->gpio_lo_mute = devm_gpiod_get(component->dev, "lineout-mute", + GPIOD_OUT_HIGH); + if (IS_ERR(ctx->gpio_lo_mute)) { + dev_err(component->dev, "Can't find GPIO_MUTE# gpio\n"); + return PTR_ERR(ctx->gpio_lo_mute); + } + + /* Create and initialize headphone jack, this jack is not mandatory, don't return if fails */ + ret = snd_soc_card_jack_new(rtd->card, "Lineout Jack", + SND_JACK_LINEOUT, &lineout_jack, + &lineout_jack_pin, 1); + if (ret) + dev_warn(component->dev, "Can't create Lineout jack\n"); + else { + lineout_jack_gpio.gpiod_dev = component->dev; + ret = snd_soc_jack_add_gpios(&lineout_jack, 1, + &lineout_jack_gpio); + if (ret) + dev_warn(component->dev, "Can't add Lineout jack gpio\n"); + } + + /* Create and initialize mic jack, this jack is not mandatory, don't return if fails */ + ret = snd_soc_card_jack_new(rtd->card, "Mic Jack", + SND_JACK_MICROPHONE, &mic_jack, + &mic_jack_pin, 1); + if (ret) + dev_warn(component->dev, "Can't create mic jack\n"); + else { + mic_jack_gpio.gpiod_dev = component->dev; + ret = snd_soc_jack_add_gpios(&mic_jack, 1, &mic_jack_gpio); + if (ret) + dev_warn(component->dev, "Can't add mic jack gpio\n"); + } + + /* Here we enable some dapms in advance to reduce the pop noise for recording via line-in */ + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_force_enable_pin(dapm, "BST1"); + snd_soc_dapm_force_enable_pin(dapm, "BST2"); + + return 0; +} + +static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) +{ + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct kbl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = device; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); +} + +static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); +} + +static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) +{ + return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); +} + +static int kabylake_rt5660_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, + RT5660_SCLK_S_PLL1, params_rate(params) * 512, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_pll(codec_dai, 0, + RT5660_PLL1_S_BCLK, + params_rate(params) * 50, + params_rate(params) * 512); + if (ret < 0) + dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret); + + return ret; +} + +static struct snd_soc_ops kabylake_rt5660_ops = { + .hw_params = kabylake_rt5660_hw_params, +}; + +static const unsigned int rates[] = { + 48000, +}; + +static const struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; + +static const unsigned int channels[] = { + DUAL_CHANNEL, +}; + +static const struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, +}; + +static int kbl_fe_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + /* + * On this platform for PCM device we support, + * 48Khz + * stereo + * 16 bit audio + */ + + runtime->hw.channels_max = DUAL_CHANNEL; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + + return 0; +} + +static const struct snd_soc_ops kabylake_rt5660_fe_ops = { + .startup = kbl_fe_startup, +}; + +/* kabylake digital audio interface glue - connects rt5660 codec <--> CPU */ +static struct snd_soc_dai_link kabylake_rt5660_dais[] = { + /* Front End DAI links */ + [KBL_DPCM_AUDIO_PB] = { + .name = "Kbl Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &kabylake_rt5660_fe_ops, + }, + [KBL_DPCM_AUDIO_CP] = { + .name = "Kbl Audio Capture Port", + .stream_name = "Audio Record", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_capture = 1, + .ops = &kabylake_rt5660_fe_ops, + }, + [KBL_DPCM_AUDIO_HDMI1_PB] = { + .name = "Kbl HDMI Port1", + .stream_name = "Hdmi1", + .cpu_dai_name = "HDMI1 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI2_PB] = { + .name = "Kbl HDMI Port2", + .stream_name = "Hdmi2", + .cpu_dai_name = "HDMI2 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .nonatomic = 1, + .dynamic = 1, + }, + [KBL_DPCM_AUDIO_HDMI3_PB] = { + .name = "Kbl HDMI Port3", + .stream_name = "Hdmi3", + .cpu_dai_name = "HDMI3 Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .init = NULL, + .nonatomic = 1, + .dynamic = 1, + }, + + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .id = 0, + .cpu_dai_name = "SSP0 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codec_name = "i2c-10EC3277:00", + .codec_dai_name = KBL_RT5660_CODEC_DAI, + .init = kabylake_rt5660_codec_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = kabylake_ssp0_fixup, + .ops = &kabylake_rt5660_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + { + .name = "iDisp1", + .id = 1, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = kabylake_hdmi1_init, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .id = 2, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi2_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .id = 3, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .platform_name = "0000:00:1f.3", + .init = kabylake_hdmi3_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + + +#define NAME_SIZE 32 +static int kabylake_card_late_probe(struct snd_soc_card *card) +{ + struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); + struct kbl_hdmi_pcm *pcm; + struct snd_soc_component *component = NULL; + int err, i = 0; + char jack_name[NAME_SIZE]; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &skylake_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &skylake_hdmi[i]); + if (err < 0) + return err; + + i++; + + } + + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); +} + +/* kabylake audio machine driver for rt5660 */ +static struct snd_soc_card kabylake_audio_card_rt5660 = { + .name = "kblrt5660", + .owner = THIS_MODULE, + .dai_link = kabylake_rt5660_dais, + .num_links = ARRAY_SIZE(kabylake_rt5660_dais), + .controls = kabylake_rt5660_controls, + .num_controls = ARRAY_SIZE(kabylake_rt5660_controls), + .dapm_widgets = kabylake_rt5660_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_rt5660_widgets), + .dapm_routes = kabylake_rt5660_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_rt5660_map), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + +static int kabylake_audio_probe(struct platform_device *pdev) +{ + struct kbl_codec_private *ctx; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + kabylake_audio_card = + (struct snd_soc_card *)pdev->id_entry->driver_data; + + kabylake_audio_card->dev = &pdev->dev; + snd_soc_card_set_drvdata(kabylake_audio_card, ctx); + return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); +} + +static const struct platform_device_id kbl_board_ids[] = { + { + .name = "kbl_rt5660", + .driver_data = + (kernel_ulong_t)&kabylake_audio_card_rt5660, + }, + { } +}; + +static struct platform_driver kabylake_audio = { + .probe = kabylake_audio_probe, + .driver = { + .name = "kbl_rt5660", + .pm = &snd_soc_pm_ops, + }, + .id_table = kbl_board_ids, +}; + +module_platform_driver(kabylake_audio) + +/* Module information */ +MODULE_DESCRIPTION("Audio Machine driver-RT5660 in I2S mode"); +MODULE_AUTHOR("Hui Wang "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:kbl_rt5660"); diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c index a317b7790fcecf..e6fa6f470526dc 100644 --- a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c @@ -96,6 +96,16 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .quirk_data = &kbl_7219_98927_codecs, .pdata = &skl_dmic_data }, + { + .id = "10EC5660", + .drv_name = "kbl_rt5660", + .fw_filename = "intel/dsp_fw_kbl.bin", + }, + { + .id = "10EC3277", + .drv_name = "kbl_rt5660", + .fw_filename = "intel/dsp_fw_kbl.bin", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines); From 59103e6dd6633092b215a9564bb6fbb243323c8b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 7 Dec 2018 17:50:03 -0600 Subject: [PATCH 0539/1995] ASoC: Intel: Skylake: Add CFL-S support It's with CNP, supposed to be equivalent with CNL entry. Keep the existing declaration style for now, at a later point we may transition and use PCI_DEVICE_DATA(). Signed-off-by: Takashi Iwai Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit e6b98db945124987b1ecec3f5f030877627e01a9) --- sound/soc/intel/skylake/skl-messages.c | 8 ++++++++ sound/soc/intel/skylake/skl.c | 3 +++ 2 files changed, 11 insertions(+) diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 8bfb8b0fa3d595..b0e6fb93eaf83c 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -247,6 +247,14 @@ static const struct skl_dsp_ops dsp_ops[] = { .init_fw = cnl_sst_init_fw, .cleanup = cnl_sst_dsp_cleanup }, + { + .id = 0xa348, + .num_cores = 4, + .loader_ops = bxt_get_loader_ops, + .init = cnl_sst_dsp_init, + .init_fw = cnl_sst_init_fw, + .cleanup = cnl_sst_dsp_cleanup + }, }; const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 780daace11cdd6..28d47b81477040 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -1103,6 +1103,9 @@ static const struct pci_device_id skl_ids[] = { /* CNL */ { PCI_DEVICE(0x8086, 0x9dc8), .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, + /* CFL */ + { PCI_DEVICE(0x8086, 0xa348), + .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, { 0, } }; MODULE_DEVICE_TABLE(pci, skl_ids); From 09da090e32543bfcaa49f0f813f941b56be73671 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 7 Dec 2018 17:50:04 -0600 Subject: [PATCH 0540/1995] ASoC: Intel: Skylake: Harden DSP detection with PCI class/subclass info The existing PPCAP and GCAP fields cannot be used reliably to determine if the DSP is enabled by the BIOS. Instead rely on the class/subclass information to find out if this driver can run or not. The values in the code don't seem to be documented in publicly available documents but are part of recommendations made to BIOS writers and have been verified to be accurate on a number of platforms. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit c746de8dbc7b0ae9df491f7a99a6dab34203b51b) --- sound/soc/intel/skylake/skl.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 28d47b81477040..5a449c505dcb2f 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -898,6 +898,21 @@ static int skl_first_init(struct hdac_bus *bus) unsigned short gcap; int cp_streams, pb_streams, start_idx; + /* + * detect DSP by checking class/subclass/prog-id information + * class=04 subclass 03 prog-if 00: no DSP, legacy driver needs to be used + * class=04 subclass 01 prog-if 00: DSP is present (and may be required e.g. for DMIC or SSP support) + * class=04 subclass 03 prog-if 80: either of DSP or legacy mode can be used + */ + if (pci->class == 0x040300) { + dev_err(bus->dev, "The DSP is not enabled on this platform, aborting probe\n"); + return -ENODEV; + } else if (pci->class != 0x040100 && pci->class != 0x040380) { + dev_err(bus->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, aborting probe\n", pci->class); + return -ENODEV; + } + dev_info(bus->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class); + err = pci_request_regions(pci, "Skylake HD audio"); if (err < 0) return err; From 96c5078b4d804f82c616c14656a1af7a2fa45752 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 7 Dec 2018 17:50:05 -0600 Subject: [PATCH 0541/1995] ASoC: Intel: Skylake: stop probe if HDaudio capabilities don't exist Check immediately if required HDaudio capabilities can't be found (no PPCAP or no streams exposed in GCAP), and move all DMA inits after the error tests. PPCAP and GCAP are not reliable indicators of DSP presence, but if they don't exist then the driver will not work. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit fa11ab5688f744bc868356f3f14c3bb9f283a780) --- sound/soc/intel/skylake/skl.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 5a449c505dcb2f..2aba3cfc16da6d 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -928,6 +928,12 @@ static int skl_first_init(struct hdac_bus *bus) snd_hdac_bus_parse_capabilities(bus); + /* check if PPCAP exists */ + if (!bus->ppcap) { + dev_err(bus->dev, "bus ppcap not set, HDaudio or DSP not present?\n"); + return -ENODEV; + } + if (skl_acquire_irq(bus, 0) < 0) return -EBUSY; @@ -937,23 +943,25 @@ static int skl_first_init(struct hdac_bus *bus) gcap = snd_hdac_chip_readw(bus, GCAP); dev_dbg(bus->dev, "chipset global capabilities = 0x%x\n", gcap); - /* allow 64bit DMA address if supported by H/W */ - if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) { - dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64)); - } else { - dma_set_mask(bus->dev, DMA_BIT_MASK(32)); - dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32)); - } - /* read number of streams from GCAP register */ cp_streams = (gcap >> 8) & 0x0f; pb_streams = (gcap >> 12) & 0x0f; - if (!pb_streams && !cp_streams) + if (!pb_streams && !cp_streams) { + dev_err(bus->dev, "no streams found in GCAP definitions?\n"); return -EIO; + } bus->num_streams = cp_streams + pb_streams; + /* allow 64bit DMA address if supported by H/W */ + if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) { + dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64)); + } else { + dma_set_mask(bus->dev, DMA_BIT_MASK(32)); + dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32)); + } + /* initialize streams */ snd_hdac_ext_stream_init_all (bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE); From 948844e590c4ef933bb0f748faa705a9e165a7f9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 7 Dec 2018 17:50:06 -0600 Subject: [PATCH 0542/1995] ASoC: Intel: Skylake: remove useless tests on HDaudio capabilities bus->ppcap is now tested upfront, there is no need to re-check if the hardware is exposed as needed. Remove tests and remove indentation. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7f981bdcf55fda28a9a70c9e8151dd200771a0a8) --- sound/soc/intel/skylake/skl.c | 40 ++++++++++++++++------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 2aba3cfc16da6d..ab43424fb2998b 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -814,12 +814,10 @@ static void skl_probe_work(struct work_struct *work) return; } - if (bus->ppcap) { - err = skl_machine_device_register(skl); - if (err < 0) { - dev_err(bus->dev, "machine register failed: %d\n", err); - goto out_err; - } + err = skl_machine_device_register(skl); + if (err < 0) { + dev_err(bus->dev, "machine register failed: %d\n", err); + goto out_err; } /* @@ -1016,25 +1014,23 @@ static int skl_probe(struct pci_dev *pci, pci_set_drvdata(skl->pci, bus); - /* check if dsp is there */ - if (bus->ppcap) { - /* create device for dsp clk */ - err = skl_clock_device_register(skl); - if (err < 0) - goto out_clk_free; + /* create device for dsp clk */ + err = skl_clock_device_register(skl); + if (err < 0) + goto out_clk_free; - err = skl_find_machine(skl, (void *)pci_id->driver_data); - if (err < 0) - goto out_nhlt_free; + err = skl_find_machine(skl, (void *)pci_id->driver_data); + if (err < 0) + goto out_nhlt_free; - err = skl_init_dsp(skl); - if (err < 0) { - dev_dbg(bus->dev, "error failed to register dsp\n"); - goto out_nhlt_free; - } - skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge; - skl->skl_sst->clock_power_gating = skl_clock_power_gating; + err = skl_init_dsp(skl); + if (err < 0) { + dev_dbg(bus->dev, "error failed to register dsp\n"); + goto out_nhlt_free; } + skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge; + skl->skl_sst->clock_power_gating = skl_clock_power_gating; + if (bus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(bus); From 060cc2b8ff005cffe79cb766c240b342aabb405c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 7 Dec 2018 17:50:07 -0600 Subject: [PATCH 0543/1995] ASoC: Intel: Skylake: add error logs on probe, remove dependency on NHLT Add error logs to make probe debug easier. Also remove hard-coded dependency on NHLT. NHLT literally stands for NonHdaudioLinkTable and is only required for SSP/DMIC interfaces. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit f231c34ca9772f0b0e2d1b781e9c415847aff522) --- sound/soc/intel/skylake/skl-nhlt.c | 3 +++ sound/soc/intel/skylake/skl.c | 41 +++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 01a050cf877537..5d125a3df52792 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -180,6 +180,9 @@ int skl_get_dmic_geo(struct skl *skl) unsigned int dmic_geo = 0; u8 j; + if (!nhlt) + return 0; + epnt = (struct nhlt_endpoint *)nhlt->desc; for (j = 0; j < nhlt->endpoint_count; j++) { diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index ab43424fb2998b..25996f586c7204 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -992,8 +992,10 @@ static int skl_probe(struct pci_dev *pci, bus = skl_to_bus(skl); err = skl_first_init(bus); - if (err < 0) + if (err < 0) { + dev_err(bus->dev, "skl_first_init failed with err: %d\n", err); goto out_free; + } skl->pci_id = pci->device; @@ -1002,26 +1004,39 @@ static int skl_probe(struct pci_dev *pci, skl->nhlt = skl_nhlt_init(bus->dev); if (skl->nhlt == NULL) { +#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) + dev_err(bus->dev, "no nhlt info found\n"); err = -ENODEV; goto out_free; - } +#else + dev_warn(bus->dev, "no nhlt info found, continuing to try to enable HDaudio codec\n"); +#endif + } else { - err = skl_nhlt_create_sysfs(skl); - if (err < 0) - goto out_nhlt_free; + err = skl_nhlt_create_sysfs(skl); + if (err < 0) { + dev_err(bus->dev, "skl_nhlt_create_sysfs failed with err: %d\n", err); + goto out_nhlt_free; + } - skl_nhlt_update_topology_bin(skl); + skl_nhlt_update_topology_bin(skl); + + /* create device for dsp clk */ + err = skl_clock_device_register(skl); + if (err < 0) { + dev_err(bus->dev, "skl_clock_device_register failed with err: %d\n", err); + goto out_clk_free; + } + } pci_set_drvdata(skl->pci, bus); - /* create device for dsp clk */ - err = skl_clock_device_register(skl); - if (err < 0) - goto out_clk_free; err = skl_find_machine(skl, (void *)pci_id->driver_data); - if (err < 0) + if (err < 0) { + dev_err(bus->dev, "skl_find_machine failed with err: %d\n", err); goto out_nhlt_free; + } err = skl_init_dsp(skl); if (err < 0) { @@ -1038,8 +1053,10 @@ static int skl_probe(struct pci_dev *pci, /* create device for soc dmic */ err = skl_dmic_device_register(skl); - if (err < 0) + if (err < 0) { + dev_err(bus->dev, "skl_dmic_device_register failed with err: %d\n", err); goto out_dsp_free; + } schedule_work(&skl->probe_work); From b49de46b625f16f33bf2b63484053a86792f28f3 Mon Sep 17 00:00:00 2001 From: Dimitris Papavasiliou Date: Sat, 24 Nov 2018 22:05:42 +0200 Subject: [PATCH 0544/1995] ASoC: pcm512x: Implement the digital_mute interface Clicks and pops of various volumes can be produced while the device is opened, closed, put into and taken out of standby, or reconfigured. Fix this, by implementing the digital_mute interface, so that the output is muted during such operations. Signed-off-by: Dimitris Papavasiliou Signed-off-by: Mark Brown (cherry picked from commit 3500f1c589e92e0b6b1f8d31b4084fbde08d49cb) --- sound/soc/codecs/pcm512x.c | 121 ++++++++++++++++++++++++++++++++++++- sound/soc/codecs/pcm512x.h | 2 + 2 files changed, 121 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index f0f2d4fd3769f5..6cb1653be80417 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -53,6 +53,8 @@ struct pcm512x_priv { unsigned long overclock_pll; unsigned long overclock_dac; unsigned long overclock_dsp; + int mute; + struct mutex mutex; }; /* @@ -384,6 +386,61 @@ static const struct soc_enum pcm512x_veds = SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4, pcm512x_ramp_step_text); +static int pcm512x_update_mute(struct pcm512x_priv *pcm512x) +{ + return regmap_update_bits( + pcm512x->regmap, PCM512x_MUTE, PCM512x_RQML | PCM512x_RQMR, + (!!(pcm512x->mute & 0x5) << PCM512x_RQML_SHIFT) + | (!!(pcm512x->mute & 0x3) << PCM512x_RQMR_SHIFT)); +} + +static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + + mutex_lock(&pcm512x->mutex); + ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4); + ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2); + mutex_unlock(&pcm512x->mutex); + + return 0; +} + +static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + int ret, changed = 0; + + mutex_lock(&pcm512x->mutex); + + if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) { + pcm512x->mute ^= 0x4; + changed = 1; + } + if ((pcm512x->mute & 0x2) == (ucontrol->value.integer.value[1] << 1)) { + pcm512x->mute ^= 0x2; + changed = 1; + } + + if (changed) { + ret = pcm512x_update_mute(pcm512x); + if (ret != 0) { + dev_err(component->dev, + "Failed to update digital mute: %d\n", ret); + mutex_unlock(&pcm512x->mutex); + return ret; + } + } + + mutex_unlock(&pcm512x->mutex); + + return changed; +} + static const struct snd_kcontrol_new pcm512x_controls[] = { SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2, PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), @@ -391,8 +448,15 @@ SOC_DOUBLE_TLV("Analogue Playback Volume", PCM512x_ANALOG_GAIN_CTRL, PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), SOC_DOUBLE_TLV("Analogue Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), -SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, - PCM512x_RQMR_SHIFT, 1, 1), +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Digital Playback Switch", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_ctl_boolean_stereo_info, + .get = pcm512x_digital_playback_switch_get, + .put = pcm512x_digital_playback_switch_put +}, SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), SOC_ENUM("DSP Program", pcm512x_dsp_program), @@ -1319,10 +1383,61 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_component *component = dai->component; + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + int ret; + unsigned int mute_det; + + mutex_lock(&pcm512x->mutex); + + if (mute) { + pcm512x->mute |= 0x1; + ret = regmap_update_bits(pcm512x->regmap, PCM512x_MUTE, + PCM512x_RQML | PCM512x_RQMR, + PCM512x_RQML | PCM512x_RQMR); + if (ret != 0) { + dev_err(component->dev, + "Failed to set digital mute: %d\n", ret); + mutex_unlock(&pcm512x->mutex); + return ret; + } + + regmap_read_poll_timeout(pcm512x->regmap, + PCM512x_ANALOG_MUTE_DET, + mute_det, (mute_det & 0x3) == 0, + 200, 10000); + + mutex_unlock(&pcm512x->mutex); + } else { + pcm512x->mute &= ~0x1; + ret = pcm512x_update_mute(pcm512x); + if (ret != 0) { + dev_err(component->dev, + "Failed to update digital mute: %d\n", ret); + mutex_unlock(&pcm512x->mutex); + return ret; + } + + regmap_read_poll_timeout(pcm512x->regmap, + PCM512x_ANALOG_MUTE_DET, + mute_det, + (mute_det & 0x3) + == ((~pcm512x->mute >> 1) & 0x3), + 200, 10000); + } + + mutex_unlock(&pcm512x->mutex); + + return 0; +} + static const struct snd_soc_dai_ops pcm512x_dai_ops = { .startup = pcm512x_dai_startup, .hw_params = pcm512x_hw_params, .set_fmt = pcm512x_set_fmt, + .digital_mute = pcm512x_digital_mute, }; static struct snd_soc_dai_driver pcm512x_dai = { @@ -1388,6 +1503,8 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap) if (!pcm512x) return -ENOMEM; + mutex_init(&pcm512x->mutex); + dev_set_drvdata(dev, pcm512x); pcm512x->regmap = regmap; diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h index d70d9c0c2088c5..9dda8693498ef6 100644 --- a/sound/soc/codecs/pcm512x.h +++ b/sound/soc/codecs/pcm512x.h @@ -112,7 +112,9 @@ #define PCM512x_RQST_SHIFT 4 /* Page 0, Register 3 - mute */ +#define PCM512x_RQMR (1 << 0) #define PCM512x_RQMR_SHIFT 0 +#define PCM512x_RQML (1 << 4) #define PCM512x_RQML_SHIFT 4 /* Page 0, Register 4 - PLL */ From 3f53d572c4237df3ccaf10864249a6e8307d50ff Mon Sep 17 00:00:00 2001 From: Rohit kumar Date: Thu, 1 Nov 2018 18:08:49 +0530 Subject: [PATCH 0545/1995] ASoC: core: Invoke pcm_new() for all DAI-link Remove no_pcm check to invoke pcm_new() for backend dai-links too. This fixes crash in hdmi codec driver during hdmi_codec_startup() while accessing chmap_info struct. chmap_info struct memory is allocated in pcm_new() of hdmi codec driver which is not invoked in case of DPCM when hdmi codec driver is part of backend dai-link. Below is the crash stack: [ 61.635493] Unable to handle kernel NULL pointer dereference at virtual address 00000018 .. [ 61.666696] CM = 0, WnR = 1 [ 61.669778] user pgtable: 4k pages, 39-bit VAs, pgd = ffffffc0d6633000 [ 61.676526] [0000000000000018] *pgd=0000000153fc8003, *pud=0000000153fc8003, *pmd=0000000000000000 [ 61.685793] Internal error: Oops: 96000046 [#1] PREEMPT SMP [ 61.722955] CPU: 7 PID: 2238 Comm: aplay Not tainted 4.14.72 #21 .. [ 61.740269] PC is at hdmi_codec_startup+0x124/0x164 [ 61.745308] LR is at hdmi_codec_startup+0xe4/0x164 Signed-off-by: Rohit kumar Signed-off-by: Mark Brown (cherry picked from commit de17f14ea576d8a0f2932404467fa916542da94d) --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b0db59e6339d97..0462b3ec977a22 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1467,7 +1467,7 @@ static int soc_link_dai_pcm_new(struct snd_soc_dai **dais, int num_dais, for (i = 0; i < num_dais; ++i) { struct snd_soc_dai_driver *drv = dais[i]->driver; - if (!rtd->dai_link->no_pcm && drv->pcm_new) + if (drv->pcm_new) ret = drv->pcm_new(rtd, dais[i]); if (ret < 0) { dev_err(dais[i]->dev, From 60eb5f3f2730e06cb26959af67f24461419d346d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 13 Dec 2018 13:03:00 -0600 Subject: [PATCH 0546/1995] ASoC: Intel: Skylake: Add more platform granularity The current SKYLAKE kconfig is a all-you-can-eat selection that will support all known plaforms. This is however not necessarily a good thing: most platforms for SKL and KBL don't support the DSP, but a number of CNL/WHL ones do. Selecting this driver in all cases isn't really smart and will require users to muck with blacklists. Partition the configs to allow distributions to select on which platform this driver is used. Keep the existing SND_SOC_INTEL_SKYLAKE config to select everything for backwards compatibility. This patch does not provide new functionality, only finer-grained choices in supported platforms. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 35bc99aaa1a3af23cf78b6b56f14230b5da3993b) --- sound/soc/intel/Kconfig | 73 ++++++++++++++++++++++++++++++---- sound/soc/intel/boards/Kconfig | 16 +++++++- sound/soc/intel/skylake/skl.c | 12 ++++++ 3 files changed, 92 insertions(+), 9 deletions(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 18e71770368550..99a62ba409df83 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -102,15 +102,74 @@ config SND_SST_ATOM_HIFI2_PLATFORM_ACPI recommended option config SND_SOC_INTEL_SKYLAKE - tristate "SKL/BXT/KBL/GLK/CNL... Platforms" + tristate "All Skylake/SST Platforms" depends on PCI && ACPI - select SND_SOC_INTEL_SKYLAKE_COMMON + select SND_SOC_INTEL_SKL + select SND_SOC_INTEL_APL + select SND_SOC_INTEL_KBL + select SND_SOC_INTEL_GLK + select SND_SOC_INTEL_CNL + select SND_SOC_INTEL_CFL help - If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/ - GeminiLake or CannonLake platform with the DSP enabled in the BIOS - then enable this option by saying Y or m. + This is a backwards-compatible option to select all devices + supported by the Intel SST/Skylake driver. This option is no + longer recommended and will be deprecated when the SOF + driver is introduced. Distributions should explicitly + select which platform uses this driver. + +config SND_SOC_INTEL_SKL + tristate "Skylake Platforms" + depends on PCI && ACPI + select SND_SOC_INTEL_SKYLAKE_FAMILY + help + If you have a Intel Skylake platform with the DSP enabled + in the BIOS then enable this option by saying Y or m. + +config SND_SOC_INTEL_APL + tristate "Broxton/ApolloLake Platforms" + depends on PCI && ACPI + select SND_SOC_INTEL_SKYLAKE_FAMILY + help + If you have a Intel Broxton/ApolloLake platform with the DSP + enabled in the BIOS then enable this option by saying Y or m. + +config SND_SOC_INTEL_KBL + tristate "Kabylake Platforms" + depends on PCI && ACPI + select SND_SOC_INTEL_SKYLAKE_FAMILY + help + If you have a Intel Kabylake platform with the DSP + enabled in the BIOS then enable this option by saying Y or m. + +config SND_SOC_INTEL_GLK + tristate "GeminiLake Platforms" + depends on PCI && ACPI + select SND_SOC_INTEL_SKYLAKE_FAMILY + help + If you have a Intel GeminiLake platform with the DSP + enabled in the BIOS then enable this option by saying Y or m. + +config SND_SOC_INTEL_CNL + tristate "CannonLake/WhiskyLake Platforms" + depends on PCI && ACPI + select SND_SOC_INTEL_SKYLAKE_FAMILY + help + If you have a Intel CNL/WHL platform with the DSP + enabled in the BIOS then enable this option by saying Y or m. + +config SND_SOC_INTEL_CFL + tristate "CoffeeLake Platforms" + depends on PCI && ACPI + select SND_SOC_INTEL_SKYLAKE_FAMILY + help + If you have a Intel CoffeeLake platform with the DSP + enabled in the BIOS then enable this option by saying Y or m. + +config SND_SOC_INTEL_SKYLAKE_FAMILY + tristate + select SND_SOC_INTEL_SKYLAKE_COMMON -if SND_SOC_INTEL_SKYLAKE +if SND_SOC_INTEL_SKYLAKE_FAMILY config SND_SOC_INTEL_SKYLAKE_SSP_CLK tristate @@ -135,7 +194,7 @@ config SND_SOC_INTEL_SKYLAKE_COMMON GeminiLake or CannonLake platform with the DSP enabled in the BIOS then enable this option by saying Y or m. -endif ## SND_SOC_INTEL_SKYLAKE +endif ## SND_SOC_INTEL_SKYLAKE_FAMILY config SND_SOC_ACPI_INTEL_MATCH tristate diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 3839d6205fcf42..0a7e40d0639572 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -172,7 +172,7 @@ config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH endif ## SND_SST_ATOM_HIFI2_PLATFORM -if SND_SOC_INTEL_SKYLAKE +if SND_SOC_INTEL_SKL config SND_SOC_INTEL_SKL_RT286_MACH tristate "SKL with RT286 I2S mode" @@ -212,6 +212,10 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +endif ## SND_SOC_INTEL_SKL + +if SND_SOC_INTEL_APL + config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH tristate "Broxton with DA7219 and MAX98357A in I2S Mode" depends on MFD_INTEL_LPSS && I2C && ACPI @@ -239,6 +243,10 @@ config SND_SOC_INTEL_BXT_RT298_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +endif ## SND_SOC_INTEL_APL + +if SND_SOC_INTEL_KBL + config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH tristate "KBL with RT5663 and MAX98927 in I2S Mode" depends on MFD_INTEL_LPSS && I2C && ACPI @@ -303,6 +311,10 @@ config SND_SOC_INTEL_KBL_RT5660_MACH create an alsa sound card for RT5660 I2S audio codec. Say Y if you have such a device. +endif ## SND_SOC_INTEL_KBL + +if SND_SOC_INTEL_GLK + config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH tristate "GLK with RT5682 and MAX98357A in I2S Mode" depends on MFD_INTEL_LPSS && I2C && ACPI @@ -317,7 +329,7 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH Say Y if you have such a device. If unsure select "N". -endif ## SND_SOC_INTEL_SKYLAKE +endif ## SND_SOC_INTEL_GLK if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 25996f586c7204..29d9b0eb83ea15 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -1124,24 +1124,36 @@ static void skl_remove(struct pci_dev *pci) /* PCI IDs */ static const struct pci_device_id skl_ids[] = { +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL) /* Sunrise Point-LP */ { PCI_DEVICE(0x8086, 0x9d70), .driver_data = (unsigned long)&snd_soc_acpi_intel_skl_machines}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) /* BXT-P */ { PCI_DEVICE(0x8086, 0x5a98), .driver_data = (unsigned long)&snd_soc_acpi_intel_bxt_machines}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) /* KBL */ { PCI_DEVICE(0x8086, 0x9D71), .driver_data = (unsigned long)&snd_soc_acpi_intel_kbl_machines}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK) /* GLK */ { PCI_DEVICE(0x8086, 0x3198), .driver_data = (unsigned long)&snd_soc_acpi_intel_glk_machines}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL) /* CNL */ { PCI_DEVICE(0x8086, 0x9dc8), .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CFL) /* CFL */ { PCI_DEVICE(0x8086, 0xa348), .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines}, +#endif { 0, } }; MODULE_DEVICE_TABLE(pci, skl_ids); From 7f05904f500e414771b3eaa96672ebcea2c20e42 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 15 Nov 2018 18:13:20 +0000 Subject: [PATCH 0547/1995] ALSA: soc-compress: add support to snd_compr_set_runtime_buffer() Existing compress offload code allocates data buffers using simple kmalloc, however there are situations where these buffers have to be mapped in smmu. So provide a way to set the runtime buffer by the driver itself, simillar to what we do with pcm. This patch adds support to set runtime dma buffer on compressed stream. Signed-off-by: Srinivas Kandagatla Acked-by: Vinod Koul Signed-off-by: Mark Brown (cherry picked from commit ba02eed9f300b6512181d526311d4e11aaa9714f) --- include/sound/compress_driver.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index ea8c93bbb0e054..0cdc3999ecfa84 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -23,6 +23,7 @@ struct snd_compr_ops; * struct snd_compr_runtime: runtime stream description * @state: stream state * @ops: pointer to DSP callbacks + * @dma_buffer_p: runtime dma buffer pointer * @buffer: pointer to kernel buffer, valid only when not in mmap mode or * DSP doesn't implement copy * @buffer_size: size of the above buffer @@ -37,6 +38,7 @@ struct snd_compr_ops; struct snd_compr_runtime { snd_pcm_state_t state; struct snd_compr_ops *ops; + struct snd_dma_buffer *dma_buffer_p; void *buffer; u64 buffer_size; u32 fragment_size; @@ -175,6 +177,23 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream) wake_up(&stream->runtime->sleep); } +/** + * snd_compr_set_runtime_buffer - Set the Compress runtime buffer + * @substream: compress substream to set + * @bufp: the buffer information, NULL to clear + * + * Copy the buffer information to runtime buffer when @bufp is non-NULL. + * Otherwise it clears the current buffer information. + */ +static inline void snd_compr_set_runtime_buffer( + struct snd_compr_stream *substream, + struct snd_dma_buffer *bufp) +{ + struct snd_compr_runtime *runtime = substream->runtime; + + runtime->dma_buffer_p = bufp; +} + int snd_compr_stop_error(struct snd_compr_stream *stream, snd_pcm_state_t state); From d5e66e8c878fd027a64b486e05aff6540458092b Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 15 Nov 2018 18:13:21 +0000 Subject: [PATCH 0548/1995] ALSA: compress: make use of runtime buffer for copy Default copy function uses kmalloc to allocate buffers, lets check if the runtime buffers are setup before making this allocations. This can be useful if the buffers are dma buffers. Signed-off-by: Srinivas Kandagatla Acked-by: Vinod Koul Signed-off-by: Mark Brown (cherry picked from commit d00f749b00f7802bf944688ad2971455f84fdacb) --- sound/core/compress_offload.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 26b5e245b0747d..a5b09e75e7874b 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -171,7 +171,8 @@ static int snd_compr_free(struct inode *inode, struct file *f) } data->stream.ops->free(&data->stream); - kfree(data->stream.runtime->buffer); + if (!data->stream.runtime->dma_buffer_p) + kfree(data->stream.runtime->buffer); kfree(data->stream.runtime); kfree(data); return 0; @@ -505,7 +506,7 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream, struct snd_compr_params *params) { unsigned int buffer_size; - void *buffer; + void *buffer = NULL; buffer_size = params->buffer.fragment_size * params->buffer.fragments; if (stream->ops->copy) { @@ -514,7 +515,18 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream, * the data from core */ } else { - buffer = kmalloc(buffer_size, GFP_KERNEL); + if (stream->runtime->dma_buffer_p) { + + if (buffer_size > stream->runtime->dma_buffer_p->bytes) + dev_err(&stream->device->dev, + "Not enough DMA buffer"); + else + buffer = stream->runtime->dma_buffer_p->area; + + } else { + buffer = kmalloc(buffer_size, GFP_KERNEL); + } + if (!buffer) return -ENOMEM; } From 365dc87bcbd1a2861b3543929c36e5a215ec4dfa Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 18 Dec 2018 16:24:54 +0800 Subject: [PATCH 0549/1995] ASoC: Intel: Haswell/Broadwell: fix setting for .dynamic field For some reason this field was set to zero when all other drivers use .dynamic = 1 for front-ends. This change was tested on Dell XPS13 and has no impact with the existing legacy driver. The SOF driver also works with this change which enables it to override the fixed topology. Signed-off-by: Rander Wang Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 906a9abc5de73c383af518f5a806f4be2993a0c7) --- sound/soc/intel/boards/broadwell.c | 2 +- sound/soc/intel/boards/haswell.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 68e6543e6cb026..99f2a0156ae88c 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -192,7 +192,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { .stream_name = "Loopback", .cpu_dai_name = "Loopback Pin", .platform_name = "haswell-pcm-audio", - .dynamic = 0, + .dynamic = 1, .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index eab1f439dd3f1a..a4022983a7ce00 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -146,7 +146,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = { .stream_name = "Loopback", .cpu_dai_name = "Loopback Pin", .platform_name = "haswell-pcm-audio", - .dynamic = 0, + .dynamic = 1, .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, From 054a35e676ee627644f399219bcba9370829fa0e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 21 Dec 2018 12:11:20 +0300 Subject: [PATCH 0550/1995] ASoC: pcm512x: Fix a double unlock in pcm512x_digital_mute() We accidentally call mutex_unlock(&pcm512x->mutex); twice in a row. I re-wrote the error handling to use "goto unlock;" instead of returning directly. Hopefully, it makes the code a little simpler. Fixes: 3500f1c589e9 ("ASoC: pcm512x: Implement the digital_mute interface") Signed-off-by: Dan Carpenter Reviwed-by: Dimitris Papavasiliou Signed-off-by: Mark Brown (cherry picked from commit 28b698b7342c7d5300cfe217cd77ff7d2a55e03d) --- sound/soc/codecs/pcm512x.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 6cb1653be80417..4cc24a5d5c3167 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1400,24 +1400,20 @@ static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute) if (ret != 0) { dev_err(component->dev, "Failed to set digital mute: %d\n", ret); - mutex_unlock(&pcm512x->mutex); - return ret; + goto unlock; } regmap_read_poll_timeout(pcm512x->regmap, PCM512x_ANALOG_MUTE_DET, mute_det, (mute_det & 0x3) == 0, 200, 10000); - - mutex_unlock(&pcm512x->mutex); } else { pcm512x->mute &= ~0x1; ret = pcm512x_update_mute(pcm512x); if (ret != 0) { dev_err(component->dev, "Failed to update digital mute: %d\n", ret); - mutex_unlock(&pcm512x->mutex); - return ret; + goto unlock; } regmap_read_poll_timeout(pcm512x->regmap, @@ -1428,9 +1424,10 @@ static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute) 200, 10000); } +unlock: mutex_unlock(&pcm512x->mutex); - return 0; + return ret; } static const struct snd_soc_dai_ops pcm512x_dai_ops = { From c1cfd3575028a6ddcffe3f5cddccce35156538f1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 21 Dec 2018 12:06:58 +0300 Subject: [PATCH 0551/1995] ALSA: compress: prevent potential divide by zero bugs The problem is seen in the q6asm_dai_compr_set_params() function: ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys, (prtd->pcm_size / prtd->periods), ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prtd->periods); In this code prtd->pcm_size is the buffer_size and prtd->periods comes from params->buffer.fragments. If we allow the number of fragments to be zero then it results in a divide by zero bug. One possible fix would be to use prtd->pcm_count directly instead of using the division to re-calculate it. But I decided that it doesn't really make sense to allow zero fragments. Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown (cherry picked from commit 678e2b44c8e3fec3afc7202f1996a4500a50be93) --- sound/core/compress_offload.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index a5b09e75e7874b..f7d2b373da0aae 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -541,7 +541,8 @@ static int snd_compress_check_input(struct snd_compr_params *params) { /* first let's check the buffer parameter's */ if (params->buffer.fragment_size == 0 || - params->buffer.fragments > INT_MAX / params->buffer.fragment_size) + params->buffer.fragments > INT_MAX / params->buffer.fragment_size || + params->buffer.fragments == 0) return -EINVAL; /* now codec parameters */ From b0370f6fa54fb03a0fdf8f0f1d0860bfc4d2c8f9 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Wed, 2 Jan 2019 18:10:35 +0000 Subject: [PATCH 0552/1995] ASoC: Intel: atom: Make PCI dependency explicit After 'commit 5d32a66541c4 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set")' dependencies on CONFIG_PCI that previously were satisfied implicitly through dependencies on CONFIG_ACPI have to be specified directly. This code relies on IOSF_MBI and IOSF_MBI depends on PCI. For this reason, add a direct dependency on CONFIG_PCI to the IOSF_MBI driver. Fixes: 5d32a66541c46 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set") Signed-off-by: Sinan Kaya Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit a3d9036078715385ba156373e6cbc1a0b1deb075) --- sound/soc/intel/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 99a62ba409df83..bd9fd2035c554b 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -91,7 +91,7 @@ config SND_SST_ATOM_HIFI2_PLATFORM_PCI config SND_SST_ATOM_HIFI2_PLATFORM_ACPI tristate "ACPI HiFi2 (Baytrail, Cherrytrail) Platforms" default ACPI - depends on X86 && ACPI + depends on X86 && ACPI && PCI select SND_SST_IPC_ACPI select SND_SST_ATOM_HIFI2_PLATFORM select SND_SOC_ACPI_INTEL_MATCH From e9408ab017d221cb9a89bd8b4e220efd0429aa53 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 2 Jan 2019 17:18:56 +0800 Subject: [PATCH 0553/1995] ASoC: rt5682: Fix recording no sound issue The ADC mixer setting needs to restore to default value after calibration. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown (cherry picked from commit 22c7d5e7bad1fb2d8b9c611acb55a389f5d848d8) --- sound/soc/codecs/rt5682.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 34cfaf8f6f3452..89c43b26c37908 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2512,6 +2512,7 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682) regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0000); regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x2000); regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x2005); + regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4); mutex_unlock(&rt5682->calibrate_mutex); From e5d9c9317fc8b219c021b3050941670a9ca6f816 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 18 Dec 2018 16:24:54 +0800 Subject: [PATCH 0554/1995] ASoC: Intel: Haswell/Broadwell: fix setting for .dynamic field For some reason this field was set to zero when all other drivers use .dynamic = 1 for front-ends. This change was tested on Dell XPS13 and has no impact with the existing legacy driver. The SOF driver also works with this change which enables it to override the fixed topology. Signed-off-by: Rander Wang Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 906a9abc5de73c383af518f5a806f4be2993a0c7) --- sound/soc/intel/boards/broadwell.c | 2 +- sound/soc/intel/boards/haswell.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 68e6543e6cb026..99f2a0156ae88c 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -192,7 +192,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { .stream_name = "Loopback", .cpu_dai_name = "Loopback Pin", .platform_name = "haswell-pcm-audio", - .dynamic = 0, + .dynamic = 1, .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index eab1f439dd3f1a..a4022983a7ce00 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -146,7 +146,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = { .stream_name = "Loopback", .cpu_dai_name = "Loopback Pin", .platform_name = "haswell-pcm-audio", - .dynamic = 0, + .dynamic = 1, .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, From 7662df90bf6fdfbfb19e4ae9d016b07322c0322d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 21 Dec 2018 12:11:20 +0300 Subject: [PATCH 0555/1995] ASoC: pcm512x: Fix a double unlock in pcm512x_digital_mute() We accidentally call mutex_unlock(&pcm512x->mutex); twice in a row. I re-wrote the error handling to use "goto unlock;" instead of returning directly. Hopefully, it makes the code a little simpler. Fixes: 3500f1c589e9 ("ASoC: pcm512x: Implement the digital_mute interface") Signed-off-by: Dan Carpenter Reviwed-by: Dimitris Papavasiliou Signed-off-by: Mark Brown (cherry picked from commit 28b698b7342c7d5300cfe217cd77ff7d2a55e03d) --- sound/soc/codecs/pcm512x.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 6cb1653be80417..4cc24a5d5c3167 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1400,24 +1400,20 @@ static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute) if (ret != 0) { dev_err(component->dev, "Failed to set digital mute: %d\n", ret); - mutex_unlock(&pcm512x->mutex); - return ret; + goto unlock; } regmap_read_poll_timeout(pcm512x->regmap, PCM512x_ANALOG_MUTE_DET, mute_det, (mute_det & 0x3) == 0, 200, 10000); - - mutex_unlock(&pcm512x->mutex); } else { pcm512x->mute &= ~0x1; ret = pcm512x_update_mute(pcm512x); if (ret != 0) { dev_err(component->dev, "Failed to update digital mute: %d\n", ret); - mutex_unlock(&pcm512x->mutex); - return ret; + goto unlock; } regmap_read_poll_timeout(pcm512x->regmap, @@ -1428,9 +1424,10 @@ static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute) 200, 10000); } +unlock: mutex_unlock(&pcm512x->mutex); - return 0; + return ret; } static const struct snd_soc_dai_ops pcm512x_dai_ops = { From 2bb275f6c21e3d8f050605037ad5502e4ce205a8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 21 Dec 2018 12:06:58 +0300 Subject: [PATCH 0556/1995] ALSA: compress: prevent potential divide by zero bugs The problem is seen in the q6asm_dai_compr_set_params() function: ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys, (prtd->pcm_size / prtd->periods), ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ prtd->periods); In this code prtd->pcm_size is the buffer_size and prtd->periods comes from params->buffer.fragments. If we allow the number of fragments to be zero then it results in a divide by zero bug. One possible fix would be to use prtd->pcm_count directly instead of using the division to re-calculate it. But I decided that it doesn't really make sense to allow zero fragments. Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown (cherry picked from commit 678e2b44c8e3fec3afc7202f1996a4500a50be93) --- sound/core/compress_offload.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index a5b09e75e7874b..f7d2b373da0aae 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -541,7 +541,8 @@ static int snd_compress_check_input(struct snd_compr_params *params) { /* first let's check the buffer parameter's */ if (params->buffer.fragment_size == 0 || - params->buffer.fragments > INT_MAX / params->buffer.fragment_size) + params->buffer.fragments > INT_MAX / params->buffer.fragment_size || + params->buffer.fragments == 0) return -EINVAL; /* now codec parameters */ From fd67aa4c22851bcfbac9ae2afbe6c44eb3eff182 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Wed, 2 Jan 2019 18:10:35 +0000 Subject: [PATCH 0557/1995] ASoC: Intel: atom: Make PCI dependency explicit After 'commit 5d32a66541c4 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set")' dependencies on CONFIG_PCI that previously were satisfied implicitly through dependencies on CONFIG_ACPI have to be specified directly. This code relies on IOSF_MBI and IOSF_MBI depends on PCI. For this reason, add a direct dependency on CONFIG_PCI to the IOSF_MBI driver. Fixes: 5d32a66541c46 ("PCI/ACPI: Allow ACPI to be built without CONFIG_PCI set") Signed-off-by: Sinan Kaya Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit a3d9036078715385ba156373e6cbc1a0b1deb075) --- sound/soc/intel/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 99a62ba409df83..bd9fd2035c554b 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -91,7 +91,7 @@ config SND_SST_ATOM_HIFI2_PLATFORM_PCI config SND_SST_ATOM_HIFI2_PLATFORM_ACPI tristate "ACPI HiFi2 (Baytrail, Cherrytrail) Platforms" default ACPI - depends on X86 && ACPI + depends on X86 && ACPI && PCI select SND_SST_IPC_ACPI select SND_SST_ATOM_HIFI2_PLATFORM select SND_SOC_ACPI_INTEL_MATCH From 0130da1a65bd1463e013d184f4d485d5d82e12ad Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 2 Jan 2019 17:18:56 +0800 Subject: [PATCH 0558/1995] ASoC: rt5682: Fix recording no sound issue The ADC mixer setting needs to restore to default value after calibration. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown (cherry picked from commit 22c7d5e7bad1fb2d8b9c611acb55a389f5d848d8) --- sound/soc/codecs/rt5682.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 34cfaf8f6f3452..89c43b26c37908 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2512,6 +2512,7 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682) regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0000); regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x2000); regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x2005); + regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4); mutex_unlock(&rt5682->calibrate_mutex); From 192760c775458b70c6971b452e63733d15c6c2d9 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 2 Nov 2018 16:18:21 +0100 Subject: [PATCH 0559/1995] ASoC: wm97xx: fix uninitialized regmap pointer problem gcc notices that without either the ac97 bus or the pdata, we never initialize the regmap pointer, which leads to an uninitialized variable access: sound/soc/codecs/wm9712.c: In function 'wm9712_soc_probe': sound/soc/codecs/wm9712.c:666:2: error: 'regmap' may be used uninitialized in this function [-Werror=maybe-uninitialized] Since that configuration is invalid, it's better to return an error here. I tried to avoid adding complexity to the conditions, and turned the #ifdef into a regular if(IS_ENABLED()) check for readability. This in turn requires moving some header file declarations out of an #ifdef. The same code is used in three drivers, all of which I'm changing the same way. Fixes: 2ed1a8e0ce8d ("ASoC: wm9712: add ac97 new bus support") Signed-off-by: Arnd Bergmann Signed-off-by: Mark Brown (cherry picked from commit 576ce4075bfa0f03e0e91a89eecc539b3b828b08) --- include/sound/soc.h | 2 +- sound/soc/codecs/wm9705.c | 10 ++++------ sound/soc/codecs/wm9712.c | 12 ++++++------ sound/soc/codecs/wm9713.c | 10 ++++------ 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 48fbaf7f3fe014..8ec1de856ee7e1 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -553,12 +553,12 @@ static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, } #endif -#ifdef CONFIG_SND_SOC_AC97_BUS struct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component); struct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component, unsigned int id, unsigned int id_mask); void snd_soc_free_ac97_component(struct snd_ac97 *ac97); +#ifdef CONFIG_SND_SOC_AC97_BUS int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops); int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops, struct platform_device *pdev); diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index ccdf088461b7f0..54c306707c02cc 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -325,8 +325,7 @@ static int wm9705_soc_probe(struct snd_soc_component *component) if (wm9705->mfd_pdata) { wm9705->ac97 = wm9705->mfd_pdata->ac97; regmap = wm9705->mfd_pdata->regmap; - } else { -#ifdef CONFIG_SND_SOC_AC97_BUS + } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) { wm9705->ac97 = snd_soc_new_ac97_component(component, WM9705_VENDOR_ID, WM9705_VENDOR_ID_MASK); if (IS_ERR(wm9705->ac97)) { @@ -339,7 +338,8 @@ static int wm9705_soc_probe(struct snd_soc_component *component) snd_soc_free_ac97_component(wm9705->ac97); return PTR_ERR(regmap); } -#endif + } else { + return -ENXIO; } snd_soc_component_set_drvdata(component, wm9705->ac97); @@ -350,14 +350,12 @@ static int wm9705_soc_probe(struct snd_soc_component *component) static void wm9705_soc_remove(struct snd_soc_component *component) { -#ifdef CONFIG_SND_SOC_AC97_BUS struct wm9705_priv *wm9705 = snd_soc_component_get_drvdata(component); - if (!wm9705->mfd_pdata) { + if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9705->mfd_pdata) { snd_soc_component_exit_regmap(component); snd_soc_free_ac97_component(wm9705->ac97); } -#endif } static const struct snd_soc_component_driver soc_component_dev_wm9705 = { diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index ade34c26ad2f33..b66b234ffc995c 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -643,8 +643,9 @@ static int wm9712_soc_probe(struct snd_soc_component *component) if (wm9712->mfd_pdata) { wm9712->ac97 = wm9712->mfd_pdata->ac97; regmap = wm9712->mfd_pdata->regmap; - } else { -#ifdef CONFIG_SND_SOC_AC97_BUS + } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) { + int ret; + wm9712->ac97 = snd_soc_new_ac97_component(component, WM9712_VENDOR_ID, WM9712_VENDOR_ID_MASK); if (IS_ERR(wm9712->ac97)) { @@ -659,7 +660,8 @@ static int wm9712_soc_probe(struct snd_soc_component *component) snd_soc_free_ac97_component(wm9712->ac97); return PTR_ERR(regmap); } -#endif + } else { + return -ENXIO; } snd_soc_component_init_regmap(component, regmap); @@ -672,14 +674,12 @@ static int wm9712_soc_probe(struct snd_soc_component *component) static void wm9712_soc_remove(struct snd_soc_component *component) { -#ifdef CONFIG_SND_SOC_AC97_BUS struct wm9712_priv *wm9712 = snd_soc_component_get_drvdata(component); - if (!wm9712->mfd_pdata) { + if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9712->mfd_pdata) { snd_soc_component_exit_regmap(component); snd_soc_free_ac97_component(wm9712->ac97); } -#endif } static const struct snd_soc_component_driver soc_component_dev_wm9712 = { diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 643863bb32e0d3..5a2fdf4f69bf3b 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -1214,8 +1214,7 @@ static int wm9713_soc_probe(struct snd_soc_component *component) if (wm9713->mfd_pdata) { wm9713->ac97 = wm9713->mfd_pdata->ac97; regmap = wm9713->mfd_pdata->regmap; - } else { -#ifdef CONFIG_SND_SOC_AC97_BUS + } else if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS)) { wm9713->ac97 = snd_soc_new_ac97_component(component, WM9713_VENDOR_ID, WM9713_VENDOR_ID_MASK); if (IS_ERR(wm9713->ac97)) @@ -1225,7 +1224,8 @@ static int wm9713_soc_probe(struct snd_soc_component *component) snd_soc_free_ac97_component(wm9713->ac97); return PTR_ERR(regmap); } -#endif + } else { + return -ENXIO; } snd_soc_component_init_regmap(component, regmap); @@ -1238,14 +1238,12 @@ static int wm9713_soc_probe(struct snd_soc_component *component) static void wm9713_soc_remove(struct snd_soc_component *component) { -#ifdef CONFIG_SND_SOC_AC97_BUS struct wm9713_priv *wm9713 = snd_soc_component_get_drvdata(component); - if (!wm9713->mfd_pdata) { + if (IS_ENABLED(CONFIG_SND_SOC_AC97_BUS) && !wm9713->mfd_pdata) { snd_soc_component_exit_regmap(component); snd_soc_free_ac97_component(wm9713->ac97); } -#endif } static const struct snd_soc_component_driver soc_component_dev_wm9713 = { From fa0c7f97fe4bdc8119d211c10c0a7e1bdab8c6bc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 21 Sep 2018 07:46:28 +0000 Subject: [PATCH 0560/1995] ASoC: tidyup for_each_card_prelinks() dai_link commit 7fe072b4df5d0 ("ASoC: add for_each_card_prelinks() macro") added new for_each_card_prelinks() macro, but it had typo. This patch fixup it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 0310820c2738e92003d9dd8cabee77ff958a16dc) --- sound/soc/mediatek/mt2701/mt2701-cs42448.c | 8 ++++---- sound/soc/mediatek/mt2701/mt2701-wm8960.c | 8 ++++---- sound/soc/mediatek/mt6797/mt6797-mt6351.c | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c index 875f8469153519..97f9f38ce6b39d 100644 --- a/sound/soc/mediatek/mt2701/mt2701-cs42448.c +++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c @@ -311,9 +311,9 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) return -EINVAL; } for_each_card_prelinks(card, i, dai_link) { - if (dai_links->platform_name) + if (dai_link->platform_name) continue; - dai_links->platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } card->dev = dev; @@ -326,9 +326,9 @@ static int mt2701_cs42448_machine_probe(struct platform_device *pdev) return -EINVAL; } for_each_card_prelinks(card, i, dai_link) { - if (dai_links->codec_name) + if (dai_link->codec_name) continue; - dai_links->codec_of_node = codec_node; + dai_link->codec_of_node = codec_node; } codec_node_bt_mrg = of_parse_phandle(pdev->dev.of_node, diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c index 9c7773f288a8c9..74a40dd212d1a3 100644 --- a/sound/soc/mediatek/mt2701/mt2701-wm8960.c +++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c @@ -107,9 +107,9 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) return -EINVAL; } for_each_card_prelinks(card, i, dai_link) { - if (dai_links->platform_name) + if (dai_link->platform_name) continue; - dai_links->platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } card->dev = &pdev->dev; @@ -122,9 +122,9 @@ static int mt2701_wm8960_machine_probe(struct platform_device *pdev) return -EINVAL; } for_each_card_prelinks(card, i, dai_link) { - if (dai_links->codec_name) + if (dai_link->codec_name) continue; - dai_links->codec_of_node = codec_node; + dai_link->codec_of_node = codec_node; } ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); diff --git a/sound/soc/mediatek/mt6797/mt6797-mt6351.c b/sound/soc/mediatek/mt6797/mt6797-mt6351.c index b569b452c54154..441ecd05e94408 100644 --- a/sound/soc/mediatek/mt6797/mt6797-mt6351.c +++ b/sound/soc/mediatek/mt6797/mt6797-mt6351.c @@ -172,7 +172,7 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) for_each_card_prelinks(card, i, dai_link) { if (dai_link->platform_name) continue; - dai_links->platform_of_node = platform_node; + dai_link->platform_of_node = platform_node; } codec_node = of_parse_phandle(pdev->dev.of_node, @@ -183,9 +183,9 @@ static int mt6797_mt6351_dev_probe(struct platform_device *pdev) return -EINVAL; } for_each_card_prelinks(card, i, dai_link) { - if (dai_links->codec_name) + if (dai_link->codec_name) continue; - dai_links->codec_of_node = codec_node; + dai_link->codec_of_node = codec_node; } ret = devm_snd_soc_register_card(&pdev->dev, card); From 09f97578d60b5e2254caf5d3079453812e2e220b Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 2 Jan 2019 13:51:15 +0800 Subject: [PATCH 0561/1995] ASoC: SOF: hda-dsp: add IPC interrupt enable/disable implementation Here implement IPC interrupt enable/disable for SKL+ platforms. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-dsp.c | 40 +++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 3 +++ 2 files changed, 43 insertions(+) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index b79e6a12b75b7a..8bb59cbf7f2067 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -244,6 +244,46 @@ int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, return ret; } +void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hda = + (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + + /* enable IPC DONE interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, + HDA_DSP_REG_HIPCCTL_DONE, + HDA_DSP_REG_HIPCCTL_DONE); + + /* enable IPC BUSY interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, + HDA_DSP_REG_HIPCCTL_BUSY, + HDA_DSP_REG_HIPCCTL_BUSY); + + /* enable IPC interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); +} + +void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hda = + (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + + /* disable IPC interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_IPC, 0); + + /* disable IPC BUSY interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, + HDA_DSP_REG_HIPCCTL_BUSY, 0); + + /* disable IPC DONE interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, + HDA_DSP_REG_HIPCCTL_DONE, 0); +} + static int hda_suspend(struct snd_sof_dev *sdev, int state) { struct sof_intel_hda_dev *hda = diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index e09b83d0bb7203..101d92b704cd48 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -408,6 +408,9 @@ bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, unsigned int core_mask); int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, unsigned int core_mask); +void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev); +void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev); + int hda_dsp_suspend(struct snd_sof_dev *sdev, int state); int hda_dsp_resume(struct snd_sof_dev *sdev); int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state); From f52bee9a40ea863bc34a907bad273e4d1a8603cb Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 2 Jan 2019 14:03:42 +0800 Subject: [PATCH 0562/1995] ASoC: SOF: hda-loader: switch to use hda_dsp_ipc_int_enable() As we have implemented hda_dsp_ipc_int_enable() for IPC interrupts enabling, here switch to use it in code loader FW init success. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-loader-skl.c | 18 ++---------------- sound/soc/sof/intel/hda-loader.c | 15 ++------------- 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index b58773cd5e15ee..d3d520ecd17a76 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -308,9 +308,6 @@ static void cl_cleanup_skl(struct snd_sof_dev *sdev) static int cl_dsp_init_skl(struct snd_sof_dev *sdev) { - struct sof_intel_hda_dev *hda = - (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; - const struct sof_intel_dsp_desc *chip = hda->desc; int ret; /* check if the core is already enabled, if yes, reset and make it run, @@ -353,19 +350,8 @@ static int cl_dsp_init_skl(struct snd_sof_dev *sdev) return ret; } - /* enable the interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, - HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); - - /* enable IPC DONE interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, - HDA_DSP_REG_HIPCCTL_DONE, - HDA_DSP_REG_HIPCCTL_DONE); - - /* enable IPC BUSY interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, - HDA_DSP_REG_HIPCCTL_BUSY, - HDA_DSP_REG_HIPCCTL_BUSY); + /* enable IPC interrupts */ + hda_dsp_ipc_int_enable(sdev); /* polling the ROM init status information. */ ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 236a8a1bb11839..0ed669d93fcb3d 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -146,19 +146,8 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, goto err; } - /* step 6: enable interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, - HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); - - /* enable IPC DONE interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, - HDA_DSP_REG_HIPCCTL_DONE, - HDA_DSP_REG_HIPCCTL_DONE); - - /* enable IPC BUSY interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, - HDA_DSP_REG_HIPCCTL_BUSY, - HDA_DSP_REG_HIPCCTL_BUSY); + /* step 6: enable IPC interrupts */ + hda_dsp_ipc_int_enable(sdev); /* step 7: wait for ROM init */ ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, From a6162cc212075933505fafebc80c4724ff9c1b7b Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Thu, 3 Jan 2019 13:15:55 +0800 Subject: [PATCH 0563/1995] ASoC: SOF: hda-dsp: disable IPC interrupt at suspend We need disable IPC interrupt at suspend, then for next resume, the purge FW IPC won't be handled by interrupt handler wrongly and lead to error like "error: waiting for HIPCIE done, reg:xxx". Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-dsp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 8bb59cbf7f2067..8673e38666f830 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -294,6 +294,9 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state) #endif int ret = 0; + /* disable IPC interrupts */ + hda_dsp_ipc_int_disable(sdev); + #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* power down all hda link */ snd_hdac_ext_bus_link_power_down_all(bus); From 9f577982e9f421ac07d6dcd243e006dd8408388f Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 4 Jan 2019 10:03:31 +0800 Subject: [PATCH 0564/1995] ASoC: SOF: optimize dsp register polling Optimize DSP register polling to poll in phases starting with finer sleep value and moving on to larger sleep values(tips from what we do in sst driver). This is helpful to reduce the extra waiting time (e.g. from 20ms to 1ms) after hw status/registers updated. Signed-off-by: Ranjani Sridharan Signed-off-by: Keyon Jie --- sound/soc/sof/ops.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index 387baeb6b9ed2d..8b92cf59031e83 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -142,37 +142,40 @@ void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar, EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced); int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset, - u32 mask, u32 target, u32 timeout) + u32 mask, u32 target, u32 timeout_ms) { - int time, ret; + u32 reg; + unsigned long tout_jiff; + int k = 0, s = 500; /* - * we will poll for couple of ms using mdelay, if not successful - * then go to longer sleep using usleep_range + * Split the loop into 2 sleep stages with varying resolution. + * To do it more accurately, the range of wakeups are: + * Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms. + * Phase 2(beyond 5ms): min sleep 5ms; max sleep 10ms. */ - /* check if set state successful */ - for (time = 5; time > 0; time--) { - if ((snd_sof_dsp_read(sdev, bar, offset) & mask) == target) + tout_jiff = jiffies + msecs_to_jiffies(timeout_ms); + do { + reg = snd_sof_dsp_read(sdev, bar, offset); + if ((reg & mask) == target) break; - msleep(20); - } - if (!time) { - /* sleeping in 10ms steps so adjust timeout value */ - timeout /= 10; + /* Phase 2 after 5ms(500us * 10) */ + if (++k > 10) + s = 5000; - for (time = timeout; time > 0; time--) { - if ((snd_sof_dsp_read(sdev, bar, offset) & mask) == target) - break; + usleep_range(s, 2 * s); + } while (time_before(jiffies, tout_jiff)); - usleep_range(5000, 10000); - } - } + if ((reg & mask) == target) { + dev_dbg(sdev->dev, "FW Poll Status: reg=%#x successful\n", reg); - ret = time ? 0 : -ETIME; + return 0; + } - return ret; + dev_dbg(sdev->dev, "FW Poll Status: reg=%#x timedout\n", reg); + return -ETIME; } EXPORT_SYMBOL(snd_sof_dsp_register_poll); From e3e4d0f3b0f8f1d1016fb776ad762a5fa63b405f Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 4 Jan 2019 10:30:34 +0800 Subject: [PATCH 0565/1995] ASoC: SOF: hda-loader: reduce timeout for ROM init and refine FW load retries There is a possibility of CSE auth failing during stress tests due to a race condition between when the audio driver requests fw authentication and then the CSE is ready. Reduce the timeout to check for ROM init and retry this step a few times to improve the chances of FW download being successful. For the retrying, we only need retry cl_dsp_init() which with race condition existed described above, here moves cl_stream_prepare() and cl_copy_fw() out of the retry loop. Here we change to do cleanup(put stream, free DMA buffer, ...) at xx_cl_boot_firmware() done, no matter it fail or success there, this will fix the stream 'leak' issue at boot_firmware() fail during suspend/resume test. Signed-off-by: Ranjani Sridharan Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-loader.c | 154 +++++++++++++++++-------------- sound/soc/sof/intel/hda.h | 1 + 2 files changed, 87 insertions(+), 68 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 0ed669d93fcb3d..fcf61e5fd7ef30 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -78,25 +78,12 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, * reset/stall and then turn it off */ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, - u32 fwsize) + u32 fwsize, int stream_tag) { - int tag, ret, i; - u32 hipcie; - struct sof_intel_hda_dev *hda = - (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; - - /* prepare DMA for code loader stream */ - tag = cl_stream_prepare(sdev, 0x40, fwsize, &sdev->dmab, - SNDRV_PCM_STREAM_PLAYBACK); - - if (tag <= 0) { - dev_err(sdev->dev, "error: dma prepare for fw loading err: %x\n", - tag); - return tag; - } - - memcpy(sdev->dmab.area, fwdata, fwsize); + int ret, i; + u32 hipcie; /* step 1: power up corex */ ret = hda_dsp_core_power_up(sdev, chip->cores_mask); @@ -108,7 +95,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, /* step 2: purge FW request */ snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, chip->ipc_req_mask | (HDA_DSP_IPC_PURGE_FW | - ((tag - 1) << 9))); + ((stream_tag - 1) << 9))); /* step 3: unset core 0 reset state & unstall/run core 0 */ ret = hda_dsp_core_run(sdev, HDA_DSP_CORE_MASK(0)); @@ -153,20 +140,15 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_ROM_STATUS, HDA_DSP_ROM_STS_MASK, HDA_DSP_ROM_INIT, - HDA_DSP_INIT_TIMEOUT); - if (ret >= 0) - goto out; - - ret = -EIO; + HDA_ROM_INIT_TIMEOUT); + if (!ret) + return 0; err: hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); - hda_dsp_core_reset_power_down(sdev, HDA_DSP_CORE_MASK(0) | - HDA_DSP_CORE_MASK(1)); - return ret; + hda_dsp_core_reset_power_down(sdev, chip->cores_mask); -out: - return tag; + return ret; } static int cl_trigger(struct snd_sof_dev *sdev, @@ -208,8 +190,8 @@ static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, ret = hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); - /* TODO: spin lock ?*/ - hstream->opened = 0; + hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_PLAYBACK, + hstream->stream_tag); hstream->running = 0; hstream->substream = NULL; @@ -269,12 +251,6 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, int tag) return ret; } - ret = cl_cleanup(sdev, &sdev->dmab, stream); - if (ret < 0) { - dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); - return ret; - } - return status; } @@ -294,7 +270,10 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) { struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev); struct firmware stripped_firmware; - int ret, tag, i; + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_stream *stream = NULL; + struct hdac_stream *s; + int ret, ret1, tag, i; stripped_firmware.data = plat_data->fw->data; stripped_firmware.size = plat_data->fw->size; @@ -303,44 +282,83 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) init_waitqueue_head(&sdev->boot_wait); sdev->boot_complete = false; - /* try attempting fw boot a few times before giving up */ + /* prepare DMA for code loader stream */ + tag = cl_stream_prepare(sdev, 0x40, stripped_firmware.size, + &sdev->dmab, SNDRV_PCM_STREAM_PLAYBACK); + + if (tag < 0) { + dev_err(sdev->dev, "error: dma prepare for fw loading err: %x\n", + tag); + return tag; + } + + memcpy(sdev->dmab.area, stripped_firmware.data, + stripped_firmware.size); + + /* try ROM init a few times before giving up */ for (i = 0; i < HDA_FW_BOOT_ATTEMPTS; i++) { - tag = cl_dsp_init(sdev, stripped_firmware.data, - stripped_firmware.size); - - if (tag <= 0) { - dev_err(sdev->dev, "error: Error code=0x%x: FW status=0x%x\n", - snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_DSP_SRAM_REG_ROM_ERROR), - snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_DSP_SRAM_REG_ROM_STATUS)); - dev_err(sdev->dev, "error: iteration %d of Core En/ROM load fail:%d\n", - i, tag); - ret = tag; - continue; - } + ret = cl_dsp_init(sdev, stripped_firmware.data, + stripped_firmware.size, tag); - /* at this point DSP ROM has been initialized and - * should be ready for code loading and firmware boot - */ - ret = cl_copy_fw(sdev, tag); - if (ret < 0) { - dev_err(sdev->dev, "error: iteration %d of load fw failed err: %d\n", - i, ret); - continue; - } + /* don't retry anymore if successful */ + if (!ret) + break; + + dev_err(sdev->dev, "error: Error code=0x%x: FW status=0x%x\n", + snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_ERROR), + snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_STATUS)); + dev_err(sdev->dev, "error: iteration %d of Core En/ROM load failed: %d\n", + i, ret); + } + + if (i == HDA_FW_BOOT_ATTEMPTS) { + dev_err(sdev->dev, "error: dsp init failed after %d attempts with err: %d\n", + i, ret); + hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); + + /* disable DSP */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, + SOF_HDA_REG_PP_PPCTL, + SOF_HDA_PPCTL_GPROCEN, 0); + goto done; + } + + /* at this point DSP ROM has been initialized and + * should be ready for code loading and firmware boot + */ + ret = cl_copy_fw(sdev, tag); + if (ret < 0) + dev_err(sdev->dev, "error: load fw failed ret: %d\n", ret); + else dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); - return ret; + +done: + /* get stream with tag for code loader stream cleanup */ + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == SNDRV_PCM_STREAM_PLAYBACK && + s->stream_tag == tag) { + stream = stream_to_hdac_ext_stream(s); + break; + } } - hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); + if (!stream) { + dev_err(sdev->dev, + "error: could not get stream with stream tag%d\n", + tag); + return -ENODEV; + } + + /* cleanup code loader stream */ + ret1 = cl_cleanup(sdev, &sdev->dmab, stream); + if (ret1 < 0) { + dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); + return ret1; + } - /* disable DSP */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, - SOF_HDA_PPCTL_GPROCEN, 0); - dev_err(sdev->dev, "error: load fw failed after %d attempts with err: %d\n", - HDA_FW_BOOT_ATTEMPTS, ret); return ret; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 101d92b704cd48..105b720d5069bd 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -198,6 +198,7 @@ #define HDA_DSP_RESET_TIMEOUT 50 #define HDA_DSP_BASEFW_TIMEOUT 3000 #define HDA_DSP_INIT_TIMEOUT 500 +#define HDA_ROM_INIT_TIMEOUT 70 #define HDA_DSP_CTRL_RESET_TIMEOUT 100 #define HDA_DSP_WAIT_TIMEOUT 500 /* 500 msec */ From 7ea949364429d4c7351d26bf53097d1c83abbf5c Mon Sep 17 00:00:00 2001 From: Xun Zhang Date: Wed, 9 Jan 2019 16:57:26 +0800 Subject: [PATCH 0566/1995] ASoC: SOF: Intel: remove kconfig related if statements All SOF-dependent statement are removed, virtual widgets shall be added in SOF topology in order to avoid missing of some codec widgets. Signed-off-by: Xun Zhang --- sound/soc/intel/boards/bytcht_da7213.c | 2 -- sound/soc/intel/boards/bytcr_rt5640.c | 2 -- sound/soc/intel/boards/bytcr_rt5651.c | 6 ------ sound/soc/intel/boards/cht_bsw_max98090_ti.c | 2 -- sound/soc/intel/boards/cht_bsw_rt5645.c | 8 -------- sound/soc/intel/boards/cht_bsw_rt5672.c | 2 -- sound/soc/sof/intel/Kconfig | 2 +- 7 files changed, 1 insertion(+), 23 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index 1e90a9c4b1e892..2179dedb28ad6d 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -56,7 +56,6 @@ static const struct snd_soc_dapm_route audio_map[] = { {"MIC1", NULL, "Headset Mic"}, {"MIC2", NULL, "Mic"}, -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) /* SOC-codec link */ {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, @@ -65,7 +64,6 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Playback", NULL, "ssp2 Tx"}, {"ssp2 Rx", NULL, "Capture"}, -#endif }; static int codec_fixup(struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index ff10a8b848c9bf..a22366ce33c403 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -845,7 +845,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) if (ret) return ret; -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) { ret = snd_soc_dapm_add_routes(&card->dapm, byt_rt5640_ssp2_aif2_map, @@ -865,7 +864,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) } if (ret) return ret; -#endif if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) { ret = snd_soc_dapm_add_routes(&card->dapm, diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 7a2c5ad020fef8..e528995668b78e 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -305,7 +305,6 @@ static const struct snd_soc_dapm_route byt_rt5651_ssp0_aif2_map[] = { }; static const struct snd_soc_dapm_route byt_rt5651_ssp2_aif1_map[] = { -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, {"codec_in0", NULL, "ssp2 Rx"}, @@ -313,7 +312,6 @@ static const struct snd_soc_dapm_route byt_rt5651_ssp2_aif1_map[] = { {"AIF1 Playback", NULL, "ssp2 Tx"}, {"ssp2 Rx", NULL, "AIF1 Capture"}, -#endif }; static const struct snd_soc_dapm_route byt_rt5651_ssp2_aif2_map[] = { @@ -878,9 +876,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) struct device *codec_dev; const char *i2c_name = NULL; const char *hp_swapped; -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) bool is_bytcr = false; -#endif int ret_val = 0; int dai_index = 0; int i; @@ -918,7 +914,6 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) if (!codec_dev) return -EPROBE_DEFER; -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) /* * swap SSP0 if bytcr is detected * (will be overridden if DMI quirk is detected) @@ -974,7 +969,6 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) byt_rt5651_quirk |= BYT_RT5651_SSP0_AIF2; } } -#endif /* check quirks before creating card */ dmi_check_system(byt_rt5651_quirk_table); diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index e74b9cc1ce8f07..08a5152e635ac8 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -91,14 +91,12 @@ static const struct snd_soc_dapm_route cht_audio_map[] = { {"Headphone", NULL, "HPR"}, {"Ext Spk", NULL, "SPKL"}, {"Ext Spk", NULL, "SPKR"}, -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) {"HiFi Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, {"codec_in0", NULL, "ssp2 Rx" }, {"codec_in1", NULL, "ssp2 Rx" }, {"ssp2 Rx", NULL, "HiFi Capture"}, -#endif {"Headphone", NULL, "Platform Clock"}, {"Headset Mic", NULL, "Platform Clock"}, {"Int Mic", NULL, "Platform Clock"}, diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index be693d02a20fe8..250a356a0cbf08 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -159,43 +159,35 @@ static const struct snd_soc_dapm_route cht_rt5650_audio_map[] = { }; static const struct snd_soc_dapm_route cht_rt5645_ssp2_aif1_map[] = { -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) {"AIF1 Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, {"codec_in0", NULL, "ssp2 Rx" }, {"codec_in1", NULL, "ssp2 Rx" }, {"ssp2 Rx", NULL, "AIF1 Capture"}, -#endif }; static const struct snd_soc_dapm_route cht_rt5645_ssp2_aif2_map[] = { -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) {"AIF2 Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, {"codec_in0", NULL, "ssp2 Rx" }, {"codec_in1", NULL, "ssp2 Rx" }, {"ssp2 Rx", NULL, "AIF2 Capture"}, -#endif }; static const struct snd_soc_dapm_route cht_rt5645_ssp0_aif1_map[] = { -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) {"AIF1 Playback", NULL, "ssp0 Tx"}, {"ssp0 Tx", NULL, "modem_out"}, {"modem_in", NULL, "ssp0 Rx" }, {"ssp0 Rx", NULL, "AIF1 Capture"}, -#endif }; static const struct snd_soc_dapm_route cht_rt5645_ssp0_aif2_map[] = { -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) {"AIF2 Playback", NULL, "ssp0 Tx"}, {"ssp0 Tx", NULL, "modem_out"}, {"modem_in", NULL, "ssp0 Rx" }, {"ssp0 Rx", NULL, "AIF2 Capture"}, -#endif }; static const struct snd_kcontrol_new cht_mc_controls[] = { diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 7d737c99d78140..9de64f447e7bed 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -128,14 +128,12 @@ static const struct snd_soc_dapm_route cht_audio_map[] = { {"Ext Spk", NULL, "SPOLN"}, {"Ext Spk", NULL, "SPORP"}, {"Ext Spk", NULL, "SPORN"}, -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL) {"AIF1 Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, {"codec_in0", NULL, "ssp2 Rx"}, {"codec_in1", NULL, "ssp2 Rx"}, {"ssp2 Rx", NULL, "AIF1 Capture"}, -#endif {"Headphone", NULL, "Platform Clock"}, {"Headset Mic", NULL, "Platform Clock"}, {"Int Mic", NULL, "Platform Clock"}, diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 6670fc3a43c2cc..a5b8b47b9deb2e 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -249,4 +249,4 @@ config SND_SOC_SOF_HDA endif ## SND_SOC_SOF_INTEL_PCI -endif ## SND_SOC_SOF_INTEL +endif ## SND_SOC_SOF_INTEL_TOPLEVEL From ed02b4f30aa7572feafea07df8941b007e0e07e8 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 9 Jan 2019 13:33:39 -0800 Subject: [PATCH 0567/1995] ASoC: SOF: add function name to the error messages There are 4 functions which could result in the same error message "failed to find dai". Add the function name in the error message so it is easy to tell which one failed. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/topology.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 79bf2b255c9bc9..1ce3d63e5f51b0 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2155,7 +2155,8 @@ static int sof_link_hda_process(struct snd_sof_dev *sdev, } if (!found) { - dev_err(sdev->dev, "error: failed to find dai %s", link->name); + dev_err(sdev->dev, "error: failed to find dai %s in %s", + link->name, __func__); return -EINVAL; } @@ -2205,8 +2206,8 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index, dai_component.dai_name = link->cpu_dai_name; dai = snd_soc_find_dai(&dai_component); if (!dai) { - dev_err(sdev->dev, "error: failed to find dai %s", - dai_component.dai_name); + dev_err(sdev->dev, "error: failed to find dai %s in %s", + dai_component.dai_name, __func__); return -EINVAL; } @@ -2348,8 +2349,8 @@ static int sof_link_hda_unload(struct snd_sof_dev *sdev, dai_component.dai_name = link->cpu_dai_name; dai = snd_soc_find_dai(&dai_component); if (!dai) { - dev_err(sdev->dev, "error: failed to find dai %s", - dai_component.dai_name); + dev_err(sdev->dev, "error: failed to find dai %s in %s", + dai_component.dai_name, __func__); return -EINVAL; } @@ -2385,7 +2386,8 @@ static int sof_link_unload(struct snd_soc_component *scomp, goto found; } - dev_err(sdev->dev, "error: failed to find dai %s", link->name); + dev_err(sdev->dev, "error: failed to find dai %s in %s", + link->name, __func__); return -EINVAL; found: From 9429ffcb9bd0e4ed1998f911dda00e97f402c636 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Thu, 10 Jan 2019 14:14:38 +0800 Subject: [PATCH 0568/1995] [DEBUG][CI]travis: update gcc version Old gcc could not work with Linux4.20 Signed-off-by: Pan Xiuli --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 727dc28a5b3f6d..3ad3d6b9a18ddc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,10 @@ git: depth: false before_install: + - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test - sudo apt-get update -qq - - sudo apt-get install -y python-ply python-git libelf-dev codespell sparse fakeroot + - sudo apt-get install -y python-ply python-git libelf-dev codespell sparse fakeroot gcc-7 g++-7 + - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 70 --slave /usr/bin/g++ g++ /usr/bin/g++-7 - git clone https://github.com/thesofproject/kconfig.git jobs: From bbaf2552f009a340929499f46424f226d4733d7b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 17 Dec 2018 12:58:05 -0800 Subject: [PATCH 0569/1995] ASoC: SOF: move SOF page table buffer alloc/free to dai load/unload Previously, the dai_load callback routine allocated the SOF pcm object (spcm) and the page table buffer associated with spcm was allocated in the pcm_new() callback. This causes an imbalance between when the memory is allocated for spcm and when it can be freed. The page table buffer is associated with spcm. So, this patch proposes to move the page table buffer allocation to the dai_load callback routine and the page table buffer freeing to the dai_unload callback thereby making them symmetrical. Also, the pcm_free() callback is no longer needed as the the pre-allocated audio buffer pages will be freed by the core. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pcm.c | 74 +++++----------------------------------- sound/soc/sof/topology.c | 53 +++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 67 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index e6fae94e4e84dc..be76b4e924083b 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -470,6 +470,11 @@ static struct snd_pcm_ops sof_pcm_ops = { .page = snd_pcm_sgbuf_ops_page, }; +/* + * Pre-allocate playback/capture audio buffer pages. + * no need to explicitly release memory preallocated by sof_pcm_new in pcm_free + * snd_pcm_lib_preallocate_free_for_all() is called by the core. + */ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component = @@ -492,7 +497,7 @@ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) dev_dbg(sdev->dev, "creating new PCM %s\n", spcm->pcm.pcm_name); - /* do we need to allocate playback PCM DMA pages */ + /* do we need to pre-allocate playback audio buffer pages */ if (!spcm->pcm.playback) goto capture; @@ -513,19 +518,10 @@ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) return ret; } - /* allocate playback page table buffer */ - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->parent, - PAGE_SIZE, &spcm->stream[stream].page_table); - if (ret < 0) { - dev_err(sdev->dev, "error: can't alloc page table for %s %d\n", - caps->name, ret); - goto free_playback_dma_buffer; - } - capture: stream = SNDRV_PCM_STREAM_CAPTURE; - /* do we need to allocate capture PCM DMA pages */ + /* do we need to pre-allocate capture audio buffer pages */ if (!spcm->pcm.capture) return ret; @@ -539,67 +535,14 @@ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) SNDRV_DMA_TYPE_DEV_SG, sdev->parent, le32_to_cpu(caps->buffer_size_min), le32_to_cpu(caps->buffer_size_max)); - if (ret) { + if (ret) dev_err(sdev->dev, "error: can't alloc DMA buffer size 0x%x/0x%x for %s %d\n", caps->buffer_size_min, caps->buffer_size_max, caps->name, ret); - goto free_playback_tables; - } - - /* allocate capture page table buffer */ - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->parent, - PAGE_SIZE, &spcm->stream[stream].page_table); - if (ret < 0) { - dev_err(sdev->dev, "error: can't alloc page table for %s %d\n", - caps->name, ret); - goto free_playback_tables; - } - - /* TODO: assign channel maps from topology */ - - return ret; - -free_playback_tables: - if (spcm->pcm.playback) - snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].page_table); - -free_playback_dma_buffer: - /* - * no need to explicitly release preallocated memory, - * snd_pcm_lib_preallocate_free_for_all() is called by the core - */ return ret; } -static void sof_pcm_free(struct snd_pcm *pcm) -{ - struct snd_sof_pcm *spcm; - struct snd_soc_pcm_runtime *rtd = pcm->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(component); - - spcm = snd_sof_find_spcm_dai(sdev, rtd); - if (!spcm) { - dev_warn(sdev->dev, "warn: can't find PCM with DAI ID %d\n", - rtd->dai_link->id); - return; - } - - if (spcm->pcm.playback) - snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].page_table); - - if (spcm->pcm.capture) - snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_CAPTURE].page_table); - - /* - * no need to explicitly release preallocated memory, - * snd_pcm_lib_preallocate_free_for_all() is called by the core - */ -} - /* fixup the BE DAI link to match any values from topology */ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) @@ -752,7 +695,6 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) pd->compr_ops = &sof_compressed_ops; #endif pd->pcm_new = sof_pcm_new; - pd->pcm_free = sof_pcm_free; pd->ignore_machine = drv_name; pd->be_hw_params_fixup = sof_pcm_dai_link_fixup; pd->be_pcm_base = SOF_BE_PCM_BASE; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 1ce3d63e5f51b0..06a305791bbf63 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1850,7 +1850,10 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_stream_caps *caps; struct snd_sof_pcm *spcm; + int stream = SNDRV_PCM_STREAM_PLAYBACK; + int ret = 0; /* don't need to do anything for BEs atm */ if (!pcm) @@ -1871,7 +1874,47 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, mutex_init(&spcm->mutex); list_add(&spcm->list, &sdev->pcm_list); - return 0; + /* do we need to allocate playback PCM DMA pages */ + if (!spcm->pcm.playback) + goto capture; + + caps = &spcm->pcm.caps[stream]; + + /* allocate playback page table buffer */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->parent, + PAGE_SIZE, &spcm->stream[stream].page_table); + if (ret < 0) { + dev_err(sdev->dev, "error: can't alloc page table for %s %d\n", + caps->name, ret); + + return ret; + } + +capture: + stream = SNDRV_PCM_STREAM_CAPTURE; + + /* do we need to allocate capture PCM DMA pages */ + if (!spcm->pcm.capture) + return ret; + + caps = &spcm->pcm.caps[stream]; + + /* allocate capture page table buffer */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->parent, + PAGE_SIZE, &spcm->stream[stream].page_table); + if (ret < 0) { + dev_err(sdev->dev, "error: can't alloc page table for %s %d\n", + caps->name, ret); + goto free_playback_tables; + } + + return ret; + +free_playback_tables: + if (spcm->pcm.playback) + snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].page_table); + + return ret; } static int sof_dai_unload(struct snd_soc_component *scomp, @@ -1879,6 +1922,14 @@ static int sof_dai_unload(struct snd_soc_component *scomp, { struct snd_sof_pcm *spcm = dobj->private; + /* free PCM DMA pages */ + if (spcm->pcm.playback) + snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].page_table); + + if (spcm->pcm.capture) + snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_CAPTURE].page_table); + + /* remove from list and free spcm */ list_del(&spcm->list); kfree(spcm); From 94ff470fb416fd4193baad2ac120a5a78f3f3540 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 7 Jan 2019 14:30:30 -0800 Subject: [PATCH 0570/1995] ASoC: topology: add SND_SOC_DOBJ_GRAPH type for dapm routes Add a new dobj type SND_SOC_DOBJ_GRAPH for dapm routes and add snd_soc_dobj member to struct snd_soc_dapm_route. This enables device drivers to save driver specific data pertaining to dapm routes and also be able to clean up the data when the driver module is unloaded. Also, reorder the snd_soc_dobj_type types to align with matching topology header types. Signed-off-by: Ranjani Sridharan --- include/sound/soc-dapm.h | 2 ++ include/sound/soc-topology.h | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index bd8163f151cb85..46f2ba3ffcb7c1 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -540,6 +540,8 @@ struct snd_soc_dapm_route { /* Note: currently only supported for links where source is a supply */ int (*connected)(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink); + + struct snd_soc_dobj dobj; }; /* dapm audio path between two widgets */ diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index fa4b8413d2e222..8c43cfc240fa33 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -38,12 +38,13 @@ struct snd_soc_dapm_route; enum snd_soc_dobj_type { SND_SOC_DOBJ_NONE = 0, /* object is not dynamic */ SND_SOC_DOBJ_MIXER, - SND_SOC_DOBJ_ENUM, SND_SOC_DOBJ_BYTES, - SND_SOC_DOBJ_PCM, + SND_SOC_DOBJ_ENUM, + SND_SOC_DOBJ_GRAPH, + SND_SOC_DOBJ_WIDGET, SND_SOC_DOBJ_DAI_LINK, + SND_SOC_DOBJ_PCM, SND_SOC_DOBJ_CODEC_LINK, - SND_SOC_DOBJ_WIDGET, }; /* dynamic control object */ From 6c7cd29042f8e0dd3b7256073bd04d278d4633c4 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 7 Jan 2019 14:36:51 -0800 Subject: [PATCH 0571/1995] ASoC: topology: modify dapm route loading routine and add dapm route unloading struct snd_soc_dapm_route has been modified to be a dynamic object so that it can be used to save driver specific data while parsing topology and clean up driver-specific data during driver unloading. This patch makes the following changes to accomplish the above: 1. Set the dobj member of snd_soc_dapm_route during the SOC_TPLG_PASS_GRAPH pass of topology parsing. 2. Add the remove_route() routine that will be called while removing all dynamic objects from the component driver. Signed-off-by: Ranjani Sridharan --- sound/soc/soc-topology.c | 102 +++++++++++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 16 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index bc09fec712c4db..b98913249dbe8b 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -432,6 +432,23 @@ static void remove_bytes(struct snd_soc_component *comp, kfree(sb); } +/* remove a route */ +static void remove_route(struct snd_soc_component *comp, + struct snd_soc_dobj *dobj, int pass) +{ + struct snd_soc_dapm_route *route = + container_of(dobj, struct snd_soc_dapm_route, dobj); + + if (pass != SOC_TPLG_PASS_GRAPH) + return; + + if (dobj->ops && dobj->ops->dapm_route_unload) + dobj->ops->dapm_route_unload(comp, dobj); + + list_del(&dobj->list); + kfree(route); +} + /* remove a widget and it's kcontrols - routes must be removed first */ static void remove_widget(struct snd_soc_component *comp, struct snd_soc_dobj *dobj, int pass) @@ -1121,9 +1138,10 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, struct snd_soc_tplg_hdr *hdr) { struct snd_soc_dapm_context *dapm = &tplg->comp->dapm; - struct snd_soc_dapm_route route; struct snd_soc_tplg_dapm_graph_elem *elem; - int count = hdr->count, i; + struct snd_soc_dapm_route **routes; + int count = hdr->count, i, j; + int ret = 0; if (tplg->pass != SOC_TPLG_PASS_GRAPH) { tplg->pos += hdr->size + hdr->payload_size; @@ -1142,36 +1160,85 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes for index %d\n", count, hdr->index); + /* allocate memory for pointer to array of dapm routes */ + routes = kcalloc(count, sizeof(struct snd_soc_dapm_route *), + GFP_KERNEL); + if (!routes) + return -ENOMEM; + + /* + * allocate memory for each dapm route in the array. + * This needs to be done individually so that + * each route can be freed when it is removed in remove_route(). + */ + for (i = 0; i < count; i++) { + routes[i] = kzalloc(sizeof(*routes[i]), GFP_KERNEL); + if (!routes[i]) { + /* free previously allocated memory */ + for (j = 0; j < i; j++) + kfree(routes[j]); + + kfree(routes); + return -ENOMEM; + } + } + for (i = 0; i < count; i++) { elem = (struct snd_soc_tplg_dapm_graph_elem *)tplg->pos; tplg->pos += sizeof(struct snd_soc_tplg_dapm_graph_elem); /* validate routes */ if (strnlen(elem->source, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { + ret = -EINVAL; + break; + } if (strnlen(elem->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { + ret = -EINVAL; + break; + } if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { + ret = -EINVAL; + break; + } + + routes[i]->source = elem->source; + routes[i]->sink = elem->sink; - route.source = elem->source; - route.sink = elem->sink; - route.connected = NULL; /* set to NULL atm for tplg users */ + /* set to NULL atm for tplg users */ + routes[i]->connected = NULL; if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0) - route.control = NULL; + routes[i]->control = NULL; else - route.control = elem->control; + routes[i]->control = elem->control; + + /* add route dobj to dobj_list */ + routes[i]->dobj.type = SND_SOC_DOBJ_GRAPH; + routes[i]->dobj.ops = tplg->ops; + routes[i]->dobj.index = tplg->index; + list_add(&routes[i]->dobj.list, &tplg->comp->dobj_list); - soc_tplg_add_route(tplg, &route); + soc_tplg_add_route(tplg, routes[i]); /* add route, but keep going if some fail */ - snd_soc_dapm_add_routes(dapm, &route, 1); + snd_soc_dapm_add_routes(dapm, routes[i], 1); } - return 0; + /* free memory allocated for all dapm routes in case of error */ + if (ret < 0) + for (i = 0; i < count ; i++) + kfree(routes[i]); + + /* + * free pointer to array of dapm routes as this is no longer needed. + * The memory allocated for each dapm route will be freed + * when it is removed in remove_route(). + */ + kfree(routes); + + return ret; } static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( @@ -2568,6 +2635,9 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) case SND_SOC_DOBJ_BYTES: remove_bytes(comp, dobj, pass); break; + case SND_SOC_DOBJ_GRAPH: + remove_route(comp, dobj, pass); + break; case SND_SOC_DOBJ_WIDGET: remove_widget(comp, dobj, pass); break; From 2cdfdd9cf2c17112c461978646df2ae1bd288232 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 7 Jan 2019 14:43:13 -0800 Subject: [PATCH 0572/1995] ASoC: SOF: add dapm_route_unload callback to topology ops Add the dapm_route_unload callback to topology ops that will be called when the SND_SOC_DOBJ_ROUTE type dynamic objects are removed from the component driver. Since snd_soc_dapm_route is a dynamically allocated, the route member of struct snd_sof_route is modified to a pointer. Also, the private member of the route's dobj needs to be set to save the handle to the snd_sof_route object. This will be used in the dapm_route_unload callback to clean up the SOF specitic route data. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pm.c | 6 ++-- sound/soc/sof/sof-priv.h | 2 +- sound/soc/sof/topology.c | 66 +++++++++++++--------------------------- 3 files changed, 25 insertions(+), 49 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 46efffc85ea3a1..7f4c4ac86c2230 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -129,10 +129,10 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "error: failed to load route sink %s control %s source %s\n", - sroute->route.sink, - sroute->route.control ? sroute->route.control + sroute->route->sink, + sroute->route->control ? sroute->route->control : "none", - sroute->route.source); + sroute->route->source); return ret; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 66f091ef9f4514..6c6f563f429643 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -281,7 +281,7 @@ struct snd_sof_widget { struct snd_sof_route { struct snd_sof_dev *sdev; - struct snd_soc_dapm_route route; + struct snd_soc_dapm_route *route; struct list_head list; /* list in sdev route list */ void *private; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 06a305791bbf63..7da41f06e1d313 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1777,6 +1777,23 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, return ret; } +static int sof_route_unload(struct snd_soc_component *scomp, + struct snd_soc_dobj *dobj) +{ + struct snd_sof_route *sroute; + + sroute = dobj->private; + if (!sroute) + return 0; + + /* free sroute and its private data */ + kfree(sroute->private); + list_del(&sroute->list); + kfree(sroute); + + return 0; +} + static int sof_widget_unload(struct snd_soc_component *scomp, struct snd_soc_dobj *dobj) { @@ -2492,17 +2509,6 @@ static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm, return 0; } -/* Used for free route in topology free stage */ -static void sof_route_remove(struct snd_soc_dapm_route *route) -{ - if (!route) - return; - - kfree(route->source); - kfree(route->sink); - kfree(route->control); -} - /* DAI link - used for any driver specific init */ static int sof_route_load(struct snd_soc_component *scomp, int index, struct snd_soc_dapm_route *route) @@ -2510,6 +2516,7 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc_pipe_comp_connect *connect; struct snd_sof_widget *source_swidget, *sink_swidget; + struct snd_soc_dobj *dobj = &route->dobj; struct snd_sof_pcm *spcm; struct snd_sof_route *sroute; struct sof_ipc_reply reply; @@ -2608,26 +2615,8 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, goto err; } - sroute->route.source = kstrdup(route->source, GFP_KERNEL); - if (!sroute->route.source) - goto err; - - sroute->route.sink = kstrdup(route->sink, GFP_KERNEL); - if (!sroute->route.sink) { - kfree(sroute->route.source); - goto err; - } - - if (route->control) { - sroute->route.control = kstrdup(route->control, - GFP_KERNEL); - if (!sroute->route.control) { - kfree(sroute->route.source); - kfree(sroute->route.sink); - goto err; - } - } - + sroute->route = route; + dobj->private = sroute; sroute->private = connect; /* add route to route list */ @@ -2713,10 +2702,7 @@ static struct snd_soc_tplg_ops sof_tplg_ops = { /* external kcontrol init - used for any driver specific init */ .dapm_route_load = sof_route_load, - /* - * .dapm_route_unload is not currently used, will be needed when - * topology is changed - */ + .dapm_route_unload = sof_route_unload, /* external widget init - used for any driver specific init */ /* .widget_load is not currently used */ @@ -2792,7 +2778,6 @@ EXPORT_SYMBOL(snd_sof_load_topology); void snd_sof_free_topology(struct snd_sof_dev *sdev) { - struct snd_sof_route *sroute, *temp; int ret; dev_dbg(sdev->dev, "free topology...\n"); @@ -2801,15 +2786,6 @@ void snd_sof_free_topology(struct snd_sof_dev *sdev) return; } - /* remove routes */ - list_for_each_entry_safe(sroute, temp, &sdev->route_list, list) { - sof_route_remove(&sroute->route); - - /* free sroute and its private data */ - kfree(sroute->private); - kfree(sroute); - } - ret = snd_soc_tplg_component_remove(sdev->component, SND_SOC_TPLG_INDEX_ALL); if (ret < 0) From 39d9015914449b5fb1b5f4f288d90f8f23e23ac4 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 17 Dec 2018 13:39:32 -0800 Subject: [PATCH 0573/1995] ASoC: SOF: core: remove call to free_topology() in case of error snd_soc_unregister_component() already handles the removal of topology components. So no need to call free_topology() after unregistering the component driver. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index e13d8dfad65b35..58ea0f200b1ead 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -355,7 +355,6 @@ static int sof_probe(struct platform_device *pdev) comp_err: snd_soc_unregister_component(&pdev->dev); - snd_sof_free_topology(sdev); fw_run_err: snd_sof_fw_unload(sdev); fw_load_err: From 09e0018857379a98e726c185d9aee4c964eaacc9 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Mon, 7 Jan 2019 20:51:03 +0800 Subject: [PATCH 0574/1995] ASoC: SOF: topology: check no_pcm in sof_link_unload We only handle BE links in sof_link_load. So we should only handle BE link in sof_link_unload, too. Signed-off-by: Bard liao --- sound/soc/sof/topology.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 7da41f06e1d313..d43b3e3107b0fe 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2446,6 +2446,10 @@ static int sof_link_unload(struct snd_soc_component *scomp, struct snd_sof_dai *sof_dai = NULL; int ret = 0; + /* only BE link is loaded by sof */ + if (!link->no_pcm) + return 0; + list_for_each_entry(sof_dai, &sdev->dai_list, list) { if (!sof_dai->name) continue; From 91e42bfcadb010fae1d2afbc21e953446abbe3d4 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Thu, 10 Jan 2019 01:20:41 +0800 Subject: [PATCH 0575/1995] ASoC: topology: fix memory leak in soc_tplg_dapm_widget_create template.sname and template.name are only freed when an error occur. They should be freed in the success return case, too. Signed-off-by: Bard liao --- sound/soc/soc-topology.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index b98913249dbe8b..a697e5552d4815 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1651,6 +1651,9 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, if (ret < 0) goto ready_err; + kfree(template.sname); + kfree(template.name); + return 0; ready_err: From e9cc0205ea6df4113bf286d4279fad7e6a6a4dae Mon Sep 17 00:00:00 2001 From: Bard liao Date: Mon, 7 Jan 2019 06:24:02 +0800 Subject: [PATCH 0576/1995] ASoC: topology: unload physical dai link in remove soc_tplg_link_config() will find the physical dai link and call soc_tplg_dai_link_load() to load the BE dai link. Currently remove_link() is only used to remove the FE dai link which is created by the topology. The BE dai link cannot however be unloaded in snd_soc_tplg_component _remove(), which is problematic if anything needs to be released or reinitialized. This patch aligns the definitions of dynamic types with the existing UAPI and adds a new remove_backend_link() routine to unload the the BE dai link when snd_soc_tplg_component_remove() is invoked. Signed-off-by: Bard liao --- include/sound/soc-topology.h | 1 + sound/soc/soc-topology.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index 8c43cfc240fa33..5223896de26f51 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -45,6 +45,7 @@ enum snd_soc_dobj_type { SND_SOC_DOBJ_DAI_LINK, SND_SOC_DOBJ_PCM, SND_SOC_DOBJ_CODEC_LINK, + SND_SOC_DOBJ_BACKEND_LINK, }; /* dynamic control object */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index a697e5552d4815..9bff5f2d533c81 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -559,6 +559,24 @@ static void remove_link(struct snd_soc_component *comp, kfree(link); } +/* unload dai link */ +static void remove_backend_link(struct snd_soc_component *comp, + struct snd_soc_dobj *dobj, int pass) +{ + if (pass != SOC_TPLG_PASS_LINK) + return; + + if (dobj->ops && dobj->ops->link_unload) + dobj->ops->link_unload(comp, dobj); + + /* + * We don't free the link here as what remove_link() do since BE + * links are not allocated by topology. + */ + + list_del(&dobj->list); +} + /* bind a kcontrol to it's IO handlers */ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, struct snd_kcontrol_new *k, @@ -2164,6 +2182,12 @@ static int soc_tplg_link_config(struct soc_tplg *tplg, return ret; } + /* for unloading it in snd_soc_tplg_component_remove */ + link->dobj.index = tplg->index; + link->dobj.ops = tplg->ops; + link->dobj.type = SND_SOC_DOBJ_BACKEND_LINK; + list_add(&link->dobj.list, &tplg->comp->dobj_list); + return 0; } @@ -2650,6 +2674,13 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) case SND_SOC_DOBJ_DAI_LINK: remove_link(comp, dobj, pass); break; + case SND_SOC_DOBJ_BACKEND_LINK: + /* + * call link_unload ops if extra + * deinitialization is needed. + */ + remove_backend_link(comp, dobj, pass); + break; default: dev_err(comp->dev, "ASoC: invalid component type %d for removal\n", dobj->type); From 3e77838aa115b272002e673d40aeb58561154d12 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 9 Jan 2019 21:56:42 -0800 Subject: [PATCH 0577/1995] ASoC: SOF: use optimized register poll for IPC DONE bit from ROM Use the optimized register polling implementation in 9f577982 for the IPC DONE bit from ROM Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-loader.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index fcf61e5fd7ef30..0eadb46b053d09 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -82,8 +82,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; - int ret, i; - u32 hipcie; + int ret; /* step 1: power up corex */ ret = hda_dsp_core_power_up(sdev, chip->cores_mask); @@ -106,25 +105,16 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, } /* step 4: wait for IPC DONE bit from ROM */ - for (i = HDA_DSP_INIT_TIMEOUT; i > 0; i--) { - hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, - chip->ipc_ack); - - if (hipcie & chip->ipc_ack_mask) { - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - chip->ipc_ack, - chip->ipc_ack_mask, - chip->ipc_ack_mask); - goto step5; - } - mdelay(1); - } + ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, + chip->ipc_ack, + chip->ipc_ack_mask, chip->ipc_ack_mask, + HDA_DSP_INIT_TIMEOUT); - dev_err(sdev->dev, "error: waiting for HIPCIE done, reg: 0x%x\n", - hipcie); - goto err; + if (ret < 0) { + dev_err(sdev->dev, "error: waiting for HIPCIE done\n"); + goto err; + } -step5: /* step 5: power down corex */ ret = hda_dsp_core_power_down(sdev, chip->cores_mask & ~(HDA_DSP_CORE_MASK(0))); From b96a806b31c16082bee0e3a365f783594d92b024 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 9 Jan 2019 22:28:38 -0800 Subject: [PATCH 0578/1995] ASoC: SOF: disable DSP if cl_copy_fw() fails Disable DSP if cl_copy_fw() fails. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-loader.c | 108 +++++++++++++++---------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 0eadb46b053d09..ef425092e1ea5d 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -171,6 +171,23 @@ static int cl_trigger(struct snd_sof_dev *sdev, } } +static struct hdac_ext_stream *get_stream_with_tag(struct snd_sof_dev *sdev, + int tag) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *s; + + /* get stream with tag */ + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == SNDRV_PCM_STREAM_PLAYBACK && + s->stream_tag == tag) { + return stream_to_hdac_ext_stream(s); + } + } + + return NULL; +} + static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, struct hdac_ext_stream *stream) { @@ -200,29 +217,10 @@ static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, return ret; } -static int cl_copy_fw(struct snd_sof_dev *sdev, int tag) +static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) { - struct hdac_bus *bus = sof_to_bus(sdev); - struct hdac_ext_stream *stream = NULL; - struct hdac_stream *s; int ret, status; - /* get stream with tag */ - list_for_each_entry(s, &bus->stream_list, list) { - if (s->direction == SNDRV_PCM_STREAM_PLAYBACK && - s->stream_tag == tag) { - stream = stream_to_hdac_ext_stream(s); - break; - } - } - - if (!stream) { - dev_err(sdev->dev, - "error: could not get stream with stream tag%d\n", - tag); - return -ENODEV; - } - ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_START); if (ret < 0) { dev_err(sdev->dev, "error: DMA trigger start failed\n"); @@ -259,10 +257,8 @@ int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev) int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) { struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev); + struct hdac_ext_stream *stream; struct firmware stripped_firmware; - struct hdac_bus *bus = sof_to_bus(sdev); - struct hdac_ext_stream *stream = NULL; - struct hdac_stream *s; int ret, ret1, tag, i; stripped_firmware.data = plat_data->fw->data; @@ -282,6 +278,16 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) return tag; } + /* get stream with tag */ + stream = get_stream_with_tag(sdev, tag); + if (!stream) { + dev_err(sdev->dev, + "error: could not get stream with stream tag %d\n", + tag); + ret = -ENODEV; + goto err; + } + memcpy(sdev->dmab.area, stripped_firmware.data, stripped_firmware.size); @@ -306,49 +312,43 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) if (i == HDA_FW_BOOT_ATTEMPTS) { dev_err(sdev->dev, "error: dsp init failed after %d attempts with err: %d\n", i, ret); - - hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); - - /* disable DSP */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, - SOF_HDA_REG_PP_PPCTL, - SOF_HDA_PPCTL_GPROCEN, 0); - goto done; + goto cleanup; } /* at this point DSP ROM has been initialized and * should be ready for code loading and firmware boot */ - ret = cl_copy_fw(sdev, tag); - if (ret < 0) - dev_err(sdev->dev, "error: load fw failed ret: %d\n", ret); - else + ret = cl_copy_fw(sdev, stream); + if (!ret) dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); + else + dev_err(sdev->dev, "error: load fw failed ret: %d\n", ret); -done: - /* get stream with tag for code loader stream cleanup */ - list_for_each_entry(s, &bus->stream_list, list) { - if (s->direction == SNDRV_PCM_STREAM_PLAYBACK && - s->stream_tag == tag) { - stream = stream_to_hdac_ext_stream(s); - break; - } - } - - if (!stream) { - dev_err(sdev->dev, - "error: could not get stream with stream tag%d\n", - tag); - return -ENODEV; - } - - /* cleanup code loader stream */ +cleanup: + /* + * Perform codeloader stream cleanup. + * This should be done even if firmware loading fails. + */ ret1 = cl_cleanup(sdev, &sdev->dmab, stream); if (ret1 < 0) { dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); - return ret1; + + /* set return value to indicate cleanup failure */ + ret = ret1; } + /* return if both copying fw and stream clean up are successful */ + if (!ret) + return ret; + + /* dump dsp registers and disable DSP upon error */ +err: + hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); + + /* disable DSP */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, + SOF_HDA_REG_PP_PPCTL, + SOF_HDA_PPCTL_GPROCEN, 0); return ret; } From b7e93bd06d1191becb96f977792a65fd778a54df Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 11 Jan 2019 13:00:59 -0600 Subject: [PATCH 0579/1995] ASoC: SOF: debug: fix spaces Reported by Mark Brown Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 5794e272fbaa79..5788690ee063da 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -48,7 +48,7 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, /* copy from DSP MMIO */ pm_runtime_get_noresume(sdev->dev); - memcpy_fromio(buf, dfse->buf + pos, size); + memcpy_fromio(buf, dfse->buf + pos, size); /* * TODO: revisit to check if we need mark_last_busy, or if we From fa46c689b091da97ee34bedb130778586710f30c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 11 Jan 2019 13:01:39 -0600 Subject: [PATCH 0580/1995] ASoC: SOF: PCM: fix spaces reported by checkpatch.pl Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index be76b4e924083b..2570ad8f987fa9 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -562,7 +562,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, /* no topology exists for this BE, try a common configuration */ if (!dai) { dev_warn(sdev->dev, "warning: no topology found for BE DAI %s config\n", - rtd->dai_link->name); + rtd->dai_link->name); /* set 48k, stereo, 16bits by default */ rate->min = 48000; From 4785f8eebfef2a1b5daaf20c39e67f1ca8935d9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Oct 2018 18:48:24 +0300 Subject: [PATCH 0581/1995] ALSA: x86: Fix runtime PM for hdmi-lpe-audio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 46e831abe864 ("drm/i915/lpe: Mark LPE audio runtime pm as "no callbacks"") broke runtime PM with lpe audio. We can no longer runtime suspend the GPU since the sysfs power/control for the lpe-audio device no longer exists and the device is considered always active. We can fix this by not marking the device as active. Cc: Chris Wilson Cc: Takashi Iwai Cc: Pierre-Louis Bossart Fixes: 46e831abe864 ("drm/i915/lpe: Mark LPE audio runtime pm as "no callbacks"") Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20181024154825.18185-1-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson Acked-by: Takashi Iwai (cherry picked from commit 8dfb839cfe737a17def8e5f88ee13c295230364a) --- sound/x86/intel_hdmi_audio.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 83d76c34594055..bbed4acaafd13b 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1877,7 +1877,6 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_mark_last_busy(&pdev->dev); - pm_runtime_set_active(&pdev->dev); dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__); for_each_port(card_ctx, port) { From 3da00946e7a9ef41f7362d0324ae8a86030889ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Oct 2018 18:48:25 +0300 Subject: [PATCH 0582/1995] ALSA: x86: Rip out the lpe audio runtime suspend/resume hooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ever since commit 46e831abe864 ("drm/i915/lpe: Mark LPE audio runtime pm as "no callbacks"") the runtime suspend/resume hooks are no longer used. Inline them into the system suspend hooks. Cc: Chris Wilson Cc: Takashi Iwai Cc: Pierre-Louis Bossart Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20181024154825.18185-2-ville.syrjala@linux.intel.com Reviewed-by: Chris Wilson Acked-by: Takashi Iwai (cherry picked from commit 0019457e31b2ebf3fab38c20c8097e658daea9b8) --- sound/x86/intel_hdmi_audio.c | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index bbed4acaafd13b..00c92eb854ce7b 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1648,7 +1648,7 @@ static int had_create_jack(struct snd_intelhad *ctx, * PM callbacks */ -static int hdmi_lpe_audio_runtime_suspend(struct device *dev) +static int __maybe_unused hdmi_lpe_audio_suspend(struct device *dev) { struct snd_intelhad_card *card_ctx = dev_get_drvdata(dev); int port; @@ -1664,23 +1664,8 @@ static int hdmi_lpe_audio_runtime_suspend(struct device *dev) } } - return 0; -} - -static int __maybe_unused hdmi_lpe_audio_suspend(struct device *dev) -{ - struct snd_intelhad_card *card_ctx = dev_get_drvdata(dev); - int err; + snd_power_change_state(card_ctx->card, SNDRV_CTL_POWER_D3hot); - err = hdmi_lpe_audio_runtime_suspend(dev); - if (!err) - snd_power_change_state(card_ctx->card, SNDRV_CTL_POWER_D3hot); - return err; -} - -static int hdmi_lpe_audio_runtime_resume(struct device *dev) -{ - pm_runtime_mark_last_busy(dev); return 0; } @@ -1688,8 +1673,10 @@ static int __maybe_unused hdmi_lpe_audio_resume(struct device *dev) { struct snd_intelhad_card *card_ctx = dev_get_drvdata(dev); - hdmi_lpe_audio_runtime_resume(dev); + pm_runtime_mark_last_busy(dev); + snd_power_change_state(card_ctx->card, SNDRV_CTL_POWER_D0); + return 0; } @@ -1907,8 +1894,6 @@ static int hdmi_lpe_audio_remove(struct platform_device *pdev) static const struct dev_pm_ops hdmi_lpe_audio_pm = { SET_SYSTEM_SLEEP_PM_OPS(hdmi_lpe_audio_suspend, hdmi_lpe_audio_resume) - SET_RUNTIME_PM_OPS(hdmi_lpe_audio_runtime_suspend, - hdmi_lpe_audio_runtime_resume, NULL) }; static struct platform_driver hdmi_lpe_audio_driver = { From 2820c4e906ff20165cdff0ec21a6e17741f2218b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Nov 2018 15:22:40 +0100 Subject: [PATCH 0583/1995] ALSA: control: Consolidate helpers for adding and replacing ctl elements Both snd_ctl_add() and snd_ctl_replace() process the things in a fairly similar way, and indeed the most of the codes can be unified. This patch is a refactoring to consolidate the both functions to call a single helper with an extra "mode" argument. There should be no functional difference, except for one additional sanity check applied now to snd_ctl_replace() (which was rather overlooking, IMO), too. Signed-off-by: Takashi Iwai (cherry picked from commit 3103c08f968ddba3fff339a59aba40389b3f724f) --- sound/core/control.c | 123 ++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 71 deletions(-) diff --git a/sound/core/control.c b/sound/core/control.c index 649d3217590ed4..fad7db40244341 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -348,22 +348,41 @@ static int snd_ctl_find_hole(struct snd_card *card, unsigned int count) return 0; } -/* add a new kcontrol object; call with card->controls_rwsem locked */ -static int __snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) +enum snd_ctl_add_mode { + CTL_ADD_EXCLUSIVE, CTL_REPLACE, CTL_ADD_ON_REPLACE, +}; + +/* add/replace a new kcontrol object; call with card->controls_rwsem locked */ +static int __snd_ctl_add_replace(struct snd_card *card, + struct snd_kcontrol *kcontrol, + enum snd_ctl_add_mode mode) { struct snd_ctl_elem_id id; unsigned int idx; unsigned int count; + struct snd_kcontrol *old; + int err; id = kcontrol->id; if (id.index > UINT_MAX - kcontrol->count) return -EINVAL; - if (snd_ctl_find_id(card, &id)) { - dev_err(card->dev, - "control %i:%i:%i:%s:%i is already present\n", - id.iface, id.device, id.subdevice, id.name, id.index); - return -EBUSY; + old = snd_ctl_find_id(card, &id); + if (!old) { + if (mode == CTL_REPLACE) + return -EINVAL; + } else { + if (mode == CTL_ADD_EXCLUSIVE) { + dev_err(card->dev, + "control %i:%i:%i:%s:%i is already present\n", + id.iface, id.device, id.subdevice, id.name, + id.index); + return -EBUSY; + } + + err = snd_ctl_remove(card, old); + if (err < 0) + return err; } if (snd_ctl_find_hole(card, kcontrol->count) < 0) @@ -382,21 +401,9 @@ static int __snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) return 0; } -/** - * snd_ctl_add - add the control instance to the card - * @card: the card instance - * @kcontrol: the control instance to add - * - * Adds the control instance created via snd_ctl_new() or - * snd_ctl_new1() to the given card. Assigns also an unique - * numid used for fast search. - * - * It frees automatically the control which cannot be added. - * - * Return: Zero if successful, or a negative error code on failure. - * - */ -int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) +static int snd_ctl_add_replace(struct snd_card *card, + struct snd_kcontrol *kcontrol, + enum snd_ctl_add_mode mode) { int err = -EINVAL; @@ -406,7 +413,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) goto error; down_write(&card->controls_rwsem); - err = __snd_ctl_add(card, kcontrol); + err = __snd_ctl_add_replace(card, kcontrol, mode); up_write(&card->controls_rwsem); if (err < 0) goto error; @@ -416,6 +423,25 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) snd_ctl_free_one(kcontrol); return err; } + +/** + * snd_ctl_add - add the control instance to the card + * @card: the card instance + * @kcontrol: the control instance to add + * + * Adds the control instance created via snd_ctl_new() or + * snd_ctl_new1() to the given card. Assigns also an unique + * numid used for fast search. + * + * It frees automatically the control which cannot be added. + * + * Return: Zero if successful, or a negative error code on failure. + * + */ +int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) +{ + return snd_ctl_add_replace(card, kcontrol, CTL_ADD_EXCLUSIVE); +} EXPORT_SYMBOL(snd_ctl_add); /** @@ -435,53 +461,8 @@ EXPORT_SYMBOL(snd_ctl_add); int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, bool add_on_replace) { - struct snd_ctl_elem_id id; - unsigned int count; - unsigned int idx; - struct snd_kcontrol *old; - int ret; - - if (!kcontrol) - return -EINVAL; - if (snd_BUG_ON(!card || !kcontrol->info)) { - ret = -EINVAL; - goto error; - } - id = kcontrol->id; - down_write(&card->controls_rwsem); - old = snd_ctl_find_id(card, &id); - if (!old) { - if (add_on_replace) - goto add; - up_write(&card->controls_rwsem); - ret = -EINVAL; - goto error; - } - ret = snd_ctl_remove(card, old); - if (ret < 0) { - up_write(&card->controls_rwsem); - goto error; - } -add: - if (snd_ctl_find_hole(card, kcontrol->count) < 0) { - up_write(&card->controls_rwsem); - ret = -ENOMEM; - goto error; - } - list_add_tail(&kcontrol->list, &card->controls); - card->controls_count += kcontrol->count; - kcontrol->id.numid = card->last_numid + 1; - card->last_numid += kcontrol->count; - id = kcontrol->id; - count = kcontrol->count; - up_write(&card->controls_rwsem); - for (idx = 0; idx < count; idx++, id.index++, id.numid++) - snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); - return 0; - -error: - snd_ctl_free_one(kcontrol); - return ret; + return snd_ctl_add_replace(card, kcontrol, + add_on_replace ? CTL_ADD_ON_REPLACE : CTL_REPLACE); } EXPORT_SYMBOL(snd_ctl_replace); @@ -1369,7 +1350,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, /* This function manage to free the instance on failure. */ down_write(&card->controls_rwsem); - err = __snd_ctl_add(card, kctl); + err = __snd_ctl_add_replace(card, kctl, CTL_ADD_EXCLUSIVE); if (err < 0) { snd_ctl_free_one(kctl); goto unlock; From 509c4e121f119b0c706ce5df210e743045acd682 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 12 Dec 2018 15:36:28 -0600 Subject: [PATCH 0584/1995] ALSA: pcm: Fix potential Spectre v1 vulnerability stream is indirectly controlled by user-space, hence leading to a potential exploitation of the Spectre variant 1 vulnerability. This issue was detected with the help of Smatch: sound/core/pcm.c:140 snd_pcm_control_ioctl() warn: potential spectre issue 'pcm->streams' [r] (local cap) Fix this by sanitizing stream before using it to index pcm->streams Notice that given that speculation windows are large, the policy is to kill the speculation on the first load and not worry if it can be completed with a dependent load/store [1]. [1] https://marc.info/?l=linux-kernel&m=152449131114778&w=2 Signed-off-by: Gustavo A. R. Silva Cc: stable@vger.kernel.org Signed-off-by: Takashi Iwai (cherry picked from commit 94ffb030b6d31ec840bb811be455dd2e26a4f43e) --- sound/core/pcm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index fdb9b92fc8d6b3..01b9d62eef14db 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -129,6 +130,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card, return -EFAULT; if (stream < 0 || stream > 1) return -EINVAL; + stream = array_index_nospec(stream, 2); if (get_user(subdevice, &info->subdevice)) return -EFAULT; mutex_lock(®ister_mutex); From 52170bb4c9318505b29a0f6b3081b06dbf38cc15 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Tue, 11 Dec 2018 15:30:27 -0600 Subject: [PATCH 0585/1995] ALSA: HDA: export process_unsol_events() The SOF implementation does not rely on the hdac_bus library, however for HDMI and HDaudio codec support it does need to deal with unsolicited events. Instead of re-inventing the wheel, export this symbol to reuse this part of the library directly. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai (cherry picked from commit 18d43c9b88eb335440c5e769eb6c2d5bc908dc61) --- include/sound/hdaudio.h | 1 + sound/hda/hdac_bus.c | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 940e2b28213358..f9b2b6330d27a1 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -387,6 +387,7 @@ void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex); int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec); void snd_hdac_bus_remove_device(struct hdac_bus *bus, struct hdac_device *codec); +void snd_hdac_bus_process_unsol_events(struct work_struct *work); static inline void snd_hdac_codec_link_up(struct hdac_device *codec) { diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c index 714a51721a313c..012305177f6822 100644 --- a/sound/hda/hdac_bus.c +++ b/sound/hda/hdac_bus.c @@ -9,8 +9,6 @@ #include #include "trace.h" -static void process_unsol_events(struct work_struct *work); - static const struct hdac_bus_ops default_ops = { .command = snd_hdac_bus_send_cmd, .get_response = snd_hdac_bus_get_response, @@ -37,7 +35,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, bus->io_ops = io_ops; INIT_LIST_HEAD(&bus->stream_list); INIT_LIST_HEAD(&bus->codec_list); - INIT_WORK(&bus->unsol_work, process_unsol_events); + INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); spin_lock_init(&bus->reg_lock); mutex_init(&bus->cmd_mutex); bus->irq = -1; @@ -148,7 +146,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_bus_queue_event); /* * process queued unsolicited events */ -static void process_unsol_events(struct work_struct *work) +void snd_hdac_bus_process_unsol_events(struct work_struct *work) { struct hdac_bus *bus = container_of(work, struct hdac_bus, unsol_work); struct hdac_device *codec; @@ -171,6 +169,7 @@ static void process_unsol_events(struct work_struct *work) drv->unsol_event(codec, res); } } +EXPORT_SYMBOL_GPL(snd_hdac_bus_process_unsol_events); /** * snd_hdac_bus_add_device - Add a codec to bus From ae5fb568f5e72041829e1e345221a01ba2b21095 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 15 Dec 2018 14:07:22 -0600 Subject: [PATCH 0586/1995] ALSA: HD-Audio: SKL+: abort probe if DSP is present and Skylake driver selected Now that the SST/Skylake driver supports per platform selectors, we can add logic to automatically select the right driver. If the Skylake driver is selected for a specific platform, and the DSP is detected at run-time based on the PCI class/subclass/prog-if information, the legacy HDaudio driver aborts the probe. This will result in a single driver probing and remove the need for modprobe blacklists. Follow-up patches will add a module parameter to bypass the logic if this automatic detection fails, or if the Skylake driver is unable to actually support the platform (firmware authentication, missing topology file, hardware issue, etc). The same mechanism will be used to conflicts generated by the same PCI ID being registered by both legacy HDAuudio and SOF drivers for Intel platforms. In other words SOF will not require changes to the HDaudio legacy. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai (cherry picked from commit c337104b1a16becc486fdc95d544c835b17021db) --- sound/pci/hda/Kconfig | 62 ++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_controller.h | 2 +- sound/pci/hda/hda_intel.c | 34 +++++++++++++++---- sound/soc/intel/Kconfig | 6 ++++ 4 files changed, 96 insertions(+), 8 deletions(-) diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 4235907b785891..0d38c006e18247 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -226,6 +226,68 @@ config SND_HDA_POWER_SAVE_DEFAULT The default time-out value in seconds for HD-audio automatic power-save mode. 0 means to disable the power-save mode. +if SND_HDA_INTEL + +# The options below should not be enabled by distributions or +# users. They are selected by Intel/Skylake or SOF drivers when they +# register for a PCI ID which is also handled by the HDAudio legacy +# driver. When this option is selected and the DSP is detected based on +# the PCI class/subclass/prog-if, the probe of the HDAudio legacy +# aborts. This mechanism removes the need for distributions to use +# blacklists. It can be bypassed with module parameters should the +# Intel/Skylake or SOF drivers fail to handle a specific platform. + +config SND_HDA_INTEL_DSP_DETECTION_SKL + bool + help + This option is selected by SOF or SST drivers, not users or distros. + It enables DSP detection based on PCI class information for + Skylake machines. + +config SND_HDA_INTEL_DSP_DETECTION_APL + bool + help + This option is selected by SOF or SST drivers, not users or distros. + It enables DSP detection based on PCI class information for + Broxton/ApolloLake machines + +config SND_HDA_INTEL_DSP_DETECTION_KBL + bool + help + This option is selected by SOF or SST drivers, not users or distros. + It enables DSP detection based on PCI class information for + KabyLake machines + +config SND_HDA_INTEL_DSP_DETECTION_GLK + bool + help + This option is selected by SOF or SST drivers, not users or distros. + It enables DSP detection based on PCI class information for + GeminiLake machines + +config SND_HDA_INTEL_DSP_DETECTION_CNL + bool + help + This option is selected by SOF or SST drivers, not users or distros. + It enables DSP detection based on PCI class information for + CannonLake machines + +config SND_HDA_INTEL_DSP_DETECTION_CFL + bool + help + This option is selected by SOF or SST drivers, not users or distros. + It enables DSP detection based on PCI class information for + CoffeeLake machines + +config SND_HDA_INTEL_DSP_DETECTION_ICL + bool + help + This option is selected by SOF or SST drivers, not users or distros. + It enables DSP detection based on PCI class information for + IceLake machines + +endif ## SND_HDA_INTEL + endif endmenu diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 7185ed574b412f..e0c3fcbaa02843 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -37,7 +37,7 @@ #else #define AZX_DCAPS_I915_COMPONENT 0 /* NOP */ #endif -/* 14 unused */ +#define AZX_DCAPS_INTEL_SHARED (1 << 14) /* shared with ASoC */ #define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */ #define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */ /* 17 unused */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e784130ea4e0eb..2ec9c896ebc089 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -357,6 +357,7 @@ enum { AZX_DCAPS_NO_64BIT |\ AZX_DCAPS_4K_BDLE_BOUNDARY | AZX_DCAPS_SNOOP_OFF) +#define AZX_DCAPS_INTEL_DSP_DETECTION(conf) (IS_ENABLED(CONFIG_SND_HDA_INTEL_DSP_DETECTION_##conf) ? AZX_DCAPS_INTEL_SHARED : 0) /* * vga_switcheroo support */ @@ -2048,6 +2049,11 @@ static int azx_probe(struct pci_dev *pci, bool schedule_probe; int err; + /* check if this driver can be used on SKL+ Intel platforms */ + if ((pci_id->driver_data & AZX_DCAPS_INTEL_SHARED) && + pci->class != 0x040300) + return -ENODEV; + if (dev >= SNDRV_CARDS) return -ENODEV; if (!enable[dev]) { @@ -2354,34 +2360,48 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, /* Sunrise Point-LP */ { PCI_DEVICE(0x8086, 0x9d70), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE | + AZX_DCAPS_INTEL_DSP_DETECTION(SKL) + }, /* Kabylake */ { PCI_DEVICE(0x8086, 0xa171), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, /* Kabylake-LP */ { PCI_DEVICE(0x8086, 0x9d71), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE | + AZX_DCAPS_INTEL_DSP_DETECTION(KBL) + }, /* Kabylake-H */ { PCI_DEVICE(0x8086, 0xa2f0), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, /* Coffelake */ { PCI_DEVICE(0x8086, 0xa348), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE | + AZX_DCAPS_INTEL_DSP_DETECTION(CFL) + }, /* Cannonlake */ { PCI_DEVICE(0x8086, 0x9dc8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE | + AZX_DCAPS_INTEL_DSP_DETECTION(CNL) + }, /* Icelake */ { PCI_DEVICE(0x8086, 0x34c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE | + AZX_DCAPS_INTEL_DSP_DETECTION(ICL) + }, /* Broxton-P(Apollolake) */ { PCI_DEVICE(0x8086, 0x5a98), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON | + AZX_DCAPS_INTEL_DSP_DETECTION(APL) + }, /* Broxton-T */ { PCI_DEVICE(0x8086, 0x1a98), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, /* Gemini-Lake */ { PCI_DEVICE(0x8086, 0x3198), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON | + AZX_DCAPS_INTEL_DSP_DETECTION(GLK) + }, /* Haswell */ { PCI_DEVICE(0x8086, 0x0a0c), .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index bd9fd2035c554b..b0764b2fe001f0 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -188,6 +188,12 @@ config SND_SOC_INTEL_SKYLAKE_COMMON select SND_SOC_TOPOLOGY select SND_SOC_INTEL_SST select SND_SOC_HDAC_HDA if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC + select SND_HDA_INTEL_DSP_DETECTION_SKL if SND_SOC_INTEL_SKL + select SND_HDA_INTEL_DSP_DETECTION_APL if SND_SOC_INTEL_APL + select SND_HDA_INTEL_DSP_DETECTION_KBL if SND_SOC_INTEL_KBL + select SND_HDA_INTEL_DSP_DETECTION_GLK if SND_SOC_INTEL_GLK + select SND_HDA_INTEL_DSP_DETECTION_CNL if SND_SOC_INTEL_CNL + select SND_HDA_INTEL_DSP_DETECTION_CFL if SND_SOC_INTEL_CFL select SND_SOC_ACPI_INTEL_MATCH help If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/ From 7c892f513af7cc92a305164650ae711206b22b15 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 15 Dec 2018 14:07:23 -0600 Subject: [PATCH 0587/1995] ALSA: HD-Audio: SKL+: force HDaudio legacy or SKL+ driver selection For HDaudio and Skylake drivers, add module parameter "pci_binding" When pci_binding == 0 (AUTO), the PCI class/subclass info is used to select drivers based on the presence of the DSP. pci_binding == 1 (LEGACY) forces the use of the HDAudio legacy driver, even if the DSP is present. pci_binding == 2 (ASOC) forces the use of the ASOC driver. The information on the DSP presence is bypassed. The value for the module parameter needs to be identical for both drivers. This parameter is intended as a back-up solution if the automatic detection fails or when the DSP usage fails. Such cases should be reported on the alsa-devel mailing list for analysis. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai (cherry picked from commit d82b51c855a20eb456ac09f2f40ea98312373263) --- include/sound/hdaudio.h | 6 +++++ sound/pci/hda/hda_intel.c | 26 ++++++++++++++++--- sound/soc/intel/skylake/skl.c | 48 ++++++++++++++++++++++++----------- 3 files changed, 62 insertions(+), 18 deletions(-) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index f9b2b6330d27a1..b4fa1c7752510b 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -98,6 +98,12 @@ enum { HDA_DEV_ASOC, }; +enum { + SND_SKL_PCI_BIND_AUTO, /* automatic selection based on pci class */ + SND_SKL_PCI_BIND_LEGACY,/* bind only with legacy driver */ + SND_SKL_PCI_BIND_ASOC /* bind only with ASoC driver */ +}; + /* direction */ enum { HDA_INPUT, HDA_OUTPUT diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 2ec9c896ebc089..e42cc22309771c 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -172,6 +172,9 @@ module_param_array(beep_mode, bool, NULL, 0444); MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode " "(0=off, 1=on) (default=1)."); #endif +static int skl_pci_binding; +module_param_named(pci_binding, skl_pci_binding, int, 0444); +MODULE_PARM_DESC(pci_binding, "PCI binding (0=auto, 1=only legacy, 2=only asoc"); #ifdef CONFIG_PM static int param_set_xint(const char *val, const struct kernel_param *kp); @@ -2050,9 +2053,26 @@ static int azx_probe(struct pci_dev *pci, int err; /* check if this driver can be used on SKL+ Intel platforms */ - if ((pci_id->driver_data & AZX_DCAPS_INTEL_SHARED) && - pci->class != 0x040300) - return -ENODEV; + if (pci_id->driver_data & AZX_DCAPS_INTEL_SHARED) { + switch (skl_pci_binding) { + case SND_SKL_PCI_BIND_AUTO: + if (pci->class != 0x040300) { + dev_info(&pci->dev, "The DSP is enabled on this platform, aborting probe\n"); + return -ENODEV; + } + dev_info(&pci->dev, "No DSP detected, continuing HDaudio legacy probe\n"); + break; + case SND_SKL_PCI_BIND_LEGACY: + dev_info(&pci->dev, "Module parameter forced binding with HDaudio legacy, bypassed detection logic\n"); + break; + case SND_SKL_PCI_BIND_ASOC: + dev_info(&pci->dev, "Module parameter forced binding with SKL+ ASoC driver, aborting probe\n"); + return -ENODEV; + default: + dev_err(&pci->dev, "invalid value for skl_pci_binding module parameter, ignored\n"); + break; + } + } if (dev >= SNDRV_CARDS) return -ENODEV; diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 29d9b0eb83ea15..60c94836bf5bc9 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -40,6 +40,9 @@ #if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) #include "../../../soc/codecs/hdac_hda.h" #endif +static int skl_pci_binding; +module_param_named(pci_binding, skl_pci_binding, int, 0444); +MODULE_PARM_DESC(pci_binding, "PCI binding (0=auto, 1=only legacy, 2=only asoc"); /* * initialize the PCI registers @@ -896,21 +899,6 @@ static int skl_first_init(struct hdac_bus *bus) unsigned short gcap; int cp_streams, pb_streams, start_idx; - /* - * detect DSP by checking class/subclass/prog-id information - * class=04 subclass 03 prog-if 00: no DSP, legacy driver needs to be used - * class=04 subclass 01 prog-if 00: DSP is present (and may be required e.g. for DMIC or SSP support) - * class=04 subclass 03 prog-if 80: either of DSP or legacy mode can be used - */ - if (pci->class == 0x040300) { - dev_err(bus->dev, "The DSP is not enabled on this platform, aborting probe\n"); - return -ENODEV; - } else if (pci->class != 0x040100 && pci->class != 0x040380) { - dev_err(bus->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, aborting probe\n", pci->class); - return -ENODEV; - } - dev_info(bus->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class); - err = pci_request_regions(pci, "Skylake HD audio"); if (err < 0) return err; @@ -984,6 +972,36 @@ static int skl_probe(struct pci_dev *pci, struct hdac_bus *bus = NULL; int err; + switch (skl_pci_binding) { + case SND_SKL_PCI_BIND_AUTO: + /* + * detect DSP by checking class/subclass/prog-id information + * class=04 subclass 03 prog-if 00: no DSP, use legacy driver + * class=04 subclass 01 prog-if 00: DSP is present + * (and may be required e.g. for DMIC or SSP support) + * class=04 subclass 03 prog-if 80: use DSP or legacy mode + */ + if (pci->class == 0x040300) { + dev_info(&pci->dev, "The DSP is not enabled on this platform, aborting probe\n"); + return -ENODEV; + } + if (pci->class != 0x040100 && pci->class != 0x040380) { + dev_err(&pci->dev, "Unknown PCI class/subclass/prog-if information (0x%06x) found, aborting probe\n", pci->class); + return -ENODEV; + } + dev_info(&pci->dev, "DSP detected with PCI class/subclass/prog-if info 0x%06x\n", pci->class); + break; + case SND_SKL_PCI_BIND_LEGACY: + dev_info(&pci->dev, "Module parameter forced binding with HDaudio legacy, aborting probe\n"); + return -ENODEV; + case SND_SKL_PCI_BIND_ASOC: + dev_info(&pci->dev, "Module parameter forced binding with SKL driver, bypassed detection logic\n"); + break; + default: + dev_err(&pci->dev, "invalid value for skl_pci_binding module parameter, ignored\n"); + break; + } + /* we use ext core ops, so provide NULL for ops here */ err = skl_create(pci, NULL, &skl); if (err < 0) From 0a21926e5a9d09704a57909d672b8b5b8285fe03 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 31 Dec 2018 19:02:01 +0100 Subject: [PATCH 0588/1995] ALSA: hda - Revert DSP detection on legacy HD-audio driver This essentially reverts the commits c337104b1a16 ("ALSA: HD-Audio: SKL+: abort probe if DSP is present and Skylake driver selected") and d82b51c855a2 ("ALSA: HD-Audio: SKL+: force HDaudio legacy or SKL+ driver selection") for the path of legacy HD-audio controller (snd-hda-intel). The automatic DSP detection and skip of binding with the legacy driver caused regressions on several machines like Dell XPS13. They give the PCI class 0x40380 indicating the availability of DSP while they don't work with ASoC SKL driver (yet). As the support of ASoC driver for such devices isn't available, it's better to revert the whole DSP-detection-and-skip behavior of the legacy driver, so that we can get the old good driver working on such devices. The pci_binding option for ASoC SKL driver is still kept so that it can work without blacklisting. Fixes: c337104b1a16 ("ALSA: HD-Audio: SKL+: abort probe if DSP is present and Skylake driver selected") Reported-by: Linus Torvalds Reported-by: Hans de Goede Reported-by: Azat Khuzhin Cc: Pierre-Louis Bossart Signed-off-by: Takashi Iwai (cherry picked from commit 3e9ad24b0e91c066311a958afbd6210dda8a43eb) --- sound/pci/hda/Kconfig | 62 ---------------------------------- sound/pci/hda/hda_controller.h | 2 +- sound/pci/hda/hda_intel.c | 54 ++++------------------------- sound/soc/intel/Kconfig | 6 ---- 4 files changed, 8 insertions(+), 116 deletions(-) diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 0d38c006e18247..4235907b785891 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -226,68 +226,6 @@ config SND_HDA_POWER_SAVE_DEFAULT The default time-out value in seconds for HD-audio automatic power-save mode. 0 means to disable the power-save mode. -if SND_HDA_INTEL - -# The options below should not be enabled by distributions or -# users. They are selected by Intel/Skylake or SOF drivers when they -# register for a PCI ID which is also handled by the HDAudio legacy -# driver. When this option is selected and the DSP is detected based on -# the PCI class/subclass/prog-if, the probe of the HDAudio legacy -# aborts. This mechanism removes the need for distributions to use -# blacklists. It can be bypassed with module parameters should the -# Intel/Skylake or SOF drivers fail to handle a specific platform. - -config SND_HDA_INTEL_DSP_DETECTION_SKL - bool - help - This option is selected by SOF or SST drivers, not users or distros. - It enables DSP detection based on PCI class information for - Skylake machines. - -config SND_HDA_INTEL_DSP_DETECTION_APL - bool - help - This option is selected by SOF or SST drivers, not users or distros. - It enables DSP detection based on PCI class information for - Broxton/ApolloLake machines - -config SND_HDA_INTEL_DSP_DETECTION_KBL - bool - help - This option is selected by SOF or SST drivers, not users or distros. - It enables DSP detection based on PCI class information for - KabyLake machines - -config SND_HDA_INTEL_DSP_DETECTION_GLK - bool - help - This option is selected by SOF or SST drivers, not users or distros. - It enables DSP detection based on PCI class information for - GeminiLake machines - -config SND_HDA_INTEL_DSP_DETECTION_CNL - bool - help - This option is selected by SOF or SST drivers, not users or distros. - It enables DSP detection based on PCI class information for - CannonLake machines - -config SND_HDA_INTEL_DSP_DETECTION_CFL - bool - help - This option is selected by SOF or SST drivers, not users or distros. - It enables DSP detection based on PCI class information for - CoffeeLake machines - -config SND_HDA_INTEL_DSP_DETECTION_ICL - bool - help - This option is selected by SOF or SST drivers, not users or distros. - It enables DSP detection based on PCI class information for - IceLake machines - -endif ## SND_HDA_INTEL - endif endmenu diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index e0c3fcbaa02843..7185ed574b412f 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -37,7 +37,7 @@ #else #define AZX_DCAPS_I915_COMPONENT 0 /* NOP */ #endif -#define AZX_DCAPS_INTEL_SHARED (1 << 14) /* shared with ASoC */ +/* 14 unused */ #define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */ #define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */ /* 17 unused */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e42cc22309771c..e784130ea4e0eb 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -172,9 +172,6 @@ module_param_array(beep_mode, bool, NULL, 0444); MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode " "(0=off, 1=on) (default=1)."); #endif -static int skl_pci_binding; -module_param_named(pci_binding, skl_pci_binding, int, 0444); -MODULE_PARM_DESC(pci_binding, "PCI binding (0=auto, 1=only legacy, 2=only asoc"); #ifdef CONFIG_PM static int param_set_xint(const char *val, const struct kernel_param *kp); @@ -360,7 +357,6 @@ enum { AZX_DCAPS_NO_64BIT |\ AZX_DCAPS_4K_BDLE_BOUNDARY | AZX_DCAPS_SNOOP_OFF) -#define AZX_DCAPS_INTEL_DSP_DETECTION(conf) (IS_ENABLED(CONFIG_SND_HDA_INTEL_DSP_DETECTION_##conf) ? AZX_DCAPS_INTEL_SHARED : 0) /* * vga_switcheroo support */ @@ -2052,28 +2048,6 @@ static int azx_probe(struct pci_dev *pci, bool schedule_probe; int err; - /* check if this driver can be used on SKL+ Intel platforms */ - if (pci_id->driver_data & AZX_DCAPS_INTEL_SHARED) { - switch (skl_pci_binding) { - case SND_SKL_PCI_BIND_AUTO: - if (pci->class != 0x040300) { - dev_info(&pci->dev, "The DSP is enabled on this platform, aborting probe\n"); - return -ENODEV; - } - dev_info(&pci->dev, "No DSP detected, continuing HDaudio legacy probe\n"); - break; - case SND_SKL_PCI_BIND_LEGACY: - dev_info(&pci->dev, "Module parameter forced binding with HDaudio legacy, bypassed detection logic\n"); - break; - case SND_SKL_PCI_BIND_ASOC: - dev_info(&pci->dev, "Module parameter forced binding with SKL+ ASoC driver, aborting probe\n"); - return -ENODEV; - default: - dev_err(&pci->dev, "invalid value for skl_pci_binding module parameter, ignored\n"); - break; - } - } - if (dev >= SNDRV_CARDS) return -ENODEV; if (!enable[dev]) { @@ -2380,48 +2354,34 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, /* Sunrise Point-LP */ { PCI_DEVICE(0x8086, 0x9d70), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE | - AZX_DCAPS_INTEL_DSP_DETECTION(SKL) - }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, /* Kabylake */ { PCI_DEVICE(0x8086, 0xa171), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, /* Kabylake-LP */ { PCI_DEVICE(0x8086, 0x9d71), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE | - AZX_DCAPS_INTEL_DSP_DETECTION(KBL) - }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, /* Kabylake-H */ { PCI_DEVICE(0x8086, 0xa2f0), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE }, /* Coffelake */ { PCI_DEVICE(0x8086, 0xa348), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE | - AZX_DCAPS_INTEL_DSP_DETECTION(CFL) - }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, /* Cannonlake */ { PCI_DEVICE(0x8086, 0x9dc8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE | - AZX_DCAPS_INTEL_DSP_DETECTION(CNL) - }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, /* Icelake */ { PCI_DEVICE(0x8086, 0x34c8), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE | - AZX_DCAPS_INTEL_DSP_DETECTION(ICL) - }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, /* Broxton-P(Apollolake) */ { PCI_DEVICE(0x8086, 0x5a98), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON | - AZX_DCAPS_INTEL_DSP_DETECTION(APL) - }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, /* Broxton-T */ { PCI_DEVICE(0x8086, 0x1a98), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, /* Gemini-Lake */ { PCI_DEVICE(0x8086, 0x3198), - .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON | - AZX_DCAPS_INTEL_DSP_DETECTION(GLK) - }, + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON }, /* Haswell */ { PCI_DEVICE(0x8086, 0x0a0c), .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index b0764b2fe001f0..bd9fd2035c554b 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -188,12 +188,6 @@ config SND_SOC_INTEL_SKYLAKE_COMMON select SND_SOC_TOPOLOGY select SND_SOC_INTEL_SST select SND_SOC_HDAC_HDA if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC - select SND_HDA_INTEL_DSP_DETECTION_SKL if SND_SOC_INTEL_SKL - select SND_HDA_INTEL_DSP_DETECTION_APL if SND_SOC_INTEL_APL - select SND_HDA_INTEL_DSP_DETECTION_KBL if SND_SOC_INTEL_KBL - select SND_HDA_INTEL_DSP_DETECTION_GLK if SND_SOC_INTEL_GLK - select SND_HDA_INTEL_DSP_DETECTION_CNL if SND_SOC_INTEL_CNL - select SND_HDA_INTEL_DSP_DETECTION_CFL if SND_SOC_INTEL_CFL select SND_SOC_ACPI_INTEL_MATCH help If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/ From 24f835a216ea0f8a8050d4bd3bf97f3a2c4ea5a6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:02 -0600 Subject: [PATCH 0589/1995] ASoC: Intel: Skylake: remove useless cast Detected with Coccinelle sound/soc/intel/skylake/skl-topology.c:3106:16-20: WARNING: casting value returned by memory allocation function to (char *) is useless. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 431b67c27c57bc6a752482727c87f6dda988aae5) --- sound/soc/intel/skylake/skl-topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index cf8848b779dcc2..389f1862bc4391 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -3103,7 +3103,7 @@ static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, ac->size = dfw_ac->max; if (ac->max) { - ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL); + ac->params = devm_kzalloc(dev, ac->max, GFP_KERNEL); if (!ac->params) return -ENOMEM; From 441090957d04ea94ef62c113de073b849c2e444d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:03 -0600 Subject: [PATCH 0590/1995] ASoC: Intel: Skylake: simplify boolean tests Detected with Coccinelle skl-messages.c:419:5-32: WARNING: Comparison to bool skl-pcm.c:1426:6-33: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit d8747d30aa7f9e7dc6123709d7ca1d8429d648b0) --- sound/soc/intel/skylake/skl-messages.c | 2 +- sound/soc/intel/skylake/skl-pcm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index b0e6fb93eaf83c..28c4806b196a2f 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -416,7 +416,7 @@ int skl_resume_dsp(struct skl *skl) snd_hdac_ext_bus_ppcap_int_enable(bus, true); /* check if DSP 1st boot is done */ - if (skl->skl_sst->is_first_boot == true) + if (skl->skl_sst->is_first_boot) return 0; /* diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 557f80c0bfe530..8e589d698c588e 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1423,7 +1423,7 @@ static int skl_platform_soc_probe(struct snd_soc_component *component) if (!ops) return -EIO; - if (skl->skl_sst->is_first_boot == false) { + if (!skl->skl_sst->is_first_boot) { dev_err(component->dev, "DSP reports first boot done!!!\n"); return -EIO; } From 089459be83f8728c8dd5e5ab74f7debc2018accd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:04 -0600 Subject: [PATCH 0591/1995] ASoC: Intel: Haswell: remove unneeded semicolon Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 6c5414589721d696fe300dc0b8720e0368e3907a) --- sound/soc/intel/haswell/sst-haswell-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index fe2c826e710c73..fb9b8608eb3b2b 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c @@ -544,7 +544,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, dev_err(rtd->dev, "error: invalid DAI ID %d\n", rtd->cpu_dai->id); return -EINVAL; - }; + } ret = sst_hsw_stream_format(hsw, pcm_data->stream, path_id, stream_type, SST_HSW_STREAM_FORMAT_PCM_FORMAT); From 5a42c7434df8d7f78f3435fd47931da12ec612e9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:05 -0600 Subject: [PATCH 0592/1995] ASoC: Intel: Haswell: assign booleans to true/false Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit bf88b3c3c277c8138d688a0fc3199b57fecfaf56) --- sound/soc/intel/haswell/sst-haswell-ipc.c | 2 +- sound/soc/intel/haswell/sst-haswell-pcm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index d33bdaf92c57c8..31fcdf12c67def 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -1216,7 +1216,7 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream) return ret; } - stream->commited = 1; + stream->commited = true; trace_hsw_stream_alloc_reply(stream); return 0; diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index fb9b8608eb3b2b..2debcc2ed99a1f 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c @@ -861,7 +861,7 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream) dev_dbg(rtd->dev, "error: free stream failed %d\n", ret); goto out; } - pcm_data->allocated = 0; + pcm_data->allocated = false; pcm_data->stream = NULL; out: From 662802691d3fb65cca557cf249d39d3f50070e1e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:06 -0600 Subject: [PATCH 0593/1995] ASoC: Intel: Baytrail: remove unneeded variable Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 060d35be2dfa9202d37f967fd20f133c530505d2) --- sound/soc/intel/baytrail/sst-baytrail-ipc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c index 260447da32b870..2cd8f9668b5046 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-ipc.c +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c @@ -278,7 +278,6 @@ static int sst_byt_process_notification(struct sst_byt *byt, struct sst_byt_stream *stream; u64 header; u8 msg_id, stream_id; - int handled = 1; header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD); msg_id = sst_byt_header_msg_id(header); @@ -298,7 +297,7 @@ static int sst_byt_process_notification(struct sst_byt *byt, break; } - return handled; + return 1; } static irqreturn_t sst_byt_irq_thread(int irq, void *context) From 5452a5dafbd9593e7ea92d6dfe04e1a93b301036 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:07 -0600 Subject: [PATCH 0594/1995] ASoC: Intel: Baytrail: simplify boolean test Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit e295450dd86d974861e1e9e302d67b0a23457ea8) --- sound/soc/intel/baytrail/sst-baytrail-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c index aabb35bf6b963d..498fb5346f1a81 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-pcm.c +++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c @@ -188,7 +188,7 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd) sst_byt_stream_start(byt, pcm_data->stream, 0); break; case SNDRV_PCM_TRIGGER_RESUME: - if (pdata->restore_stream == true) + if (pdata->restore_stream) schedule_work(&pcm_data->work); else sst_byt_stream_resume(byt, pcm_data->stream); From 62b3cd3629d8a84deb349bb408d314c30cc78655 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:08 -0600 Subject: [PATCH 0595/1995] ASoC: Intel: Atom: simplify boolean tests Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 10583cdac237b32c0d3f6027b06c5eec8bf91211) --- sound/soc/intel/atom/sst-atom-controls.c | 2 +- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 2 +- sound/soc/intel/atom/sst/sst_acpi.c | 2 +- sound/soc/intel/atom/sst/sst_drv_interface.c | 2 +- sound/soc/intel/atom/sst/sst_loader.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 3672d36b4b66f4..d1207ea53523d4 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -647,7 +647,7 @@ static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w, set_mixer = false; } - if (set_mixer == false) + if (!set_mixer) return 0; if (SND_SOC_DAPM_EVENT_ON(event) || diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index afc5598660955a..aefa5ce4cb592e 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -190,7 +190,7 @@ int sst_fill_stream_params(void *substream, map = ctx->pdata->pdev_strm_map; map_size = ctx->pdata->strm_map_size; - if (is_compress == true) + if (is_compress) cstream = (struct snd_compr_stream *)substream; else pstream = (struct snd_pcm_substream *)substream; diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index ac542535b9d53f..3a95ebbfc45d30 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -334,7 +334,7 @@ static int sst_acpi_probe(struct platform_device *pdev) return ret; ret = is_byt_cr(dev, &bytcr); - if (!((ret < 0) || (bytcr == false))) { + if (!(ret < 0 || !bytcr)) { dev_info(dev, "Detected Baytrail-CR platform\n"); /* override resource info */ diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c index 5455d6e0ab53cc..a592df06aa58eb 100644 --- a/sound/soc/intel/atom/sst/sst_drv_interface.c +++ b/sound/soc/intel/atom/sst/sst_drv_interface.c @@ -146,7 +146,7 @@ static int sst_power_control(struct device *dev, bool state) int ret = 0; int usage_count = 0; - if (state == true) { + if (state) { ret = pm_runtime_get_sync(dev); usage_count = GET_USAGE_COUNT(dev); dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count); diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c index b8c456753f015f..321c783cf833ca 100644 --- a/sound/soc/intel/atom/sst/sst_loader.c +++ b/sound/soc/intel/atom/sst/sst_loader.c @@ -269,7 +269,7 @@ static void sst_do_memcpy(struct list_head *memcpy_list) struct sst_memcpy_list *listnode; list_for_each_entry(listnode, memcpy_list, memcpylist) { - if (listnode->is_io == true) + if (listnode->is_io) memcpy32_toio((void __iomem *)listnode->dstn, listnode->src, listnode->size); else From c43dd88964396309821218f06705eead86baf0bf Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:10 -0600 Subject: [PATCH 0596/1995] ASoC: Intel: boards: use snd_mask_set_format in all machine drivers Fix Sparse warnings with two machine drivers which weren't updated Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 4e88068ed0888549acd1cbb2f6e271b007051203) --- sound/soc/intel/boards/glk_rt5682_max98357a.c | 2 +- sound/soc/intel/boards/kbl_da7219_max98927.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index c74c4f17316fe8..0739e3a75083f1 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -164,7 +164,7 @@ static int geminilake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, /* set SSP to 24 bit */ snd_mask_none(fmt); - snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); return 0; } diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 723a4935ed76ed..6dd5c69671b3f6 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -221,7 +221,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, rate->min = rate->max = 48000; channels->min = channels->max = 2; snd_mask_none(fmt); - snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); } /* @@ -229,7 +229,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, * thus changing the mask here */ if (!strcmp(be_dai_link->name, "SSP0-Codec")) - snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); return 0; } From 8fd0199524fc01a19a2b3503750560aadbe0a14e Mon Sep 17 00:00:00 2001 From: Yizhuo Date: Thu, 3 Jan 2019 13:59:12 -0800 Subject: [PATCH 0597/1995] ASoC: Variable "val" in function rt274_i2c_probe() could be uninitialized Inside function rt274_i2c_probe(), if regmap_read() function returns -EINVAL, then local variable "val" leaves uninitialized but used in if statement. This is potentially unsafe. Signed-off-by: Yizhuo Signed-off-by: Mark Brown (cherry picked from commit 8c3590de0a378c2449fc1aec127cc693632458e4) --- sound/soc/codecs/rt274.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index 0ef966d56bac30..e2855ab9a2c6b5 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -1128,8 +1128,11 @@ static int rt274_i2c_probe(struct i2c_client *i2c, return ret; } - regmap_read(rt274->regmap, + ret = regmap_read(rt274->regmap, RT274_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &val); + if (ret) + return ret; + if (val != RT274_VENDOR_ID) { dev_err(&i2c->dev, "Device with ID register %#x is not rt274\n", val); From 84ff7952d8c0ac4fd9f5735530bd6dc76a8da525 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:26 +0100 Subject: [PATCH 0598/1995] ASoC: es8316: Add jack-detect support Adding jack-detect support may seem weird for a codec with only a single output, but it is necessary. The ES8316 appnote showing the intended usage uses a jack-receptacle which physically disconnects the speakers from the output when a jack is plugged in. But all 3 devices using the es8316 which I have (2 Cherry Trail devices and one Bay Trail CR device), use an analog mux to disconnect the speakers, driven by a GPIO. In order to enable/disable the speakers at the right time, we need jack-detect. The same goes for the microphone where we must correctly set the mux for the single ADC to either the internal or the headset microphone. All devices I have support the es8316's builtin jack-detect functionality. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit 822257661031faa437336058d8a32bf1844ad9c6) --- sound/soc/codecs/es8316.c | 195 +++++++++++++++++++++++++++++++++++++- sound/soc/codecs/es8316.h | 7 ++ 2 files changed, 198 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index e97d12d578b00c..26413851e43464 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -15,12 +15,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include "es8316.h" /* In slave mode at single speed, the codec is documented as accepting 5 @@ -33,6 +35,11 @@ static const unsigned int supported_mclk_lrck_ratios[] = { }; struct es8316_priv { + struct mutex lock; + struct regmap *regmap; + struct snd_soc_component *component; + struct snd_soc_jack *jack; + int irq; unsigned int sysclk; unsigned int allowed_rates[NR_SUPPORTED_MCLK_LRCK_RATIOS]; struct snd_pcm_hw_constraint_list sysclk_constraints; @@ -529,8 +536,162 @@ static struct snd_soc_dai_driver es8316_dai = { .symmetric_rates = 1, }; +static void es8316_enable_micbias_for_mic_gnd_short_detect( + struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Bias"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Analog power"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Mic Bias"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); + + msleep(20); +} + +static void es8316_disable_micbias_for_mic_gnd_short_detect( + struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Bias"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Analog power"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Bias"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); +} + +static irqreturn_t es8316_irq(int irq, void *data) +{ + struct es8316_priv *es8316 = data; + struct snd_soc_component *comp = es8316->component; + unsigned int flags; + + mutex_lock(&es8316->lock); + + regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags); + if (flags == 0x00) + goto out; /* Powered-down / reset */ + + /* Catch spurious IRQ before set_jack is called */ + if (!es8316->jack) + goto out; + + dev_dbg(comp->dev, "gpio flags %#04x\n", flags); + if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) { + /* Jack removed, or spurious IRQ? */ + if (es8316->jack->status & SND_JACK_MICROPHONE) + es8316_disable_micbias_for_mic_gnd_short_detect(comp); + + if (es8316->jack->status & SND_JACK_HEADPHONE) { + snd_soc_jack_report(es8316->jack, 0, + SND_JACK_HEADSET | SND_JACK_BTN_0); + dev_dbg(comp->dev, "jack unplugged\n"); + } + } else if (!(es8316->jack->status & SND_JACK_HEADPHONE)) { + /* Jack inserted, determine type */ + es8316_enable_micbias_for_mic_gnd_short_detect(comp); + regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags); + dev_dbg(comp->dev, "gpio flags %#04x\n", flags); + if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) { + /* Jack unplugged underneath us */ + es8316_disable_micbias_for_mic_gnd_short_detect(comp); + } else if (flags & ES8316_GPIO_FLAG_GM_NOT_SHORTED) { + /* Open, headset */ + snd_soc_jack_report(es8316->jack, + SND_JACK_HEADSET, + SND_JACK_HEADSET); + /* Keep mic-gnd-short detection on for button press */ + } else { + /* Shorted, headphones */ + snd_soc_jack_report(es8316->jack, + SND_JACK_HEADPHONE, + SND_JACK_HEADSET); + /* No longer need mic-gnd-short detection */ + es8316_disable_micbias_for_mic_gnd_short_detect(comp); + } + } else if (es8316->jack->status & SND_JACK_MICROPHONE) { + /* Interrupt while jack inserted, report button state */ + if (flags & ES8316_GPIO_FLAG_GM_NOT_SHORTED) { + /* Open, button release */ + snd_soc_jack_report(es8316->jack, 0, SND_JACK_BTN_0); + } else { + /* Short, button press */ + snd_soc_jack_report(es8316->jack, + SND_JACK_BTN_0, + SND_JACK_BTN_0); + } + } + +out: + mutex_unlock(&es8316->lock); + return IRQ_HANDLED; +} + +static void es8316_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack) +{ + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + mutex_lock(&es8316->lock); + + es8316->jack = jack; + + if (es8316->jack->status & SND_JACK_MICROPHONE) + es8316_enable_micbias_for_mic_gnd_short_detect(component); + + snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE, + ES8316_GPIO_ENABLE_INTERRUPT, + ES8316_GPIO_ENABLE_INTERRUPT); + + mutex_unlock(&es8316->lock); + + /* Enable irq and sync initial jack state */ + enable_irq(es8316->irq); + es8316_irq(es8316->irq, es8316); +} + +static void es8316_disable_jack_detect(struct snd_soc_component *component) +{ + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + disable_irq(es8316->irq); + + mutex_lock(&es8316->lock); + + snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE, + ES8316_GPIO_ENABLE_INTERRUPT, 0); + + if (es8316->jack->status & SND_JACK_MICROPHONE) { + es8316_disable_micbias_for_mic_gnd_short_detect(component); + snd_soc_jack_report(es8316->jack, 0, SND_JACK_BTN_0); + } + + es8316->jack = NULL; + + mutex_unlock(&es8316->lock); +} + +static int es8316_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) +{ + if (jack) + es8316_enable_jack_detect(component, jack); + else + es8316_disable_jack_detect(component); + + return 0; +} + static int es8316_probe(struct snd_soc_component *component) { + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + es8316->component = component; + /* Reset codec and enable current state machine */ snd_soc_component_write(component, ES8316_RESET, 0x3f); usleep_range(5000, 5500); @@ -555,6 +716,7 @@ static int es8316_probe(struct snd_soc_component *component) static const struct snd_soc_component_driver soc_component_dev_es8316 = { .probe = es8316_probe, + .set_jack = es8316_set_jack, .controls = es8316_snd_controls, .num_controls = ARRAY_SIZE(es8316_snd_controls), .dapm_widgets = es8316_dapm_widgets, @@ -566,18 +728,29 @@ static const struct snd_soc_component_driver soc_component_dev_es8316 = { .non_legacy_dai_naming = 1, }; +static const struct regmap_range es8316_volatile_ranges[] = { + regmap_reg_range(ES8316_GPIO_FLAG, ES8316_GPIO_FLAG), +}; + +static const struct regmap_access_table es8316_volatile_table = { + .yes_ranges = es8316_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(es8316_volatile_ranges), +}; + static const struct regmap_config es8316_regmap = { .reg_bits = 8, .val_bits = 8, .max_register = 0x53, + .volatile_table = &es8316_volatile_table, .cache_type = REGCACHE_RBTREE, }; static int es8316_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { + struct device *dev = &i2c_client->dev; struct es8316_priv *es8316; - struct regmap *regmap; + int ret; es8316 = devm_kzalloc(&i2c_client->dev, sizeof(struct es8316_priv), GFP_KERNEL); @@ -586,9 +759,23 @@ static int es8316_i2c_probe(struct i2c_client *i2c_client, i2c_set_clientdata(i2c_client, es8316); - regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); + es8316->regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap); + if (IS_ERR(es8316->regmap)) + return PTR_ERR(es8316->regmap); + + es8316->irq = i2c_client->irq; + mutex_init(&es8316->lock); + + ret = devm_request_threaded_irq(dev, es8316->irq, NULL, es8316_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "es8316", es8316); + if (ret == 0) { + /* Gets re-enabled by es8316_set_jack() */ + disable_irq(es8316->irq); + } else { + dev_warn(dev, "Failed to get IRQ %d: %d\n", es8316->irq, ret); + es8316->irq = -ENXIO; + } return devm_snd_soc_register_component(&i2c_client->dev, &soc_component_dev_es8316, diff --git a/sound/soc/codecs/es8316.h b/sound/soc/codecs/es8316.h index 6bcdd63ea45948..439a0130cbb7d5 100644 --- a/sound/soc/codecs/es8316.h +++ b/sound/soc/codecs/es8316.h @@ -126,4 +126,11 @@ #define ES8316_SERDATA2_LEN_16 0x0c #define ES8316_SERDATA2_LEN_32 0x10 +/* ES8316_GPIO_DEBOUNCE */ +#define ES8316_GPIO_ENABLE_INTERRUPT 0x02 + +/* ES8316_GPIO_FLAG */ +#define ES8316_GPIO_FLAG_GM_NOT_SHORTED 0x02 +#define ES8316_GPIO_FLAG_HP_NOT_INSERTED 0x04 + #endif From 23df2f2cb786f9171c4b62cce460278f211ec020 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:27 +0100 Subject: [PATCH 0599/1995] ASoC: es8316: Add DAC mono mix switch mixer control Export the DAC functionality to mix left + right together and then output the same (mixed) signal on both outputs. Various (x86) tablets with an ES8316 codec use a single speaker connected between the headhpone LOUT and ROUT pins, expecting the output to be in a mono differential mode. Presumably this is done to use the power of both the left and right outputs to allow the speaker to be louder. The ES8316 codec does not have a differential output mode, but we can emulate this by making both channels output the same through the mono mix switch, combined with setting the Playback Polarity control to "R Invert", which applias a 180 degrees phase inversion to the right channel. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit 24b53f17a3f24967b8b523243f9f7fc361427119) --- sound/soc/codecs/es8316.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 26413851e43464..98464ba1046c18 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -101,6 +101,7 @@ static const struct snd_kcontrol_new es8316_snd_controls[] = { SOC_SINGLE("DAC Notch Filter Switch", ES8316_DAC_SET2, 6, 1, 0), SOC_SINGLE("DAC Double Fs Switch", ES8316_DAC_SET2, 7, 1, 0), SOC_SINGLE("DAC Stereo Enhancement", ES8316_DAC_SET3, 0, 7, 0), + SOC_SINGLE("DAC Mono Mix Switch", ES8316_DAC_SET3, 3, 1, 0), SOC_ENUM("Capture Polarity", adcpol), SOC_SINGLE("Mic Boost Switch", ES8316_ADC_D2SEPGA, 0, 1, 0), From 15d9fe6de671537905178105bdea2e037a59d983 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:28 +0100 Subject: [PATCH 0600/1995] ASoC: Intel: bytcht_es8316: Sort includes alphabetically For lack of a better (non-random) way of sorting includes more and more files in the kernel are moving over to sorting the includes alphabetically. Move the bytcht_es8316 driver over to this sorting before we add a bunch of more includes. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 6ca382c4363d6c636200ccdd9ac95f44b1a498ea) --- sound/soc/intel/boards/bytcht_es8316.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index adc26dfc7d654d..5d8ecc100766c0 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -19,13 +19,13 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include +#include #include #include #include -#include #include #include -#include #include #include #include From 80525a9f4bc2b829cac3f05996cd64a9fdc391d8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:29 +0100 Subject: [PATCH 0601/1995] ASoC: Intel: bytcht_es8316: Minor refactoring Some minor refactoring: 1) Group the code setting the card dev and prive pointers together with registering the card 2) Properly put the comment about registering the card at the place where we actually register the card and add a new comment for getting the clk 3) Add a struct device *dev helper variable (this will be used more in follow up commits) 4) Reword error message to have the same "foo failed: %d" wording as others Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 86909c8f77c5eda17a9b5dc954849e25df1ffe0f) --- sound/soc/intel/boards/bytcht_es8316.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 5d8ecc100766c0..e29f00560b008b 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -237,17 +237,18 @@ static char codec_name[SND_ACPI_I2C_ID_LEN]; static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { struct byt_cht_es8316_private *priv; + struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; const char *i2c_name = NULL; int dai_index = 0; int i; int ret = 0; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - mach = (&pdev->dev)->platform_data; + mach = dev->platform_data; /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_cht_es8316_dais); i++) { if (!strcmp(byt_cht_es8316_dais[i].codec_name, @@ -265,26 +266,25 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_dais[dai_index].codec_name = codec_name; } - /* register the soc card */ - byt_cht_es8316_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); - - priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + /* get the clock */ + priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3"); if (IS_ERR(priv->mclk)) { ret = PTR_ERR(priv->mclk); - dev_err(&pdev->dev, - "Failed to get MCLK from pmc_plt_clk_3: %d\n", - ret); + dev_err(dev, "clk_get pmc_plt_clk_3 failed: %d\n", ret); return ret; } - ret = devm_snd_soc_register_card(&pdev->dev, &byt_cht_es8316_card); + /* register the soc card */ + byt_cht_es8316_card.dev = dev; + snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); + + ret = devm_snd_soc_register_card(dev, &byt_cht_es8316_card); if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); + dev_err(dev, "snd_soc_register_card failed: %d\n", ret); return ret; } platform_set_drvdata(pdev, &byt_cht_es8316_card); - return ret; + return 0; } static struct platform_driver snd_byt_cht_es8316_mc_driver = { From 54e37c3cbe06a9ced8972f84917b220804c0fd60 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:30 +0100 Subject: [PATCH 0602/1995] ASoC: Intel: bytcht_es8316: Add support for SSP0 (BYTCR) Add support for having the codec connected to SSP0 instead of SSP2. This is controlled through a new quirk parameter, similar to how this is done in the bytcr_rt5640 and bytcr_rt5651 machine drivers. Bay Trail CR (cost reduced) SoCs do not have an SSP2, so we default to SSP0 there. Note the SPP0 quirk gets BIT(16) because bits 0-15 are reserved for non boolean quirks like the input-map added in a later commit in this series. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 349e13862c9975c613aac9dc7fa953e70cff9d06) --- sound/soc/intel/boards/bytcht_es8316.c | 76 ++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index e29f00560b008b..3358d82499a3a6 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -37,6 +39,20 @@ struct byt_cht_es8316_private { struct clk *mclk; }; +#define BYT_CHT_ES8316_SSP0 BIT(16) + +static int quirk; + +static int quirk_override = -1; +module_param_named(quirk, quirk_override, int, 0444); +MODULE_PARM_DESC(quirk, "Board-specific quirk override"); + +static void log_quirks(struct device *dev) +{ + if (quirk & BYT_CHT_ES8316_SSP0) + dev_info(dev, "quirk SSP0 enabled"); +} + static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), @@ -55,7 +71,16 @@ static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, +}; + +static const struct snd_soc_dapm_route byt_cht_es8316_ssp0_map[] = { + {"Playback", NULL, "ssp0 Tx"}, + {"ssp0 Tx", NULL, "modem_out"}, + {"modem_in", NULL, "ssp0 Rx"}, + {"ssp0 Rx", NULL, "Capture"}, +}; +static const struct snd_soc_dapm_route byt_cht_es8316_ssp2_map[] = { {"Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, @@ -74,10 +99,23 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_card *card = runtime->card; struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); + const struct snd_soc_dapm_route *custom_map; + int num_routes; int ret; card->dapm.idle_bias_off = true; + if (quirk & BYT_CHT_ES8316_SSP0) { + custom_map = byt_cht_es8316_ssp0_map; + num_routes = ARRAY_SIZE(byt_cht_es8316_ssp0_map); + } else { + custom_map = byt_cht_es8316_ssp2_map; + num_routes = ARRAY_SIZE(byt_cht_es8316_ssp2_map); + } + ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + if (ret) + return ret; + /* * The firmware might enable the clock at boot (this information * may or may not be reflected in the enable clock register). @@ -123,14 +161,21 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - int ret; + int ret, bits; /* The DSP will covert the FE rate to 48k, stereo */ rate->min = rate->max = 48000; channels->min = channels->max = 2; - /* set SSP2 to 24-bit */ - params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + if (quirk & BYT_CHT_ES8316_SSP0) { + /* set SSP0 to 16-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); + bits = 16; + } else { + /* set SSP2 to 24-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + bits = 24; + } /* * Default mode for SSP configuration is TDM 4 slot, override config @@ -147,7 +192,7 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, return ret; } - ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, bits); if (ret < 0) { dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); return ret; @@ -232,6 +277,11 @@ static struct snd_soc_card byt_cht_es8316_card = { .fully_routed = true, }; +static const struct x86_cpu_id baytrail_cpu_ids[] = { + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT }, /* Valleyview */ + {} +}; + static char codec_name[SND_ACPI_I2C_ID_LEN]; static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) @@ -266,6 +316,24 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_dais[dai_index].codec_name = codec_name; } + /* Check for BYTCR or other platform and setup quirks */ + if (x86_match_cpu(baytrail_cpu_ids) && + mach->mach_params.acpi_ipc_irq_index == 0) { + /* On BYTCR default to SSP0 */ + quirk = BYT_CHT_ES8316_SSP0; + } else { + quirk = 0; + } + if (quirk_override != -1) { + dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", quirk, + quirk_override); + quirk = quirk_override; + } + log_quirks(dev); + + if (quirk & BYT_CHT_ES8316_SSP0) + byt_cht_es8316_dais[dai_index].cpu_dai_name = "ssp0-port"; + /* get the clock */ priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3"); if (IS_ERR(priv->mclk)) { From 521e0826aa29e3e40fe98a7af8d5146896fdc7ab Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:31 +0100 Subject: [PATCH 0603/1995] ASoC: Intel: bytcht_es8316: Add jack-detect support Hookup the jack-detect support added to the codec driver. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 4bf538b42933253296daf86aab7ede56b5fb97bf) --- sound/soc/intel/boards/bytcht_es8316.c | 67 +++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 3358d82499a3a6..905dd690471076 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -22,12 +22,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -37,6 +39,7 @@ struct byt_cht_es8316_private { struct clk *mclk; + struct snd_soc_jack jack; }; #define BYT_CHT_ES8316_SSP0 BIT(16) @@ -55,6 +58,7 @@ static void log_quirks(struct device *dev) static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), /* * The codec supports two analog microphone inputs. I have only @@ -68,6 +72,7 @@ static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { {"MIC1", NULL, "Microphone 1"}, {"MIC2", NULL, "Microphone 2"}, + {"MIC1", NULL, "Headset Mic"}, {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, @@ -91,12 +96,25 @@ static const struct snd_soc_dapm_route byt_cht_es8316_ssp2_map[] = { static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Microphone 1"), SOC_DAPM_PIN_SWITCH("Microphone 2"), }; +static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) { + struct snd_soc_component *codec = runtime->codec_dai->component; struct snd_soc_card *card = runtime->card; struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); const struct snd_soc_dapm_route *custom_map; @@ -143,6 +161,18 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) return ret; } + ret = snd_soc_card_jack_new(card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &priv->jack, byt_cht_es8316_jack_pins, + ARRAY_SIZE(byt_cht_es8316_jack_pins)); + if (ret) { + dev_err(card->dev, "jack creation failed %d\n", ret); + return ret; + } + + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_soc_component_set_jack(codec, &priv->jack, NULL); + return 0; } @@ -263,6 +293,39 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { /* SoC card */ +static char codec_name[SND_ACPI_I2C_ID_LEN]; + +static int byt_cht_es8316_suspend(struct snd_soc_card *card) +{ + struct snd_soc_component *component; + + for_each_card_components(card, component) { + if (!strcmp(component->name, codec_name)) { + dev_dbg(component->dev, "disabling jack detect before suspend\n"); + snd_soc_component_set_jack(component, NULL, NULL); + break; + } + } + + return 0; +} + +static int byt_cht_es8316_resume(struct snd_soc_card *card) +{ + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component; + + for_each_card_components(card, component) { + if (!strcmp(component->name, codec_name)) { + dev_dbg(component->dev, "re-enabling jack detect after resume\n"); + snd_soc_component_set_jack(component, &priv->jack, NULL); + break; + } + } + + return 0; +} + static struct snd_soc_card byt_cht_es8316_card = { .name = "bytcht-es8316", .owner = THIS_MODULE, @@ -275,6 +338,8 @@ static struct snd_soc_card byt_cht_es8316_card = { .controls = byt_cht_es8316_controls, .num_controls = ARRAY_SIZE(byt_cht_es8316_controls), .fully_routed = true, + .suspend_pre = byt_cht_es8316_suspend, + .resume_post = byt_cht_es8316_resume, }; static const struct x86_cpu_id baytrail_cpu_ids[] = { @@ -282,8 +347,6 @@ static const struct x86_cpu_id baytrail_cpu_ids[] = { {} }; -static char codec_name[SND_ACPI_I2C_ID_LEN]; - static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { struct byt_cht_es8316_private *priv; From a917eea1e855bd20091a9afb1098d5c821cf1277 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:32 +0100 Subject: [PATCH 0604/1995] ASoC: Intel: bytcht_es8316: Add external speaker mux support The ES8316 only has a single (amplified) output. The ES8316 appnote showing the intended usage uses a jack-receptacle which physically disconnects the speakers from the output when a jack is plugged in. But all 3 devices using the es8316 which I have (2 Cherry Trail devices and one Bay Trail CR device), use an analog mux to disconnect the speakers, driven by a GPIO. This commit adds support for this, modelling this as a separate speaker widget / dapm pin-switch which sets the mux to drive the speakers when selected. The intend is for userspace to use the recently added jack-detect support and then automatically select either the Headphone or Speaker output based on that. Note this commit includes a workaround for an ACPI table bug which is present on 2 of the 3 devices I have, see the added comment in the code. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 0d3e91da0750835cfd5c16487ffb3cdd752ea53a) --- sound/soc/intel/boards/bytcht_es8316.c | 98 ++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 905dd690471076..8e504fca4624c8 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -19,8 +19,11 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include #include #include +#include +#include #include #include #include @@ -40,6 +43,8 @@ struct byt_cht_es8316_private { struct clk *mclk; struct snd_soc_jack jack; + struct gpio_desc *speaker_en_gpio; + bool speaker_en; }; #define BYT_CHT_ES8316_SSP0 BIT(16) @@ -56,7 +61,24 @@ static void log_quirks(struct device *dev) dev_info(dev, "quirk SSP0 enabled"); } +static int byt_cht_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_card *card = w->dapm->card; + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); + + if (SND_SOC_DAPM_EVENT_ON(event)) + priv->speaker_en = true; + else + priv->speaker_en = false; + + gpiod_set_value_cansleep(priv->speaker_en_gpio, priv->speaker_en); + + return 0; +} + static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), @@ -67,6 +89,10 @@ static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { */ SND_SOC_DAPM_MIC("Microphone 1", NULL), SND_SOC_DAPM_MIC("Microphone 2", NULL), + + SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, + byt_cht_es8316_speaker_power_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), }; static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { @@ -76,6 +102,14 @@ static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, + + /* + * There is no separate speaker output instead the speakers are muxed to + * the HP outputs. The mux is controlled by the "Speaker Power" supply. + */ + {"Speaker", NULL, "HPOL"}, + {"Speaker", NULL, "HPOR"}, + {"Speaker", NULL, "Speaker Power"}, }; static const struct snd_soc_dapm_route byt_cht_es8316_ssp0_map[] = { @@ -95,6 +129,7 @@ static const struct snd_soc_dapm_route byt_cht_es8316_ssp2_map[] = { }; static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Microphone 1"), @@ -323,6 +358,25 @@ static int byt_cht_es8316_resume(struct snd_soc_card *card) } } + /* + * Some Cherry Trail boards with an ES8316 codec have a bug in their + * ACPI tables where the MSSL1680 touchscreen's _PS0 and _PS3 methods + * wrongly also set the speaker-enable GPIO to 1/0. Testing has shown + * that this really is a bug and the GPIO has no influence on the + * touchscreen at all. + * + * The silead.c touchscreen driver does not support runtime suspend, so + * the GPIO can only be changed underneath us during a system suspend. + * This resume() function runs from a pm complete() callback, and thus + * is guaranteed to run after the touchscreen driver/ACPI-subsys has + * brought the touchscreen back up again (and thus changed the GPIO). + * + * So to work around this we pass GPIOD_FLAGS_BIT_NONEXCLUSIVE when + * requesting the GPIO and we set its value here to undo any changes + * done by the touchscreen's broken _PS0 ACPI method. + */ + gpiod_set_value_cansleep(priv->speaker_en_gpio, priv->speaker_en); + return 0; } @@ -347,12 +401,20 @@ static const struct x86_cpu_id baytrail_cpu_ids[] = { {} }; +static const struct acpi_gpio_params first_gpio = { 0, 0, false }; + +static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = { + { "speaker-enable-gpios", &first_gpio, 1 }, + { }, +}; + static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; const char *i2c_name = NULL; + struct device *codec_dev; int dai_index = 0; int i; int ret = 0; @@ -405,12 +467,39 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) return ret; } + /* get speaker enable GPIO */ + codec_dev = bus_find_device_by_name(&i2c_bus_type, NULL, codec_name); + if (!codec_dev) + return -EPROBE_DEFER; + + devm_acpi_dev_add_driver_gpios(codec_dev, byt_cht_es8316_gpios); + priv->speaker_en_gpio = + gpiod_get_index(codec_dev, "speaker-enable", 0, + /* see comment in byt_cht_es8316_resume */ + GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); + put_device(codec_dev); + + if (IS_ERR(priv->speaker_en_gpio)) { + ret = PTR_ERR(priv->speaker_en_gpio); + switch (ret) { + case -ENOENT: + priv->speaker_en_gpio = NULL; + break; + default: + dev_err(dev, "get speaker GPIO failed: %d\n", ret); + /* fall through */ + case -EPROBE_DEFER: + return ret; + } + } + /* register the soc card */ byt_cht_es8316_card.dev = dev; snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); ret = devm_snd_soc_register_card(dev, &byt_cht_es8316_card); if (ret) { + gpiod_put(priv->speaker_en_gpio); dev_err(dev, "snd_soc_register_card failed: %d\n", ret); return ret; } @@ -418,11 +507,20 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) return 0; } +static int snd_byt_cht_es8316_mc_remove(struct platform_device *pdev) +{ + struct byt_cht_es8316_private *priv = platform_get_drvdata(pdev); + + gpiod_put(priv->speaker_en_gpio); + return 0; +} + static struct platform_driver snd_byt_cht_es8316_mc_driver = { .driver = { .name = "bytcht_es8316", }, .probe = snd_byt_cht_es8316_mc_probe, + .remove = snd_byt_cht_es8316_mc_remove, }; module_platform_driver(snd_byt_cht_es8316_mc_driver); From 785190543411424d53804d3510390d3af13ef039 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:33 +0100 Subject: [PATCH 0605/1995] ASoC: Intel: bytcht_es8316: Add input-map support After adding jack-detect support we have 3 microphone input switches: "Microphone 1", "Microphone 2" and "Headset Mic". But the ES8316 has only 2 microphone inputs. In the app-note explaining how to use the codec and on the 3 boards I have one input is used for an internal microphone and one for the headset microphone. On the 2 CHT boards I have the internal mic is on on MIC1 and the headset mic is on MIC2, on the BYTCR board I have it is the other way around. This commit replaces the 2 "Microphone 1" and "Microphone 2" input switches with a single "Internal Mic" switch and adds support for selecting either possible input mapping. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 730501a91d94b652275e049e101ed44cdbfdf31b) --- sound/soc/intel/boards/bytcht_es8316.c | 58 ++++++++++++++++++-------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 8e504fca4624c8..941a66f94660e4 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -47,6 +47,12 @@ struct byt_cht_es8316_private { bool speaker_en; }; +enum { + BYT_CHT_ES8316_INTMIC_IN1_MAP, + BYT_CHT_ES8316_INTMIC_IN2_MAP, +}; + +#define BYT_CHT_ES8316_MAP(quirk) ((quirk) & GENMASK(3, 0)) #define BYT_CHT_ES8316_SSP0 BIT(16) static int quirk; @@ -57,6 +63,10 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override"); static void log_quirks(struct device *dev) { + if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN1_MAP) + dev_info(dev, "quirk IN1_MAP enabled"); + if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN2_MAP) + dev_info(dev, "quirk IN2_MAP enabled"); if (quirk & BYT_CHT_ES8316_SSP0) dev_info(dev, "quirk SSP0 enabled"); } @@ -81,14 +91,7 @@ static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { SND_SOC_DAPM_SPK("Speaker", NULL), SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), - - /* - * The codec supports two analog microphone inputs. I have only - * tested MIC1. A DMIC route could also potentially be added - * if such functionality is found on another platform. - */ - SND_SOC_DAPM_MIC("Microphone 1", NULL), - SND_SOC_DAPM_MIC("Microphone 2", NULL), + SND_SOC_DAPM_MIC("Internal Mic", NULL), SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, byt_cht_es8316_speaker_power_event, @@ -96,10 +99,6 @@ static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { }; static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { - {"MIC1", NULL, "Microphone 1"}, - {"MIC2", NULL, "Microphone 2"}, - {"MIC1", NULL, "Headset Mic"}, - {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, @@ -112,6 +111,16 @@ static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { {"Speaker", NULL, "Speaker Power"}, }; +static const struct snd_soc_dapm_route byt_cht_es8316_intmic_in1_map[] = { + {"MIC1", NULL, "Internal Mic"}, + {"MIC2", NULL, "Headset Mic"}, +}; + +static const struct snd_soc_dapm_route byt_cht_es8316_intmic_in2_map[] = { + {"MIC2", NULL, "Internal Mic"}, + {"MIC1", NULL, "Headset Mic"}, +}; + static const struct snd_soc_dapm_route byt_cht_es8316_ssp0_map[] = { {"Playback", NULL, "ssp0 Tx"}, {"ssp0 Tx", NULL, "modem_out"}, @@ -132,8 +141,7 @@ static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { SOC_DAPM_PIN_SWITCH("Speaker"), SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Microphone 1"), - SOC_DAPM_PIN_SWITCH("Microphone 2"), + SOC_DAPM_PIN_SWITCH("Internal Mic"), }; static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { @@ -158,6 +166,21 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) card->dapm.idle_bias_off = true; + switch (BYT_CHT_ES8316_MAP(quirk)) { + case BYT_CHT_ES8316_INTMIC_IN1_MAP: + default: + custom_map = byt_cht_es8316_intmic_in1_map; + num_routes = ARRAY_SIZE(byt_cht_es8316_intmic_in1_map); + break; + case BYT_CHT_ES8316_INTMIC_IN2_MAP: + custom_map = byt_cht_es8316_intmic_in2_map; + num_routes = ARRAY_SIZE(byt_cht_es8316_intmic_in2_map); + break; + } + ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + if (ret) + return ret; + if (quirk & BYT_CHT_ES8316_SSP0) { custom_map = byt_cht_es8316_ssp0_map; num_routes = ARRAY_SIZE(byt_cht_es8316_ssp0_map); @@ -444,10 +467,11 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) /* Check for BYTCR or other platform and setup quirks */ if (x86_match_cpu(baytrail_cpu_ids) && mach->mach_params.acpi_ipc_irq_index == 0) { - /* On BYTCR default to SSP0 */ - quirk = BYT_CHT_ES8316_SSP0; + /* On BYTCR default to SSP0, internal-mic-in2-map */ + quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP; } else { - quirk = 0; + /* Others default to internal-mic-in1-map */ + quirk = BYT_CHT_ES8316_INTMIC_IN1_MAP; } if (quirk_override != -1) { dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", quirk, From 09f9c2315d0712fe8d16a0191a085fa98074d609 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:34 +0100 Subject: [PATCH 0606/1995] ASoC: Intel: bytcht_es8316: Set card long_name based on quirks Depending on the input-map and on if 1 or 2 speakers are connected, userspace needs to use a different UCM profile. Since we already deal with quirks in the kernel driver and set the input-map from the kernel, add a quirk for devices with a single / mono speaker and set the card's long_name based on the input and speaker quirks, so that userspace can use the long_name to pick the right UCM profile. This change, including how the long_name is build-up mirrors how we do this in the bytcr_rt5640 and bytcr_rt5651 machine drivers. Note since all devices I have access to use a mono speaker setup I've chosen to default the speaker setting to mono. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 249d2fc9e55c324dda968252ea3ad0ac21c72b8f) --- sound/soc/intel/boards/bytcht_es8316.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 941a66f94660e4..cdf2061e7613d9 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -54,6 +54,7 @@ enum { #define BYT_CHT_ES8316_MAP(quirk) ((quirk) & GENMASK(3, 0)) #define BYT_CHT_ES8316_SSP0 BIT(16) +#define BYT_CHT_ES8316_MONO_SPEAKER BIT(17) static int quirk; @@ -69,6 +70,8 @@ static void log_quirks(struct device *dev) dev_info(dev, "quirk IN2_MAP enabled"); if (quirk & BYT_CHT_ES8316_SSP0) dev_info(dev, "quirk SSP0 enabled"); + if (quirk & BYT_CHT_ES8316_MONO_SPEAKER) + dev_info(dev, "quirk MONO_SPEAKER enabled\n"); } static int byt_cht_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, @@ -352,6 +355,7 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { /* SoC card */ static char codec_name[SND_ACPI_I2C_ID_LEN]; +static char long_name[50]; /* = "bytcht-es8316-*-spk-*-mic" */ static int byt_cht_es8316_suspend(struct snd_soc_card *card) { @@ -433,6 +437,7 @@ static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = { static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { + const char * const mic_name[] = { "in1", "in2" }; struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; @@ -467,11 +472,13 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) /* Check for BYTCR or other platform and setup quirks */ if (x86_match_cpu(baytrail_cpu_ids) && mach->mach_params.acpi_ipc_irq_index == 0) { - /* On BYTCR default to SSP0, internal-mic-in2-map */ - quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP; + /* On BYTCR default to SSP0, internal-mic-in2-map, mono-spk */ + quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP | + BYT_CHT_ES8316_MONO_SPEAKER; } else { - /* Others default to internal-mic-in1-map */ - quirk = BYT_CHT_ES8316_INTMIC_IN1_MAP; + /* Others default to internal-mic-in1-map, mono-speaker */ + quirk = BYT_CHT_ES8316_INTMIC_IN1_MAP | + BYT_CHT_ES8316_MONO_SPEAKER; } if (quirk_override != -1) { dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", quirk, @@ -518,6 +525,10 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) } /* register the soc card */ + snprintf(long_name, sizeof(long_name), "bytcht-es8316-%s-spk-%s-mic", + (quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "mono" : "stereo", + mic_name[BYT_CHT_ES8316_MAP(quirk)]); + byt_cht_es8316_card.long_name = long_name; byt_cht_es8316_card.dev = dev; snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); From 7a38e3bf69746c2c6f5578fb3e487d98fcd93e17 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:35 +0100 Subject: [PATCH 0607/1995] ASoC: Intel: Add ACPI match table entry for ES8316 codec on BYTCR platform Some BYTCR devices use an ES8316 codec, add an ACPI match table entry for this. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 5198baf8817d7e6e0fe2f3e74ea2ead714b74d9c) --- sound/soc/intel/common/soc-acpi-intel-byt-match.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 097dc06377baaf..47a90909b95689 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -154,6 +154,15 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .sof_tplg_filename = "intel/sof-byt-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, + { + .id = "ESSX8316", + .drv_name = "bytcht_es8316", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcht_es8316", + .sof_fw_filename = "intel/sof-byt.ri", + .sof_tplg_filename = "intel/sof-byt-es8316.tplg", + .asoc_plat_name = "sst-mfld-platform", + }, /* some Baytrail platforms rely on RT5645, use CHT machine driver */ { .id = "10EC5645", From 36b8b219c763ba43cccc624dd0d05c7dea426977 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 2 Jan 2019 20:39:03 +0100 Subject: [PATCH 0608/1995] ASoC: Intel: sst: Simplify is_byt_cr() is_byt_cr() and its usage can be simplified by returning the bool directly, instead of through a pointer. This works because the return value is just treated as bytcr = false and is not used otherwise. This patch also removes the extra check of IS_ENABLED(CONFIG_IOSF_MBI) in favor of checking iosf_mbi_available() directly. The header already takes care of returning false if the config option is not enabled. No functional change. Signed-off-by: Stephan Gerhold Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit b97205ef95efddee018061dfee14c995be08dde3) --- sound/soc/intel/atom/sst/sst_acpi.c | 33 ++++++++++++----------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 3a95ebbfc45d30..9eaac450f8649a 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -255,18 +255,15 @@ static int is_byt(void) return status; } -static int is_byt_cr(struct device *dev, bool *bytcr) +static bool is_byt_cr(struct device *dev) { int status = 0; - if (IS_ENABLED(CONFIG_IOSF_MBI)) { - u32 bios_status; - - if (!is_byt() || !iosf_mbi_available()) { - /* bail silently */ - return status; - } + if (!is_byt()) + return false; + if (iosf_mbi_available()) { + u32 bios_status; status = iosf_mbi_read(BT_MBI_UNIT_PMC, /* 0x04 PUNIT */ MBI_REG_READ, /* 0x10 */ 0x006, /* BIOS_CONFIG */ @@ -278,15 +275,17 @@ static int is_byt_cr(struct device *dev, bool *bytcr) /* bits 26:27 mirror PMIC options */ bios_status = (bios_status >> 26) & 3; - if ((bios_status == 1) || (bios_status == 3)) - *bytcr = true; - else - dev_info(dev, "BYT-CR not detected\n"); + if (bios_status == 1 || bios_status == 3) { + dev_info(dev, "Detected Baytrail-CR platform\n"); + return true; + } + + dev_info(dev, "BYT-CR not detected\n"); } } else { - dev_info(dev, "IOSF_MBI not enabled, no BYT-CR detection\n"); + dev_info(dev, "IOSF_MBI not available, no BYT-CR detection\n"); } - return status; + return false; } @@ -301,7 +300,6 @@ static int sst_acpi_probe(struct platform_device *pdev) struct platform_device *plat_dev; struct sst_platform_info *pdata; unsigned int dev_id; - bool bytcr = false; id = acpi_match_device(dev->driver->acpi_match_table, dev); if (!id) @@ -333,10 +331,7 @@ static int sst_acpi_probe(struct platform_device *pdev) if (ret < 0) return ret; - ret = is_byt_cr(dev, &bytcr); - if (!(ret < 0 || !bytcr)) { - dev_info(dev, "Detected Baytrail-CR platform\n"); - + if (is_byt_cr(dev)) { /* override resource info */ byt_rvp_platform_data.res_info = &bytcr_res_info; } From 36fdc9784757395015f69cd7f7a250ae819a79b4 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 2 Jan 2019 20:39:06 +0100 Subject: [PATCH 0609/1995] ASoC: Intel: sst: Fallback to BYT-CR if IRQ 5 is missing Some devices detected as BYT-T by the PMIC-type based detection have only a single IRQ listed in the 80860F28 ACPI device. This causes -ENXIO later when attempting to get the IRQ at index 5. It turns out these devices behave more like BYT-CR devices, and using the IRQ at index 0 makes sound work correctly. This patch adds a fallback for these devices to is_byt_cr(): If there is no IRQ resource at index 5, treating the device as BYT-T is guaranteed to fail later, so we can safely treat these devices as BYT-CR without breaking any working device. Link: http://mailman.alsa-project.org/pipermail/alsa-devel/2018-December/143176.html Signed-off-by: Stephan Gerhold Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit fee15714552dbf420264da6f88dd813b8502592b) --- sound/soc/intel/atom/sst/sst_acpi.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 9eaac450f8649a..ae17ce4677a5c0 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -255,8 +255,9 @@ static int is_byt(void) return status; } -static bool is_byt_cr(struct device *dev) +static bool is_byt_cr(struct platform_device *pdev) { + struct device *dev = &pdev->dev; int status = 0; if (!is_byt()) @@ -285,6 +286,17 @@ static bool is_byt_cr(struct device *dev) } else { dev_info(dev, "IOSF_MBI not available, no BYT-CR detection\n"); } + + if (platform_get_resource(pdev, IORESOURCE_IRQ, 5) == NULL) { + /* + * Some devices detected as BYT-T have only a single IRQ listed, + * causing platform_get_irq with index 5 to return -ENXIO. + * The correct IRQ in this case is at index 0, as on BYT-CR. + */ + dev_info(dev, "Falling back to Baytrail-CR platform\n"); + return true; + } + return false; } @@ -331,7 +343,7 @@ static int sst_acpi_probe(struct platform_device *pdev) if (ret < 0) return ret; - if (is_byt_cr(dev)) { + if (is_byt_cr(pdev)) { /* override resource info */ byt_rvp_platform_data.res_info = &bytcr_res_info; } From a1ebba549d660aecb86ebd085c62ec8e98d12856 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 2 Jan 2019 20:39:08 +0100 Subject: [PATCH 0610/1995] ASoC: Intel: bytcr_rt5640: Add quirks for ASUS MeMO Pad 7 (ME176C) Add quirks to select the correct input map, jack-detect options and channel map to make sound work on the ASUS MeMO Pad 7 (ME176C). Note: Although sound works out of the box, jack detection currently requires overriding the ACPI DSDT table. This is necessary because the rt5640 ACPI device (10EC5640) has the wrong GPIO listed as interrupt (one of the Bluetooth GPIOs). The correct GPIO is GPO2 0x0004 (listed as the first GPIO in the Intel(R) Audio Machine Driver - AMCR0F28 device). Signed-off-by: Stephan Gerhold Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 51a13e401a83ef37aa98c049c2c30bba885676c2) --- sound/soc/intel/boards/bytcr_rt5640.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index a22366ce33c403..ca8b4d5ff70f9f 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -428,6 +428,18 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF1 | BYT_RT5640_MCLK_EN), }, + { + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ME176C"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), From b1c061c2660a3e99adafa7549d8d01d4bd1b9c8a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:29 -0600 Subject: [PATCH 0611/1995] ASoC: dmic: declare trigger function as static No reason why this is global, fix warnings with W=1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 902d82222270c957d12fa2e9856484d600a88d20) --- sound/soc/codecs/dmic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index da921da50ef0fc..de041369e5a749 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -44,8 +44,8 @@ struct dmic { int modeswitch_delay; }; -int dmic_daiops_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) +static int dmic_daiops_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; struct dmic *dmic = snd_soc_component_get_drvdata(component); From 1464129293c0cc901cc48135f77dbce0c2f68864 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:30 -0600 Subject: [PATCH 0612/1995] ASoC: max98090: remove unused constant variables Fix warnings with W=1 If these variables are useful then this driver should be modified to expose them. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 97d8f6b71f56865e52d472247fe728700ef7128d) --- sound/soc/codecs/max98090.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index c97f21836c66a2..30c242c38d9960 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -314,9 +314,6 @@ static const DECLARE_TLV_DB_SCALE(max98090_av_tlv, -1200, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_dvg_tlv, 0, 600, 0); static const DECLARE_TLV_DB_SCALE(max98090_dv_tlv, -1500, 100, 0); -static const DECLARE_TLV_DB_SCALE(max98090_sidetone_tlv, -6050, 200, 0); - -static const DECLARE_TLV_DB_SCALE(max98090_alc_tlv, -1500, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_alcmakeup_tlv, 0, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_alccomp_tlv, -3100, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_drcexp_tlv, -6600, 100, 0); @@ -817,18 +814,6 @@ static SOC_ENUM_SINGLE_VIRT_DECL(dmic_mux_enum, dmic_mux_text); static const struct snd_kcontrol_new max98090_dmic_mux = SOC_DAPM_ENUM("DMIC Mux", dmic_mux_enum); -static const char *max98090_micpre_text[] = { "Off", "On" }; - -static SOC_ENUM_SINGLE_DECL(max98090_pa1en_enum, - M98090_REG_MIC1_INPUT_LEVEL, - M98090_MIC_PA1EN_SHIFT, - max98090_micpre_text); - -static SOC_ENUM_SINGLE_DECL(max98090_pa2en_enum, - M98090_REG_MIC2_INPUT_LEVEL, - M98090_MIC_PA2EN_SHIFT, - max98090_micpre_text); - /* LINEA mixer switch */ static const struct snd_kcontrol_new max98090_linea_mixer_controls[] = { SOC_DAPM_SINGLE("IN1 Switch", M98090_REG_LINE_INPUT_CONFIG, From a794a6edf094b4d3c8c56615a65b3252b5db437a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:31 -0600 Subject: [PATCH 0613/1995] ASoC: es8316: remove unused constant variables Fix warnings with W=1 If these variables are useful this driver should be modified to expose them. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 37b6f0350374e6c683bc2c2d8a54d4504bc04ec1) --- sound/soc/codecs/es8316.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 98464ba1046c18..6d4a323f786b00 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -167,8 +167,6 @@ static const char * const es8316_hpmux_texts[] = { "lin-rin with Boost and PGA" }; -static const unsigned int es8316_hpmux_values[] = { 0, 1, 2, 3 }; - static SOC_ENUM_SINGLE_DECL(es8316_left_hpmux_enum, ES8316_HPMIX_SEL, 4, es8316_hpmux_texts); @@ -199,8 +197,6 @@ static const char * const es8316_dacsrc_texts[] = { "RDATA TO LDAC, LDATA TO RDAC", }; -static const unsigned int es8316_dacsrc_values[] = { 0, 1, 2, 3 }; - static SOC_ENUM_SINGLE_DECL(es8316_dacsrc_mux_enum, ES8316_DAC_SET1, 6, es8316_dacsrc_texts); From 69fba497d1619a7f838c379d5b50d0ad4056624a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:32 -0600 Subject: [PATCH 0614/1995] ASoC: codecs: fix kernel doc descriptions Missing or spurious parameter descriptions. Fix warnings with W=1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit dc22a4093f5d2973bef5f72b00da74ce61458bc0) --- sound/soc/codecs/nau8825.c | 1 + sound/soc/codecs/rt5514.c | 1 + sound/soc/codecs/rt5677.c | 8 ++++---- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 7bbcbf5f05c887..47e65cf9987925 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -351,6 +351,7 @@ static void nau8825_hpvol_ramp(struct nau8825 *nau8825, * Computes log10 of a value; the result is round off to 3 decimal. This func- * tion takes reference to dvb-math. The source code locates as the following. * Linux/drivers/media/dvb-core/dvb_math.c + * @value: input for log10 * * return log10(value) * 1000 */ diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index a67de68b6da6c6..f9ad6e36ab16bc 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -489,6 +489,7 @@ static const struct snd_kcontrol_new rt5514_sto2_dmic_mux = /** * rt5514_calc_dmic_clk - Calculate the frequency divider parameter of dmic. * + * @component: only used for dev_warn * @rate: base clock rate. * * Choose divider parameter that gives the highest possible DMIC frequency in diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 9b7a1833d3316c..6fc70e441458de 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -547,7 +547,7 @@ static bool rt5677_readable_register(struct device *dev, unsigned int reg) * @rt5677: Private Data. * @addr: Address index. * @value: Address data. - * + * @opcode: opcode value * * Returns 0 for success or negative error code. */ @@ -602,7 +602,7 @@ static int rt5677_dsp_mode_i2c_write_addr(struct rt5677_priv *rt5677, /** * rt5677_dsp_mode_i2c_read_addr - Read value from address on DSP mode. - * rt5677: Private Data. + * @rt5677: Private Data. * @addr: Address index. * @value: Address data. * @@ -651,7 +651,7 @@ static int rt5677_dsp_mode_i2c_read_addr( /** * rt5677_dsp_mode_i2c_write - Write register on DSP mode. - * rt5677: Private Data. + * @rt5677: Private Data. * @reg: Register index. * @value: Register data. * @@ -667,7 +667,7 @@ static int rt5677_dsp_mode_i2c_write(struct rt5677_priv *rt5677, /** * rt5677_dsp_mode_i2c_read - Read register on DSP mode. - * @codec: SoC audio codec device. + * @rt5677: Private Data * @reg: Register index. * @value: Register data. * From bc15e5ed56f90e6ed92a3c339b0d099881306d3c Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 4 Jan 2019 20:02:33 -0600 Subject: [PATCH 0615/1995] ASoC: rt5645: remove unused mux define rt5645_if3_adc_in_mux, rt5645_inr_mux, and rt5645_inl_mux are not used. Remove them from the driver. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit c3db21324442137552041711a878d75358c993ae) --- sound/soc/codecs/rt5645.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index be674688dc4061..52ce380c8f3ac6 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -1288,30 +1288,6 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5645_dac_r2_mux = SOC_DAPM_ENUM("DAC2 R source", rt5645_dac2r_enum); - -/* INL/R source */ -static const char * const rt5645_inl_src[] = { - "IN2P", "MonoP" -}; - -static SOC_ENUM_SINGLE_DECL( - rt5645_inl_enum, RT5645_INL1_INR1_VOL, - RT5645_INL_SEL_SFT, rt5645_inl_src); - -static const struct snd_kcontrol_new rt5645_inl_mux = - SOC_DAPM_ENUM("INL source", rt5645_inl_enum); - -static const char * const rt5645_inr_src[] = { - "IN2N", "MonoN" -}; - -static SOC_ENUM_SINGLE_DECL( - rt5645_inr_enum, RT5645_INL1_INR1_VOL, - RT5645_INR_SEL_SFT, rt5645_inr_src); - -static const struct snd_kcontrol_new rt5645_inr_mux = - SOC_DAPM_ENUM("INR source", rt5645_inr_enum); - /* Stereo1 ADC source */ /* MX-27 [12] */ static const char * const rt5645_stereo_adc1_src[] = { @@ -1611,18 +1587,6 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5645_if2_adc_in_mux = SOC_DAPM_ENUM("IF2 ADC IN source", rt5645_if2_adc_in_enum); -/* MX-2F [1:0] */ -static const char * const rt5645_if3_adc_in_src[] = { - "IF_ADC1", "IF_ADC2", "VAD_ADC" -}; - -static SOC_ENUM_SINGLE_DECL( - rt5645_if3_adc_in_enum, RT5645_DIG_INF1_DATA, - RT5645_IF3_ADC_IN_SFT, rt5645_if3_adc_in_src); - -static const struct snd_kcontrol_new rt5645_if3_adc_in_mux = - SOC_DAPM_ENUM("IF3 ADC IN source", rt5645_if3_adc_in_enum); - /* MX-31 [15] [13] [11] [9] */ static const char * const rt5645_pdm_src[] = { "Mono DAC", "Stereo DAC" From 580f7b39ceefcdee89528efde4e85ba943051c05 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 4 Jan 2019 20:02:34 -0600 Subject: [PATCH 0616/1995] ASoC: rt5670: remove unused mux/mixer define Some mux/mixer are not used. Remove them from the driver. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 6606f9df60bcb632e047e0f8a268e327cebcc3db) --- sound/soc/codecs/rt5670.c | 54 --------------------------------------- 1 file changed, 54 deletions(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 453328c988c0cf..9a037108b1aea5 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -1057,20 +1057,6 @@ static const struct snd_kcontrol_new rt5670_lout_mix[] = { RT5670_M_OV_R_LM_SFT, 1, 1), }; -static const struct snd_kcontrol_new rt5670_hpl_mix[] = { - SOC_DAPM_SINGLE("DAC L1 Switch", RT5670_HPO_MIXER, - RT5670_M_DACL1_HML_SFT, 1, 1), - SOC_DAPM_SINGLE("INL1 Switch", RT5670_HPO_MIXER, - RT5670_M_INL1_HML_SFT, 1, 1), -}; - -static const struct snd_kcontrol_new rt5670_hpr_mix[] = { - SOC_DAPM_SINGLE("DAC R1 Switch", RT5670_HPO_MIXER, - RT5670_M_DACR1_HMR_SFT, 1, 1), - SOC_DAPM_SINGLE("INR1 Switch", RT5670_HPO_MIXER, - RT5670_M_INR1_HMR_SFT, 1, 1), -}; - static const struct snd_kcontrol_new lout_l_enable_control = SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5670_LOUT1, RT5670_L_MUTE_SFT, 1, 1); @@ -1196,24 +1182,6 @@ static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc2_enum, RT5670_STO2_ADC_MIXER, static const struct snd_kcontrol_new rt5670_sto2_adc_2_mux = SOC_DAPM_ENUM("Stereo2 ADC 2 Mux", rt5670_stereo2_adc2_enum); - -/* MX-27 MX26 [10] */ -static const char * const rt5670_stereo_adc_src[] = { - "ADC1L ADC2R", "ADC3" -}; - -static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_adc_enum, RT5670_STO1_ADC_MIXER, - RT5670_ADC_SRC_SFT, rt5670_stereo_adc_src); - -static const struct snd_kcontrol_new rt5670_sto_adc_mux = - SOC_DAPM_ENUM("Stereo1 ADC source", rt5670_stereo1_adc_enum); - -static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc_enum, RT5670_STO2_ADC_MIXER, - RT5670_ADC_SRC_SFT, rt5670_stereo_adc_src); - -static const struct snd_kcontrol_new rt5670_sto2_adc_mux = - SOC_DAPM_ENUM("Stereo2 ADC source", rt5670_stereo2_adc_enum); - /* MX-27 MX-26 [9:8] */ static const char * const rt5670_stereo_dmic_src[] = { "DMIC1", "DMIC2", "DMIC3" @@ -1231,17 +1199,6 @@ static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_dmic_enum, RT5670_STO2_ADC_MIXER, static const struct snd_kcontrol_new rt5670_sto2_dmic_mux = SOC_DAPM_ENUM("Stereo2 DMIC source", rt5670_stereo2_dmic_enum); -/* MX-27 [0] */ -static const char * const rt5670_stereo_dmic3_src[] = { - "DMIC3", "PDM ADC" -}; - -static SOC_ENUM_SINGLE_DECL(rt5670_stereo_dmic3_enum, RT5670_STO1_ADC_MIXER, - RT5670_DMIC3_SRC_SFT, rt5670_stereo_dmic3_src); - -static const struct snd_kcontrol_new rt5670_sto_dmic3_mux = - SOC_DAPM_ENUM("Stereo DMIC3 source", rt5670_stereo_dmic3_enum); - /* Mono ADC source */ /* MX-28 [12] */ static const char * const rt5670_mono_adc_l1_src[] = { @@ -1334,17 +1291,6 @@ static SOC_ENUM_SINGLE_DECL(rt5670_if2_adc_in_enum, RT5670_DIG_INF1_DATA, static const struct snd_kcontrol_new rt5670_if2_adc_in_mux = SOC_DAPM_ENUM("IF2 ADC IN source", rt5670_if2_adc_in_enum); -/* MX-30 [5:4] */ -static const char * const rt5670_if4_adc_in_src[] = { - "IF_ADC1", "IF_ADC2", "IF_ADC3" -}; - -static SOC_ENUM_SINGLE_DECL(rt5670_if4_adc_in_enum, RT5670_DIG_INF2_DATA, - RT5670_IF4_ADC_IN_SFT, rt5670_if4_adc_in_src); - -static const struct snd_kcontrol_new rt5670_if4_adc_in_mux = - SOC_DAPM_ENUM("IF4 ADC IN source", rt5670_if4_adc_in_enum); - /* MX-31 [15] [13] [11] [9] */ static const char * const rt5670_pdm_src[] = { "Mono DAC", "Stereo DAC" From a47303e05f29998e66785b3d42028c40bf88cf77 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:35 -0600 Subject: [PATCH 0617/1995] ASoC: max98383: fix boolean assignments to true/false Reported by Coccinelle: sound/soc/codecs/max98373.c:411:2-20: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98373.c:922:2-27: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98373.c:924:2-27: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7c3727ba7de2b94a066e38776660e648fa4ed28a) --- sound/soc/codecs/max98373.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 9c8616a7b61c9d..528695cd6a1ca7 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -408,7 +408,7 @@ static int max98373_dac_event(struct snd_soc_dapm_widget *w, regmap_update_bits(max98373->regmap, MAX98373_R20FF_GLOBAL_SHDN, MAX98373_GLOBAL_EN_MASK, 0); - max98373->tdm_mode = 0; + max98373->tdm_mode = false; break; default: return 0; @@ -919,9 +919,9 @@ static int max98373_i2c_probe(struct i2c_client *i2c, /* update interleave mode info */ if (device_property_read_bool(&i2c->dev, "maxim,interleave_mode")) - max98373->interleave_mode = 1; + max98373->interleave_mode = true; else - max98373->interleave_mode = 0; + max98373->interleave_mode = false; /* regmap initialization */ From d5b6052ca015ecaa19d8c6daafeaccde02395ebb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:37 -0600 Subject: [PATCH 0618/1995] ASoC: cs4271: fix boolean assignments Reported by Coccinelle: sound/soc/codecs/cs4271.c:226:2-16: WARNING: Assignment of bool to 0/1 sound/soc/codecs/cs4271.c:229:2-16: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 3c17bcfd35bca1bee34709e7509646b5bc88643f) --- sound/soc/codecs/cs4271.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 849fdb2cb26043..1104830edaf83d 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -223,10 +223,10 @@ static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai, switch (format & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: - cs4271->master = 0; + cs4271->master = false; break; case SND_SOC_DAIFMT_CBM_CFM: - cs4271->master = 1; + cs4271->master = true; val |= CS4271_MODE1_MASTER; break; default: From 65c100805f02063cd5e52f7ba4c1c713f8c667bc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:38 -0600 Subject: [PATCH 0619/1995] ASoC: rt274: fix boolean tests Reported by Coccinelle: sound/soc/codecs/rt274.c:958:6-8: WARNING: Comparison to bool sound/soc/codecs/rt274.c:961:6-9: WARNING: Comparison to bool sound/soc/codecs/rt274.c:384:5-7: WARNING: Comparison to bool sound/soc/codecs/rt274.c:387:5-8: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit b793a1e4ebad5c9066f404dee13fec875fb9b4e5) --- sound/soc/codecs/rt274.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index e2855ab9a2c6b5..9e88f7b25d3808 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -381,10 +381,10 @@ static void rt274_jack_detect_work(struct work_struct *work) if (rt274_jack_detect(rt274, &hp, &mic) < 0) return; - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt274->jack, status, @@ -955,10 +955,10 @@ static irqreturn_t rt274_irq(int irq, void *data) ret = rt274_jack_detect(rt274, &hp, &mic); if (ret == 0) { - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt274->jack, status, From 8e2408cdbe40c7921ce74c47e3b3a7efcc5692b4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:39 -0600 Subject: [PATCH 0620/1995] ASoc: rt286: fix boolean tests Reported by Coccinelle: sound/soc/codecs/rt286.c:927:5-7: WARNING: Comparison to bool sound/soc/codecs/rt286.c:930:5-8: WARNING: Comparison to bool sound/soc/codecs/rt286.c:299:5-7: WARNING: Comparison to bool sound/soc/codecs/rt286.c:302:5-8: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit af3b2b54cb294b997ad9a2a88ed3c6c9af7d03c0) --- sound/soc/codecs/rt286.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 0b0f748bffbe70..c9457c247a03ca 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -296,10 +296,10 @@ static void rt286_jack_detect_work(struct work_struct *work) rt286_jack_detect(rt286, &hp, &mic); - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt286->jack, status, @@ -924,10 +924,10 @@ static irqreturn_t rt286_irq(int irq, void *data) /* Clear IRQ */ regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x1, 0x1); - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt286->jack, status, From ec07a001c438e10eed4606b275a19fcbc34b9068 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:40 -0600 Subject: [PATCH 0621/1995] ASoC: rt5640: fix boolean assignments Reported by Coccinelle: sound/soc/codecs/rt5640.c:980:2-17: WARNING: Assignment of bool to 0/1 sound/soc/codecs/rt5640.c:984:2-17: WARNING: Assignment of bool to 0/1 sound/soc/codecs/rt5640.c:2825:1-16: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit e0a99927ff5f395f24e09e6297858cd2006793f7) --- sound/soc/codecs/rt5640.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index fc530481a6e476..b3580ecadecf5b 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -977,11 +977,11 @@ static int rt5640_hp_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: rt5640_pmu_depop(component); - rt5640->hp_mute = 0; + rt5640->hp_mute = false; break; case SND_SOC_DAPM_PRE_PMD: - rt5640->hp_mute = 1; + rt5640->hp_mute = true; msleep(70); break; @@ -2822,7 +2822,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5640->regmap, RT5640_DUMMY1, RT5640_MCLK_DET, RT5640_MCLK_DET); - rt5640->hp_mute = 1; + rt5640->hp_mute = true; rt5640->irq = i2c->irq; INIT_DELAYED_WORK(&rt5640->bp_work, rt5640_button_press_work); INIT_WORK(&rt5640->jack_work, rt5640_jack_work); From 572dbdcf4f09a4a037ae1630b04a430f612bf84c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:41 -0600 Subject: [PATCH 0622/1995] ASoC: max98927: fix boolean assignments Reported by Coccinelle: sound/soc/codecs/max98927.c:508:2-20: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98927.c:889:3-28: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98927.c:891:3-28: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98927.c:893:2-27: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 091cd877d8d6b2b934d565134172db771907d50a) --- sound/soc/codecs/max98927.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index 065303a465359b..e53d2007f3be77 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -505,7 +505,7 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - max98927->tdm_mode = 0; + max98927->tdm_mode = false; break; case SND_SOC_DAPM_POST_PMU: regmap_update_bits(max98927->regmap, @@ -886,11 +886,11 @@ static int max98927_i2c_probe(struct i2c_client *i2c, if (!of_property_read_u32(i2c->dev.of_node, "interleave_mode", &value)) { if (value > 0) - max98927->interleave_mode = 1; + max98927->interleave_mode = true; else - max98927->interleave_mode = 0; + max98927->interleave_mode = false; } else - max98927->interleave_mode = 0; + max98927->interleave_mode = false; /* regmap initialization */ max98927->regmap From 416312613f7ccc8332117245ce04816d42cd4c65 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:42 -0600 Subject: [PATCH 0623/1995] ASoC: rt5651: fix boolean assignments Reported by Coccinelle: sound/soc/codecs/rt5651.c:750:2-17: WARNING: Assignment of bool to 0/1 sound/soc/codecs/rt5651.c:754:2-17: WARNING: Assignment of bool to 0/1 sound/soc/codecs/rt5651.c:2192:1-16: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 577dc32f9a6fc20cd404e0eb965659e9271c78be) --- sound/soc/codecs/rt5651.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index b7ba64350a07cc..3882e238ff99f0 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -747,11 +747,11 @@ static int rt5651_hp_event(struct snd_soc_dapm_widget *w, RT5651_HP_CP_PD | RT5651_HP_SG_EN); regmap_update_bits(rt5651->regmap, RT5651_PR_BASE + RT5651_CHPUMP_INT_REG1, 0x0700, 0x0400); - rt5651->hp_mute = 0; + rt5651->hp_mute = false; break; case SND_SOC_DAPM_PRE_PMD: - rt5651->hp_mute = 1; + rt5651->hp_mute = true; usleep_range(70000, 75000); break; @@ -2189,7 +2189,7 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); rt5651->irq = i2c->irq; - rt5651->hp_mute = 1; + rt5651->hp_mute = true; INIT_DELAYED_WORK(&rt5651->bp_work, rt5651_button_press_work); INIT_WORK(&rt5651->jack_detect_work, rt5651_jack_detect_work); From fe0aa27966dc65366935dcf80dad37a198eec42b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:43 -0600 Subject: [PATCH 0624/1995] ASoC: nau8824: fix boolean assignment Reported by Coccinelle: nau8824.c:810:6-12: ERROR: Assignment of bool to non-0/1 constant Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 290da7a7e349566f0e1541b14f25b722f58f236b) --- sound/soc/codecs/nau8824.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index 468d5143e2c4f7..87ed3dc496dc2d 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -807,7 +807,7 @@ static const struct snd_soc_dapm_route nau8824_dapm_routes[] = { static bool nau8824_is_jack_inserted(struct nau8824 *nau8824) { struct snd_soc_jack *jack = nau8824->jack; - bool insert = FALSE; + bool insert = false; if (nau8824->irq && jack) insert = jack->status & SND_JACK_HEADPHONE; From 13dd53caccfe072a0fd88515345a0fbdc3dcd477 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:44 -0600 Subject: [PATCH 0625/1995] ASoC: tscs42xx.c: fix boolean test Reported by Coccinelle: sound/soc/codecs/tscs42xx.c:392:5-31: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit f361ca36802031ae3abf9860a02e1d5931c04b63) --- sound/soc/codecs/tscs42xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c index 7396a6e5277e68..27b8c6ba72fa87 100644 --- a/sound/soc/codecs/tscs42xx.c +++ b/sound/soc/codecs/tscs42xx.c @@ -389,7 +389,7 @@ static int dac_event(struct snd_soc_dapm_widget *w, mutex_lock(&tscs42xx->coeff_ram_lock); - if (tscs42xx->coeff_ram_synced == false) { + if (!tscs42xx->coeff_ram_synced) { ret = write_coeff_ram(component, tscs42xx->coeff_ram, 0x00, COEFF_RAM_COEFF_COUNT); if (ret < 0) From 46cafa49924d8d3dc0beef25d8255969c171f266 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:45 -0600 Subject: [PATCH 0626/1995] ASoC: mt6351: remove unneeded variable Reported by Coccinelle: mt6351.c:1418:5-8: Unneeded variable: "ret". Return "0" on line 1437 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit d61780c155e8bef8dceb3ac98d29f79c24e264eb) --- sound/soc/codecs/mt6351.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/mt6351.c b/sound/soc/codecs/mt6351.c index f73dcd753584f5..4b3ce01c5a93b6 100644 --- a/sound/soc/codecs/mt6351.c +++ b/sound/soc/codecs/mt6351.c @@ -1415,8 +1415,6 @@ static const struct snd_soc_dapm_route mt6351_dapm_routes[] = { static int mt6351_codec_init_reg(struct snd_soc_component *cmpnt) { - int ret = 0; - /* Disable CLKSQ 26MHz */ regmap_update_bits(cmpnt->regmap, MT6351_TOP_CLKSQ, 0x0001, 0x0); /* disable AUDGLB */ @@ -1434,7 +1432,7 @@ static int mt6351_codec_init_reg(struct snd_soc_component *cmpnt) /* Reverse the PMIC clock*/ regmap_update_bits(cmpnt->regmap, MT6351_AFE_PMIC_NEWIF_CFG2, 0x8000, 0x8000); - return ret; + return 0; } static int mt6351_codec_probe(struct snd_soc_component *cmpnt) From 7b54b92127c75f5853183f402fc8bb276e5c648c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:46 -0600 Subject: [PATCH 0627/1995] ASoC: da7219: fix endianness issues Reported by Sparse. da7219.c:440:44: warning: cast to restricted __le16 da7219.c:461:13: warning: incorrect type in assignment (different base types) da7219.c:461:13: expected unsigned short [unsigned] [usertype] val da7219.c:461:13: got restricted __le16 [usertype] da7219.c:1451:16: warning: incorrect type in assignment (different base types) da7219.c:1451:16: expected unsigned short [unsigned] [usertype] offset da7219.c:1451:16: got restricted __le16 [usertype] da7219-aad.c:150:37: warning: incorrect type in assignment (different base types) da7219-aad.c:150:37: expected unsigned short [unsigned] [usertype] tonegen_freq_hptest da7219-aad.c:150:37: got restricted __le16 [usertype] da7219-aad.c:157:37: warning: incorrect type in assignment (different base types) da7219-aad.c:157:37: expected unsigned short [unsigned] [usertype] tonegen_freq_hptest da7219-aad.c:157:37: got restricted __le16 [usertype] Cc: Adam Thomson Signed-off-by: Pierre-Louis Bossart Reviewed-by: Adam Thomson Signed-off-by: Mark Brown (cherry picked from commit 123c3def3bc5ea9958b8191d8139f610ed972d18) --- sound/soc/codecs/da7219-aad.c | 2 +- sound/soc/codecs/da7219.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index 2c7d5088e6f275..e0964b20a38993 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -117,7 +117,7 @@ static void da7219_aad_hptest_work(struct work_struct *work) struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - u16 tonegen_freq_hptest; + __le16 tonegen_freq_hptest; u8 pll_srm_sts, pll_ctrl, gain_ramp_ctrl, accdet_cfg8; int report = 0, ret = 0; diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index e46e9f4bc99468..ce165047b9f936 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -423,7 +423,7 @@ static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mixer_ctrl = (struct soc_mixer_control *) kcontrol->private_value; unsigned int reg = mixer_ctrl->reg; - u16 val; + __le16 val; int ret; mutex_lock(&da7219->ctrl_lock); @@ -450,7 +450,7 @@ static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mixer_ctrl = (struct soc_mixer_control *) kcontrol->private_value; unsigned int reg = mixer_ctrl->reg; - u16 val; + __le16 val; int ret; /* @@ -1396,7 +1396,7 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, struct snd_soc_component *component = dai->component; struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); u8 dai_bclks_per_wclk; - u16 offset; + __le16 offset; u32 frame_size; /* No channels enabled so disable TDM, revert to 64-bit frames */ From 0ec366539f3b6e35f68e00c4c573d5e805b2f7c8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:47 -0600 Subject: [PATCH 0628/1995] ASoC: da7219: use logical AND Reported by Sparse: da7219.c:841:57: warning: dubious: x & !y Cc: Adam Thomson Signed-off-by: Pierre-Louis Bossart Reviewed-by: Adam Thomson Signed-off-by: Mark Brown (cherry picked from commit b468f379e1e01b723825267431d3ba60f824fda2) --- sound/soc/codecs/da7219.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index ce165047b9f936..513ec036865363 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -838,7 +838,7 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w, ++i; msleep(50); } - } while ((i < DA7219_SRM_CHECK_RETRIES) & (!srm_lock)); + } while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock)); if (!srm_lock) dev_warn(component->dev, "SRM failed to lock\n"); From 0b0c7a5b5cfc89e9d74b91e07647316b2f2d98cf Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 4 Jan 2019 20:02:48 -0600 Subject: [PATCH 0629/1995] ASoC: rt5645: store eq kcontrol byte in __be The eq parameters binary is stored in __be. However, it is unsigned short in rt5645_eq_param_s{} which will cause incorrect type assignment. So add struct rt5645_eq_param_s_be16{} to store the eq binary and convert it to unsigned short in rt5645->eq_param. Cc: Oder Chiou Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 60b52ed627213d1782e70b9810f5668f61bba3a8) --- sound/soc/codecs/rt5645.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 52ce380c8f3ac6..9a0751978090a2 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -401,6 +401,11 @@ struct rt5645_eq_param_s { unsigned short val; }; +struct rt5645_eq_param_s_be16 { + __be16 reg; + __be16 val; +}; + static const char *const rt5645_supply_names[] = { "avdd", "cpvdd", @@ -672,8 +677,8 @@ static int rt5645_hweq_get(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component); - struct rt5645_eq_param_s *eq_param = - (struct rt5645_eq_param_s *)ucontrol->value.bytes.data; + struct rt5645_eq_param_s_be16 *eq_param = + (struct rt5645_eq_param_s_be16 *)ucontrol->value.bytes.data; int i; for (i = 0; i < RT5645_HWEQ_NUM; i++) { @@ -698,36 +703,33 @@ static int rt5645_hweq_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component); - struct rt5645_eq_param_s *eq_param = - (struct rt5645_eq_param_s *)ucontrol->value.bytes.data; + struct rt5645_eq_param_s_be16 *eq_param = + (struct rt5645_eq_param_s_be16 *)ucontrol->value.bytes.data; int i; for (i = 0; i < RT5645_HWEQ_NUM; i++) { - eq_param[i].reg = be16_to_cpu(eq_param[i].reg); - eq_param[i].val = be16_to_cpu(eq_param[i].val); + rt5645->eq_param[i].reg = be16_to_cpu(eq_param[i].reg); + rt5645->eq_param[i].val = be16_to_cpu(eq_param[i].val); } /* The final setting of the table should be RT5645_EQ_CTRL2 */ for (i = RT5645_HWEQ_NUM - 1; i >= 0; i--) { - if (eq_param[i].reg == 0) + if (rt5645->eq_param[i].reg == 0) continue; - else if (eq_param[i].reg != RT5645_EQ_CTRL2) + else if (rt5645->eq_param[i].reg != RT5645_EQ_CTRL2) return 0; else break; } for (i = 0; i < RT5645_HWEQ_NUM; i++) { - if (!rt5645_validate_hweq(eq_param[i].reg) && - eq_param[i].reg != 0) + if (!rt5645_validate_hweq(rt5645->eq_param[i].reg) && + rt5645->eq_param[i].reg != 0) return 0; - else if (eq_param[i].reg == 0) + else if (rt5645->eq_param[i].reg == 0) break; } - memcpy(rt5645->eq_param, eq_param, - RT5645_HWEQ_NUM * sizeof(struct rt5645_eq_param_s)); - return 0; } From d0be29b75f12607b931f94c5fe184835138cc6ce Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 4 Jan 2019 20:02:49 -0600 Subject: [PATCH 0630/1995] ASoC: rl6437a: use __be32 for a __be32 buf The buf in rl6347a_hw_read is __be32. Cc: Oder Chiou Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit b8e022e83ba99a0deb27e929033008402f863dd7) --- sound/soc/codecs/rl6347a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rl6347a.c b/sound/soc/codecs/rl6347a.c index 8f571cf8edd4d0..c0d729b4527724 100644 --- a/sound/soc/codecs/rl6347a.c +++ b/sound/soc/codecs/rl6347a.c @@ -64,8 +64,8 @@ int rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value) struct i2c_client *client = context; struct i2c_msg xfer[2]; int ret; - __be32 be_reg; - unsigned int index, vid, buf = 0x0; + __be32 be_reg, buf = 0x0; + unsigned int index, vid; /* handle index registers */ if (reg <= 0xff) { From 6b911fc1a36a5b6376d086220496023a6d9cc8a1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:36 -0600 Subject: [PATCH 0631/1995] ASoC: rt298: fix boolean tests Reported by Coccinelle: sound/soc/codecs/rt298.c:992:6-8: WARNING: Comparison to bool sound/soc/codecs/rt298.c:995:6-9: WARNING: Comparison to bool sound/soc/codecs/rt298.c:317:5-7: WARNING: Comparison to bool sound/soc/codecs/rt298.c:320:5-8: WARNING: Comparison to bool sound/soc/codecs/rt298.c:348:5-7: WARNING: Comparison to bool sound/soc/codecs/rt298.c:351:5-8: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit f0627d006047299e427f026942fed22b111f04f5) --- sound/soc/codecs/rt298.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index 06cdba4edfe2cd..bcf5bab3196916 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -314,10 +314,10 @@ static void rt298_jack_detect_work(struct work_struct *work) if (rt298_jack_detect(rt298, &hp, &mic) < 0) return; - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt298->jack, status, @@ -345,10 +345,10 @@ int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *j regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2); rt298_jack_detect(rt298, &hp, &mic); - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt298->jack, status, @@ -989,10 +989,10 @@ static irqreturn_t rt298_irq(int irq, void *data) regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x1, 0x1); if (ret == 0) { - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt298->jack, status, From 1ab9e40953e563359d8e0a8bd732703623d050ed Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Tue, 25 Dec 2018 20:29:48 -0600 Subject: [PATCH 0632/1995] ASoC: atom: fix a missing check of snd_pcm_lib_malloc_pages snd_pcm_lib_malloc_pages() may fail, so let's check its status and return its error code upstream. Signed-off-by: Kangjie Lu Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown Cc: stable@vger.kernel.org (cherry picked from commit 44fabd8cdaaa3acb80ad2bb3b5c61ae2136af661) --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index aefa5ce4cb592e..b0873fea23ab4e 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -399,7 +399,13 @@ static int sst_media_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); + int ret; + + ret = + snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(params)); + if (ret) + return ret; memset(substream->runtime->dma_area, 0, params_buffer_bytes(params)); return 0; } From 689440a261ea09f32465e8aa598e22404d4e8606 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:19 +0100 Subject: [PATCH 0633/1995] ASoC: Intel: common: Add quirk for PoV P1006W tablet The Point of View TAB-P1006W-232 (v1.0) tablet uses 10EC5640 as ACPI HID, but it has a rt5651 codec add a quirk for this. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit d3dcc5882ca95c9207b5232395c291d34a511627) --- .../intel/common/soc-acpi-intel-byt-match.c | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 47a90909b95689..96f9c553fe6c9f 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -21,6 +21,7 @@ static unsigned long byt_machine_id; #define BYT_THINKPAD_10 1 +#define BYT_POV_P1006W 2 static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id) { @@ -28,6 +29,11 @@ static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id) return 1; } +static int byt_pov_p1006w_quirk_cb(const struct dmi_system_id *id) +{ + byt_machine_id = BYT_POV_P1006W; + return 1; +} static const struct dmi_system_id byt_table[] = { { @@ -58,6 +64,17 @@ static const struct dmi_system_id byt_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Miix 2 10"), }, }, + { + /* Point of View mobii wintab p1006w (v1.0) */ + .callback = byt_pov_p1006w_quirk_cb, + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "BayTrail"), + /* Note 105b is Foxcon's USB/PCI vendor id */ + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "105B"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"), + }, + }, { } }; @@ -71,16 +88,30 @@ static struct snd_soc_acpi_mach byt_thinkpad_10 = { .asoc_plat_name = "sst-mfld-platform", }; +static struct snd_soc_acpi_mach byt_pov_p1006w = { + .id = "10EC5640", + .drv_name = "bytcr_rt5651", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcr_rt5651", + .sof_fw_filename = "intel/sof-byt.ri", + .sof_tplg_filename = "intel/sof-byt-rt5651.tplg", + .asoc_plat_name = "sst-mfld-platform", +}; + static struct snd_soc_acpi_mach *byt_quirk(void *arg) { struct snd_soc_acpi_mach *mach = arg; dmi_check_system(byt_table); - if (byt_machine_id == BYT_THINKPAD_10) + switch (byt_machine_id) { + case BYT_THINKPAD_10: return &byt_thinkpad_10; - else + case BYT_POV_P1006W: + return &byt_pov_p1006w; + default: return mach; + } } struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_legacy_machines[] = { From 460a2831e47c14f94ad4fa06ae18af6b0648a6a5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:20 +0100 Subject: [PATCH 0634/1995] ASoC: rt5651: Add ACPI ID 10EC5640 Some BYT platforms have a RT5651 codec while using an ACPI node with a HID of 10EC5640 to describe the coded. Add the 10EC5640 HID to the acpi_device_id list, so that the rt5651 will bind to the codec on these devices. Like the rt5645 and rt5670 drivers which also have the 10EC5640 ACPI HID in their acpi_device_id list for similar reasons, the rt5651 driver checks the codecs device-id register so that it will only bind if the codec actually is a rt5651 and it will ignore actual rt5640 codecs. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit d306873589c5a4c13df7176cd73d66ebfa690064) --- sound/soc/codecs/rt5651.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 3882e238ff99f0..9a007c16263161 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -2138,6 +2138,7 @@ MODULE_DEVICE_TABLE(of, rt5651_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id rt5651_acpi_match[] = { { "10EC5651", 0 }, + { "10EC5640", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, rt5651_acpi_match); From 174899fb305ba1316f6ce9a3e9fb0db1aaa28297 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:21 +0100 Subject: [PATCH 0635/1995] ASoC: rt5651: Add support for jack detect using an external GPIO Some board designs hook the jack-detect up to an external GPIO, rather then to one of the codec pins, add support for this. Figuring out which GPIO to use is pretty much board specific so I've chosen to let the machine driver pass the gpio_desc as data argument to snd_soc_component_set_jack() rather then add support for getting the GPIO to the codec driver. This keeps the codec code nice and clean. Note that using an external GPIO for this conflicts with button-press support, so this commit disables button-press support when an external GPIO is used. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit c2ec9d957d2bf49d69afb1b872cb2363c6cb5862) --- sound/soc/codecs/rt5651.c | 54 +++++++++++++++++++++++++++------------ sound/soc/codecs/rt5651.h | 1 + 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 9a007c16263161..75994297c8964a 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -1621,6 +1622,12 @@ static bool rt5651_jack_inserted(struct snd_soc_component *component) struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component); int val; + if (rt5651->gpiod_hp_det) { + val = gpiod_get_value_cansleep(rt5651->gpiod_hp_det); + dev_dbg(component->dev, "jack-detect gpio %d\n", val); + return val; + } + val = snd_soc_component_read32(component, RT5651_INT_IRQ_ST); dev_dbg(component->dev, "irq status %#04x\n", val); @@ -1761,6 +1768,13 @@ static int rt5651_detect_headset(struct snd_soc_component *component) return SND_JACK_HEADPHONE; } +static bool rt5651_support_button_press(struct rt5651_priv *rt5651) +{ + /* Button press support only works with internal jack-detection */ + return (rt5651->hp_jack->status & SND_JACK_MICROPHONE) && + rt5651->gpiod_hp_det == NULL; +} + static void rt5651_jack_detect_work(struct work_struct *work) { struct rt5651_priv *rt5651 = @@ -1785,15 +1799,15 @@ static void rt5651_jack_detect_work(struct work_struct *work) WARN_ON(rt5651->ovcd_irq_enabled); rt5651_enable_micbias1_for_ovcd(component); report = rt5651_detect_headset(component); - if (report == SND_JACK_HEADSET) { + dev_dbg(component->dev, "detect report %#02x\n", report); + snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET); + if (rt5651_support_button_press(rt5651)) { /* Enable ovcd IRQ for button press detect. */ rt5651_enable_micbias1_ovcd_irq(component); } else { /* No more need for overcurrent detect. */ rt5651_disable_micbias1_for_ovcd(component); } - dev_dbg(component->dev, "detect report %#02x\n", report); - snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET); } else if (rt5651->ovcd_irq_enabled && rt5651_micbias1_ovcd(component)) { dev_dbg(component->dev, "OVCD IRQ\n"); @@ -1837,16 +1851,20 @@ static void rt5651_cancel_work(void *data) } static void rt5651_enable_jack_detect(struct snd_soc_component *component, - struct snd_soc_jack *hp_jack) + struct snd_soc_jack *hp_jack, + struct gpio_desc *gpiod_hp_det) { struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component); - - /* IRQ output on GPIO1 */ - snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1, - RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ); + bool using_internal_jack_detect = true; /* Select jack detect source */ switch (rt5651->jd_src) { + case RT5651_JD_NULL: + rt5651->gpiod_hp_det = gpiod_hp_det; + if (!rt5651->gpiod_hp_det) + return; /* No jack detect */ + using_internal_jack_detect = false; + break; case RT5651_JD1_1: snd_soc_component_update_bits(component, RT5651_JD_CTRL2, RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_1); @@ -1865,16 +1883,20 @@ static void rt5651_enable_jack_detect(struct snd_soc_component *component, snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1, RT5651_JD2_IRQ_EN, RT5651_JD2_IRQ_EN); break; - case RT5651_JD_NULL: - return; default: dev_err(component->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n"); return; } - /* Enable jack detect power */ - snd_soc_component_update_bits(component, RT5651_PWR_ANLG2, - RT5651_PWR_JD_M, RT5651_PWR_JD_M); + if (using_internal_jack_detect) { + /* IRQ output on GPIO1 */ + snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1, + RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ); + + /* Enable jack detect power */ + snd_soc_component_update_bits(component, RT5651_PWR_ANLG2, + RT5651_PWR_JD_M, RT5651_PWR_JD_M); + } /* Set OVCD threshold current and scale-factor */ snd_soc_component_write(component, RT5651_PR_BASE + RT5651_BIAS_CUR4, @@ -1903,7 +1925,7 @@ static void rt5651_enable_jack_detect(struct snd_soc_component *component, RT5651_MB1_OC_STKY_MASK, RT5651_MB1_OC_STKY_EN); rt5651->hp_jack = hp_jack; - if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) { + if (rt5651_support_button_press(rt5651)) { rt5651_enable_micbias1_for_ovcd(component); rt5651_enable_micbias1_ovcd_irq(component); } @@ -1920,7 +1942,7 @@ static void rt5651_disable_jack_detect(struct snd_soc_component *component) disable_irq(rt5651->irq); rt5651_cancel_work(rt5651); - if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) { + if (rt5651_support_button_press(rt5651)) { rt5651_disable_micbias1_ovcd_irq(component); rt5651_disable_micbias1_for_ovcd(component); snd_soc_jack_report(rt5651->hp_jack, 0, SND_JACK_BTN_0); @@ -1933,7 +1955,7 @@ static int rt5651_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jack, void *data) { if (jack) - rt5651_enable_jack_detect(component, jack); + rt5651_enable_jack_detect(component, jack, data); else rt5651_disable_jack_detect(component); diff --git a/sound/soc/codecs/rt5651.h b/sound/soc/codecs/rt5651.h index ac6de6fb541498..41fcb8b5eb4072 100644 --- a/sound/soc/codecs/rt5651.h +++ b/sound/soc/codecs/rt5651.h @@ -2073,6 +2073,7 @@ struct rt5651_priv { struct regmap *regmap; /* Jack and button detect data */ struct snd_soc_jack *hp_jack; + struct gpio_desc *gpiod_hp_det; struct work_struct jack_detect_work; struct delayed_work bp_work; bool ovcd_irq_enabled; From db567b67f6c993c609a4d48011da1b8a965c261f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:22 +0100 Subject: [PATCH 0636/1995] ASoC: Intel: bytcr_rt5651: Revert "Fix DMIC map headsetmic mapping" Commit 37c7401e8c1f ("ASoC: Intel: bytcr_rt5651: Fix DMIC map headsetmic mapping"), changed the headsetmic mapping from IN3P to IN2P, this was based on the observation that all bytcr_rt5651 devices I have access to (7 devices) where all using IN3P for the headsetmic. This was an attempt to unifify / simplify the mapping, but it was wrong. None of those devices was actually using a digital internal mic. Now I've access to a Point of View TAB-P1006W-232 (v1.0) tabler, which does use a DMIC and it does have its headsetmic connected to IN2P, showing that the original mapping was correct, so this commit reverts the change changing the mapping back to IN2P. Fixes: 37c7401e8c1f ("ASoC: Intel: bytcr_rt5651: Fix DMIC map ... mapping") Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit aee48a9ffa5a128bf4e433c57c39e015ea5b0208) --- sound/soc/intel/boards/bytcr_rt5651.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index e528995668b78e..0ed844f2ad01ae 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -266,7 +266,7 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = { static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic_map[] = { {"DMIC L1", NULL, "Internal Mic"}, {"DMIC R1", NULL, "Internal Mic"}, - {"IN3P", NULL, "Headset Mic"}, + {"IN2P", NULL, "Headset Mic"}, }; static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_map[] = { From 16f636b8a7aa089a8342614454817f460aea086e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:23 +0100 Subject: [PATCH 0637/1995] ASoC: Intel: bytcr_rt5651: Add quirks module parameter Add quirks module parameter to allow manually specifying quirks from the kernel commandline (or modprobe.conf). Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit 7eb187313eef4c8faa49f70c9c7d8918e1052207) --- sound/soc/intel/boards/bytcr_rt5651.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 0ed844f2ad01ae..6d8ef9dd106ea3 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -98,6 +98,10 @@ struct byt_rt5651_private { static unsigned long byt_rt5651_quirk = BYT_RT5651_DEFAULT_QUIRKS | BYT_RT5651_IN2_MAP; +static unsigned int quirk_override; +module_param_named(quirk, quirk_override, uint, 0444); +MODULE_PARM_DESC(quirk, "Board-specific quirk override"); + static void log_quirks(struct device *dev) { if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_DMIC_MAP) @@ -973,6 +977,12 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) /* check quirks before creating card */ dmi_check_system(byt_rt5651_quirk_table); + if (quirk_override) { + dev_info(&pdev->dev, "Overriding quirk 0x%x => 0x%x\n", + (unsigned int)byt_rt5651_quirk, quirk_override); + byt_rt5651_quirk = quirk_override; + } + /* Must be called before register_card, also see declaration comment. */ ret_val = byt_rt5651_add_codec_device_props(codec_dev); if (ret_val) { From f238cfa4d662cd6707c9792cf0ece8acb31ee3c7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:24 +0100 Subject: [PATCH 0638/1995] ASoC: Intel: bytcr_rt5651: Add support for jack-detect using an external GPIO Some board designs hook the jack-detect up to an external GPIO, rather then to one of the codec pins, add support for this. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit 90768eaf064041937ef4d6ca95c7e86774cd34a4) --- sound/soc/intel/boards/bytcr_rt5651.c | 43 ++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 6d8ef9dd106ea3..9a2ee9080897e5 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -91,6 +91,7 @@ enum { struct byt_rt5651_private { struct clk *mclk; struct gpio_desc *ext_amp_gpio; + struct gpio_desc *hp_detect; struct snd_soc_jack jack; }; @@ -499,6 +500,7 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card); const struct snd_soc_dapm_route *custom_map; int num_routes; + int report; int ret; card->dapm.idle_bias_off = true; @@ -582,20 +584,27 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) dev_err(card->dev, "unable to set MCLK rate\n"); } - if (BYT_RT5651_JDSRC(byt_rt5651_quirk)) { + report = 0; + if (BYT_RT5651_JDSRC(byt_rt5651_quirk)) + report = SND_JACK_HEADSET | SND_JACK_BTN_0; + else if (priv->hp_detect) + report = SND_JACK_HEADSET; + + if (report) { ret = snd_soc_card_jack_new(runtime->card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &priv->jack, bytcr_jack_pins, + report, &priv->jack, bytcr_jack_pins, ARRAY_SIZE(bytcr_jack_pins)); if (ret) { dev_err(runtime->dev, "jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, - KEY_PLAYPAUSE); + if (report & SND_JACK_BTN_0) + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, + KEY_PLAYPAUSE); - ret = snd_soc_component_set_jack(codec, &priv->jack, NULL); + ret = snd_soc_component_set_jack(codec, &priv->jack, + priv->hp_detect); if (ret) return ret; } @@ -767,7 +776,8 @@ static int byt_rt5651_resume(struct snd_soc_card *card) for_each_card_components(card, component) { if (!strcmp(component->name, byt_rt5651_codec_name)) { dev_dbg(component->dev, "re-enabling jack detect after resume\n"); - snd_soc_component_set_jack(component, &priv->jack, NULL); + snd_soc_component_set_jack(component, &priv->jack, + priv->hp_detect); break; } } @@ -1012,6 +1022,25 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) return ret_val; } } + priv->hp_detect = devm_fwnode_get_index_gpiod_from_child( + &pdev->dev, "hp-detect", 0, + codec_dev->fwnode, + GPIOD_IN, "hp-detect"); + if (IS_ERR(priv->hp_detect)) { + ret_val = PTR_ERR(priv->hp_detect); + switch (ret_val) { + case -ENOENT: + priv->hp_detect = NULL; + break; + default: + dev_err(&pdev->dev, "Failed to get hp-detect GPIO: %d\n", + ret_val); + /* fall through */ + case -EPROBE_DEFER: + put_device(codec_dev); + return ret_val; + } + } } put_device(codec_dev); From a4060e460ec9f8a626cb164f5f1e975e510c2166 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:25 +0100 Subject: [PATCH 0639/1995] ASoC: Intel: bytcr_rt5651: Add quirk for PoV TAB-P1006W-232 (v1.0) tablet Add a DMI quirk for the Point of View TAB-P1006W-232 (v1.0) tablet, this tablet is special in a number of ways: 1) It uses the 2nd GPIO resource in the ACPI tables for jack-detect rather then using the rt5651 codec's builtin jack-detect functionality 2) It uses the 3th GPIO resource in the ACPI tables to control the external amplifier rather then the usual first non GpioInt resource and the GPIO is active-low. 3) It is a BYTCR device, without a CHAN package and it uses SSP0-AIF1 rather then the default SSP0-AIF2. 4) Its internal mic is a digital mic (the first x86 rt5651 device that I'm aware of which does this), combined with having its headset-mic connected to IN2. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit fee3e1cbd6cd74925286a571b567ec18728818a7) --- sound/soc/intel/boards/bytcr_rt5651.c | 48 ++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 9a2ee9080897e5..b618d984e2d566 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -95,6 +95,8 @@ struct byt_rt5651_private { struct snd_soc_jack jack; }; +static const struct acpi_gpio_mapping *byt_rt5651_gpios; + /* Default: jack-detect on JD1_1, internal mic on in2, headsetmic on in3 */ static unsigned long byt_rt5651_quirk = BYT_RT5651_DEFAULT_QUIRKS | BYT_RT5651_IN2_MAP; @@ -365,6 +367,22 @@ static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream, return byt_rt5651_prepare_and_enable_pll1(codec_dai, rate, bclk_ratio); } +static const struct acpi_gpio_params pov_p1006w_hp_detect = { 1, 0, false }; +static const struct acpi_gpio_params pov_p1006w_ext_amp_en = { 2, 0, true }; + +static const struct acpi_gpio_mapping byt_rt5651_pov_p1006w_gpios[] = { + { "hp-detect-gpios", &pov_p1006w_hp_detect, 1, }, + { "ext-amp-enable-gpios", &pov_p1006w_ext_amp_en, 1, }, + { }, +}; + +static int byt_rt5651_pov_p1006w_quirk_cb(const struct dmi_system_id *id) +{ + byt_rt5651_quirk = (unsigned long)id->driver_data; + byt_rt5651_gpios = byt_rt5651_pov_p1006w_gpios; + return 1; +} + static int byt_rt5651_quirk_cb(const struct dmi_system_id *id) { byt_rt5651_quirk = (unsigned long)id->driver_data; @@ -440,6 +458,23 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = { .driver_data = (void *)(BYT_RT5651_MCLK_EN | BYT_RT5651_IN1_MAP), }, + { + /* Point of View mobii wintab p1006w (v1.0) */ + .callback = byt_rt5651_pov_p1006w_quirk_cb, + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "BayTrail"), + /* Note 105b is Foxcon's USB/PCI vendor id */ + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "105B"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"), + }, + .driver_data = (void *)(BYT_RT5651_DMIC_MAP | + BYT_RT5651_OVCD_TH_2000UA | + BYT_RT5651_OVCD_SF_0P75 | + BYT_RT5651_DMIC_EN | + BYT_RT5651_MCLK_EN | + BYT_RT5651_SSP0_AIF1), + }, { /* VIOS LTH17 */ .callback = byt_rt5651_quirk_cb, @@ -848,7 +883,7 @@ static int snd_byt_rt5651_acpi_resource(struct acpi_resource *ares, void *arg) return 0; } -static void snd_byt_rt5651_mc_add_amp_en_gpio_mapping(struct device *codec) +static void snd_byt_rt5651_mc_pick_amp_en_gpio_mapping(struct device *codec) { struct byt_rt5651_acpi_resource_data data = { 0, -1 }; LIST_HEAD(resources); @@ -866,10 +901,10 @@ static void snd_byt_rt5651_mc_add_amp_en_gpio_mapping(struct device *codec) switch (data.gpio_int_idx) { case 0: - devm_acpi_dev_add_driver_gpios(codec, byt_rt5651_amp_en_second); + byt_rt5651_gpios = byt_rt5651_amp_en_second; break; case 1: - devm_acpi_dev_add_driver_gpios(codec, byt_rt5651_amp_en_first); + byt_rt5651_gpios = byt_rt5651_amp_en_first; break; default: dev_warn(codec, "Unknown GpioInt index %d, not adding external amplifier GPIO mapping\n", @@ -1001,8 +1036,11 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) } /* Cherry Trail devices use an external amplifier enable gpio */ - if (x86_match_cpu(cherrytrail_cpu_ids)) { - snd_byt_rt5651_mc_add_amp_en_gpio_mapping(codec_dev); + if (x86_match_cpu(cherrytrail_cpu_ids) && !byt_rt5651_gpios) + snd_byt_rt5651_mc_pick_amp_en_gpio_mapping(codec_dev); + + if (byt_rt5651_gpios) { + devm_acpi_dev_add_driver_gpios(codec_dev, byt_rt5651_gpios); priv->ext_amp_gpio = devm_fwnode_get_index_gpiod_from_child( &pdev->dev, "ext-amp-enable", 0, codec_dev->fwnode, From 8a455ed4ab965ae4e74990f60029ffc3556e2c03 Mon Sep 17 00:00:00 2001 From: Yizhuo Date: Mon, 7 Jan 2019 12:12:32 -0800 Subject: [PATCH 0640/1995] ASoC: rt274: Variable "buf" in function rt274_jack_detect() could be uninitialized In function rt274_jack_detect(), local variable "buf" could be uninitialized if function regmap_read() returns -EINVAL. However, it will be used to calculate "hp" and "mic" and make their value unpredictable while those value are used in the caller. This is potentially unsafe. Signed-off-by: Yizhuo Signed-off-by: Mark Brown (cherry picked from commit 4a8191aa9e057ea38279ef9e809265ba3966be40) --- sound/soc/codecs/rt274.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index 9e88f7b25d3808..adf59039a3b6ba 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -353,6 +353,7 @@ static void rt274_index_sync(struct snd_soc_component *component) static int rt274_jack_detect(struct rt274_priv *rt274, bool *hp, bool *mic) { unsigned int buf; + int ret; *hp = false; *mic = false; @@ -360,9 +361,15 @@ static int rt274_jack_detect(struct rt274_priv *rt274, bool *hp, bool *mic) if (!rt274->component) return -EINVAL; - regmap_read(rt274->regmap, RT274_GET_HP_SENSE, &buf); + ret = regmap_read(rt274->regmap, RT274_GET_HP_SENSE, &buf); + if (ret) + return ret; + *hp = buf & 0x80000000; - regmap_read(rt274->regmap, RT274_GET_MIC_SENSE, &buf); + ret = regmap_read(rt274->regmap, RT274_GET_MIC_SENSE, &buf); + if (ret) + return ret; + *mic = buf & 0x80000000; pr_debug("*hp = %d *mic = %d\n", *hp, *mic); From 1cf9dd1487b9709b91a0cac9fc79804076590a0f Mon Sep 17 00:00:00 2001 From: Ajit Pandey Date: Wed, 9 Jan 2019 14:17:07 +0530 Subject: [PATCH 0641/1995] ASoC: soc-core: defer card probe until all component is added to list DAI component probe is not called if it is not present in component list during sound card registration. Check if component is available in component list for platform and cpu dai before soundcard registration. Signed-off-by: Ajit Pandey Signed-off-by: Rohit kumar Signed-off-by: Mark Brown (cherry picked from commit 8780cf1142a59568a3aa77959cbd76b2edb6fd81) --- sound/soc/soc-core.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0462b3ec977a22..eec92f17dd1596 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1027,7 +1027,6 @@ static int snd_soc_init_platform(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_dai_link_component *platform = dai_link->platform; - /* * FIXME * @@ -1129,6 +1128,14 @@ static int soc_init_dai_link(struct snd_soc_card *card, link->name); return -EINVAL; } + + /* + * Defer card registartion if platform dai component is not added to + * component list. + */ + if (!soc_find_component(link->platform->of_node, link->platform->name)) + return -EPROBE_DEFER; + /* * CPU device may be specified by either name or OF node, but * can be left unspecified, and will be matched based on DAI @@ -1140,6 +1147,14 @@ static int soc_init_dai_link(struct snd_soc_card *card, link->name); return -EINVAL; } + + /* + * Defer card registartion if cpu dai component is not added to + * component list. + */ + if (!soc_find_component(link->cpu_of_node, link->cpu_name)) + return -EPROBE_DEFER; + /* * At least one of CPU DAI name or CPU device name/node must be * specified From f217b079a56f9f5b407a086c17a182ae82b8b08f Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Mon, 7 Jan 2019 16:11:46 +0000 Subject: [PATCH 0642/1995] ASoC: da7219: MCLK should be enabled before DAI clocks For platforms using the Common Clock Framework to control the codec's DAI clocks, MCLK should be enabled prior to DAI clocks being turned on. For some platforms the codec is already provided with an MCLK reference and can therefore control MCLK itself as it needs to. To improve functionality MCLK is now added as a parent to the DAI clocks, if MCLK was provided, so that if they are enabled MCLK will automatically be enabled as a prerequisite by the CCF. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown (cherry picked from commit a6028cc60aad18d5d7c25d99b5cb8c24399387c3) --- sound/soc/codecs/da7219.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 513ec036865363..a20a610c7ee557 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1804,7 +1804,7 @@ static const struct clk_ops da7219_dai_clks_ops = { .is_prepared = da7219_dai_clks_is_prepared, }; -static void da7219_register_dai_clks(struct snd_soc_component *component) +static int da7219_register_dai_clks(struct snd_soc_component *component) { struct device *dev = component->dev; struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); @@ -1812,9 +1812,17 @@ static void da7219_register_dai_clks(struct snd_soc_component *component) struct clk_init_data init = {}; struct clk *dai_clks; struct clk_lookup *dai_clks_lookup; + const char *parent_name; + + if (da7219->mclk) { + parent_name = __clk_get_name(da7219->mclk); + init.parent_names = &parent_name; + init.num_parents = 1; + } else { + init.parent_names = NULL; + init.num_parents = 0; + } - init.parent_names = NULL; - init.num_parents = 0; init.name = pdata->dai_clks_name; init.ops = &da7219_dai_clks_ops; da7219->dai_clks_hw.init = &init; @@ -1823,7 +1831,7 @@ static void da7219_register_dai_clks(struct snd_soc_component *component) if (IS_ERR(dai_clks)) { dev_warn(dev, "Failed to register DAI clocks: %ld\n", PTR_ERR(dai_clks)); - return; + return PTR_ERR(dai_clks); } da7219->dai_clks = dai_clks; @@ -1835,13 +1843,18 @@ static void da7219_register_dai_clks(struct snd_soc_component *component) dai_clks_lookup = clkdev_create(dai_clks, pdata->dai_clks_name, "%s", dev_name(dev)); if (!dai_clks_lookup) - dev_warn(dev, "Failed to create DAI clkdev"); + return -ENOMEM; else da7219->dai_clks_lookup = dai_clks_lookup; } + + return 0; } #else -static inline void da7219_register_dai_clks(struct snd_soc_component *component) {} +static inline int da7219_register_dai_clks(struct snd_soc_component *component) +{ + return 0; +} #endif /* CONFIG_COMMON_CLK */ static void da7219_handle_pdata(struct snd_soc_component *component) @@ -1854,8 +1867,6 @@ static void da7219_handle_pdata(struct snd_soc_component *component) da7219->wakeup_source = pdata->wakeup_source; - da7219_register_dai_clks(component); - /* Mic Bias voltages */ switch (pdata->micbias_lvl) { case DA7219_MICBIAS_1_6V: @@ -1947,6 +1958,11 @@ static int da7219_probe(struct snd_soc_component *component) } } + /* Register CCF DAI clock control */ + ret = da7219_register_dai_clks(component); + if (ret) + return ret; + /* Default PC counter to free-running */ snd_soc_component_update_bits(component, DA7219_PC_COUNT, DA7219_PC_FREERUN_MASK, DA7219_PC_FREERUN_MASK); From 22e0655ae8740c72fac7223f6a9eece3db091468 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 8 Jan 2019 09:13:28 +0000 Subject: [PATCH 0643/1995] ASoC: da7219: Add recalc_rate function to return DAI clock rate By making MCLK parent of DAI clocks, when querying the rate of the clock the rate returned is now given from the parent clock so gives the MCLK rate rather than 0 as previously returned. This is a bit misleading, and actually there's no major reason why we can't at least return the DAI WCLK rate, as set in HW, so that's what we now do. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown (cherry picked from commit a58943abcb08cfbe6c36648602d796c5834ee8a9) --- sound/soc/codecs/da7219.c | 45 ++++++++++++++++++++++++++++++++++++--- sound/soc/codecs/da7219.h | 1 + 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index a20a610c7ee557..b1df4bb361050e 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1767,7 +1767,7 @@ static int da7219_dai_clks_prepare(struct clk_hw *hw) { struct da7219_priv *da7219 = container_of(hw, struct da7219_priv, dai_clks_hw); - struct snd_soc_component *component = da7219->aad->component; + struct snd_soc_component *component = da7219->component; snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, DA7219_DAI_CLK_EN_MASK, @@ -1780,7 +1780,7 @@ static void da7219_dai_clks_unprepare(struct clk_hw *hw) { struct da7219_priv *da7219 = container_of(hw, struct da7219_priv, dai_clks_hw); - struct snd_soc_component *component = da7219->aad->component; + struct snd_soc_component *component = da7219->component; snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, DA7219_DAI_CLK_EN_MASK, 0); @@ -1790,7 +1790,7 @@ static int da7219_dai_clks_is_prepared(struct clk_hw *hw) { struct da7219_priv *da7219 = container_of(hw, struct da7219_priv, dai_clks_hw); - struct snd_soc_component *component = da7219->aad->component; + struct snd_soc_component *component = da7219->component; u8 clk_reg; clk_reg = snd_soc_component_read32(component, DA7219_DAI_CLK_MODE); @@ -1798,10 +1798,47 @@ static int da7219_dai_clks_is_prepared(struct clk_hw *hw) return !!(clk_reg & DA7219_DAI_CLK_EN_MASK); } +static unsigned long da7219_dai_clks_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct da7219_priv *da7219 = + container_of(hw, struct da7219_priv, dai_clks_hw); + struct snd_soc_component *component = da7219->component; + u8 fs = snd_soc_component_read32(component, DA7219_SR); + + switch (fs & DA7219_SR_MASK) { + case DA7219_SR_8000: + return 8000; + case DA7219_SR_11025: + return 11025; + case DA7219_SR_12000: + return 12000; + case DA7219_SR_16000: + return 16000; + case DA7219_SR_22050: + return 22050; + case DA7219_SR_24000: + return 24000; + case DA7219_SR_32000: + return 32000; + case DA7219_SR_44100: + return 44100; + case DA7219_SR_48000: + return 48000; + case DA7219_SR_88200: + return 88200; + case DA7219_SR_96000: + return 96000; + default: + return 0; + } +} + static const struct clk_ops da7219_dai_clks_ops = { .prepare = da7219_dai_clks_prepare, .unprepare = da7219_dai_clks_unprepare, .is_prepared = da7219_dai_clks_is_prepared, + .recalc_rate = da7219_dai_clks_recalc_rate, }; static int da7219_register_dai_clks(struct snd_soc_component *component) @@ -1825,6 +1862,7 @@ static int da7219_register_dai_clks(struct snd_soc_component *component) init.name = pdata->dai_clks_name; init.ops = &da7219_dai_clks_ops; + init.flags = CLK_GET_RATE_NOCACHE; da7219->dai_clks_hw.init = &init; dai_clks = devm_clk_register(dev, &da7219->dai_clks_hw); @@ -1912,6 +1950,7 @@ static int da7219_probe(struct snd_soc_component *component) unsigned int rev; int ret; + da7219->component = component; mutex_init(&da7219->ctrl_lock); mutex_init(&da7219->pll_lock); diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index 3a006862f0e791..366cf46118a005 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -809,6 +809,7 @@ struct da7219_aad_priv; /* Private data */ struct da7219_priv { + struct snd_soc_component *component; struct da7219_aad_priv *aad; struct da7219_pdata *pdata; From bcbd543812df170be7dcbe7ab7ed617a3d7b664b Mon Sep 17 00:00:00 2001 From: Mac Chiang Date: Wed, 5 Dec 2018 18:11:19 +0800 Subject: [PATCH 0644/1995] ASoC: Intel: Boards: move the codec PLL configuration to _init move the codec PLL to rt5682_codec_init, because codec only need to config the clock source/PLL once. As the result, remove the platform_clock_controls since no need to control clock anymore. Signed-off-by: Shuming Fan Signed-off-by: Mac Chiang Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 239b8b34a856777e562373ae0de605536a7ccade) --- sound/soc/intel/boards/glk_rt5682_max98357a.c | 45 +++---------------- 1 file changed, 7 insertions(+), 38 deletions(-) diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index 0739e3a75083f1..f6597c216fa8d3 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -55,39 +55,6 @@ enum { GLK_DPCM_AUDIO_HDMI3_PB, }; -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; - int ret = 0; - - codec_dai = snd_soc_card_get_codec_dai(card, GLK_REALTEK_CODEC_DAI); - 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_sysclk(codec_dai, 0, 0, 0); - if (ret) - dev_err(card->dev, "failed to stop sysclk: %d\n", ret); - } else if (SND_SOC_DAPM_EVENT_ON(event)) { - ret = snd_soc_dai_set_pll(codec_dai, 0, RT5682_PLL1_S_MCLK, - GLK_PLAT_CLK_FREQ, RT5682_PLL_FREQ); - if (ret < 0) { - dev_err(card->dev, "can't set codec pll: %d\n", ret); - return ret; - } - } - - if (ret) - dev_err(card->dev, "failed to start internal clk: %d\n", ret); - - return ret; -} - static const struct snd_kcontrol_new geminilake_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), @@ -102,14 +69,10 @@ static const struct snd_soc_dapm_widget geminilake_widgets[] = { SND_SOC_DAPM_SPK("HDMI1", NULL), SND_SOC_DAPM_SPK("HDMI2", NULL), SND_SOC_DAPM_SPK("HDMI3", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), }; static const struct snd_soc_dapm_route geminilake_map[] = { /* HP jack connectors - unknown if we have jack detection */ - { "Headphone Jack", NULL, "Platform Clock" }, { "Headphone Jack", NULL, "HPOL" }, { "Headphone Jack", NULL, "HPOR" }, @@ -117,7 +80,6 @@ static const struct snd_soc_dapm_route geminilake_map[] = { { "Spk", NULL, "Speaker" }, /* other jacks */ - { "Headset Mic", NULL, "Platform Clock" }, { "IN1P", NULL, "Headset Mic" }, /* digital mics */ @@ -177,6 +139,13 @@ static int geminilake_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_jack *jack; int ret; + ret = snd_soc_dai_set_pll(codec_dai, 0, RT5682_PLL1_S_MCLK, + GLK_PLAT_CLK_FREQ, RT5682_PLL_FREQ); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec pll: %d\n", ret); + return ret; + } + /* Configure sysclk for codec */ ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, RT5682_PLL_FREQ, SND_SOC_CLOCK_IN); From 4f1fb53a03cb18ff1fad5edecf1907285fc0ed7d Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 10 Jan 2019 01:43:09 +0000 Subject: [PATCH 0645/1995] ASoC: Intel: bytcht_es8316: use correct drvdata in snd_byt_cht_es8316_mc_remove() The snd_byt_cht_es8316_mc_remove() use the platform drvdata as a type of 'struct byt_cht_es8316_private', but snd_byt_cht_es8316_mc_probe() set it to 'struct snd_soc_card', as suggested by Dan Carpenter, fix the usage in snd_byt_cht_es8316_mc_remove(). Fixes: 0d3e91da0750 ("ASoC: Intel: bytcht_es8316: Add external speaker mux support") Signed-off-by: Wei Yongjun Acked-by: Pierre-Louis Bossart Reviewed-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit f833fe2056b3a6d69598ef029cede6e77dcc1b14) --- sound/soc/intel/boards/bytcht_es8316.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index cdf2061e7613d9..fa9c4cf97686d9 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -544,7 +544,8 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) static int snd_byt_cht_es8316_mc_remove(struct platform_device *pdev) { - struct byt_cht_es8316_private *priv = platform_get_drvdata(pdev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); gpiod_put(priv->speaker_en_gpio); return 0; From 8f13ab598c431545379818cf7266f5cf810c8379 Mon Sep 17 00:00:00 2001 From: Rohit kumar Date: Thu, 10 Jan 2019 14:32:41 +0530 Subject: [PATCH 0646/1995] ASoC: soc-core: Hold client_mutex around soc_init_dai_link() soc_init_dai_link() calls soc_find_component() which needs to be within client_mutex lock. Add client_mutex lock around soc_init_dai_link() in snd_soc_register_card() to avoid lockdep warning. Fixes: 8780cf1142a5 ("ASoC: soc-core: defer card probe until all component is added to list") Reported-by: Kuninori Morimoto Signed-off-by: Rohit kumar Signed-off-by: Ajit Pandey Signed-off-by: Mark Brown (cherry picked from commit 04eb1efcd614d6f067b76a355b3a3599667959dc) --- sound/soc/soc-core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index eec92f17dd1596..0934b36645b3ea 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1027,6 +1027,7 @@ static int snd_soc_init_platform(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_dai_link_component *platform = dai_link->platform; + /* * FIXME * @@ -2754,15 +2755,18 @@ int snd_soc_register_card(struct snd_soc_card *card) if (!card->name || !card->dev) return -EINVAL; + mutex_lock(&client_mutex); for_each_card_prelinks(card, i, link) { ret = soc_init_dai_link(card, link); if (ret) { dev_err(card->dev, "ASoC: failed to init link %s\n", link->name); + mutex_unlock(&client_mutex); return ret; } } + mutex_unlock(&client_mutex); dev_set_drvdata(card->dev, card); From 7c7d68887aa5491fa691eae653a08662bc3808e7 Mon Sep 17 00:00:00 2001 From: Ajit Pandey Date: Fri, 11 Jan 2019 13:44:02 +0530 Subject: [PATCH 0647/1995] ASoC: soc-core: Fix null pointer dereference in soc_find_component soc_find_component() may lead to null pointer exception if both arguments i.e of_node and name is NULL. Add NULL check before calling soc_find_component(). Also fix some typos. Fixes: 8780cf1142a5 ("ASoC: soc-core: defer card probe until all component is added to list") Reported-by: Pierre-Louis Bossart Signed-off-by: Ajit Pandey Signed-off-by: Rohit kumar --- sound/soc/soc-core.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0934b36645b3ea..df05fb862f4bc8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1131,11 +1131,13 @@ static int soc_init_dai_link(struct snd_soc_card *card, } /* - * Defer card registartion if platform dai component is not added to + * Defer card registration if platform dai component is not added to * component list. */ - if (!soc_find_component(link->platform->of_node, link->platform->name)) - return -EPROBE_DEFER; + if (link->platform->of_node || link->platform->name) + if (!soc_find_component(link->platform->of_node, + link->platform->name)) + return -EPROBE_DEFER; /* * CPU device may be specified by either name or OF node, but @@ -1150,11 +1152,12 @@ static int soc_init_dai_link(struct snd_soc_card *card, } /* - * Defer card registartion if cpu dai component is not added to + * Defer card registration if cpu dai component is not added to * component list. */ - if (!soc_find_component(link->cpu_of_node, link->cpu_name)) - return -EPROBE_DEFER; + if (link->cpu_of_node || link->cpu_name) + if (!soc_find_component(link->cpu_of_node, link->cpu_name)) + return -EPROBE_DEFER; /* * At least one of CPU DAI name or CPU device name/node must be From 2cf34472e253a10bbbf27264894115a596557b3d Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 9 Jan 2019 16:20:51 +0800 Subject: [PATCH 0648/1995] ALSA: hda: Fix a mask wrong issue in snd_hdac_stream_start() To enable SIE(Stream Interrupt Enable) in snd_hdac_stream_start(), we should set both mask and value to be "1 << azx_dev->index" for register update, the mask was 0, here fix it. Signed-off-by: Keyon Jie Signed-off-by: Takashi Iwai (cherry picked from commit fc2a6cf060d0c6feeb3719bf40088e48c5926e40) --- sound/hda/hdac_stream.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index eee422390d8e26..ba73a33480b66f 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -56,7 +56,9 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start) azx_dev->start_wallclk -= azx_dev->period_wallclk; /* enable SIE */ - snd_hdac_chip_updatel(bus, INTCTL, 0, 1 << azx_dev->index); + snd_hdac_chip_updatel(bus, INTCTL, + 1 << azx_dev->index, + 1 << azx_dev->index); /* set DMA start and interrupt mask */ snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_DMA_START | SD_INT_MASK); From 84d0af0436eec3f345f523fa6855545dd55df0ac Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 11 Jan 2019 13:44:59 -0600 Subject: [PATCH 0649/1995] ASOC: Intel: bxt_pcm512x: fix warnings w/ set_format Reported by Sparse Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bxt_pcm512x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bxt_pcm512x.c b/sound/soc/intel/boards/bxt_pcm512x.c index 32ada659c7afbe..003159aa875c64 100644 --- a/sound/soc/intel/boards/bxt_pcm512x.c +++ b/sound/soc/intel/boards/bxt_pcm512x.c @@ -122,7 +122,7 @@ static int codec_fixup(struct snd_soc_pcm_runtime *rtd, /* set SSP5 to 24 bit */ snd_mask_none(fmt); - snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); return 0; } From 5091f1fa177f9e5b455ba8b866fd1cd4bcd8d4d1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 11 Jan 2019 15:51:07 -0600 Subject: [PATCH 0650/1995] Revert "ASoC: soc-core: Fix null pointer dereference in soc_find_component" This reverts commit 7c7d68887aa5491fa691eae653a08662bc3808e7. Signed-off-by: Pierre-Louis Bossart --- sound/soc/soc-core.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index df05fb862f4bc8..0934b36645b3ea 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1131,13 +1131,11 @@ static int soc_init_dai_link(struct snd_soc_card *card, } /* - * Defer card registration if platform dai component is not added to + * Defer card registartion if platform dai component is not added to * component list. */ - if (link->platform->of_node || link->platform->name) - if (!soc_find_component(link->platform->of_node, - link->platform->name)) - return -EPROBE_DEFER; + if (!soc_find_component(link->platform->of_node, link->platform->name)) + return -EPROBE_DEFER; /* * CPU device may be specified by either name or OF node, but @@ -1152,12 +1150,11 @@ static int soc_init_dai_link(struct snd_soc_card *card, } /* - * Defer card registration if cpu dai component is not added to + * Defer card registartion if cpu dai component is not added to * component list. */ - if (link->cpu_of_node || link->cpu_name) - if (!soc_find_component(link->cpu_of_node, link->cpu_name)) - return -EPROBE_DEFER; + if (!soc_find_component(link->cpu_of_node, link->cpu_name)) + return -EPROBE_DEFER; /* * At least one of CPU DAI name or CPU device name/node must be From d868f5c068b62be259de1a93f0b2b37346048a18 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 11 Jan 2019 15:51:31 -0600 Subject: [PATCH 0651/1995] Revert "ASoC: soc-core: defer card probe until all component is added to list" This reverts commit 1cf9dd1487b9709b91a0cac9fc79804076590a0f. Signed-off-by: Pierre-Louis Bossart --- sound/soc/soc-core.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0934b36645b3ea..9fd83dc569ebe6 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1129,14 +1129,6 @@ static int soc_init_dai_link(struct snd_soc_card *card, link->name); return -EINVAL; } - - /* - * Defer card registartion if platform dai component is not added to - * component list. - */ - if (!soc_find_component(link->platform->of_node, link->platform->name)) - return -EPROBE_DEFER; - /* * CPU device may be specified by either name or OF node, but * can be left unspecified, and will be matched based on DAI @@ -1148,14 +1140,6 @@ static int soc_init_dai_link(struct snd_soc_card *card, link->name); return -EINVAL; } - - /* - * Defer card registartion if cpu dai component is not added to - * component list. - */ - if (!soc_find_component(link->cpu_of_node, link->cpu_name)) - return -EPROBE_DEFER; - /* * At least one of CPU DAI name or CPU device name/node must be * specified From 8ba11407f61cc7b78a60c9b244dc963d468ef10b Mon Sep 17 00:00:00 2001 From: Bard liao Date: Thu, 10 Jan 2019 06:29:56 +0800 Subject: [PATCH 0652/1995] ASoC: SOF: intel: hda: remove unrequired null checking sdev->pdata->hw_pdata is assigned in hda_dsp_probe() so sdev->pdata->hw_pdata won't be null in hda_dsp_remove(). Signed-off-by: Bard liao --- sound/soc/sof/intel/hda.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 32ceeb110cb959..d62ea91d3f583a 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -543,17 +543,14 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; struct hdac_bus *bus = sof_to_bus(sdev); struct pci_dev *pci = sdev->pci; - const struct sof_intel_dsp_desc *chip = NULL; - - if (hda) - chip = hda->desc; + const struct sof_intel_dsp_desc *chip = hda->desc; #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* codec removal, invoke bus_device_remove */ snd_hdac_ext_bus_device_remove(bus); #endif - if (hda && (!IS_ERR_OR_NULL(hda->dmic_dev))) + if (!IS_ERR_OR_NULL(hda->dmic_dev)) platform_device_unregister(hda->dmic_dev); /* disable DSP IRQ */ From 9a9bde51b6a54b24d4a39515e15f3f735cda4569 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 15 Jan 2019 10:29:56 +0800 Subject: [PATCH 0653/1995] ASoC: SOF: refine block comment style for hda Use correct style for block comment Signed-off-by: Rander Wang --- sound/soc/sof/intel/hda-dai.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index ae7258450f3d2c..85f0bedf4acdb7 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -32,16 +32,16 @@ struct hda_pipe_params { unsigned int link_bps; }; -/* Unlike GP dma, there is a set of stream registers in hda controller to - * control the link dma channels. Each register controls one link dma - * channel and the relation is fixed. To make sure FW uses the correct - * link dma channel, host allocates stream register and sends the - * corresponding link dma channel to FW to allocate link dma channel +/* + * Unlike GP dma, there is a set of stream registers in hda controller + * to control the link dma channels. Each register controls one link + * dma channel and the relation is fixed. To make sure FW uses correct + * link dma channels, host allocates stream registers and sends the + * corresponding link dma channels to FW to allocate link dma channel * * FIXME: this API is abused in the sense that tx_num and rx_num are * passed as arguments, not returned. We need to find a better way to * retrieve the stream tag allocated for the link DMA - * */ static int hda_link_dma_get_channels(struct snd_soc_dai *dai, unsigned int *tx_num, From 7279c78412ea709da42fc982e29f6d229263ad13 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 15 Jan 2019 17:57:22 +0800 Subject: [PATCH 0654/1995] ASoC: SOF: refine block comment Use correct style for block comment Signed-off-by: Rander Wang --- sound/soc/sof/topology.c | 44 ++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index d43b3e3107b0fe..93177e21754c6e 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -15,13 +15,17 @@ #include "ops.h" #define COMP_ID_UNASSIGNED 0xffffffff -/* Constants used in the computation of linear volume gain from dB gain */ -/* 20th root of 10 in Q1.16 fixed-point notation*/ +/* + * Constants used in the computation of linear volume gain + * from dB gain 20th root of 10 in Q1.16 fixed-point notation + */ #define VOL_TWENTIETH_ROOT_OF_TEN 73533 /* 40th root of 10 in Q1.16 fixed-point notation*/ #define VOL_FORTIETH_ROOT_OF_TEN 69419 -/* Volume fractional word length */ -/* Define to 16 sets the volume linear gain value to use Qx.16 format */ +/* + * Volume fractional word length define to 16 sets + * the volume linear gain value to use Qx.16 format + */ #define VOLUME_FWL 16 /* 0.5 dB step value in topology TLV */ #define VOL_HALF_DB_STEP 50 @@ -57,9 +61,10 @@ static inline int get_tlv_data(const int *p, int tlv[TLV_ITEMS]) return 0; } -/* Function to truncate an unsigned 64-bit number - * by x bits and return 32-bit unsigned number - * This function also takes care of rounding while truncating +/* + * Function to truncate an unsigned 64-bit number + * by x bits and return 32-bit unsigned number. This + * function also takes care of rounding while truncating */ static inline u32 vol_shift_64(u64 i, u32 x) { @@ -73,13 +78,14 @@ static inline u32 vol_shift_64(u64 i, u32 x) return (u32)(((i >> (x - 1)) + 1) >> 1); } -/* Function to compute a ^ exp where, - * a is a fractional number represented by a fixed-point integer - * with a fractional world length of "fwl" +/* + * Function to compute a ^ exp where, + * a is a fractional number represented by a fixed-point + * integer with a fractional world length of "fwl" * exp is an integer * fwl is the fractional word length - * Return value is a fractional number represented by a fixed-point - * integer with a fractional word length of "fwl" + * Return value is a fractional number represented by a + * fixed-point integer with a fractional word length of "fwl" */ static u32 vol_pow32(u32 a, int exp, u32 fwl) { @@ -99,7 +105,8 @@ static u32 vol_pow32(u32 a, int exp, u32 fwl) /* mutiply a "iter" times to compute power */ for (i = 0; i < iter; i++) { - /* Product of 2 Qx.fwl fixed-point numbers yields a Q2*x.2*fwl + /* + * Product of 2 Qx.fwl fixed-point numbers yields a Q2*x.2*fwl * Truncate product back to fwl fractional bits with rounding */ power = vol_shift_64((u64)power * a, fwl); @@ -117,7 +124,8 @@ static u32 vol_pow32(u32 a, int exp, u32 fwl) return (u32)numerator; } -/* Function to calculate volume gain from TLV data +/* + * Function to calculate volume gain from TLV data. * This function can only handle gain steps that are multiples of 0.5 dB */ static u32 vol_compute_gain(u32 value, int *tlv) @@ -135,8 +143,9 @@ static u32 vol_compute_gain(u32 value, int *tlv) */ dB_gain = tlv[TLV_MIN] + (value * tlv[TLV_STEP]) / 100; - /* compute linear gain - * represented by fixed-point int with VOLUME_FWL fractional bits + /* + * compute linear gain represented by fixed-point + * int with VOLUME_FWL fractional bits */ linear_gain = vol_pow32(VOL_TWENTIETH_ROOT_OF_TEN, dB_gain, VOLUME_FWL); @@ -152,7 +161,8 @@ static u32 vol_compute_gain(u32 value, int *tlv) return linear_gain; } -/* Set up volume table for kcontrols from tlv data +/* + * Set up volume table for kcontrols from tlv data * "size" specifies the number of entries in the table */ static int set_up_volume_table(struct snd_sof_control *scontrol, From eec37ea077b00dd285c91b0e08ac96636c87ed60 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 11 Jan 2019 16:08:02 +0800 Subject: [PATCH 0655/1995] ASoC: SOF: refine dai link config saving Move the code for playback and capture into sof_link_hda_process. This make code simpler and do configuration in one loop Check status in functions for dai link config saving. Machine driver may define dai link with playback and capture enabled, but the dai link in topology would support both, one or none of them. So a warning would be reported here. Signed-off-by: Rander Wang --- sound/soc/sof/topology.c | 129 +++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 61 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 93177e21754c6e..56c5dfff559c2b 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2001,6 +2001,7 @@ static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size, struct sof_ipc_dai_config *config) { struct snd_sof_dai *dai; + int found = 0; list_for_each_entry(dai, &sdev->dai_list, list) { if (!dai->name) @@ -2010,9 +2011,21 @@ static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size, dai->dai_config = kmemdup(config, size, GFP_KERNEL); if (!dai->dai_config) return -ENOMEM; + + found = 1; } } + /* + * machine driver may define a dai link with playback and capture + * dai enabled, but the dai link in topology would support both, one + * or none of them. Here print a warning message to notify user + */ + if (!found) { + dev_warn(sdev->dev, "warning: failed to find dai for dai link %s", + link->name); + } + return 0; } @@ -2204,48 +2217,75 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, return ret; } +/* + * for hda link, playback and capture are supported by different dai + * in FW. Here get the dai_index, set dma channel of each dai + * and send config to FW. In FW, each dai sets config by dai_index + */ static int sof_link_hda_process(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link, struct sof_ipc_dai_config *config, - int slot, - int direction) + int tx_slot, + int rx_slot) { struct sof_ipc_reply reply; u32 size = sizeof(*config); - struct snd_sof_dai *dai; + struct snd_sof_dai *sof_dai; int found = 0; int ret; - /* for hda link, playback and capture are supported by different - * dai in FW. Here get the dai_index of each dai and send config - * to FW. In FW, each dai sets config by dai_index - */ - list_for_each_entry(dai, &sdev->dai_list, list) { - if (!dai->name) + list_for_each_entry(sof_dai, &sdev->dai_list, list) { + if (!sof_dai->name) continue; - if (strcmp(link->name, dai->name) == 0 && - dai->comp_dai.direction == direction) { - config->dai_index = dai->comp_dai.dai_index; + if (strcmp(link->name, sof_dai->name) == 0) { + if (sof_dai->comp_dai.direction == + SNDRV_PCM_STREAM_PLAYBACK) { + if (!link->dpcm_playback) + return -EINVAL; + + config->hda.link_dma_ch = tx_slot; + } else { + if (!link->dpcm_capture) + return -EINVAL; + + config->hda.link_dma_ch = rx_slot; + } + + config->dai_index = sof_dai->comp_dai.dai_index; found = 1; - break; + + /* save config in dai component */ + sof_dai->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!sof_dai->dai_config) + return -ENOMEM; + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + config->hdr.cmd, config, size, + &reply, sizeof(reply)); + + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DAI config for direction:%d of HDA dai %d\n", + sof_dai->comp_dai.direction, + config->dai_index); + + return ret; + } } } + /* + * machine driver may define a dai link with playback and capture + * dai enabled, but the dai link in topology would support both, one + * or none of them. Here print a warning message to notify user + */ if (!found) { - dev_err(sdev->dev, "error: failed to find dai %s in %s", - link->name, __func__); - return -EINVAL; + dev_warn(sdev->dev, "warning: failed to find dai for dai link %s", + link->name); } - config->hda.link_dma_ch = slot; - - /* send message to DSP */ - ret = sof_ipc_tx_message(sdev->ipc, - config->hdr.cmd, config, size, &reply, - sizeof(reply)); - - return ret; + return 0; } static int sof_link_hda_load(struct snd_soc_component *scomp, int index, @@ -2258,7 +2298,6 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link_component dai_component; struct snd_soc_tplg_private *private = &cfg->priv; struct snd_soc_dai *dai; - u32 size = sizeof(*config); u32 tx_num = 0; u32 tx_slot = 0; @@ -2304,42 +2343,10 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index, return ret; } - /* for hda link, playback and capture are supported by different - * dai in FW. Here send dai config according to capability of dai. - */ - if (link->dpcm_playback) { - ret = sof_link_hda_process(sdev, link, config, tx_slot, - SNDRV_PCM_STREAM_PLAYBACK); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to set DAI config for playback dai HDA%d\n", - config->dai_index); - - return ret; - } - } - - if (link->dpcm_capture) { - ret = sof_link_hda_process(sdev, link, config, rx_slot, - SNDRV_PCM_STREAM_CAPTURE); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to set DAI config for capture dai HDA%d\n", - config->dai_index); - - return ret; - } - } - - /* set config for all DAI's with name matching the link name */ - ret = sof_set_dai_config(sdev, size, link, config); - if (ret < 0) { - if (link->dpcm_playback) - dev_err(sdev->dev, "error: failed to save DAI config for playback HDA%d\n", - config->dai_index); - - if (link->dpcm_capture) - dev_err(sdev->dev, "error: failed to save DAI config for capture HDA%d\n", - config->dai_index); - } + ret = sof_link_hda_process(sdev, link, config, tx_slot, rx_slot); + if (ret < 0) + dev_err(sdev->dev, "error: failed to process hda dai link %s", + link->name); return ret; } From 402113769e10194fe588bf8a827cf7da55e6a2d4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 15 Jan 2019 15:38:09 -0600 Subject: [PATCH 0656/1995] ASoC: SOF: topology: Fix spaces and out-of-memory messages make checkpatch.pl happy Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/topology.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 56c5dfff559c2b..1c3e69722583dd 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1510,7 +1510,6 @@ static int sof_effect_fir_load(struct snd_soc_component *scomp, int index, fir->comp.pipeline_id = index; fir->config.hdr.size = sizeof(fir->config); - ret = sof_parse_tokens(scomp, &fir->config, comp_tokens, ARRAY_SIZE(comp_tokens), private->array, le32_to_cpu(private->size)); @@ -2132,10 +2131,8 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, config->dmic.num_pdm_active; ipc_config = kzalloc(size, GFP_KERNEL); - if (!ipc_config) { - dev_err(sdev->dev, "error: allocating memory for config\n"); + if (!ipc_config) return -ENOMEM; - } /* copy the common dai config and dmic params */ memcpy(ipc_config, config, sizeof(*config)); From a7bbfa40e5933f4fa2aa5a957e493554ce4e1ca8 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 15 Jan 2019 11:32:42 -0800 Subject: [PATCH 0657/1995] Revert "ALSA: HACK: Fix rmmod crash" This reverts commit a29b55c7fe216898576f74eb5fb7f1cf36d8535b. "ALSA: HACK: Fix rmmod crash" Revert this hack. Not sure what it was intended for originally. Signed-off-by: Ranjani Sridharan --- sound/core/pcm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 69d64aa07dffc0..01b9d62eef14db 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -1157,7 +1157,6 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) list_del_init(&pcm->list); for (cidx = 0; cidx < 2; cidx++) { for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) { -#if 0 snd_pcm_stream_lock_irq(substream); if (substream->runtime) { if (snd_pcm_running(substream)) @@ -1169,7 +1168,6 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) wake_up(&substream->runtime->tsleep); } snd_pcm_stream_unlock_irq(substream); -#endif } } From 2e5d949bdb79b7dee8307edd81e395578bcd566f Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Mon, 14 Jan 2019 14:08:56 +0200 Subject: [PATCH 0658/1995] ASoC: SOF: Add token for tone generator sample rate Signed-off-by: Seppo Ingalsuo --- include/uapi/sound/sof/tokens.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 98c2257e8e8286..c894b51b34b690 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -90,6 +90,9 @@ #define SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE 705 #define SOF_TKN_INTEL_DMIC_PDM_SKEW 706 +/* Tone */ +#define SOF_TKN_TONE_SAMPLE_RATE 800 + #define SOF_TKN_EFFECT_TYPE 900 #endif From b19fc74ed99089a73bc068dc5dea969aa02f77ee Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 15 Jan 2019 12:30:48 -0800 Subject: [PATCH 0659/1995] Revert "ASoC: SOF: topology: continue parsing when num_hw_configs is not 1" This reverts commit 7af711b952284ee41fcda0c4ba9f6ea831ea170a. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/topology.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 1c3e69722583dd..db882ac24621b7 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2366,10 +2366,12 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, if (!link->no_pcm) return 0; - /* usually we use 1 config, but for HDA it may be 0 ATM */ - if (le32_to_cpu(cfg->num_hw_configs) != 1) - dev_warn(sdev->dev, "warn: unexpected DAI config count %d!\n", - le32_to_cpu(cfg->num_hw_configs)); + /* only support 1 config atm */ + if (le32_to_cpu(cfg->num_hw_configs) != 1) { + dev_err(sdev->dev, "error: unexpected DAI config count %d\n", + le32_to_cpu(cfg->num_hw_configs)); + return -EINVAL; + } /* check we have some tokens - we need at least DAI type */ if (le32_to_cpu(private->size) == 0) { From 17394b583106e1cb001221033ca2d5136eede305 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 15 Jan 2019 12:43:59 -0800 Subject: [PATCH 0660/1995] ASoC: SOF: update check for num_hw_configs in sof_link_load() With the changes in SOF topology to add hw_config for HDA links, all dai links should have at least 1 hw_config in topology. But older topologies built before this change was incorporated might have no hw_configs for HDA dai links. So make an exception for those. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/topology.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index db882ac24621b7..ec92b8c33a7fbd 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2366,13 +2366,6 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, if (!link->no_pcm) return 0; - /* only support 1 config atm */ - if (le32_to_cpu(cfg->num_hw_configs) != 1) { - dev_err(sdev->dev, "error: unexpected DAI config count %d\n", - le32_to_cpu(cfg->num_hw_configs)); - return -EINVAL; - } - /* check we have some tokens - we need at least DAI type */ if (le32_to_cpu(private->size) == 0) { dev_err(sdev->dev, "error: expected tokens for DAI, none found\n"); @@ -2391,6 +2384,17 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, return ret; } + /* + * DAI links are expected to have at least 1 hw_config. + * But some older topologies might have no hw_config for HDA dai links. + */ + if (!le32_to_cpu(cfg->num_hw_configs) && + config.type != SOF_DAI_INTEL_HDA) { + dev_err(sdev->dev, "error: unexpected DAI config count %d!\n", + le32_to_cpu(cfg->num_hw_configs)); + return -EINVAL; + } + /* configure dai IPC message */ hw_config = &cfg->hw_config[0]; From f9d0898b03abc07dc85bbbecfad0d3a80ddd6760 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 14 Jan 2019 22:41:25 -0800 Subject: [PATCH 0661/1995] Revert "ASoC:core:bug fix: oops caused by pointer dereference." This reverts commit 4c10c446363c340d865e9ba6358032cf498b1b6a "ASoC:core:bug fix: oops caused by pointer dereference." Signed-off-by: Ranjani Sridharan --- sound/soc/soc-core.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 600ce3acdd1acd..02d72b4f3aa745 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2188,21 +2188,11 @@ static int soc_probe(struct platform_device *pdev) static int soc_cleanup_card_resources(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; - struct snd_soc_component *component; - int ret; /* make sure any delayed work runs */ for_each_card_rtds(card, rtd) flush_delayed_work(&rtd->delayed_work); - /* remove dynamic controls for all component driver */ - list_for_each_entry(component, &card->component_dev_list, card_list) { - ret = snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); - if (ret < 0) - dev_err(component->dev, - "error: component free failed %d\n", ret); - } - /* free the ALSA card at first; this syncs with pending operations */ snd_card_free(card->snd_card); From 24e06b04bb18dcb37c9913df991f4f14559b168c Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 14 Jan 2019 22:41:50 -0800 Subject: [PATCH 0662/1995] Revert "ASoC:topology:bug fix:check return value avoid oops." This reverts commit 5711d8e9d7614ea7727599317d2fbc08f7ef5646 "ASoC:topology:bug fix:check return value avoid oops." Signed-off-by: Ranjani Sridharan --- sound/soc/soc-dapm.c | 99 ++++---------------------------------------- 1 file changed, 9 insertions(+), 90 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 51ad4f9d3d8f28..8f0b2a35651dc1 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2396,11 +2396,12 @@ static void dapm_free_path(struct snd_soc_dapm_path *path) kfree(path); } -static void snd_soc_dapm_free_widget_data(struct snd_soc_dapm_widget *w) +void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) { struct snd_soc_dapm_path *p, *next_p; enum snd_soc_dapm_direction dir; + list_del(&w->list); /* * remove source and sink paths associated to this widget. * While removing the path, remove reference to it from both @@ -2413,12 +2414,6 @@ static void snd_soc_dapm_free_widget_data(struct snd_soc_dapm_widget *w) kfree(w->kcontrols); kfree_const(w->name); -} - -void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) -{ - list_del(&w->list); - snd_soc_dapm_free_widget_data(w); kfree(w); } @@ -3037,16 +3032,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes); */ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) { - struct snd_soc_dapm_widget *w, *last; + struct snd_soc_dapm_widget *w; unsigned int val; - int ret = 0; mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); - /* - * widgets with the snd_soc_dapm_kcontrol ID and .num_controls = 0 can - * be appended to the list while scanning it, this is safe. - */ list_for_each_entry(w, &card->widgets, list) { if (w->new) @@ -3057,8 +3047,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) sizeof(struct snd_kcontrol *), GFP_KERNEL); if (!w->kcontrols) { - ret = -ENOMEM; - goto out_free; + mutex_unlock(&card->dapm_mutex); + return -ENOMEM; } } @@ -3066,30 +3056,24 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) case snd_soc_dapm_switch: case snd_soc_dapm_mixer: case snd_soc_dapm_mixer_named_ctl: - ret = dapm_new_mixer(w); + dapm_new_mixer(w); break; case snd_soc_dapm_mux: case snd_soc_dapm_demux: - ret = dapm_new_mux(w); + dapm_new_mux(w); break; case snd_soc_dapm_pga: case snd_soc_dapm_effect: case snd_soc_dapm_out_drv: - ret = dapm_new_pga(w); + dapm_new_pga(w); break; case snd_soc_dapm_dai_link: - ret = dapm_new_dai_link(w); + dapm_new_dai_link(w); break; default: break; } - if (ret < 0) { - kfree(w->kcontrols); - w->kcontrols = NULL; - goto out_free; - } - /* Read the initial power state from the device */ if (w->reg >= 0) { soc_dapm_read(w->dapm, w->reg, &val); @@ -3098,11 +3082,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) if (val == w->on_val) w->power = 1; } - } - - list_for_each_entry(w, &card->widgets, list) { - if (w->new) - continue; w->new = 1; @@ -3113,66 +3092,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP); mutex_unlock(&card->dapm_mutex); return 0; - -out_free: - last = w; - - /* - * If any new widgets have been created above for .autodisable = 1 - * controls, they are also on this list, but at its very end. We're - * processing an error case, so the loop above was interrupted before - * reaching dynamically added widgets, since the latter cannot fail - - * their .num_controls = 0, so allocation cannot fail, and their type is - * snd_soc_dapm_kcontrol, those cannot fail either. Therefore "last" - * points to a widget before the first dynamic one. - */ - list_for_each_entry(w, &card->widgets, list) { - unsigned int i; - - if (w->new) - continue; - - if (w == last) - break; - - switch (w->id) { - case snd_soc_dapm_switch: - case snd_soc_dapm_mixer: - case snd_soc_dapm_mixer_named_ctl: - for (i = 0; i < w->num_kcontrols; i++) { - struct snd_kcontrol *kcontrol = w->kcontrols[i]; - struct dapm_kcontrol_data *data = - kcontrol->private_data; - struct soc_mixer_control *mc = - (struct soc_mixer_control *) - kcontrol->private_value; - - if (mc->autodisable) - snd_soc_dapm_free_widget(data->widget); - } - break; - case snd_soc_dapm_demux: - case snd_soc_dapm_mux: - for (i = 0; i < w->num_kcontrols; i++) { - struct snd_kcontrol *kcontrol = w->kcontrols[i]; - struct dapm_kcontrol_data *data = - kcontrol->private_data; - struct soc_enum *e = (struct soc_enum *) - kcontrol->private_value; - - if (e->autodisable) - snd_soc_dapm_free_widget(data->widget); - } - break; - default: - break; - } - - snd_soc_dapm_free_widget_data(w); - } - - mutex_unlock(&card->dapm_mutex); - return ret; } EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); From 760c99a0e586fd422d824c07ecc2c4b110e0f068 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 14 Jan 2019 23:50:28 -0800 Subject: [PATCH 0663/1995] Revert "soc: fix a use after free case" This reverts commit 057637349447338e7eeb289921380cd7011b84c9 "soc: fix a use after free case" Signed-off-by: Ranjani Sridharan --- sound/soc/soc-core.c | 2 +- sound/soc/soc-topology.c | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 02d72b4f3aa745..7f2eb7e6c709b6 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -951,7 +951,7 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order) { int err; - if (!dai || !dai->probed || !dai->driver || + if (!dai || !dai->probed || dai->driver->remove_order != order) return; diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 9bff5f2d533c81..ff84fe2a9c31db 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -520,7 +520,6 @@ static void remove_dai(struct snd_soc_component *comp, { struct snd_soc_dai_driver *dai_drv = container_of(dobj, struct snd_soc_dai_driver, dobj); - struct snd_soc_dai *dai; if (pass != SOC_TPLG_PASS_PCM_DAI) return; @@ -528,10 +527,6 @@ static void remove_dai(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->dai_unload) dobj->ops->dai_unload(comp, dobj); - list_for_each_entry(dai, &comp->dai_list, list) - if (dai->driver == dai_drv) - dai->driver = NULL; - kfree(dai_drv->name); list_del(&dobj->list); kfree(dai_drv); From 6b7db561d610bbd24348f0cf2e8d3a8d6ceb42f1 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 14 Jan 2019 23:20:04 -0800 Subject: [PATCH 0664/1995] ASoC: SOF: platform_device_unregister() should be the last step in sof_remove() platform_device_unregister() performs the cleanup of card resources and frees the card. But, in order to free up the resources related to topology in the SOF driver, card information needs to be valid. So move platform_device_unregister() to be the last step in sof_remove(). This will avoid the possibility of the card being freed before topology is freed and causing null pointer exceptions during SOF device removal. This makes the following commits redundant which were previously meant to address this issue: "ASoC:core:bug fix: oops caused by pointer dereference." - 4c10c44 "soc: fix a use after free case" - 0576373 "ASoC:topology:bug fix:check return value avoid oops." - 5711d8e Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 58ea0f200b1ead..8df9e1e375a8e2 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -372,15 +372,21 @@ static int sof_remove(struct platform_device *pdev) struct snd_sof_dev *sdev = dev_get_drvdata(&pdev->dev); struct snd_sof_pdata *pdata = sdev->pdata; - if (pdata && !IS_ERR_OR_NULL(pdata->pdev_mach)) - platform_device_unregister(pdata->pdev_mach); - snd_soc_unregister_component(&pdev->dev); snd_sof_fw_unload(sdev); snd_sof_ipc_free(sdev); snd_sof_free_debug(sdev); snd_sof_free_trace(sdev); snd_sof_remove(sdev); + + /* + * platform_device_unregister() frees the card and its resources. + * So it should be called after unregistering the comp driver + * so that the card is valid while unregistering comp driver. + */ + if (pdata && !IS_ERR_OR_NULL(pdata->pdev_mach)) + platform_device_unregister(pdata->pdev_mach); + return 0; } From 6262b8827cd54b181d1d4ddb831768023187da61 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Tue, 4 Dec 2018 00:45:11 +0800 Subject: [PATCH 0665/1995] ASoC: SOF: intel: set stream decouple false in hw_free move snd_hdac_ext_stream_decouple(bus, stream, false) to hda_link_hw_free() as snd_hdac_ext_stream_decouple(bus,stream, true) is called by hda_link_hw_params(). Signed-off-by: Bard liao --- sound/soc/sof/intel/hda-dai.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 85f0bedf4acdb7..f7b9771ec3cd93 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -170,9 +170,6 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, { struct hdac_ext_stream *link_dev = snd_soc_dai_get_dma_data(dai, substream); - struct hdac_stream *hstream = substream->runtime->private_data; - struct hdac_bus *bus = hstream->bus; - struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream); dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); switch (cmd) { @@ -186,8 +183,6 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: snd_hdac_ext_link_stream_clear(link_dev); - if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) - snd_hdac_ext_stream_decouple(bus, stream, false); break; default: @@ -222,6 +217,7 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream, bus = hstream->bus; rtd = snd_pcm_substream_chip(substream); link_dev = snd_soc_dai_get_dma_data(dai, substream); + snd_hdac_ext_stream_decouple(bus, link_dev, false); name = rtd->codec_dai->component->name; link = snd_hdac_ext_bus_get_link(bus, name); if (!link) From 4393aa92b0a15265116f704b4f0145d86ec71421 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 17 Jan 2019 16:32:16 +0200 Subject: [PATCH 0666/1995] ASoC: SOF: Allow block ops from multiple bars This allows for example loading firmware that uses different memory zones for data/text sections. Signed-off-by: Daniel Baluta --- sound/soc/sof/hw-spi.c | 8 ++++---- sound/soc/sof/intel/bdw.c | 3 ++- sound/soc/sof/intel/byt.c | 3 ++- sound/soc/sof/intel/hda-ipc.c | 3 ++- sound/soc/sof/intel/hda.c | 11 ++++++----- sound/soc/sof/intel/hsw.c | 3 ++- sound/soc/sof/ipc.c | 8 ++++---- sound/soc/sof/loader.c | 9 +++++---- sound/soc/sof/ops.h | 8 ++++---- sound/soc/sof/sof-priv.h | 8 ++++---- sound/soc/sof/utils.c | 8 ++++---- 11 files changed, 39 insertions(+), 33 deletions(-) diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index 920540356e6e77..02dab65b2cbe1f 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -36,8 +36,8 @@ * Memory copy. */ -static void spi_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, - size_t size) +static void spi_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, + void *dest, size_t size) { u8 *buf; int ret; @@ -62,8 +62,8 @@ static void spi_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, } } -static void spi_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, - size_t size) +static void spi_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, + void *src, size_t size) { int ret; u8 *buf; diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 25e28bbef43590..f6eb51605f7a6d 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -423,7 +423,8 @@ static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return 0; /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); + sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, + sizeof(*fw_ready)); snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, fw_ready->dspbox_size, diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 4d0d11a10f3dc3..a6a2dfecf820ce 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -204,7 +204,8 @@ static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return 0; /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); + sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, + sizeof(*fw_ready)); snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, fw_ready->dspbox_size, diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 5673905046cf3f..9ddfa9e1f96868 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -370,7 +370,8 @@ int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return 0; /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); + sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, + sizeof(*fw_ready)); /* make sure ABI version is compatible */ ret = snd_sof_ipc_valid(sdev); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index d62ea91d3f583a..007db62cebb2e5 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -105,15 +105,16 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev, u32 *stack, size_t stack_words) { /* first read registers */ - sof_block_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); + sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset, xoops, + sizeof(*xoops)); /* then get panic info */ - sof_block_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), - panic_info, sizeof(*panic_info)); + sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset + + sizeof(*xoops), panic_info, sizeof(*panic_info)); /* then get the stack */ - sof_block_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + - sizeof(*panic_info), stack, + sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset + + sizeof(*xoops) + sizeof(*panic_info), stack, stack_words * sizeof(u32)); } diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index cbffbdcf932c3e..d1c3ed9b0247d7 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -424,7 +424,8 @@ static int hsw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return 0; /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); + sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, + sizeof(*fw_ready)); snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, fw_ready->dspbox_size, diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 60bfa6a76ddc02..b2c073945423b4 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -627,8 +627,8 @@ int snd_sof_ipc_set_comp_data(struct snd_sof_ipc *ipc, /* read firmware volume */ if (scontrol->readback_offset != 0) { /* we can read value header via mmaped region */ - snd_sof_dsp_block_write(sdev, scontrol->readback_offset, - cdata->chanv, + snd_sof_dsp_block_write(sdev, sdev->mmio_bar, + scontrol->readback_offset, cdata->chanv, sizeof(struct sof_ipc_ctrl_value_chan) * cdata->num_elems); @@ -669,8 +669,8 @@ int snd_sof_ipc_get_comp_data(struct snd_sof_ipc *ipc, /* read firmware byte counters */ if (scontrol->readback_offset != 0) { /* we can read values via mmaped region */ - snd_sof_dsp_block_read(sdev, scontrol->readback_offset, - cdata->chanv, + snd_sof_dsp_block_read(sdev, sdev->mmio_bar, + scontrol->readback_offset, cdata->chanv, sizeof(struct sof_ipc_ctrl_value_chan) * cdata->num_elems); diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 3362861f2795e8..6710dc00fe9e22 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -45,13 +45,14 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) return -ENOMEM; /* get first header */ - snd_sof_dsp_block_read(sdev, offset, ext_data, sizeof(*ext_hdr)); + snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, ext_data, + sizeof(*ext_hdr)); ext_hdr = (struct sof_ipc_ext_data_hdr *)ext_data; while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) { /* read in ext structure */ offset += sizeof(*ext_hdr); - snd_sof_dsp_block_read(sdev, offset, + snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, ext_data + sizeof(*ext_hdr), ext_hdr->hdr.size - sizeof(*ext_hdr)); @@ -77,7 +78,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) /* move to next header */ offset += ext_hdr->hdr.size; - snd_sof_dsp_block_read(sdev, offset, ext_data, + snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, ext_data, sizeof(*ext_hdr)); ext_hdr = (struct sof_ipc_ext_data_hdr *)ext_data; } @@ -146,7 +147,7 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, block->size); return -EINVAL; } - snd_sof_dsp_block_write(sdev, offset, + snd_sof_dsp_block_write(sdev, sdev->mmio_bar, offset, (void *)block + sizeof(*block), block->size); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 68c340a3f3a153..2ae15025ed693c 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -182,18 +182,18 @@ static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar, } /* block IO */ -static inline void snd_sof_dsp_block_read(struct snd_sof_dev *sdev, +static inline void snd_sof_dsp_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, size_t bytes) { if (sof_ops(sdev)->block_read) - sof_ops(sdev)->block_read(sdev, offset, dest, bytes); + sof_ops(sdev)->block_read(sdev, bar, offset, dest, bytes); } -static inline void snd_sof_dsp_block_write(struct snd_sof_dev *sdev, +static inline void snd_sof_dsp_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, size_t bytes) { if (sof_ops(sdev)->block_write) - sof_ops(sdev)->block_write(sdev, offset, src, bytes); + sof_ops(sdev)->block_write(sdev, bar, offset, src, bytes); } /* mailbox */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 6c6f563f429643..212b79594486af 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -102,9 +102,9 @@ struct snd_sof_dsp_ops { u64 (*read64)(struct snd_sof_dev *sof_dev, void __iomem *addr); /* memcpy IO */ - void (*block_read)(struct snd_sof_dev *sof_dev, + void (*block_read)(struct snd_sof_dev *sof_dev, u32 bar, u32 offset, void *dest, size_t size); - void (*block_write)(struct snd_sof_dev *sof_dev, + void (*block_write)(struct snd_sof_dev *sof_dev, u32 bar, u32 offset, void *src, size_t size); /* doorbell */ @@ -558,9 +558,9 @@ void sof_mailbox_write(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes); void sof_mailbox_read(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes); -void sof_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, +void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, size_t size); -void sof_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, +void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, size_t size); #endif diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index 863c5a1f186250..484f57e1554a49 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -121,10 +121,10 @@ EXPORT_SYMBOL(sof_mailbox_read); * Memory copy. */ -void sof_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, +void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, size_t size) { - void __iomem *dest = sdev->bar[sdev->mmio_bar] + offset; + void __iomem *dest = sdev->bar[bar] + offset; const u8 *src_byte = src; u32 affected_mask; u32 tmp = 0; @@ -152,10 +152,10 @@ void sof_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, } EXPORT_SYMBOL(sof_block_write); -void sof_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, +void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, size_t size) { - void __iomem *src = sdev->bar[sdev->mmio_bar] + offset; + void __iomem *src = sdev->bar[bar] + offset; memcpy_fromio(dest, src, size); } From e6c9fa0145238a26d8bfcd85fed5bbde0f705d6b Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 16 Jan 2019 10:47:34 +0800 Subject: [PATCH 0667/1995] ASoC: SOF: refine more block comments Use correct style for block comments. It should be like /* * xxxxx * xxxxx */ Signed-off-by: Rander Wang --- sound/soc/sof/control.c | 11 +++++++---- sound/soc/sof/intel/hda-loader-skl.c | 21 +++++++++++++-------- sound/soc/sof/intel/hda-loader.c | 3 ++- sound/soc/sof/intel/hda-stream.c | 9 +++++---- sound/soc/sof/ipc.c | 3 ++- sound/soc/sof/ops.c | 3 ++- sound/soc/sof/topology.c | 8 +++++--- sound/soc/sof/virtio-be.c | 3 ++- sound/soc/sof/xtensa/core.c | 8 +++++--- 9 files changed, 43 insertions(+), 26 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index ab9ff937c3c3a1..71950d39aa5bf3 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -219,14 +219,16 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, int max_size = SOF_IPC_MSG_MAX_SIZE - sizeof(const struct sof_ipc_ctrl_data); - /* The beginning of bytes data contains a header from where + /* + * The beginning of bytes data contains a header from where * the length (as bytes) is needed to know the correct copy * length of data from tlvd->tlv. */ if (copy_from_user(&header, tlvd, sizeof(const struct snd_ctl_tlv))) return -EFAULT; - /* The maximum length that can be copied is limited by IPC max + /* + * The maximum length that can be copied is limited by IPC max * length and topology defined length for ext bytes control. */ if (be->max < max_size) /* min() not used to avoid sparse warnings */ @@ -309,8 +311,9 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, return ret; } - /* Decrement the limit by ext bytes header size to ensure - * the user space buffer is not exceeded. + /* + * Decrement the limit by ext bytes header size to + * ensure the user space buffer is not exceeded. */ size -= sizeof(const struct snd_ctl_tlv); diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index d3d520ecd17a76..7a9cf5e46c8442 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -169,7 +169,8 @@ static void cl_skl_cldma_stream_clear(struct snd_sof_dev *sdev) /* make sure Run bit is cleared before setting stream register */ cl_skl_cldma_stream_run(sdev, 0); - /* Disable the Interrupt On Completion, FIFO Error Interrupt, + /* + * Disable the Interrupt On Completion, FIFO Error Interrupt, * Descriptor Error Interrupt and set the cldma stream number to 0. */ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, @@ -254,7 +255,8 @@ static void cl_skl_cldma_setup_controller(struct snd_sof_dev *sdev, snd_sof_dsp_write(sdev, HDA_DSP_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, count - 1); - /* Set the Interrupt On Completion, FIFO Error Interrupt, + /* + * Set the Interrupt On Completion, FIFO Error Interrupt, * Descriptor Error Interrupt and the cldma stream number. */ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, @@ -310,8 +312,9 @@ static int cl_dsp_init_skl(struct snd_sof_dev *sdev) { int ret; - /* check if the core is already enabled, if yes, reset and make it run, - * if not, powerdown and enable it again. + /* + * check if the core is already enabled, if yes, reset and + * make it run. If not, powerdown and enable it again. */ if (hda_dsp_core_is_enabled(sdev, HDA_DSP_CORE_MASK(0))) { @@ -327,8 +330,9 @@ static int cl_dsp_init_skl(struct snd_sof_dev *sdev) goto err; } } else { - /* if not enabled, power down it first and then powerup and run - * the core. + /* + * if not enabled, power down it first and + * then powerup and runthe core. */ ret = hda_dsp_core_reset_power_down(sdev, HDA_DSP_CORE_MASK(0)); if (ret < 0) { @@ -494,8 +498,9 @@ int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev) init_waitqueue_head(&sdev->boot_wait); sdev->boot_complete = false; - /* at this point DSP ROM has been initialized and should be ready for - * code loading and firmware boot + /* + * at this point DSP ROM has been initialized and should + * be ready for code loading and firmware boot */ ret = cl_copy_fw_skl(sdev); if (ret < 0) { diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index ef425092e1ea5d..ef968a6b6d720d 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -315,7 +315,8 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) goto cleanup; } - /* at this point DSP ROM has been initialized and + /* + * at this point DSP ROM has been initialized and * should be ready for code loading and firmware boot */ ret = cl_copy_fw(sdev, stream); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 0fbcda92395d9f..f62f6a51caadb2 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -352,8 +352,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, return ret; } - /* set up stream descriptor for DMA */ - /* program stream tag */ + /* program stream tag to set up stream descriptor for DMA */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, SOF_HDA_CL_SD_CTL_STREAM_TAG_MASK, hstream->stream_tag << @@ -510,8 +509,10 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) return -EINVAL; } - /* mem alloc for the position buffer */ - /* TODO: check position buffer update */ + /* + * mem alloc for the position buffer + * TODO: check position buffer update + */ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, SOF_HDA_DPIB_ENTRY_SIZE * num_total, &bus->posbuf); diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index b2c073945423b4..b52fee9c6c482c 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -203,7 +203,8 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, ret = wait_event_timeout(msg->waitq, msg->ipc_complete, msecs_to_jiffies(IPC_TIMEOUT_MS)); - /* ipc_lock is used to protect ipc message list shared by user + /* + * ipc_lock is used to protect ipc message list shared by user * contexts and a workqueue. There is no need to save interrupt * status with spin_lock_irqsave. */ diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index 8b92cf59031e83..fb77499b89d66d 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -183,7 +183,8 @@ void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset) { dev_err(sdev->dev, "error : DSP panic!\n"); - /* check if DSP is not ready and did not set the dsp_oops_offset. + /* + * check if DSP is not ready and did not set the dsp_oops_offset. * if the dsp_oops_offset is not set, set it from the panic message. * Also add a check to memory window setting with panic message. */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index ec92b8c33a7fbd..57a7b48d5dd895 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -138,8 +138,9 @@ static u32 vol_compute_gain(u32 value, int *tlv) if (value == 0 && tlv[TLV_MUTE]) return 0; - /* compute dB gain from tlv - * tlv_step in topology is multiplied by 100 + /* + * compute dB gain from tlv. tlv_step + * in topology is multiplied by 100 */ dB_gain = tlv[TLV_MIN] + (value * tlv[TLV_STEP]) / 100; @@ -2602,7 +2603,8 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, connect->sink_id = sink_swidget->comp_id; - /* Some virtual routes and widgets may been added in topology for + /* + * Some virtual routes and widgets may been added in topology for * compatibility. For virtual routes, both sink and source are not * buffer. Since only buffer linked to component is supported by * FW, others are reported as error, add check in route function, diff --git a/sound/soc/sof/virtio-be.c b/sound/soc/sof/virtio-be.c index eca63a8765fe1d..bd71466a368a64 100644 --- a/sound/soc/sof/virtio-be.c +++ b/sound/soc/sof/virtio-be.c @@ -22,7 +22,8 @@ #include "sof-priv.h" #include "ops.h" -/* BE driver +/* + * BE driver * * This driver will create IO Queues for communition from FE drivers. * The FE driver will send real IPC structures over the queue and then diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c index 930d6749a560ed..c3ad23a85b99fe 100644 --- a/sound/soc/sof/xtensa/core.c +++ b/sound/soc/sof/xtensa/core.c @@ -19,8 +19,9 @@ struct xtensa_exception_cause { const char *description; }; -/* From 4.4.1.5 table 4-64 Exception Causes of - * Xtensa Instruction Set Architecture (ISA) Reference Manual +/* + * From 4.4.1.5 table 4-64 Exception Causes of Xtensa + * Instruction Set Architecture (ISA) Reference Manual */ static const struct xtensa_exception_cause xtensa_exception_causes[] = { {0, "IllegalInstructionCause", "Illegal instruction"}, @@ -116,7 +117,8 @@ static void xtensa_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack, dev_err(sdev->dev, "stack dump from 0x%8.8x\n", stack_ptr); - /* example output: + /* + * example output: * 0x0049fbb0: 8000f2d0 0049fc00 6f6c6c61 00632e63 */ for (i = 0; i < stack_words; i += 4) { From 6ee633241db043c824595137f2ef69f1780460c0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 16 Jan 2019 15:52:47 -0600 Subject: [PATCH 0668/1995] ASoC: SOF: fix error logs on failed request_firmware Add filename, align topology and loader cases. Comment from Mark Brown. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/loader.c | 4 ++-- sound/soc/sof/topology.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 6710dc00fe9e22..7083d993e331aa 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -239,8 +239,8 @@ int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev) ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev); if (ret < 0) { - dev_err(sdev->dev, "error: request firmware failed err: %d\n", - ret); + dev_err(sdev->dev, "error: request firmware %s failed err: %d\n", + fw_filename, ret); return ret; } diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 57a7b48d5dd895..5d554f6c0333f4 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2781,7 +2781,7 @@ int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file) ret = request_firmware(&fw, file, sdev->dev); if (ret < 0) { - dev_err(sdev->dev, "error: tplg %s load failed with %d\n", + dev_err(sdev->dev, "error: tplg request firmware %s failed err: %d\n", file, ret); return ret; } From f21fd0442c6d01049cb05c3a5d688da45f4660b9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 16 Jan 2019 15:54:58 -0600 Subject: [PATCH 0669/1995] ASoC: SOF: debug: move to EXPORT_SYMBOL_GPL We don't have a good reason to use EXPORT_SYMBOL since this part only makes sense for Linux. Comment from Mark Brown. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/debug.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 5788690ee063da..f59980831b2ea9 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -106,7 +106,7 @@ int snd_sof_debugfs_io_create_item(struct snd_sof_dev *sdev, return 0; } -EXPORT_SYMBOL(snd_sof_debugfs_io_create_item); +EXPORT_SYMBOL_GPL(snd_sof_debugfs_io_create_item); /* create FS entry for debug files to expose kernel memory */ int snd_sof_debugfs_buf_create_item(struct snd_sof_dev *sdev, @@ -136,7 +136,7 @@ int snd_sof_debugfs_buf_create_item(struct snd_sof_dev *sdev, return 0; } -EXPORT_SYMBOL(snd_sof_debugfs_buf_create_item); +EXPORT_SYMBOL_GPL(snd_sof_debugfs_buf_create_item); int snd_sof_dbg_init(struct snd_sof_dev *sdev) { @@ -165,10 +165,10 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) return 0; } -EXPORT_SYMBOL(snd_sof_dbg_init); +EXPORT_SYMBOL_GPL(snd_sof_dbg_init); void snd_sof_free_debug(struct snd_sof_dev *sdev) { debugfs_remove_recursive(sdev->debugfs_root); } -EXPORT_SYMBOL(snd_sof_free_debug); +EXPORT_SYMBOL_GPL(snd_sof_free_debug); From 33e3caadf90f7405bb510da4901d083e32b847e8 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 17 Jan 2019 10:19:09 -0800 Subject: [PATCH 0670/1995] ASoC: SOF: remove prepare() PM callback This change pre-dates all the recent updates done to improve suspend stress test pass rates. It is no longer needed. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pm.c | 27 +++++---------------------- sound/soc/sof/sof-pci-dev.c | 2 -- sound/soc/sof/sof-priv.h | 4 ---- 3 files changed, 5 insertions(+), 28 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 7f4c4ac86c2230..93102993b508dc 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -170,10 +170,12 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev) } /* restore pipeline kcontrols */ - if (sdev->restore_kcontrols) - return sof_restore_kcontrols(sdev); + ret = sof_restore_kcontrols(sdev); + if (ret < 0) + dev_err(sdev->dev, + "error: restoring kcontrols after resume\n"); - return 0; + return ret; } static int sof_send_pm_ipc(struct snd_sof_dev *sdev, int cmd) @@ -344,9 +346,6 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) "error: failed to power down DSP during suspend %d\n", ret); - /* set flag for restoring kcontrols upon resuming */ - sdev->restore_kcontrols = true; - return ret; } @@ -373,19 +372,3 @@ int snd_sof_suspend(struct device *dev) return sof_suspend(dev, false); } EXPORT_SYMBOL(snd_sof_suspend); - -int snd_sof_prepare(struct device *dev) -{ - struct sof_platform_priv *priv = dev_get_drvdata(dev); - struct snd_sof_dev *sdev = dev_get_drvdata(&priv->pdev_pcm->dev); - - /* - * PCI devices are brought back to full power before system suspend. - * Setting this flag will prevent restoring kcontrols - * when resuming before system suspend - */ - sdev->restore_kcontrols = false; - - return 0; -} -EXPORT_SYMBOL(snd_sof_prepare); diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 881cac96f07a57..a62ff9c337486e 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -148,8 +148,6 @@ static const struct dev_pm_ops sof_pci_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, NULL) - .prepare = snd_sof_prepare, - }; static int sof_pci_probe(struct pci_dev *pci, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 212b79594486af..21d6c873f87795 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -375,9 +375,6 @@ struct snd_sof_dev { u32 dtrace_error; u32 msi_enabled; - /* PM */ - u32 restore_kcontrols; /* restore kcontrols upon resume */ - void *private; /* core does not touch this */ }; @@ -397,7 +394,6 @@ int snd_sof_runtime_suspend(struct device *dev); int snd_sof_runtime_resume(struct device *dev); int snd_sof_resume(struct device *dev); int snd_sof_suspend(struct device *dev); -int snd_sof_prepare(struct device *dev); int snd_sof_suspend_late(struct device *dev); void snd_sof_new_platform_drv(struct snd_sof_dev *sdev); From 169157d5c1cb0ce94e75e2127c993ce4a62f9508 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 17 Jan 2019 10:21:05 -0800 Subject: [PATCH 0671/1995] ASoC: SOF: remove definition for snd_sof_suspend_late() SOF doesn't use it anymore. So no need to define it. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/sof-priv.h | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 21d6c873f87795..7bc98382e366ad 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -394,7 +394,6 @@ int snd_sof_runtime_suspend(struct device *dev); int snd_sof_runtime_resume(struct device *dev); int snd_sof_resume(struct device *dev); int snd_sof_suspend(struct device *dev); -int snd_sof_suspend_late(struct device *dev); void snd_sof_new_platform_drv(struct snd_sof_dev *sdev); From dcab075c4cc76c8ac0005fa7ee460b789fb96cdf Mon Sep 17 00:00:00 2001 From: Bard liao Date: Wed, 16 Jan 2019 06:17:44 +0800 Subject: [PATCH 0672/1995] ASoC: intel: add sof rt5682 machine driver The machine driver is a generic machine driver for SOF with rt5682 codec, currently support ICL and CML. Signed-off-by: Bard liao --- sound/soc/intel/boards/Kconfig | 14 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/sof_rt5682.c | 359 ++++++++++++++++++ .../intel/common/soc-acpi-intel-cnl-match.c | 7 + .../intel/common/soc-acpi-intel-icl-match.c | 7 + 5 files changed, 389 insertions(+) create mode 100644 sound/soc/intel/boards/sof_rt5682.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 6f242aabd52ed2..25796ef5a15602 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -377,4 +377,18 @@ config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC +if SND_SOC_SOF_HDA_COMMON +config SND_SOC_INTEL_SOF_RT5682_MACH + tristate "SOF with rt5682 codec in I2S Mode" + depends on MFD_INTEL_LPSS && I2C && ACPI + select SND_SOC_RT5682 + select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC machine driver for SOF platforms + with rt5682 codec. + Say Y if you have such a device. + If unsure select "N". +endif ## SND_SOC_SOF_HDA_COMMON + endif ## SND_SOC_INTEL_MACH diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index a9408475f2593e..fde39ebbb1049d 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -18,6 +18,7 @@ snd-soc-sst-cht-bsw-nau8824-objs := cht_bsw_nau8824.o snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o +snd-soc-sof_rt5682-objs := sof_rt5682.o snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o @@ -28,6 +29,7 @@ snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c new file mode 100644 index 00000000000000..935f8acbf5953e --- /dev/null +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2019 Intel Corporation. + +/* + * Intel SOF Machine Driver with Realtek rt5682 Codec + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/rt5682.h" +#include "../../codecs/hdac_hdmi.h" + +#define DUAL_CHANNEL 2 +#define QUAD_CHANNEL 4 +#define NAME_SIZE 32 + +#define SOF_RT5682_MCLK_EN BIT(0) +#define SOF_RT5682_MCLK_24MHZ BIT(1) +#define SOF_RT5682_SSP0 BIT(2) +#define SOF_RT5682_SSP1 BIT(3) + +static char sof_rt5682_cpu_dai_name[9]; /* = "SSP[0/1] Pin" */ +static char sof_rt5682_dai_link_name[11]; /* = "SSP[0/1]-Codec" */ + +/* Default: MCLK on, MCLK 19.2M, SSP0 */ +static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP0; + +static struct snd_soc_jack sof_hdmi[3]; + +struct sof_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct sof_card_private { + struct snd_soc_jack sof_headset; + struct list_head hdmi_pcm_list; +}; + +static int sof_rt5682_quirk_cb(const struct dmi_system_id *id) +{ + sof_rt5682_quirk = (unsigned long)id->driver_data; + return 1; +} + +static const struct dmi_system_id sof_rt5682_quirk_table[] = { + { + .callback = sof_rt5682_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "WhiskeyLake Client"), + }, + .driver_data = (void *)(SOF_RT5682_MCLK_EN | + SOF_RT5682_MCLK_24MHZ | + SOF_RT5682_SSP1), + }, + { + .callback = sof_rt5682_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"), + }, + .driver_data = (void *)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP0), + }, + {} +}; + +static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct sof_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = dai->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_component *component = rtd->codec_dai->component; + struct snd_soc_jack *jack; + int ret; + + /* need to enable ASRC function for 24MHz mclk rate */ + if ((sof_rt5682_quirk & SOF_RT5682_MCLK_EN) && + (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ)) { + rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER, + RT5682_CLK_SEL_I2S1_ASRC); + } + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->sof_headset, NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + jack = &ctx->sof_headset; + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + ret = snd_soc_component_set_jack(component, jack, NULL); + + if (ret) { + dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); + return ret; + } + + return ret; +}; + +static int sof_rt5682_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 clk_id, clk_freq, pll_out, ret; + + if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) { + clk_id = RT5682_PLL1_S_MCLK; + if (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ) + clk_freq = 24000000; + else + clk_freq = 19200000; + } else { + clk_id = RT5682_PLL1_S_BCLK1; + clk_freq = params_rate(params) * 50; + } + + pll_out = params_rate(params) * 512; + + ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); + if (ret < 0) + dev_err(rtd->dev, "snd_soc_dai_set_pll err = %d\n", ret); + + /* Configure sysclk for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, + pll_out, SND_SOC_CLOCK_IN); + if (ret < 0) + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + + /* + * slot_width should equal or large than data length, set them + * be the same + */ + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, + params_width(params)); + if (ret < 0) { + dev_err(rtd->dev, "set TDM slot err:%d\n", ret); + return ret; + } + + return ret; +} + +static struct snd_soc_ops sof_rt5682_ops = { + .hw_params = sof_rt5682_hw_params, +}; + +/* sof digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link sof_rt5682_dais[] = { + /* Back End DAI links */ + { + .name = "SSP0-Codec", + .id = 0, + .cpu_dai_name = "SSP0 Pin", + .codec_name = "i2c-10EC5682:00", + .codec_dai_name = "rt5682-aif1", + .init = sof_rt5682_codec_init, + .ops = &sof_rt5682_ops, + .nonatomic = true, + .dpcm_playback = 1, + .dpcm_capture = 1, + .no_pcm = 1, + }, + { + .name = "dmic01", + .id = 1, + .cpu_dai_name = "DMIC01 Pin", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + }, + { + .name = "iDisp1", + .id = 2, + .cpu_dai_name = "iDisp1 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .init = sof_hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp2", + .id = 3, + .cpu_dai_name = "iDisp2 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi2", + .init = sof_hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, + { + .name = "iDisp3", + .id = 4, + .cpu_dai_name = "iDisp3 Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi3", + .init = sof_hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +static int sof_card_late_probe(struct snd_soc_card *card) +{ + struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component = NULL; + char jack_name[NAME_SIZE]; + struct sof_hdmi_pcm *pcm; + int err = 0; + int i = 0; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &sof_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &sof_hdmi[i]); + if (err < 0) + return err; + + i++; + } + + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); +} + +static const struct snd_kcontrol_new sof_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +static const struct snd_soc_dapm_widget sof_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_dapm_route sof_map[] = { + /* HP jack connectors - unknown if we have jack detection */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + + /* other jacks */ + { "IN1P", NULL, "Headset Mic" }, + +}; + +/* sof audio machine driver for rt5682 codec */ +static struct snd_soc_card sof_audio_card_rt5682 = { + .name = "sof_rt5682", + .owner = THIS_MODULE, + .dai_link = sof_rt5682_dais, + .num_links = ARRAY_SIZE(sof_rt5682_dais), + .controls = sof_controls, + .num_controls = ARRAY_SIZE(sof_controls), + .dapm_widgets = sof_widgets, + .num_dapm_widgets = ARRAY_SIZE(sof_widgets), + .dapm_routes = sof_map, + .num_dapm_routes = ARRAY_SIZE(sof_map), + .fully_routed = true, + .late_probe = sof_card_late_probe, +}; + +static int sof_audio_probe(struct platform_device *pdev) +{ + struct sof_card_private *ctx; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + dmi_check_system(sof_rt5682_quirk_table); + + if (sof_rt5682_quirk & SOF_RT5682_SSP1) { + snprintf(sof_rt5682_dai_link_name, + sizeof(sof_rt5682_dai_link_name), + "%s", "SSP1-Codec"); + snprintf(sof_rt5682_cpu_dai_name, + sizeof(sof_rt5682_cpu_dai_name), + "%s", "SSP1 Pin"); + sof_rt5682_dais[0].name = sof_rt5682_dai_link_name; + sof_rt5682_dais[0].cpu_dai_name = sof_rt5682_cpu_dai_name; + } + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + sof_audio_card_rt5682.dev = &pdev->dev; + snd_soc_card_set_drvdata(&sof_audio_card_rt5682, ctx); + + return devm_snd_soc_register_card(&pdev->dev, + &sof_audio_card_rt5682); +} + +static struct platform_driver sof_audio = { + .probe = sof_audio_probe, + .driver = { + .name = "sof_rt5682", + .pm = &snd_soc_pm_ops, + }, +}; +module_platform_driver(sof_audio) + +/* Module information */ +MODULE_DESCRIPTION("SOF Audio Machine driver"); +MODULE_AUTHOR("Bard Liao "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:sof_rt5682"); diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index ae3be064e75e99..ea8872dc4d8ee4 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -33,6 +33,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .sof_tplg_filename = "intel/sof-cnl.tplg", .asoc_plat_name = "0000:00:0e.0", }, + { + .id = "10EC5682", + .drv_name = "sof_rt5682", + .sof_fw_filename = "intel/sof-cnl.ri", + .sof_tplg_filename = "intel/sof-cml-rt5682.tplg", + .asoc_plat_name = "0000:00:0e.0", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c index 33b441dca4d308..c58e86d9692b41 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -24,6 +24,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { .sof_tplg_filename = "intel/sof-icl-rt274.tplg", .asoc_plat_name = "0000:00:1f.3", }, + { + .id = "10EC5682", + .drv_name = "sof_rt5682", + .sof_fw_filename = "intel/sof-icl.ri", + .sof_tplg_filename = "intel/sof-icl-rt5682.tplg", + .asoc_plat_name = "0000:00:1f.3", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_icl_machines); From a5dd3186a67ba718862381e97a5f80ee93a99ce4 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Thu, 17 Jan 2019 07:28:45 +0800 Subject: [PATCH 0673/1995] ASoC: SOF: topology: remove snd_sof_free_topology snd_soc_tplg_component_remove() will be invoked by snd_soc_unregister_ component(), and we call snd_soc_unregister_component() in sof_remove(). So we don't need to call it again in snd_sof_free_topology(). Also, the tplg_loaded is not needed since topology load/unload are even now. Signed-off-by: Bard liao --- sound/soc/sof/pcm.c | 5 ----- sound/soc/sof/sof-priv.h | 4 ++-- sound/soc/sof/topology.c | 26 -------------------------- 3 files changed, 2 insertions(+), 33 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 2570ad8f987fa9..cf3ce29c318996 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -668,12 +668,7 @@ static int sof_pcm_probe(struct snd_soc_component *component) static void sof_pcm_remove(struct snd_soc_component *component) { - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(component); - pm_runtime_disable(component->dev); - snd_sof_free_topology(sdev); - } void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 7bc98382e366ad..d704cc5c0969ab 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -351,7 +351,6 @@ struct snd_sof_dev { struct list_head dai_list; struct list_head route_list; struct snd_soc_component *component; - int tplg_loaded; /* keep track of topology load success */ /* FW configuration */ struct sof_ipc_dma_buffer_data *info_buffer; @@ -464,11 +463,12 @@ int snd_sof_ipc_get_comp_data(struct snd_sof_ipc *ipc, /* * Topology. + * There is no snd_sof_free_topology since topology components will + * be freed by snd_soc_unregister_component, */ int snd_sof_init_topology(struct snd_sof_dev *sdev, struct snd_soc_tplg_ops *ops); int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file); -void snd_sof_free_topology(struct snd_sof_dev *sdev); int snd_sof_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 5d554f6c0333f4..f013b1f8dc6b8a 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2772,11 +2772,6 @@ int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file) const struct firmware *fw; int ret; - if (sdev->tplg_loaded) { - dev_err(sdev->dev, "error: topology already loaded ?\n"); - return -EINVAL; - } - dev_dbg(sdev->dev, "loading topology:%s\n", file); ret = request_firmware(&fw, file, sdev->dev); @@ -2795,29 +2790,8 @@ int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file) ret = -EINVAL; } - sdev->tplg_loaded = true; - release_firmware(fw); return ret; } EXPORT_SYMBOL(snd_sof_load_topology); -void snd_sof_free_topology(struct snd_sof_dev *sdev) -{ - int ret; - - dev_dbg(sdev->dev, "free topology...\n"); - if (!sdev->tplg_loaded) { - dev_dbg(sdev->dev, "No topology loaded, nothing to free ...\n"); - return; - } - - ret = snd_soc_tplg_component_remove(sdev->component, - SND_SOC_TPLG_INDEX_ALL); - if (ret < 0) - dev_err(sdev->dev, - "error: tplg component free failed %d\n", ret); - - sdev->tplg_loaded = false; -} -EXPORT_SYMBOL(snd_sof_free_topology); From 5bea51e99687c764022305bcdb4e8ab34f89220a Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 15 Jan 2019 11:27:39 +0800 Subject: [PATCH 0674/1995] ASoC: rt5682: Fix PLL source register definitions Fix typo which causes headphone no sound while using BCLK as PLL source. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown (cherry picked from commit ee7ea2a9a318a89d21b156dc75e54d53904bdbe5) --- sound/soc/codecs/rt5682.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h index d82a8301fd745c..96944cff0ed730 100644 --- a/sound/soc/codecs/rt5682.h +++ b/sound/soc/codecs/rt5682.h @@ -849,18 +849,18 @@ #define RT5682_SCLK_SRC_PLL2 (0x2 << 13) #define RT5682_SCLK_SRC_SDW (0x3 << 13) #define RT5682_SCLK_SRC_RCCLK (0x4 << 13) -#define RT5682_PLL1_SRC_MASK (0x3 << 10) -#define RT5682_PLL1_SRC_SFT 10 -#define RT5682_PLL1_SRC_MCLK (0x0 << 10) -#define RT5682_PLL1_SRC_BCLK1 (0x1 << 10) -#define RT5682_PLL1_SRC_SDW (0x2 << 10) -#define RT5682_PLL1_SRC_RC (0x3 << 10) -#define RT5682_PLL2_SRC_MASK (0x3 << 8) -#define RT5682_PLL2_SRC_SFT 8 -#define RT5682_PLL2_SRC_MCLK (0x0 << 8) -#define RT5682_PLL2_SRC_BCLK1 (0x1 << 8) -#define RT5682_PLL2_SRC_SDW (0x2 << 8) -#define RT5682_PLL2_SRC_RC (0x3 << 8) +#define RT5682_PLL2_SRC_MASK (0x3 << 10) +#define RT5682_PLL2_SRC_SFT 10 +#define RT5682_PLL2_SRC_MCLK (0x0 << 10) +#define RT5682_PLL2_SRC_BCLK1 (0x1 << 10) +#define RT5682_PLL2_SRC_SDW (0x2 << 10) +#define RT5682_PLL2_SRC_RC (0x3 << 10) +#define RT5682_PLL1_SRC_MASK (0x3 << 8) +#define RT5682_PLL1_SRC_SFT 8 +#define RT5682_PLL1_SRC_MCLK (0x0 << 8) +#define RT5682_PLL1_SRC_BCLK1 (0x1 << 8) +#define RT5682_PLL1_SRC_SDW (0x2 << 8) +#define RT5682_PLL1_SRC_RC (0x3 << 8) From 163cd51ed19d7aacde132f3dee62da7edd91bd0c Mon Sep 17 00:00:00 2001 From: Silvio Cesare Date: Sat, 12 Jan 2019 16:28:43 +0100 Subject: [PATCH 0675/1995] ASoC: dapm: change snprintf to scnprintf for possible overflow Change snprintf to scnprintf. There are generally two cases where using snprintf causes problems. 1) Uses of size += snprintf(buf, SIZE - size, fmt, ...) In this case, if snprintf would have written more characters than what the buffer size (SIZE) is, then size will end up larger than SIZE. In later uses of snprintf, SIZE - size will result in a negative number, leading to problems. Note that size might already be too large by using size = snprintf before the code reaches a case of size += snprintf. 2) If size is ultimately used as a length parameter for a copy back to user space, then it will potentially allow for a buffer overflow and information disclosure when size is greater than SIZE. When the size is used to index the buffer directly, we can have memory corruption. This also means when size = snprintf... is used, it may also cause problems since size may become large. Copying to userspace is mitigated by the HARDENED_USERCOPY kernel configuration. The solution to these issues is to use scnprintf which returns the number of characters actually written to the buffer, so the size variable will never exceed SIZE. Signed-off-by: Silvio Cesare Cc: Liam Girdwood Cc: Mark Brown Cc: Dan Carpenter Cc: Kees Cook Cc: Will Deacon Cc: Greg KH Signed-off-by: Willy Tarreau Signed-off-by: Mark Brown (cherry picked from commit e581e151e965bf1f2815dd94620b638fec4d0a7e) --- sound/soc/soc-dapm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index a5178845065b35..2c4c1341953929 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2019,19 +2019,19 @@ static ssize_t dapm_widget_power_read_file(struct file *file, out = is_connected_output_ep(w, NULL, NULL); } - ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", + ret = scnprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", w->name, w->power ? "On" : "Off", w->force ? " (forced)" : "", in, out); if (w->reg >= 0) - ret += snprintf(buf + ret, PAGE_SIZE - ret, + ret += scnprintf(buf + ret, PAGE_SIZE - ret, " - R%d(0x%x) mask 0x%x", w->reg, w->reg, w->mask << w->shift); - ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n"); if (w->sname) - ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n", + ret += scnprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n", w->sname, w->active ? "active" : "inactive"); @@ -2044,7 +2044,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file, if (!p->connect) continue; - ret += snprintf(buf + ret, PAGE_SIZE - ret, + ret += scnprintf(buf + ret, PAGE_SIZE - ret, " %s \"%s\" \"%s\"\n", (rdir == SND_SOC_DAPM_DIR_IN) ? "in" : "out", p->name ? p->name : "static", From 49c0190ab56699bacd913d82fe351849b7c8dde5 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 15 Jan 2019 11:57:23 -0600 Subject: [PATCH 0676/1995] ASoC: rt5514-spi: Fix potential NULL pointer dereference There is a potential NULL pointer dereference in case devm_kzalloc() fails and returns NULL. Fix this by adding a NULL check on rt5514_dsp. This issue was detected with the help of Coccinelle. Fixes: 6eebf35b0e4a ("ASoC: rt5514: add rt5514 SPI driver") Cc: stable@vger.kernel.org Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown (cherry picked from commit 060d0bf491874daece47053c4e1fb0489eb867d2) --- sound/soc/codecs/rt5514-spi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 4d46f4567c3a8c..bec2eefa8b0f03 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -280,6 +280,8 @@ static int rt5514_spi_pcm_probe(struct snd_soc_component *component) rt5514_dsp = devm_kzalloc(component->dev, sizeof(*rt5514_dsp), GFP_KERNEL); + if (!rt5514_dsp) + return -ENOMEM; rt5514_dsp->dev = &rt5514_spi->dev; mutex_init(&rt5514_dsp->dma_lock); From b2b8f8ac659e9c2db6111a0378f657a6c65414a5 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Thu, 17 Jan 2019 06:08:53 +0800 Subject: [PATCH 0677/1995] ASoC: rt5682: add default pdata for i2s mode Add a default pdata which can fit most HW design. So we don't need to add a lot of DMI checking in this driver. Signed-off-by: Bard liao Signed-off-by: Mark Brown (cherry picked from commit 3ac1b2e4158c73175278a27c5551fa331c260b48) --- sound/soc/codecs/rt5682.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 89c43b26c37908..bd45d0343913c0 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -43,6 +43,12 @@ static const char *rt5682_supply_names[RT5682_NUM_SUPPLIES] = { "VBAT", }; +static const struct rt5682_platform_data i2s_default_platform_data = { + .dmic1_data_pin = RT5682_DMIC1_DATA_GPIO2, + .dmic1_clk_pin = RT5682_DMIC1_CLK_GPIO3, + .jd_src = RT5682_JD1, +}; + struct rt5682_priv { struct snd_soc_component *component; struct rt5682_platform_data pdata; @@ -2534,6 +2540,8 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, rt5682); + rt5682->pdata = i2s_default_platform_data; + if (pdata) rt5682->pdata = *pdata; else From 502bcb58c2fbcc8ab2c0237bd32016f039db8689 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 18 Jan 2019 11:20:41 +0900 Subject: [PATCH 0678/1995] ASoC: soc.h: add explanation of legacy/modern style of dai_link Current ALSA SoC is assuming 1 CPU 1 Platform (= DMA) style system. Because of this background, it is directly using xxx_name / xxx_of_node / xxx_dai_name on dai_link. Let's call it as legacy style here. More complex style system like multi CPU multi Platform (= DMA) will coming. To supporting it, we can use snd_soc_dai_link_component on dai_link. Let's call it as modern style here. But current ALSA SoC can't support it so far. Thus, we need to have multi CPU / multi Codec / multi Platform style in the future on ALSA SoC. Currently we already have multi Codec support. Platform is starting to use modern style on dai_link, but still style only. Multi Platform is not yet implemented. And we still don't have multi CPU support on ALSA SoC, and not have modern style either. Currently, if driver is using legacy style Codec/Platform, it will be converted to modern style on soc-core. This means, we are using glue code for legacy vs modern style so far on ALSA SoC. We can fully switch to modern style on all drivers if ALSA SoC supported modern style for CPU, and then, legacy style code will be removed from ALSA SoC. Untile then, we need to keep both legacy/modern style and its glue code. This patch adds such future plan and background on soc.h Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 62bc79d35ebb55451112979babea864975cfd16d) --- include/sound/soc.h | 36 ++++++++++++++++++++++++++++++++++++ sound/soc/soc-core.c | 20 ++++++++++++++++++-- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 8ec1de856ee7e1..12e67273cf65dc 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -891,6 +891,18 @@ struct snd_soc_dai_link { /* config - must be set by machine driver */ const char *name; /* Codec name */ const char *stream_name; /* Stream name */ + + /* + * cpu_name + * cpu_of_node + * cpu_dai_name + * + * These are legacy style, and will be replaced to + * modern style (= snd_soc_dai_link_component) in the future, + * but, not yet supported so far. + * If modern style was supported for CPU, all driver will switch + * to use it, and, legacy style code will be removed from ALSA SoC. + */ /* * You MAY specify the link's CPU-side device, either by device name, * or by DT/OF node, but not both. If this information is omitted, @@ -906,6 +918,19 @@ struct snd_soc_dai_link { * only, which only works well when that device exposes a single DAI. */ const char *cpu_dai_name; + + /* + * codec_name + * codec_of_node + * codec_dai_name + * + * These are legacy style, it will be converted to modern style + * (= snd_soc_dai_link_component) automatically in soc-core + * if driver is using legacy style. + * Driver shouldn't use both legacy and modern style in the same time. + * If modern style was supported for CPU, all driver will switch + * to use it, and, legacy style code will be removed from ALSA SoC. + */ /* * You MUST specify the link's codec, either by device name, or by * DT/OF node, but not both. @@ -918,6 +943,17 @@ struct snd_soc_dai_link { struct snd_soc_dai_link_component *codecs; unsigned int num_codecs; + /* + * platform_name + * platform_of_node + * + * These are legacy style, it will be converted to modern style + * (= snd_soc_dai_link_component) automatically in soc-core + * if driver is using legacy style. + * Driver shouldn't use both legacy and modern style in the same time. + * If modern style was supported for CPU, all driver will switch + * to use it, and, legacy style code will be removed from ALSA SoC. + */ /* * You MAY specify the link's platform/PCM/DMA driver, either by * device name, or by DT/OF node, but not both. Some forms of link diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9fd83dc569ebe6..f340cfa13dd6e0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1029,9 +1029,14 @@ static int snd_soc_init_platform(struct snd_soc_card *card, struct snd_soc_dai_link_component *platform = dai_link->platform; /* - * FIXME + * REMOVE ME * - * this function should be removed in the future + * This is glue code for Legacy vs Modern dai_link. + * This function will be removed if all derivers are switched to + * modern style dai_link. + * Driver shouldn't use both legacy and modern style in the same time. + * see + * soc.h :: struct snd_soc_dai_link */ /* convert Legacy platform link */ if (!platform) { @@ -1058,6 +1063,17 @@ static int snd_soc_init_platform(struct snd_soc_card *card, static int snd_soc_init_multicodec(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { + /* + * REMOVE ME + * + * This is glue code for Legacy vs Modern dai_link. + * This function will be removed if all derivers are switched to + * modern style dai_link. + * Driver shouldn't use both legacy and modern style in the same time. + * see + * soc.h :: struct snd_soc_dai_link + */ + /* Legacy codec/codec_dai link is a single entry in multicodec */ if (dai_link->codec_name || dai_link->codec_of_node || dai_link->codec_dai_name) { From c74579aa177b334b0b96b2b23f08014c5b70e223 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 8 Jan 2019 11:37:31 +0100 Subject: [PATCH 0679/1995] ASoC: intel: skl: Fix display power regression Since the refactoring of HD-audio display power management, the display power status is managed per domain. Meanwhile the ASoC hdac_hdmi driver still keeps and relies (incorrectly) on the refcounting together with ASoC skl driver, and this leads to the display state always on. This patch is an attempt to address the regression by simplifying the PM code of ASoC skl and hdac_hdmi drivers. Basically, since the refactoring, we don't have to manage the display power at HD-audio controller suspend / resume but only at HD-audio HDMI codec suspend / resume. So the patch drops the superfluous snd_hdac_display_power() calls in skl driver. Meanwhile, in hdac_hdmi side, we rewrite the PM call just to re-use the runtime PM callbacks like other drivers do. Now the logic is simple: turn off at suspend and turn on at resume. The patch also fixes the possibly missing display-power off at skl driver removal as well as some error paths at probe. Fixes: 029d92c289bd ("ALSA: hda: Refactor display power management") Reported-by: Libin Yang Signed-off-by: Takashi Iwai (cherry picked from commit 687ae9e287b3a1a71e5e1c2a9c96b23d70768821) --- sound/soc/codecs/hdac_hdmi.c | 116 ++++------------------------------ sound/soc/intel/skylake/skl.c | 13 ++-- 2 files changed, 17 insertions(+), 112 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 3ab2949c1dfa45..b19d7a3e7a2cc0 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1890,51 +1890,31 @@ static void hdmi_codec_remove(struct snd_soc_component *component) pm_runtime_disable(&hdev->dev); } -#ifdef CONFIG_PM -static int hdmi_codec_prepare(struct device *dev) -{ - struct hdac_device *hdev = dev_to_hdac_dev(dev); - - pm_runtime_get_sync(&hdev->dev); - - /* - * Power down afg. - * codec_read is preferred over codec_write to set the power state. - * This way verb is send to set the power state and response - * is received. So setting power state is ensured without using loop - * to read the state. - */ - snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE, - AC_PWRST_D3); - - return 0; -} - -static void hdmi_codec_complete(struct device *dev) +#ifdef CONFIG_PM_SLEEP +static int hdmi_codec_resume(struct device *dev) { struct hdac_device *hdev = dev_to_hdac_dev(dev); struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); + int ret; - /* Power up afg */ - snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE, - AC_PWRST_D0); - - hdac_hdmi_skl_enable_all_pins(hdev); - hdac_hdmi_skl_enable_dp12(hdev); - + ret = pm_runtime_force_resume(dev); + if (ret < 0) + return ret; /* * As the ELD notify callback request is not entertained while the * device is in suspend state. Need to manually check detection of * all pins here. pin capablity change is not support, so use the * already set pin caps. + * + * NOTE: this is safe to call even if the codec doesn't actually resume. + * The pin check involves only with DRM audio component hooks, so it + * works even if the HD-audio side is still dreaming peacefully. */ hdac_hdmi_present_sense_all_pins(hdev, hdmi, false); - - pm_runtime_put_sync(&hdev->dev); + return 0; } #else -#define hdmi_codec_prepare NULL -#define hdmi_codec_complete NULL +#define hdmi_codec_resume NULL #endif static const struct snd_soc_component_driver hdmi_hda_codec = { @@ -2135,75 +2115,6 @@ static int hdac_hdmi_dev_remove(struct hdac_device *hdev) } #ifdef CONFIG_PM -/* - * Power management sequences - * ========================== - * - * The following explains the PM handling of HDAC HDMI with its parent - * device SKL and display power usage - * - * Probe - * ----- - * In SKL probe, - * 1. skl_probe_work() powers up the display (refcount++ -> 1) - * 2. enumerates the codecs on the link - * 3. powers down the display (refcount-- -> 0) - * - * In HDAC HDMI probe, - * 1. hdac_hdmi_dev_probe() powers up the display (refcount++ -> 1) - * 2. probe the codec - * 3. put the HDAC HDMI device to runtime suspend - * 4. hdac_hdmi_runtime_suspend() powers down the display (refcount-- -> 0) - * - * Once children are runtime suspended, SKL device also goes to runtime - * suspend - * - * HDMI Playback - * ------------- - * Open HDMI device, - * 1. skl_runtime_resume() invoked - * 2. hdac_hdmi_runtime_resume() powers up the display (refcount++ -> 1) - * - * Close HDMI device, - * 1. hdac_hdmi_runtime_suspend() powers down the display (refcount-- -> 0) - * 2. skl_runtime_suspend() invoked - * - * S0/S3 Cycle with playback in progress - * ------------------------------------- - * When the device is opened for playback, the device is runtime active - * already and the display refcount is 1 as explained above. - * - * Entering to S3, - * 1. hdmi_codec_prepare() invoke the runtime resume of codec which just - * increments the PM runtime usage count of the codec since the device - * is in use already - * 2. skl_suspend() powers down the display (refcount-- -> 0) - * - * Wakeup from S3, - * 1. skl_resume() powers up the display (refcount++ -> 1) - * 2. hdmi_codec_complete() invokes the runtime suspend of codec which just - * decrements the PM runtime usage count of the codec since the device - * is in use already - * - * Once playback is stopped, the display refcount is set to 0 as explained - * above in the HDMI playback sequence. The PM handlings are designed in - * such way that to balance the refcount of display power when the codec - * device put to S3 while playback is going on. - * - * S0/S3 Cycle without playback in progress - * ---------------------------------------- - * Entering to S3, - * 1. hdmi_codec_prepare() invoke the runtime resume of codec - * 2. skl_runtime_resume() invoked - * 3. hdac_hdmi_runtime_resume() powers up the display (refcount++ -> 1) - * 4. skl_suspend() powers down the display (refcount-- -> 0) - * - * Wakeup from S3, - * 1. skl_resume() powers up the display (refcount++ -> 1) - * 2. hdmi_codec_complete() invokes the runtime suspend of codec - * 3. hdac_hdmi_runtime_suspend() powers down the display (refcount-- -> 0) - * 4. skl_runtime_suspend() invoked - */ static int hdac_hdmi_runtime_suspend(struct device *dev) { struct hdac_device *hdev = dev_to_hdac_dev(dev); @@ -2277,8 +2188,7 @@ static int hdac_hdmi_runtime_resume(struct device *dev) static const struct dev_pm_ops hdac_hdmi_pm = { SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL) - .prepare = hdmi_codec_prepare, - .complete = hdmi_codec_complete, + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, hdmi_codec_resume) }; static const struct hda_device_id hdmi_list[] = { diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 60c94836bf5bc9..4ed5b7e17d44aa 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -336,9 +336,6 @@ static int skl_suspend(struct device *dev) skl->skl_sst->fw_loaded = false; } - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - return 0; } @@ -350,10 +347,6 @@ static int skl_resume(struct device *dev) struct hdac_ext_link *hlink = NULL; int ret; - /* Turned OFF in HDMI codec driver after codec reconfiguration */ - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - /* * resume only when we are not in suspend active, otherwise need to * restore the device @@ -446,8 +439,10 @@ static int skl_free(struct hdac_bus *bus) snd_hdac_ext_bus_exit(bus); cancel_work_sync(&skl->probe_work); - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); snd_hdac_i915_exit(bus); + } return 0; } @@ -814,7 +809,7 @@ static void skl_probe_work(struct work_struct *work) err = skl_platform_register(bus->dev); if (err < 0) { dev_err(bus->dev, "platform register failed: %d\n", err); - return; + goto out_err; } err = skl_machine_device_register(skl); From 6aac9301cd215862c65a48781a4f4678ace5d7d7 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 14 Jan 2019 16:52:06 +0800 Subject: [PATCH 0680/1995] ASoC: SOF: select machine driver after hda detection It is ugly in pci probing function to check hda for machine driver. Now select hda machine driver in hda probing function and use nocodec machine driver if none of I2S or hda is selected after dsp probing Check following conditions to select machine driver 1. codec_num = 2 -> use hda with HDMI + HDAudio 2. codec_num = 1 -> use hda with HDMI if nocdec is disabled 3. codec_num = 1 -> use nocodec if enabled in the build (for validation) 4. codec_num = 0 -> use nocodec if enabled in the build step 2 is for on a headless device like Up2 Signed-off-by: Rander Wang --- sound/soc/sof/core.c | 42 ++++++++++++++++++++++++++-- sound/soc/sof/intel/hda.c | 56 +++++++++++++++++++++++++++++++++---- sound/soc/sof/intel/hda.h | 2 ++ sound/soc/sof/sof-pci-dev.c | 36 ++---------------------- 4 files changed, 93 insertions(+), 43 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 8df9e1e375a8e2..4b794575ec7693 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -224,7 +224,35 @@ int snd_sof_create_page_table(struct snd_sof_dev *sdev, /* * SOF Driver enumeration. */ +static int sof_machine_check(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + + if (!plat_data->machine) { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) + struct snd_soc_acpi_mach *machine; + int ret; + + /* fallback to nocodec mode */ + dev_warn(sdev->dev, "No ASoC machine driver found - using nocodec\n"); + machine = devm_kzalloc(sdev->dev, sizeof(*machine), GFP_KERNEL); + if (!machine) + return -ENOMEM; + + ret = sof_nocodec_setup(sdev->dev, plat_data, machine, + plat_data->desc, plat_data->desc->ops); + if (ret < 0) + return ret; + + plat_data->machine = machine; +#else + dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); + return -ENODEV; +#endif + } + return 0; +} static int sof_probe(struct platform_device *pdev) { struct snd_sof_pdata *plat_data = dev_get_platdata(&pdev->dev); @@ -257,9 +285,6 @@ static int sof_probe(struct platform_device *pdev) spin_lock_init(&sdev->ipc_lock); spin_lock_init(&sdev->hw_lock); - /* set up platform component driver */ - snd_sof_new_platform_drv(sdev); - /* set default timeouts if none provided */ if (plat_data->desc->ipc_timeout == 0) sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC_MS; @@ -277,6 +302,17 @@ static int sof_probe(struct platform_device *pdev) return ret; } + /* check machine info */ + ret = sof_machine_check(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to get machine info %d\n", + ret); + goto dbg_err; + } + + /* set up platform component driver */ + snd_sof_new_platform_drv(sdev); + /* register any debug/trace capabilities */ ret = snd_sof_dbg_init(sdev); if (ret < 0) { diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 007db62cebb2e5..69e9d18bd30cc7 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -25,6 +25,10 @@ #include "../../codecs/hdac_hda.h" #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +#include +#endif + /* platform specific devices */ #include "shim.h" @@ -226,7 +230,12 @@ static int hda_init_caps(struct snd_sof_dev *sdev) struct pci_dev *pci = sdev->pci; struct hdac_ext_link *hlink = NULL; struct snd_soc_acpi_mach_params *mach_params; + struct snd_soc_acpi_mach *hda_mach = NULL; + struct snd_sof_pdata *pdata = sdev->pdata; + struct snd_soc_acpi_mach *mach; + int codec_num = 0; int ret = 0; + int i; device_disable_async_suspend(bus->dev); @@ -252,15 +261,50 @@ static int hda_init_caps(struct snd_sof_dev *sdev) } /* codec detection */ - if (!bus->codec_mask) + if (!bus->codec_mask) { dev_info(bus->dev, "no hda codecs found!\n"); - else - dev_info(bus->dev, "hda codecs found, mask %lx!\n", bus->codec_mask); + } else { + dev_info(bus->dev, "hda codecs found, mask %lx\n", + bus->codec_mask); + + for (i = 0; i < HDA_MAX_CODECS; i++) { + if (bus->codec_mask & (1 << i)) + codec_num++; + } + + /* + * If no machine driver is found, then: + * + * hda machine driver is used if : + * 1. there are HDMI codec and one external HDAudio codec + * 2. only HDMI codec and NOCODEC is not enabled + * + * nocodec machine driver would be used if: + * 1. only HDMI codec and but NOCODEC is enabled + * 2. there is no codec found + */ + if (!pdata->machine && codec_num <= 2 && + HDA_IDISP_CODEC(bus->codec_mask)) { + if (codec_num == 2 || + !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) { + hda_mach = snd_soc_acpi_intel_hda_machines; + mach = pdata->desc->machines; + hda_mach->sof_fw_filename = + mach->sof_fw_filename; + pdata->machine = hda_mach; + + dev_info(bus->dev, "using HDA machine driver %s now\n", + hda_mach->drv_name); + } + } + } /* used by hda machine driver to create dai links */ - mach_params = (struct snd_soc_acpi_mach_params *) - &sdev->pdata->machine->mach_params; - mach_params->codec_mask = bus->codec_mask; + if (pdata->machine) { + mach_params = (struct snd_soc_acpi_mach_params *) + &pdata->machine->mach_params; + mach_params->codec_mask = bus->codec_mask; + } /* create codec instances */ hda_codec_probe_bus(sdev); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 105b720d5069bd..38ac2ccc3a4267 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -338,6 +338,8 @@ #define HDA_ADSP_FW_STATUS_SKL HDA_ADSP_SRAM0_BASE_SKL #define HDA_ADSP_ERROR_CODE_SKL (HDA_ADSP_FW_STATUS_SKL + 0x4) +#define HDA_IDISP_CODEC(x) ((x) & BIT(2)) + struct sof_intel_dsp_bdl { __le32 addr_l; __le32 addr_h; diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index a62ff9c337486e..20ebd9ac579046 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -203,42 +203,10 @@ static int sof_pci_probe(struct pci_dev *pci, #else /* find machine */ mach = snd_soc_acpi_find_machine(desc->machines); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - if (!mach) { - dev_warn(dev, "No matching ASoC machine driver found - falling back to HDA codec\n"); - mach = snd_soc_acpi_intel_hda_machines; - mach->sof_fw_filename = desc->nocodec_fw_filename; - - /* - * TODO: we need to find a way to check if codecs are actually - * present - */ - } -#endif /* CONFIG_SND_SOC_SOF_HDA */ - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) - if (!mach) { - /* fallback to nocodec mode */ - dev_warn(dev, "No matching ASoC machine driver found - using nocodec\n"); - mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); - if (!mach) { - ret = -ENOMEM; - goto release_regions; - } - ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); - if (ret < 0) - goto release_regions; - } -#endif /* CONFIG_SND_SOC_SOF_NOCODEC */ - + if (!mach) + dev_warn(dev, "warning: No matching ASoC machine driver found\n"); #endif /* CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE */ - if (!mach) { - dev_err(dev, "error: no matching ASoC machine driver found - aborting probe\n"); - ret = -ENODEV; - goto release_regions; - } - sof_pdata->id = pci_id->device; sof_pdata->name = pci_name(pci); sof_pdata->machine = mach; From d3c50a2a3b11bf7916a882a4448d00d20dff2f89 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 16 Jan 2019 14:16:25 +0800 Subject: [PATCH 0681/1995] ASoC: SOF: move sof_bes_setup to nocodec file The change for machine driver would make a error that sof and nocodec module are dependent on each other. Signed-off-by: Rander Wang --- sound/soc/sof/nocodec.c | 36 ++++++++++++++++++++++++++++++++++-- sound/soc/sof/utils.c | 33 --------------------------------- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index 4bb6a74093336d..9851ce7c1e8ec0 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -16,6 +16,38 @@ static struct snd_soc_card sof_nocodec_card = { .name = "nocodec", /* the sof- prefix is added by the core */ }; +int sof_nocodec_bes_setup(struct device *dev, const struct snd_sof_dsp_ops *ops, + struct snd_soc_dai_link *links, int link_num, + struct snd_soc_card *card) +{ + int i; + + if (!ops || !links || !card) + return -EINVAL; + + /* set up BE dai_links */ + for (i = 0; i < link_num; i++) { + links[i].name = devm_kasprintf(dev, GFP_KERNEL, + "NoCodec-%d", i); + if (!links[i].name) + return -ENOMEM; + + links[i].id = i; + links[i].no_pcm = 1; + links[i].cpu_dai_name = ops->drv[i].name; + links[i].platform_name = "sof-audio"; + links[i].codec_dai_name = "snd-soc-dummy-dai"; + links[i].codec_name = "snd-soc-dummy"; + links[i].dpcm_playback = 1; + links[i].dpcm_capture = 1; + } + + card->dai_link = links; + card->num_links = link_num; + + return 0; +} + int sof_nocodec_setup(struct device *dev, struct snd_sof_pdata *sof_pdata, struct snd_soc_acpi_mach *mach, @@ -40,8 +72,8 @@ int sof_nocodec_setup(struct device *dev, if (!links) return -ENOMEM; - ret = sof_bes_setup(dev, ops, links, ops->num_drv, - &sof_nocodec_card); + ret = sof_nocodec_bes_setup(dev, ops, links, ops->num_drv, + &sof_nocodec_card); return ret; } EXPORT_SYMBOL(sof_nocodec_setup); diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index 484f57e1554a49..6167e05d5a6dea 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -14,39 +14,6 @@ #include #include "sof-priv.h" -int sof_bes_setup(struct device *dev, const struct snd_sof_dsp_ops *ops, - struct snd_soc_dai_link *links, int link_num, - struct snd_soc_card *card) -{ - int i; - - if (!ops || !links || !card) - return -EINVAL; - - /* set up BE dai_links */ - for (i = 0; i < link_num; i++) { - links[i].name = devm_kasprintf(dev, GFP_KERNEL, - "NoCodec-%d", i); - if (!links[i].name) - return -ENOMEM; - - links[i].id = i; - links[i].no_pcm = 1; - links[i].cpu_dai_name = ops->drv[i].name; - links[i].platform_name = "sof-audio"; - links[i].codec_dai_name = "snd-soc-dummy-dai"; - links[i].codec_name = "snd-soc-dummy"; - links[i].dpcm_playback = 1; - links[i].dpcm_capture = 1; - } - - card->dai_link = links; - card->num_links = link_num; - - return 0; -} -EXPORT_SYMBOL(sof_bes_setup); - /* register sof platform device */ int sof_create_platform_device(struct sof_platform_priv *priv) { From 74277c26e101d452c16e2a516e18235fceff836c Mon Sep 17 00:00:00 2001 From: Bard liao Date: Tue, 22 Jan 2019 07:02:07 +0800 Subject: [PATCH 0682/1995] ASoC: SOF: update nocodec_tplg_filename of cnl update nocodec_tplg_filename of cnl to sof-cnl-nocodec.tplg to match the name defined in topology. Signed-off-by: Bard liao --- sound/soc/sof/sof-pci-dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 20ebd9ac579046..198905bef358ad 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -90,7 +90,7 @@ static const struct sof_dev_desc cnl_desc = { .resindex_dma_base = -1, .chip_info = &cnl_chip_info, .nocodec_fw_filename = "intel/sof-cnl.ri", - .nocodec_tplg_filename = "intel/sof-cnl.tplg", + .nocodec_tplg_filename = "intel/sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops }; From 3938c73d4a086684a6107a19733f7eb27bf38e9c Mon Sep 17 00:00:00 2001 From: Ajit Pandey Date: Wed, 9 Jan 2019 14:17:07 +0530 Subject: [PATCH 0683/1995] ASoC: soc-core: defer card probe until all component is added to list DAI component probe is not called if it is not present in component list during sound card registration. Check if component is available in component list for platform and cpu dai before soundcard registration. Signed-off-by: Ajit Pandey Signed-off-by: Rohit kumar Signed-off-by: Mark Brown (cherry picked from commit 8780cf1142a59568a3aa77959cbd76b2edb6fd81) --- sound/soc/soc-core.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index f340cfa13dd6e0..019bd5d418d1be 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1027,7 +1027,6 @@ static int snd_soc_init_platform(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_dai_link_component *platform = dai_link->platform; - /* * REMOVE ME * @@ -1145,6 +1144,14 @@ static int soc_init_dai_link(struct snd_soc_card *card, link->name); return -EINVAL; } + + /* + * Defer card registartion if platform dai component is not added to + * component list. + */ + if (!soc_find_component(link->platform->of_node, link->platform->name)) + return -EPROBE_DEFER; + /* * CPU device may be specified by either name or OF node, but * can be left unspecified, and will be matched based on DAI @@ -1156,6 +1163,14 @@ static int soc_init_dai_link(struct snd_soc_card *card, link->name); return -EINVAL; } + + /* + * Defer card registartion if cpu dai component is not added to + * component list. + */ + if (!soc_find_component(link->cpu_of_node, link->cpu_name)) + return -EPROBE_DEFER; + /* * At least one of CPU DAI name or CPU device name/node must be * specified From f8cfeae8829a1f7e8bd12d6b6b4b94a072bb2402 Mon Sep 17 00:00:00 2001 From: Rohit kumar Date: Thu, 10 Jan 2019 14:32:41 +0530 Subject: [PATCH 0684/1995] ASoC: soc-core: Hold client_mutex around soc_init_dai_link() soc_init_dai_link() calls soc_find_component() which needs to be within client_mutex lock. Add client_mutex lock around soc_init_dai_link() in snd_soc_register_card() to avoid lockdep warning. Fixes: 8780cf1142a5 ("ASoC: soc-core: defer card probe until all component is added to list") Reported-by: Kuninori Morimoto Signed-off-by: Rohit kumar Signed-off-by: Ajit Pandey Signed-off-by: Mark Brown (cherry picked from commit 04eb1efcd614d6f067b76a355b3a3599667959dc) --- sound/soc/soc-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 019bd5d418d1be..440e54ff743c56 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1027,6 +1027,7 @@ static int snd_soc_init_platform(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_dai_link_component *platform = dai_link->platform; + /* * REMOVE ME * From 5ff09f2ef282ed6ab5cf8f041e760221a4eb6cc2 Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Thu, 10 Jan 2019 16:21:04 -0800 Subject: [PATCH 0685/1995] ASoC: soc-core: fix init platform memory handling snd_soc_init_platform initializes pointers to snd_soc_dai_link which is statically allocated and it does this by devm_kzalloc. In the event of an EPROBE_DEFER the memory will be freed and the pointers are left dangling. snd_soc_init_platform sees the dangling pointers and assumes they are pointing to initialized memory and does not reallocate them on the second probe attempt which results in a use after free bug since devm has freed the memory from the first probe attempt. Since the intention for snd_soc_dai_link->platform is that it can be set statically by the machine driver we need to respect the pointer in the event we did not set it but still catch dangling pointers. The solution is to add a flag to track whether the pointer was dynamically allocated or not. Signed-off-by: Curtis Malainey Signed-off-by: Mark Brown (cherry picked from commit 09ac6a817bd687e7f5dac00470262efdd72f9319) --- include/sound/soc.h | 6 ++++++ sound/soc/soc-core.c | 11 ++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 12e67273cf65dc..c31b6d122ff68c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1021,6 +1021,12 @@ struct snd_soc_dai_link { /* Do not create a PCM for this DAI link (Backend link) */ unsigned int ignore:1; + /* + * This driver uses legacy platform naming. Set by the core, machine + * drivers should not modify this value. + */ + unsigned int legacy_platform:1; + struct list_head list; /* DAI link list of the soc card */ struct snd_soc_dobj dobj; /* For topology */ }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 440e54ff743c56..3aec1212636961 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1039,17 +1039,18 @@ static int snd_soc_init_platform(struct snd_soc_card *card, * soc.h :: struct snd_soc_dai_link */ /* convert Legacy platform link */ - if (!platform) { + if (!platform || dai_link->legacy_platform) { platform = devm_kzalloc(card->dev, sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); if (!platform) return -ENOMEM; - dai_link->platform = platform; - platform->name = dai_link->platform_name; - platform->of_node = dai_link->platform_of_node; - platform->dai_name = NULL; + dai_link->platform = platform; + dai_link->legacy_platform = 1; + platform->name = dai_link->platform_name; + platform->of_node = dai_link->platform_of_node; + platform->dai_name = NULL; } /* if there's no platform we match on the empty platform */ From 674e8cf7983206388a4eac7aedba6fa952dfe6a1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 14 Jan 2019 23:29:36 +0000 Subject: [PATCH 0686/1995] ASoC: core: Make snd_soc_find_component() more robust There are some use cases where you're checking for a lot of things on a card and it makes sense that you might end up trying to call snd_soc_find_component() without either a name or an of_node. Currently in that case we try to dereference the name and crash but it's more useful to allow the caller to just treat that as a case where we don't find anything, that error handling will already exist. Inspired by a patch from Ajit Pandey fixing some callers. Fixes: 8780cf1142a5 ("ASoC: soc-core: defer card probe until all component is added to list") Reported-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 5a7b2aabc1aa0393f067d9325ada96fdf67f8cb7) --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3aec1212636961..edc2b9ae878ceb 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -742,7 +742,7 @@ static struct snd_soc_component *soc_find_component( if (of_node) { if (component->dev->of_node == of_node) return component; - } else if (strcmp(component->name, name) == 0) { + } else if (name && strcmp(component->name, name) == 0) { return component; } } From cf6d25d82d2ecd7209e179fe9ba58a1e987a79ac Mon Sep 17 00:00:00 2001 From: Matthias Reichl Date: Tue, 15 Jan 2019 17:51:07 +0100 Subject: [PATCH 0687/1995] ASoC: core: Don't defer probe on optional, NULL components cpu and platform are optional components in DAI links. For example codec-codec links usually have no platform set. Call snd_soc_find_component only if the name or of_node of a cpu or platform is set. Otherwise it will return NULL and soc_init_dai_link bails out immediately with -EPROBE_DEFER, meaning registering a card with NULL cpu or platform in DAI links can never succeed. Fixes: 8780cf1142a5 ("ASoC: soc-core: defer card probe until all component is added to list") Signed-off-by: Matthias Reichl Signed-off-by: Mark Brown (cherry picked from commit 2833548ecbb385a289124077ab4d812258a867d5) --- sound/soc/soc-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index edc2b9ae878ceb..79f41b616d115f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1151,7 +1151,8 @@ static int soc_init_dai_link(struct snd_soc_card *card, * Defer card registartion if platform dai component is not added to * component list. */ - if (!soc_find_component(link->platform->of_node, link->platform->name)) + if ((link->platform->of_node || link->platform->name) && + !soc_find_component(link->platform->of_node, link->platform->name)) return -EPROBE_DEFER; /* @@ -1170,7 +1171,8 @@ static int soc_init_dai_link(struct snd_soc_card *card, * Defer card registartion if cpu dai component is not added to * component list. */ - if (!soc_find_component(link->cpu_of_node, link->cpu_name)) + if ((link->cpu_of_node || link->cpu_name) && + !soc_find_component(link->cpu_of_node, link->cpu_name)) return -EPROBE_DEFER; /* From 018a62b165d57b7902bf3428027e9e84ee177f0b Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 18 Jan 2019 10:55:04 +0100 Subject: [PATCH 0688/1995] ASoC: soc-core: remove error due to probe deferral Deferred probes shouldn't cause error messages in the boot log, so change the dev_err() to the more harmless dev_info(). Signed-off-by: Stefan Agner Signed-off-by: Mark Brown (cherry picked from commit 7c7e2d6a9ca3c74ba7ed4da2a75916b2f9ae38f0) --- sound/soc/soc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 79f41b616d115f..de2851f1b3df3a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -903,8 +903,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card, for (i = 0; i < rtd->num_codecs; i++) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { - dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", - codecs[i].dai_name); + dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", + codecs[i].dai_name); goto _err_defer; } snd_soc_rtdcom_add(rtd, codec_dais[i]->component); From 9ff9c48f9ede33933d8dd84f05a3b62bb29d8fcf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 6 Nov 2018 04:36:27 +0000 Subject: [PATCH 0689/1995] [BACKPORT] ASoC: generic/simple-card: squash commit Add the following patches in one squashed commit. This is only necessary to fix backport issues in soc-core and has no functional impact on Intel platforms. 39ee0b3401fe ASoC: audio-graph-card: remove endpoint bidirectional check 1a115f3a5418 ASoC: audio-graph-scu-card: remove endpoint bidirectional check 5049a6e7316c ASoC: audio-graph-scu-card: remove error check which never happen c0f4697c5dbc ASoC: simple-card-utils: remove asoc_simple_card_clk_register() f31a17105560 ASoC: simple-card-utils: accept NULL parameter on asoc_simple_card_xxx() a48bf02b35d9 ASoC: simple-card-utils: tidyup asoc_simple_card_parse_convert() 33404f3f10be ASoC: simple_card_utils: remove "option" from asoc_simple_card_of_parse_routing() ca8d95c70937 ASoC: simple-scu-card: tidyup "prefix" parsing 2624fc788224 ASoC: audio-graph-scu-card: tidyup "prefix" parsing 7f07a39acf05 ASoC: audio-graph-scu-card: tidyup "convert-rate/channels" parsing 338d7159c488 ASoC: audio-graph-scu-card: tidyup asoc_simple_card_parse_daifmt() timing c3830f1a00f0 ASoC: audio-graph-card: tidyup typo SND_AUDIO_GRAPH_CARD 64ef0817b967 ASoC: audio-graph-card: tidyup define position b6f3fc005a2c ASoC: simple-card-utils: fixup asoc_simple_card_get_dai_id() counting c89ff03ac8c6 ASoC: audio-graph-scu-card: care link / dai count a1af9858edae ASoC: audio-graph-scu-card: use cpu/codec pointer on graph_dai_props 7c2ae7981d73 ASoC: audio-graph-scu-card: care multi DPCM codec_conf 0e3460bceedc ASoC: audio-graph-card: use cpu/codec pointer on graph_dai_props 1d52a74ea230 ASoC: Use of_node_name_eq for node name comparisons 2b320e046495 ASoC: simple-card-utils: fix build warning without CONFIG_OF 4fb7f4df49d3 ASoC: simple-card: use cpu/codec pointer on simple_dai_props dbd08fe59cf8 ASoC: simple-scu-card: tidyup asoc_simple_card_parse_daifmt() timing da32d6537802 ASoC: simple-scu-card: add dai-link support b8d8f9a58fd9 ASoC: simple-scu-card: care link / dai count 09ee83367976 ASoC: simple-scu-card: tidyup "convert-rate/channels" parsing e6a3ff2ed4c9 ASoC: simple-scu-card: use cpu/codec pointer on graph_dai_props 0a26d6df4fd8 ASoC: simple-scu-card: care multi DPCM codec_conf 869858f84a65 ASoC: simple-card: Dereference pointer for memcpy sizeof in asoc_simple_card_probe b8b89f5ee0b2 ASoC: simple-card-utils: fixup asoc_simple_card_get_dai_id() ID method ae3cb5790906 ASoC: audio-graph-card: merge audio-graph-scu-card 56eb818191fb ASoC: audio-graph-card: tidyup mclk-fs method 7ced65ffb82f ASoC: audio-graph-card: tidyup convert_rate/channel method 66164a4da30d ASoC: audio-graph-card: tidyup prefix for snd_soc_codec_conf da215354eb55 ASoC: simple-card: merge simple-scu-card 79e834914d1f ASoC: simple-card: tidyup mclk-fs method dd82410f7e93 ASoC: simple-card: tidyup convert_rate/channel method cfc652a73331 ASoC: simple-card: tidyup prefix for snd_soc_codec_conf a0c426fe1433 ASoC: simple-card-utils: check "reg" property on asoc_simple_card_get_dai_id() 40dfae169ad0 ASoC: audio-graph-card: add asoc_graph_card_get_conversion() 61c263ac27a3 ASoC: audio-graph-scu-card: remove audio-graph-scu-card c8ed6aca6b82 ASoC: simple-scu-card: remove simple-scu-card de2949fe2621 ASoC: audio-graph-card: add 1 CPU : 1 Codec support again 1e4771a62fd7 ASoC: audio-graph-card: add link_info dd98fbc558a0 ASoC: audio-graph-card: cleanup DAI link loop method - step1 fce9b90c1ab7 ASoC: audio-graph-card: cleanup DAI link loop method - step2 97fe6ca41465 ASoC: audio-graph-card: reduce naming prefix 7e5e1f8bbaa8 ASoC: simple-card: add asoc_simple_card_get_conversion() 7adee60ee273 ASoC: simple-card: add 1 CPU : 1 Codec support again 17029e494edc ASoC: simple-card: add link_info d947cdfd4be2 ASoC: simple-card: cleanup DAI link loop method - step1 c39291a76444 ASoC: simple-card: cleanup DAI link loop method - step2 2d01a84605a5 ASoC: simple-card: reduce naming prefix Signed-off-by: Pierre-Louis Bossart --- include/sound/simple_card_utils.h | 6 +- sound/soc/fsl/fsl-asoc-card.c | 6 +- sound/soc/generic/Kconfig | 21 +- sound/soc/generic/Makefile | 4 - sound/soc/generic/audio-graph-card.c | 618 +++++++++++++++++----- sound/soc/generic/audio-graph-scu-card.c | 431 ---------------- sound/soc/generic/simple-card-utils.c | 53 +- sound/soc/generic/simple-card.c | 622 ++++++++++++++++++----- sound/soc/generic/simple-scu-card.c | 330 ------------ 9 files changed, 1015 insertions(+), 1076 deletions(-) delete mode 100644 sound/soc/generic/audio-graph-scu-card.c delete mode 100644 sound/soc/generic/simple-scu-card.c diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index fb0318f9b10f38..6d69ed2bd7b111 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -116,12 +116,12 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card); void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data, struct snd_pcm_hw_params *params); -void asoc_simple_card_parse_convert(struct device *dev, char *prefix, +void asoc_simple_card_parse_convert(struct device *dev, + struct device_node *np, char *prefix, struct asoc_simple_card_data *data); int asoc_simple_card_of_parse_routing(struct snd_soc_card *card, - char *prefix, - int optional); + char *prefix); int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card, char *prefix); diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 44433b20435cce..81f2fe2c6d2302 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -571,17 +571,17 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) } /* Common settings for corresponding Freescale CPU DAI driver */ - if (strstr(cpu_np->name, "ssi")) { + if (of_node_name_eq(cpu_np, "ssi")) { /* Only SSI needs to configure AUDMUX */ ret = fsl_asoc_card_audmux_init(np, priv); if (ret) { dev_err(&pdev->dev, "failed to init audmux\n"); goto asrc_fail; } - } else if (strstr(cpu_np->name, "esai")) { + } else if (of_node_name_eq(cpu_np, "esai")) { priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL; priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL; - } else if (strstr(cpu_np->name, "sai")) { + } else if (of_node_name_eq(cpu_np, "sai")) { priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1; priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1; } diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig index c954be0a0f96b0..83f1243145b00b 100644 --- a/sound/soc/generic/Kconfig +++ b/sound/soc/generic/Kconfig @@ -6,28 +6,13 @@ config SND_SIMPLE_CARD select SND_SIMPLE_CARD_UTILS help This option enables generic simple sound card support - -config SND_SIMPLE_SCU_CARD - tristate "ASoC Simple SCU sound card support" - depends on OF - select SND_SIMPLE_CARD_UTILS - help - This option enables generic simple SCU sound card support. - It supports DPCM of multi CPU single Codec system. + It also support DPCM of multi CPU single Codec ststem. config SND_AUDIO_GRAPH_CARD tristate "ASoC Audio Graph sound card support" depends on OF select SND_SIMPLE_CARD_UTILS help - This option enables generic simple simple sound card support - with OF-graph DT bindings. - -config SND_AUDIO_GRAPH_SCU_CARD - tristate "ASoC Audio Graph SCU sound card support" - depends on OF - select SND_SIMPLE_CARD_UTILS - help - This option enables generic simple SCU sound card support + This option enables generic simple sound card support with OF-graph DT bindings. - It supports DPCM of multi CPU single Codec ststem. + It also support DPCM of multi CPU single Codec ststem. diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile index 9dec293a4c4de9..21c29e5e0671e2 100644 --- a/sound/soc/generic/Makefile +++ b/sound/soc/generic/Makefile @@ -1,12 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 snd-soc-simple-card-utils-objs := simple-card-utils.o snd-soc-simple-card-objs := simple-card.o -snd-soc-simple-scu-card-objs := simple-scu-card.o snd-soc-audio-graph-card-objs := audio-graph-card.o -snd-soc-audio-graph-scu-card-objs := audio-graph-scu-card.o obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o -obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o obj-$(CONFIG_SND_AUDIO_GRAPH_CARD) += snd-soc-audio-graph-card.o -obj-$(CONFIG_SND_AUDIO_GRAPH_SCU_CARD) += snd-soc-audio-graph-scu-card.o diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 25c819e402e185..3ec96cdc683b5a 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -20,28 +20,45 @@ #include #include -struct graph_card_data { +struct graph_priv { struct snd_soc_card snd_card; struct graph_dai_props { - struct asoc_simple_dai cpu_dai; - struct asoc_simple_dai codec_dai; + struct asoc_simple_dai *cpu_dai; + struct asoc_simple_dai *codec_dai; struct snd_soc_dai_link_component codecs; /* single codec */ struct snd_soc_dai_link_component platform; + struct asoc_simple_card_data adata; + struct snd_soc_codec_conf *codec_conf; unsigned int mclk_fs; } *dai_props; - unsigned int mclk_fs; struct asoc_simple_jack hp_jack; struct asoc_simple_jack mic_jack; struct snd_soc_dai_link *dai_link; + struct asoc_simple_dai *dais; + struct snd_soc_codec_conf *codec_conf; struct gpio_desc *pa_gpio; }; -static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event) +struct link_info { + int dais; /* number of dai */ + int link; /* number of link */ + int conf; /* number of codec_conf */ + int cpu; /* turn for CPU / Codec */ +}; + +#define graph_priv_to_card(priv) (&(priv)->snd_card) +#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i)) +#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev) +#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i)) + +#define PREFIX "audio-graph-card," + +static int graph_outdrv_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) { struct snd_soc_dapm_context *dapm = w->dapm; - struct graph_card_data *priv = snd_soc_card_get_drvdata(dapm->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(dapm->card); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -57,60 +74,53 @@ static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w, return 0; } -static const struct snd_soc_dapm_widget asoc_graph_card_dapm_widgets[] = { +static const struct snd_soc_dapm_widget graph_dapm_widgets[] = { SND_SOC_DAPM_OUT_DRV_E("Amplifier", SND_SOC_NOPM, - 0, 0, NULL, 0, asoc_graph_card_outdrv_event, + 0, 0, NULL, 0, graph_outdrv_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), }; -#define graph_priv_to_card(priv) (&(priv)->snd_card) -#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i)) -#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev) -#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i)) - -static int asoc_graph_card_startup(struct snd_pcm_substream *substream) +static int graph_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); int ret; - ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai); + ret = asoc_simple_card_clk_enable(dai_props->cpu_dai); if (ret) return ret; - ret = asoc_simple_card_clk_enable(&dai_props->codec_dai); + ret = asoc_simple_card_clk_enable(dai_props->codec_dai); if (ret) - asoc_simple_card_clk_disable(&dai_props->cpu_dai); + asoc_simple_card_clk_disable(dai_props->cpu_dai); return ret; } -static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) +static void graph_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - asoc_simple_card_clk_disable(&dai_props->cpu_dai); + asoc_simple_card_clk_disable(dai_props->cpu_dai); - asoc_simple_card_clk_disable(&dai_props->codec_dai); + asoc_simple_card_clk_disable(dai_props->codec_dai); } -static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int graph_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; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); unsigned int mclk, mclk_fs = 0; int ret = 0; - if (priv->mclk_fs) - mclk_fs = priv->mclk_fs; - else if (dai_props->mclk_fs) + if (dai_props->mclk_fs) mclk_fs = dai_props->mclk_fs; if (mclk_fs) { @@ -130,158 +140,495 @@ static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream, return ret; } -static const struct snd_soc_ops asoc_graph_card_ops = { - .startup = asoc_graph_card_startup, - .shutdown = asoc_graph_card_shutdown, - .hw_params = asoc_graph_card_hw_params, +static const struct snd_soc_ops graph_ops = { + .startup = graph_startup, + .shutdown = graph_shutdown, + .hw_params = graph_hw_params, }; -static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) +static int graph_dai_init(struct snd_soc_pcm_runtime *rtd) { - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *codec = rtd->codec_dai; - struct snd_soc_dai *cpu = rtd->cpu_dai; - struct graph_dai_props *dai_props = - graph_priv_to_props(priv, rtd->num); - int ret; + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); + int ret = 0; - ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai); + ret = asoc_simple_card_init_dai(rtd->codec_dai, + dai_props->codec_dai); if (ret < 0) return ret; - ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai); + ret = asoc_simple_card_init_dai(rtd->cpu_dai, + dai_props->cpu_dai); if (ret < 0) return ret; return 0; } -static int asoc_graph_card_dai_link_of(struct device_node *cpu_port, - struct graph_card_data *priv, - int idx) +static int graph_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); + + asoc_simple_card_convert_fixup(&dai_props->adata, params); + + return 0; +} + +static void graph_get_conversion(struct device *dev, + struct device_node *ep, + struct asoc_simple_card_data *adata) +{ + struct device_node *top = dev->of_node; + struct device_node *port = of_get_parent(ep); + struct device_node *ports = of_get_parent(port); + struct device_node *node = of_graph_get_port_parent(ep); + + asoc_simple_card_parse_convert(dev, top, NULL, adata); + asoc_simple_card_parse_convert(dev, node, PREFIX, adata); + asoc_simple_card_parse_convert(dev, ports, NULL, adata); + asoc_simple_card_parse_convert(dev, port, NULL, adata); + asoc_simple_card_parse_convert(dev, ep, NULL, adata); +} + +static int graph_dai_link_of_dpcm(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li, + int dup_codec) { struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx); - struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai; - struct asoc_simple_dai *codec_dai = &dai_props->codec_dai; - struct device_node *cpu_ep = of_get_next_child(cpu_port, NULL); - struct device_node *codec_ep = of_graph_get_remote_endpoint(cpu_ep); - struct device_node *rcpu_ep = of_graph_get_remote_endpoint(codec_ep); + struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); + struct device_node *top = dev->of_node; + struct device_node *ep = li->cpu ? cpu_ep : codec_ep; + struct device_node *port; + struct device_node *ports; + struct device_node *node; + struct asoc_simple_dai *dai; + struct snd_soc_dai_link_component *codecs = dai_link->codecs; int ret; - if (rcpu_ep != cpu_ep) { - dev_err(dev, "remote-endpoint mismatch (%s/%s/%s)\n", - cpu_ep->name, codec_ep->name, rcpu_ep->name); - ret = -EINVAL; - goto dai_link_of_err; + /* Do it all CPU endpoint, and 1st Codec endpoint */ + if (!li->cpu && dup_codec) + return 0; + + port = of_get_parent(ep); + ports = of_get_parent(port); + node = of_graph_get_port_parent(ep); + + li->link++; + + dev_dbg(dev, "link_of DPCM (%pOF)\n", ep); + + of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(ports, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(port, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(ep, "mclk-fs", &dai_props->mclk_fs); + + graph_get_conversion(dev, ep, &dai_props->adata); + + of_node_put(ports); + of_node_put(port); + of_node_put(node); + + if (li->cpu) { + + /* BE is dummy */ + codecs->of_node = NULL; + codecs->dai_name = "snd-soc-dummy-dai"; + codecs->name = "snd-soc-dummy"; + + /* FE settings */ + dai_link->dynamic = 1; + dai_link->dpcm_merged_format = 1; + + dai = + dai_props->cpu_dai = &priv->dais[li->dais++]; + + ret = asoc_simple_card_parse_graph_cpu(ep, dai_link); + if (ret) + return ret; + + ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai); + if (ret < 0) + return ret; + + ret = asoc_simple_card_set_dailink_name(dev, dai_link, + "fe.%s", + dai_link->cpu_dai_name); + if (ret < 0) + return ret; + + /* card->num_links includes Codec */ + asoc_simple_card_canonicalize_cpu(dai_link, + of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); + } else { + struct snd_soc_codec_conf *cconf; + + /* FE is dummy */ + dai_link->cpu_of_node = NULL; + dai_link->cpu_dai_name = "snd-soc-dummy-dai"; + dai_link->cpu_name = "snd-soc-dummy"; + + /* BE settings */ + dai_link->no_pcm = 1; + dai_link->be_hw_params_fixup = graph_be_hw_params_fixup; + + dai = + dai_props->codec_dai = &priv->dais[li->dais++]; + + cconf = + dai_props->codec_conf = &priv->codec_conf[li->conf++]; + + ret = asoc_simple_card_parse_graph_codec(ep, dai_link); + if (ret < 0) + return ret; + + ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai); + if (ret < 0) + return ret; + + ret = asoc_simple_card_set_dailink_name(dev, dai_link, + "be.%s", + codecs->dai_name); + if (ret < 0) + return ret; + + /* check "prefix" from top node */ + snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, + "prefix"); + snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node, + PREFIX "prefix"); + snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node, + "prefix"); + snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node, + "prefix"); } + ret = asoc_simple_card_of_parse_tdm(ep, dai); + if (ret) + return ret; + + ret = asoc_simple_card_canonicalize_dailink(dai_link); + if (ret < 0) + return ret; + ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep, NULL, &dai_link->dai_fmt); if (ret < 0) - goto dai_link_of_err; + return ret; + + dai_link->dpcm_playback = 1; + dai_link->dpcm_capture = 1; + dai_link->ops = &graph_ops; + dai_link->init = graph_dai_init; + + return 0; +} - of_property_read_u32(cpu_ep, "mclk-fs", &dai_props->mclk_fs); - of_property_read_u32(codec_ep, "mclk-fs", &dai_props->mclk_fs); +static int graph_dai_link_of(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li) +{ + struct device *dev = graph_priv_to_dev(priv); + struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); + struct device_node *top = dev->of_node; + struct device_node *cpu_port; + struct device_node *cpu_ports; + struct device_node *codec_port; + struct device_node *codec_ports; + struct asoc_simple_dai *cpu_dai; + struct asoc_simple_dai *codec_dai; + int ret; + + /* Do it only CPU turn */ + if (!li->cpu) + return 0; + + cpu_port = of_get_parent(cpu_ep); + cpu_ports = of_get_parent(cpu_port); + codec_port = of_get_parent(codec_ep); + codec_ports = of_get_parent(codec_port); + + dev_dbg(dev, "link_of (%pOF)\n", cpu_ep); + + li->link++; + + cpu_dai = + dai_props->cpu_dai = &priv->dais[li->dais++]; + codec_dai = + dai_props->codec_dai = &priv->dais[li->dais++]; + + /* Factor to mclk, used in hw_params() */ + of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(cpu_ports, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(codec_ports, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(cpu_port, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(codec_port, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(cpu_ep, "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(codec_ep, "mclk-fs", &dai_props->mclk_fs); + of_node_put(cpu_port); + of_node_put(cpu_ports); + of_node_put(codec_port); + of_node_put(codec_ports); + + ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep, + NULL, &dai_link->dai_fmt); + if (ret < 0) + return ret; ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link); if (ret < 0) - goto dai_link_of_err; + return ret; ret = asoc_simple_card_parse_graph_codec(codec_ep, dai_link); if (ret < 0) - goto dai_link_of_err; + return ret; ret = asoc_simple_card_of_parse_tdm(cpu_ep, cpu_dai); if (ret < 0) - goto dai_link_of_err; + return ret; ret = asoc_simple_card_of_parse_tdm(codec_ep, codec_dai); if (ret < 0) - goto dai_link_of_err; + return ret; ret = asoc_simple_card_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai); if (ret < 0) - goto dai_link_of_err; + return ret; ret = asoc_simple_card_parse_clk_codec(dev, codec_ep, dai_link, codec_dai); if (ret < 0) - goto dai_link_of_err; + return ret; ret = asoc_simple_card_canonicalize_dailink(dai_link); if (ret < 0) - goto dai_link_of_err; + return ret; ret = asoc_simple_card_set_dailink_name(dev, dai_link, "%s-%s", dai_link->cpu_dai_name, dai_link->codecs->dai_name); if (ret < 0) - goto dai_link_of_err; + return ret; - dai_link->ops = &asoc_graph_card_ops; - dai_link->init = asoc_graph_card_dai_init; + dai_link->ops = &graph_ops; + dai_link->init = graph_dai_init; asoc_simple_card_canonicalize_cpu(dai_link, of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); -dai_link_of_err: - of_node_put(cpu_ep); - of_node_put(rcpu_ep); - of_node_put(codec_ep); - - return ret; + return 0; } -static int asoc_graph_card_parse_of(struct graph_card_data *priv) +static int graph_for_each_link(struct graph_priv *priv, + struct link_info *li, + int (*func_noml)(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li), + int (*func_dpcm)(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li, int dup_codec)) { struct of_phandle_iterator it; struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_card *card = graph_priv_to_card(priv); struct device_node *node = dev->of_node; - int rc, idx = 0; + struct device_node *cpu_port; + struct device_node *cpu_ep; + struct device_node *codec_ep; + struct device_node *codec_port; + struct device_node *codec_port_old = NULL; + struct asoc_simple_card_data adata; + int rc, ret; + + /* loop for all listed CPU port */ + of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { + cpu_port = it.node; + cpu_ep = NULL; + + /* loop for all CPU endpoint */ + while (1) { + cpu_ep = of_get_next_child(cpu_port, cpu_ep); + if (!cpu_ep) + break; + + /* get codec */ + codec_ep = of_graph_get_remote_endpoint(cpu_ep); + codec_port = of_get_parent(codec_ep); + + of_node_put(codec_ep); + of_node_put(codec_port); + + /* get convert-xxx property */ + memset(&adata, 0, sizeof(adata)); + graph_get_conversion(dev, codec_ep, &adata); + graph_get_conversion(dev, cpu_ep, &adata); + + /* + * It is DPCM + * if Codec port has many endpoints, + * or has convert-xxx property + */ + if ((of_get_child_count(codec_port) > 1) || + adata.convert_rate || adata.convert_channels) + ret = func_dpcm(priv, cpu_ep, codec_ep, li, + (codec_port_old == codec_port)); + /* else normal sound */ + else + ret = func_noml(priv, cpu_ep, codec_ep, li); + + if (ret < 0) + return ret; + + codec_port_old = codec_port; + } + } + + return 0; +} + +static int graph_parse_of(struct graph_priv *priv) +{ + struct snd_soc_card *card = graph_priv_to_card(priv); + struct link_info li; int ret; ret = asoc_simple_card_of_parse_widgets(card, NULL); if (ret < 0) return ret; - ret = asoc_simple_card_of_parse_routing(card, NULL, 1); + ret = asoc_simple_card_of_parse_routing(card, NULL); if (ret < 0) return ret; - /* Factor to mclk, used in hw_params() */ - of_property_read_u32(node, "mclk-fs", &priv->mclk_fs); - - of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { - ret = asoc_graph_card_dai_link_of(it.node, priv, idx++); - if (ret < 0) { - of_node_put(it.node); - + memset(&li, 0, sizeof(li)); + for (li.cpu = 1; li.cpu >= 0; li.cpu--) { + /* + * Detect all CPU first, and Detect all Codec 2nd. + * + * In Normal sound case, all DAIs are detected + * as "CPU-Codec". + * + * In DPCM sound case, + * all CPUs are detected as "CPU-dummy", and + * all Codecs are detected as "dummy-Codec". + * To avoid random sub-device numbering, + * detect "dummy-Codec" in last; + */ + ret = graph_for_each_link(priv, &li, + graph_dai_link_of, + graph_dai_link_of_dpcm); + if (ret < 0) return ret; - } } return asoc_simple_card_parse_card_name(card, NULL); } -static int asoc_graph_get_dais_count(struct device *dev) +static int graph_count_noml(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li) { - struct of_phandle_iterator it; - struct device_node *node = dev->of_node; - int count = 0; - int rc; + struct device *dev = graph_priv_to_dev(priv); - of_for_each_phandle(&it, rc, node, "dais", NULL, 0) - count++; + li->link += 1; /* 1xCPU-Codec */ + li->dais += 2; /* 1xCPU + 1xCodec */ - return count; + dev_dbg(dev, "Count As Normal\n"); + + return 0; } -static int asoc_graph_soc_card_probe(struct snd_soc_card *card) +static int graph_count_dpcm(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li, + int dup_codec) { - struct graph_card_data *priv = snd_soc_card_get_drvdata(card); + struct device *dev = graph_priv_to_dev(priv); + + li->link++; /* 1xCPU-dummy */ + li->dais++; /* 1xCPU */ + + if (!dup_codec) { + li->link++; /* 1xdummy-Codec */ + li->conf++; /* 1xdummy-Codec */ + li->dais++; /* 1xCodec */ + } + + dev_dbg(dev, "Count As DPCM\n"); + + return 0; +} + +static void graph_get_dais_count(struct graph_priv *priv, + struct link_info *li) +{ + struct device *dev = graph_priv_to_dev(priv); + + /* + * link_num : number of links. + * CPU-Codec / CPU-dummy / dummy-Codec + * dais_num : number of DAIs + * ccnf_num : number of codec_conf + * same number for "dummy-Codec" + * + * ex1) + * CPU0 --- Codec0 link : 5 + * CPU1 --- Codec1 dais : 7 + * CPU2 -/ ccnf : 1 + * CPU3 --- Codec2 + * + * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec + * => 7 DAIs = 4xCPU + 3xCodec + * => 1 ccnf = 1xdummy-Codec + * + * ex2) + * CPU0 --- Codec0 link : 5 + * CPU1 --- Codec1 dais : 6 + * CPU2 -/ ccnf : 1 + * CPU3 -/ + * + * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec + * => 6 DAIs = 4xCPU + 2xCodec + * => 1 ccnf = 1xdummy-Codec + * + * ex3) + * CPU0 --- Codec0 link : 6 + * CPU1 -/ dais : 6 + * CPU2 --- Codec1 ccnf : 2 + * CPU3 -/ + * + * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec + * => 6 DAIs = 4xCPU + 2xCodec + * => 2 ccnf = 2xdummy-Codec + * + * ex4) + * CPU0 --- Codec0 (convert-rate) link : 3 + * CPU1 --- Codec1 dais : 4 + * ccnf : 1 + * + * => 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec + * => 4 DAIs = 2xCPU + 2xCodec + * => 1 ccnf = 1xdummy-Codec + */ + graph_for_each_link(priv, li, + graph_count_noml, + graph_count_dpcm); + dev_dbg(dev, "link %d, dais %d, ccnf %d\n", + li->link, li->dais, li->conf); +} + +static int graph_card_probe(struct snd_soc_card *card) +{ + struct graph_priv *priv = snd_soc_card_get_drvdata(card); int ret; ret = asoc_simple_card_init_hp(card, &priv->hp_jack, NULL); @@ -295,27 +642,40 @@ static int asoc_graph_soc_card_probe(struct snd_soc_card *card) return 0; } -static int asoc_graph_card_probe(struct platform_device *pdev) +static int graph_probe(struct platform_device *pdev) { - struct graph_card_data *priv; + struct graph_priv *priv; struct snd_soc_dai_link *dai_link; struct graph_dai_props *dai_props; + struct asoc_simple_dai *dais; struct device *dev = &pdev->dev; struct snd_soc_card *card; - int num, ret, i; + struct snd_soc_codec_conf *cconf; + struct link_info li; + int ret, i; /* Allocate the private data and the DAI link array */ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - num = asoc_graph_get_dais_count(dev); - if (num == 0) + card = graph_priv_to_card(priv); + card->owner = THIS_MODULE; + card->dev = dev; + card->dapm_widgets = graph_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(graph_dapm_widgets); + card->probe = graph_card_probe; + + memset(&li, 0, sizeof(li)); + graph_get_dais_count(priv, &li); + if (!li.link || !li.dais) return -EINVAL; - dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL); - dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL); - if (!dai_props || !dai_link) + dai_props = devm_kcalloc(dev, li.link, sizeof(*dai_props), GFP_KERNEL); + dai_link = devm_kcalloc(dev, li.link, sizeof(*dai_link), GFP_KERNEL); + dais = devm_kcalloc(dev, li.dais, sizeof(*dais), GFP_KERNEL); + cconf = devm_kcalloc(dev, li.conf, sizeof(*cconf), GFP_KERNEL); + if (!dai_props || !dai_link || !dais) return -ENOMEM; /* @@ -324,7 +684,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) * see * soc-core.c :: snd_soc_init_multicodec() */ - for (i = 0; i < num; i++) { + for (i = 0; i < li.link; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; dai_link[i].platform = &dai_props[i].platform; @@ -337,20 +697,17 @@ static int asoc_graph_card_probe(struct platform_device *pdev) return ret; } - priv->dai_props = dai_props; - priv->dai_link = dai_link; + priv->dai_props = dai_props; + priv->dai_link = dai_link; + priv->dais = dais; + priv->codec_conf = cconf; - /* Init snd_soc_card */ - card = graph_priv_to_card(priv); - card->owner = THIS_MODULE; - card->dev = dev; - card->dai_link = dai_link; - card->num_links = num; - card->dapm_widgets = asoc_graph_card_dapm_widgets; - card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets); - card->probe = asoc_graph_soc_card_probe; - - ret = asoc_graph_card_parse_of(priv); + card->dai_link = dai_link; + card->num_links = li.link; + card->codec_conf = cconf; + card->num_configs = li.conf; + + ret = graph_parse_of(priv); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(dev, "parse error %d\n", ret); @@ -370,29 +727,30 @@ static int asoc_graph_card_probe(struct platform_device *pdev) return ret; } -static int asoc_graph_card_remove(struct platform_device *pdev) +static int graph_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); return asoc_simple_card_clean_reference(card); } -static const struct of_device_id asoc_graph_of_match[] = { +static const struct of_device_id graph_of_match[] = { { .compatible = "audio-graph-card", }, + { .compatible = "audio-graph-scu-card", }, {}, }; -MODULE_DEVICE_TABLE(of, asoc_graph_of_match); +MODULE_DEVICE_TABLE(of, graph_of_match); -static struct platform_driver asoc_graph_card = { +static struct platform_driver graph_card = { .driver = { .name = "asoc-audio-graph-card", .pm = &snd_soc_pm_ops, - .of_match_table = asoc_graph_of_match, + .of_match_table = graph_of_match, }, - .probe = asoc_graph_card_probe, - .remove = asoc_graph_card_remove, + .probe = graph_probe, + .remove = graph_remove, }; -module_platform_driver(asoc_graph_card); +module_platform_driver(graph_card); MODULE_ALIAS("platform:asoc-audio-graph-card"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c deleted file mode 100644 index b83bb31021a9fb..00000000000000 --- a/sound/soc/generic/audio-graph-scu-card.c +++ /dev/null @@ -1,431 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// ASoC audio graph SCU sound card support -// -// Copyright (C) 2017 Renesas Solutions Corp. -// Kuninori Morimoto -// -// based on -// ${LINUX}/sound/soc/generic/simple-scu-card.c -// ${LINUX}/sound/soc/generic/audio-graph-card.c - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct graph_card_data { - struct snd_soc_card snd_card; - struct snd_soc_codec_conf codec_conf; - struct graph_dai_props { - struct asoc_simple_dai dai; - struct snd_soc_dai_link_component codecs; - struct snd_soc_dai_link_component platform; - } *dai_props; - struct snd_soc_dai_link *dai_link; - struct asoc_simple_card_data adata; -}; - -#define graph_priv_to_card(priv) (&(priv)->snd_card) -#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i)) -#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev) -#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i)) - -static int asoc_graph_card_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - - return asoc_simple_card_clk_enable(&dai_props->dai); -} - -static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - - asoc_simple_card_clk_disable(&dai_props->dai); -} - -static const struct snd_soc_ops asoc_graph_card_ops = { - .startup = asoc_graph_card_startup, - .shutdown = asoc_graph_card_shutdown, -}; - -static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) -{ - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai; - struct snd_soc_dai_link *dai_link; - struct graph_dai_props *dai_props; - int num = rtd->num; - - dai_link = graph_priv_to_link(priv, num); - dai_props = graph_priv_to_props(priv, num); - dai = dai_link->dynamic ? - rtd->cpu_dai : - rtd->codec_dai; - - return asoc_simple_card_init_dai(dai, &dai_props->dai); -} - -static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - - asoc_simple_card_convert_fixup(&priv->adata, params); - - return 0; -} - -static int asoc_graph_card_dai_link_of(struct device_node *ep, - struct graph_card_data *priv, - unsigned int daifmt, - int idx, int is_fe) -{ - struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, idx); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, idx); - struct snd_soc_card *card = graph_priv_to_card(priv); - int ret; - - if (is_fe) { - struct snd_soc_dai_link_component *codecs; - - /* BE is dummy */ - codecs = dai_link->codecs; - codecs->of_node = NULL; - codecs->dai_name = "snd-soc-dummy-dai"; - codecs->name = "snd-soc-dummy"; - - /* FE settings */ - dai_link->dynamic = 1; - dai_link->dpcm_merged_format = 1; - - ret = asoc_simple_card_parse_graph_cpu(ep, dai_link); - if (ret) - return ret; - - ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, &dai_props->dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "fe.%s", - dai_link->cpu_dai_name); - if (ret < 0) - return ret; - - /* card->num_links includes Codec */ - asoc_simple_card_canonicalize_cpu(dai_link, - of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); - } else { - /* FE is dummy */ - dai_link->cpu_of_node = NULL; - dai_link->cpu_dai_name = "snd-soc-dummy-dai"; - dai_link->cpu_name = "snd-soc-dummy"; - - /* BE settings */ - dai_link->no_pcm = 1; - dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup; - - ret = asoc_simple_card_parse_graph_codec(ep, dai_link); - if (ret < 0) - return ret; - - ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, &dai_props->dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "be.%s", - dai_link->codecs->dai_name); - if (ret < 0) - return ret; - - snd_soc_of_parse_audio_prefix(card, - &priv->codec_conf, - dai_link->codecs->of_node, - "prefix"); - } - - ret = asoc_simple_card_of_parse_tdm(ep, &dai_props->dai); - if (ret) - return ret; - - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - return ret; - - dai_link->dai_fmt = daifmt; - dai_link->dpcm_playback = 1; - dai_link->dpcm_capture = 1; - dai_link->ops = &asoc_graph_card_ops; - dai_link->init = asoc_graph_card_dai_init; - - return 0; -} - -static int asoc_graph_card_parse_of(struct graph_card_data *priv) -{ - struct of_phandle_iterator it; - struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_card *card = graph_priv_to_card(priv); - struct device_node *node = dev->of_node; - struct device_node *cpu_port; - struct device_node *cpu_ep; - struct device_node *codec_ep; - struct device_node *rcpu_ep; - struct device_node *codec_port; - struct device_node *codec_port_old; - unsigned int daifmt = 0; - int dai_idx, ret; - int rc, codec; - - if (!node) - return -EINVAL; - - /* - * we need to consider "widgets", "mclk-fs" around here - * see simple-card - */ - - ret = asoc_simple_card_of_parse_routing(card, NULL, 0); - if (ret < 0) - return ret; - - asoc_simple_card_parse_convert(dev, NULL, &priv->adata); - - /* - * it supports multi CPU, single CODEC only here - * see asoc_graph_get_dais_count - */ - - /* find 1st codec */ - of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { - cpu_port = it.node; - cpu_ep = of_get_next_child(cpu_port, NULL); - codec_ep = of_graph_get_remote_endpoint(cpu_ep); - rcpu_ep = of_graph_get_remote_endpoint(codec_ep); - - of_node_put(cpu_ep); - of_node_put(codec_ep); - of_node_put(rcpu_ep); - - if (!codec_ep) - continue; - - if (rcpu_ep != cpu_ep) { - dev_err(dev, "remote-endpoint missmatch (%s/%s/%s)\n", - cpu_ep->name, codec_ep->name, rcpu_ep->name); - ret = -EINVAL; - goto parse_of_err; - } - - ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep, - NULL, &daifmt); - if (ret < 0) { - of_node_put(cpu_port); - goto parse_of_err; - } - } - - dai_idx = 0; - codec_port_old = NULL; - for (codec = 0; codec < 2; codec++) { - /* - * To listup valid sounds continuously, - * detect all CPU-dummy first, and - * detect all dummy-Codec second - */ - of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { - cpu_port = it.node; - cpu_ep = of_get_next_child(cpu_port, NULL); - codec_ep = of_graph_get_remote_endpoint(cpu_ep); - codec_port = of_graph_get_port_parent(codec_ep); - - of_node_put(cpu_ep); - of_node_put(codec_ep); - of_node_put(codec_port); - - if (codec) { - if (!codec_port) - continue; - - if (codec_port_old == codec_port) - continue; - - codec_port_old = codec_port; - - /* Back-End (= Codec) */ - ret = asoc_graph_card_dai_link_of(codec_ep, priv, daifmt, dai_idx++, 0); - if (ret < 0) { - of_node_put(cpu_port); - goto parse_of_err; - } - } else { - /* Front-End (= CPU) */ - ret = asoc_graph_card_dai_link_of(cpu_ep, priv, daifmt, dai_idx++, 1); - if (ret < 0) { - of_node_put(cpu_port); - goto parse_of_err; - } - } - } - } - - ret = asoc_simple_card_parse_card_name(card, NULL); - if (ret) - goto parse_of_err; - - ret = 0; - -parse_of_err: - return ret; -} - -static int asoc_graph_get_dais_count(struct device *dev) -{ - struct of_phandle_iterator it; - struct device_node *node = dev->of_node; - struct device_node *cpu_port; - struct device_node *cpu_ep; - struct device_node *codec_ep; - struct device_node *codec_port; - struct device_node *codec_port_old; - int count = 0; - int rc; - - codec_port_old = NULL; - of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { - cpu_port = it.node; - cpu_ep = of_get_next_child(cpu_port, NULL); - codec_ep = of_graph_get_remote_endpoint(cpu_ep); - codec_port = of_graph_get_port_parent(codec_ep); - - of_node_put(cpu_ep); - of_node_put(codec_ep); - of_node_put(codec_port); - - if (cpu_ep) - count++; - - if (!codec_port) - continue; - - if (codec_port_old == codec_port) - continue; - - count++; - codec_port_old = codec_port; - } - - return count; -} - -static int asoc_graph_card_probe(struct platform_device *pdev) -{ - struct graph_card_data *priv; - struct snd_soc_dai_link *dai_link; - struct graph_dai_props *dai_props; - struct device *dev = &pdev->dev; - struct snd_soc_card *card; - int num, ret, i; - - /* Allocate the private data and the DAI link array */ - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - num = asoc_graph_get_dais_count(dev); - if (num == 0) - return -EINVAL; - - dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL); - dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL); - if (!dai_props || !dai_link) - return -ENOMEM; - - /* - * Use snd_soc_dai_link_component instead of legacy style - * It is codec only. but cpu/platform will be supported in the future. - * see - * soc-core.c :: snd_soc_init_multicodec() - */ - for (i = 0; i < num; i++) { - dai_link[i].codecs = &dai_props[i].codecs; - dai_link[i].num_codecs = 1; - dai_link[i].platform = &dai_props[i].platform; - } - - priv->dai_props = dai_props; - priv->dai_link = dai_link; - - /* Init snd_soc_card */ - card = graph_priv_to_card(priv); - card->owner = THIS_MODULE; - card->dev = dev; - card->dai_link = priv->dai_link; - card->num_links = num; - card->codec_conf = &priv->codec_conf; - card->num_configs = 1; - - ret = asoc_graph_card_parse_of(priv); - if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "parse error %d\n", ret); - goto err; - } - - snd_soc_card_set_drvdata(card, priv); - - ret = devm_snd_soc_register_card(dev, card); - if (ret < 0) - goto err; - - return 0; -err: - asoc_simple_card_clean_reference(card); - - return ret; -} - -static int asoc_graph_card_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - return asoc_simple_card_clean_reference(card); -} - -static const struct of_device_id asoc_graph_of_match[] = { - { .compatible = "audio-graph-scu-card", }, - {}, -}; -MODULE_DEVICE_TABLE(of, asoc_graph_of_match); - -static struct platform_driver asoc_graph_card = { - .driver = { - .name = "asoc-audio-graph-scu-card", - .pm = &snd_soc_pm_ops, - .of_match_table = asoc_graph_of_match, - }, - .probe = asoc_graph_card_probe, - .remove = asoc_graph_card_remove, -}; -module_platform_driver(asoc_graph_card); - -MODULE_ALIAS("platform:asoc-audio-graph-scu-card"); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("ASoC Audio Graph SCU Sound Card"); -MODULE_AUTHOR("Kuninori Morimoto "); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index f34cc6cddfa283..336895f7fd1e9e 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -32,10 +32,11 @@ void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data, } EXPORT_SYMBOL_GPL(asoc_simple_card_convert_fixup); -void asoc_simple_card_parse_convert(struct device *dev, char *prefix, +void asoc_simple_card_parse_convert(struct device *dev, + struct device_node *np, + char *prefix, struct asoc_simple_card_data *data) { - struct device_node *np = dev->of_node; char prop[128]; if (!prefix) @@ -151,21 +152,19 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name); -static void asoc_simple_card_clk_register(struct asoc_simple_dai *dai, - struct clk *clk) -{ - dai->clk = clk; -} - int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai) { - return clk_prepare_enable(dai->clk); + if (dai) + return clk_prepare_enable(dai->clk); + + return 0; } EXPORT_SYMBOL_GPL(asoc_simple_card_clk_enable); void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai) { - clk_disable_unprepare(dai->clk); + if (dai) + clk_disable_unprepare(dai->clk); } EXPORT_SYMBOL_GPL(asoc_simple_card_clk_disable); @@ -200,7 +199,7 @@ int asoc_simple_card_parse_clk(struct device *dev, if (!IS_ERR(clk)) { simple_dai->sysclk = clk_get_rate(clk); - asoc_simple_card_clk_register(simple_dai, clk); + simple_dai->clk = clk; } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) { simple_dai->sysclk = val; } else { @@ -272,13 +271,32 @@ static int asoc_simple_card_get_dai_id(struct device_node *ep) { struct device_node *node; struct device_node *endpoint; + struct of_endpoint info; int i, id; int ret; + /* use driver specified DAI ID if exist */ ret = snd_soc_get_dai_id(ep); if (ret != -ENOTSUPP) return ret; + /* use endpoint/port reg if exist */ + ret = of_graph_parse_endpoint(ep, &info); + if (ret == 0) { + /* + * Because it will count port/endpoint if it doesn't have "reg". + * But, we can't judge whether it has "no reg", or "reg = <0>" + * only of_graph_parse_endpoint(). + * We need to check "reg" property + */ + if (of_get_property(ep, "reg", NULL)) + return info.id; + + node = of_get_parent(ep); + of_node_put(node); + if (of_get_property(node, "reg", NULL)) + return info.port; + } node = of_graph_get_port_parent(ep); /* @@ -348,6 +366,9 @@ int asoc_simple_card_init_dai(struct snd_soc_dai *dai, { int ret; + if (!simple_dai) + return 0; + if (simple_dai->sysclk) { ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk, simple_dai->clk_direction); @@ -415,8 +436,7 @@ int asoc_simple_card_clean_reference(struct snd_soc_card *card) EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference); int asoc_simple_card_of_parse_routing(struct snd_soc_card *card, - char *prefix, - int optional) + char *prefix) { struct device_node *node = card->dev->of_node; char prop[128]; @@ -426,11 +446,8 @@ int asoc_simple_card_of_parse_routing(struct snd_soc_card *card, snprintf(prop, sizeof(prop), "%s%s", prefix, "routing"); - if (!of_property_read_bool(node, prop)) { - if (optional) - return 0; - return -EINVAL; - } + if (!of_property_read_bool(node, prop)) + return 0; return snd_soc_of_parse_audio_routing(card, prop); } diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 5a3f59aa4ba55c..479de236e694e2 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -15,19 +15,29 @@ #include #include -struct simple_card_data { +struct simple_priv { struct snd_soc_card snd_card; struct simple_dai_props { - struct asoc_simple_dai cpu_dai; - struct asoc_simple_dai codec_dai; + struct asoc_simple_dai *cpu_dai; + struct asoc_simple_dai *codec_dai; struct snd_soc_dai_link_component codecs; /* single codec */ struct snd_soc_dai_link_component platform; + struct asoc_simple_card_data adata; + struct snd_soc_codec_conf *codec_conf; unsigned int mclk_fs; } *dai_props; - unsigned int mclk_fs; struct asoc_simple_jack hp_jack; struct asoc_simple_jack mic_jack; struct snd_soc_dai_link *dai_link; + struct asoc_simple_dai *dais; + struct snd_soc_codec_conf *codec_conf; +}; + +struct link_info { + int dais; /* number of dai */ + int link; /* number of link */ + int conf; /* number of codec_conf */ + int cpu; /* turn for CPU / Codec */ }; #define simple_priv_to_card(priv) (&(priv)->snd_card) @@ -39,40 +49,43 @@ struct simple_card_data { #define CELL "#sound-dai-cells" #define PREFIX "simple-audio-card," -static int asoc_simple_card_startup(struct snd_pcm_substream *substream) +static int simple_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); int ret; - ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai); + ret = asoc_simple_card_clk_enable(dai_props->cpu_dai); if (ret) return ret; - ret = asoc_simple_card_clk_enable(&dai_props->codec_dai); + ret = asoc_simple_card_clk_enable(dai_props->codec_dai); if (ret) - asoc_simple_card_clk_disable(&dai_props->cpu_dai); + asoc_simple_card_clk_disable(dai_props->cpu_dai); return ret; } -static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) +static void simple_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); - asoc_simple_card_clk_disable(&dai_props->cpu_dai); + asoc_simple_card_clk_disable(dai_props->cpu_dai); - asoc_simple_card_clk_disable(&dai_props->codec_dai); + asoc_simple_card_clk_disable(dai_props->codec_dai); } -static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai, - unsigned long rate) +static int simple_set_clk_rate(struct asoc_simple_dai *simple_dai, + unsigned long rate) { + if (!simple_dai) + return 0; + if (!simple_dai->clk) return 0; @@ -82,31 +95,29 @@ static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai, return clk_set_rate(simple_dai->clk, rate); } -static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int simple_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; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); unsigned int mclk, mclk_fs = 0; int ret = 0; - if (priv->mclk_fs) - mclk_fs = priv->mclk_fs; - else if (dai_props->mclk_fs) + if (dai_props->mclk_fs) mclk_fs = dai_props->mclk_fs; if (mclk_fs) { mclk = params_rate(params) * mclk_fs; - ret = asoc_simple_set_clk_rate(&dai_props->codec_dai, mclk); + ret = simple_set_clk_rate(dai_props->codec_dai, mclk); if (ret < 0) return ret; - ret = asoc_simple_set_clk_rate(&dai_props->cpu_dai, mclk); + ret = simple_set_clk_rate(dai_props->cpu_dai, mclk); if (ret < 0) return ret; @@ -125,80 +136,249 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, return ret; } -static const struct snd_soc_ops asoc_simple_card_ops = { - .startup = asoc_simple_card_startup, - .shutdown = asoc_simple_card_shutdown, - .hw_params = asoc_simple_card_hw_params, +static const struct snd_soc_ops simple_ops = { + .startup = simple_startup, + .shutdown = simple_shutdown, + .hw_params = simple_hw_params, }; -static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) +static int simple_dai_init(struct snd_soc_pcm_runtime *rtd) { - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *codec = rtd->codec_dai; - struct snd_soc_dai *cpu = rtd->cpu_dai; - struct simple_dai_props *dai_props = - simple_priv_to_props(priv, rtd->num); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); int ret; - ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai); + ret = asoc_simple_card_init_dai(rtd->codec_dai, + dai_props->codec_dai); if (ret < 0) return ret; - ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai); + ret = asoc_simple_card_init_dai(rtd->cpu_dai, + dai_props->cpu_dai); if (ret < 0) return ret; return 0; } -static int asoc_simple_card_dai_link_of(struct device_node *node, - struct simple_card_data *priv, - int idx, - bool is_top_level_node) +static int simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); + + asoc_simple_card_convert_fixup(&dai_props->adata, params); + + return 0; +} + +static void simple_get_conversion(struct device *dev, + struct device_node *np, + struct asoc_simple_card_data *adata) +{ + struct device_node *top = dev->of_node; + struct device_node *node = of_get_parent(np); + + asoc_simple_card_parse_convert(dev, top, PREFIX, adata); + asoc_simple_card_parse_convert(dev, node, PREFIX, adata); + asoc_simple_card_parse_convert(dev, node, NULL, adata); + asoc_simple_card_parse_convert(dev, np, NULL, adata); + + of_node_put(node); +} + +static int simple_dai_link_of_dpcm(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, + bool is_top) { struct device *dev = simple_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); - struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai; - struct asoc_simple_dai *codec_dai = &dai_props->codec_dai; - struct device_node *cpu = NULL; - struct device_node *plat = NULL; - struct device_node *codec = NULL; + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); + struct asoc_simple_dai *dai; + struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct device_node *top = dev->of_node; + struct device_node *node = of_get_parent(np); char prop[128]; char *prefix = ""; - int ret, single_cpu; + int ret; + + /* + * |CPU |Codec : turn + * CPU |Pass |return + * Codec |return|Pass + * np + */ + if (li->cpu == (np == codec)) + return 0; + + dev_dbg(dev, "link_of DPCM (%pOF)\n", np); + + li->link++; + + of_node_put(node); /* For single DAI link & old style of DT node */ - if (is_top_level_node) + if (is_top) prefix = PREFIX; - snprintf(prop, sizeof(prop), "%scpu", prefix); - cpu = of_get_child_by_name(node, prop); + if (li->cpu) { + int is_single_links = 0; - if (!cpu) { - ret = -EINVAL; - dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); - goto dai_link_of_err; + /* BE is dummy */ + codecs->of_node = NULL; + codecs->dai_name = "snd-soc-dummy-dai"; + codecs->name = "snd-soc-dummy"; + + /* FE settings */ + dai_link->dynamic = 1; + dai_link->dpcm_merged_format = 1; + + dai = + dai_props->cpu_dai = &priv->dais[li->dais++]; + + ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL, + &is_single_links); + if (ret) + return ret; + + ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai); + if (ret < 0) + return ret; + + ret = asoc_simple_card_set_dailink_name(dev, dai_link, + "fe.%s", + dai_link->cpu_dai_name); + if (ret < 0) + return ret; + + asoc_simple_card_canonicalize_cpu(dai_link, is_single_links); + } else { + struct snd_soc_codec_conf *cconf; + + /* FE is dummy */ + dai_link->cpu_of_node = NULL; + dai_link->cpu_dai_name = "snd-soc-dummy-dai"; + dai_link->cpu_name = "snd-soc-dummy"; + + /* BE settings */ + dai_link->no_pcm = 1; + dai_link->be_hw_params_fixup = simple_be_hw_params_fixup; + + dai = + dai_props->codec_dai = &priv->dais[li->dais++]; + + cconf = + dai_props->codec_conf = &priv->codec_conf[li->conf++]; + + ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL); + if (ret < 0) + return ret; + + ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai); + if (ret < 0) + return ret; + + ret = asoc_simple_card_set_dailink_name(dev, dai_link, + "be.%s", + codecs->dai_name); + if (ret < 0) + return ret; + + /* check "prefix" from top node */ + snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, + PREFIX "prefix"); + snd_soc_of_parse_node_prefix(node, cconf, codecs->of_node, + "prefix"); + snd_soc_of_parse_node_prefix(np, cconf, codecs->of_node, + "prefix"); } + simple_get_conversion(dev, np, &dai_props->adata); + + ret = asoc_simple_card_of_parse_tdm(np, dai); + if (ret) + return ret; + + ret = asoc_simple_card_canonicalize_dailink(dai_link); + if (ret < 0) + return ret; + + snprintf(prop, sizeof(prop), "%smclk-fs", prefix); + of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(node, prop, &dai_props->mclk_fs); + of_property_read_u32(np, prop, &dai_props->mclk_fs); + + ret = asoc_simple_card_parse_daifmt(dev, node, codec, + prefix, &dai_link->dai_fmt); + if (ret < 0) + return ret; + + dai_link->dpcm_playback = 1; + dai_link->dpcm_capture = 1; + dai_link->ops = &simple_ops; + dai_link->init = simple_dai_init; + + return 0; +} + +static int simple_dai_link_of(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, + bool is_top) +{ + struct device *dev = simple_priv_to_dev(priv); + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); + struct asoc_simple_dai *cpu_dai; + struct asoc_simple_dai *codec_dai; + struct device_node *top = dev->of_node; + struct device_node *cpu = NULL; + struct device_node *node = NULL; + struct device_node *plat = NULL; + char prop[128]; + char *prefix = ""; + int ret, single_cpu; + + /* + * |CPU |Codec : turn + * CPU |Pass |return + * Codec |return|return + * np + */ + if (!li->cpu || np == codec) + return 0; + + cpu = np; + node = of_get_parent(np); + li->link++; + + dev_dbg(dev, "link_of (%pOF)\n", node); + + /* For single DAI link & old style of DT node */ + if (is_top) + prefix = PREFIX; + snprintf(prop, sizeof(prop), "%splat", prefix); plat = of_get_child_by_name(node, prop); - snprintf(prop, sizeof(prop), "%scodec", prefix); - codec = of_get_child_by_name(node, prop); - - if (!codec) { - ret = -EINVAL; - dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); - goto dai_link_of_err; - } + cpu_dai = + dai_props->cpu_dai = &priv->dais[li->dais++]; + codec_dai = + dai_props->codec_dai = &priv->dais[li->dais++]; ret = asoc_simple_card_parse_daifmt(dev, node, codec, prefix, &dai_link->dai_fmt); if (ret < 0) goto dai_link_of_err; - of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs); + snprintf(prop, sizeof(prop), "%smclk-fs", prefix); + of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs); + of_property_read_u32(node, prop, &dai_props->mclk_fs); + of_property_read_u32(cpu, prop, &dai_props->mclk_fs); + of_property_read_u32(codec, prop, &dai_props->mclk_fs); ret = asoc_simple_card_parse_cpu(cpu, dai_link, DAI, CELL, &single_cpu); @@ -240,20 +420,87 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, if (ret < 0) goto dai_link_of_err; - dai_link->ops = &asoc_simple_card_ops; - dai_link->init = asoc_simple_card_dai_init; + dai_link->ops = &simple_ops; + dai_link->init = simple_dai_init; asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); dai_link_of_err: - of_node_put(cpu); - of_node_put(codec); + of_node_put(node); return ret; } -static int asoc_simple_card_parse_aux_devs(struct device_node *node, - struct simple_card_data *priv) +static int simple_for_each_link(struct simple_priv *priv, + struct link_info *li, + int (*func_noml)(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top), + int (*func_dpcm)(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top)) +{ + struct device *dev = simple_priv_to_dev(priv); + struct device_node *top = dev->of_node; + struct device_node *node; + bool is_top = 0; + + /* Check if it has dai-link */ + node = of_get_child_by_name(top, PREFIX "dai-link"); + if (!node) { + node = top; + is_top = 1; + } + + /* loop for all dai-link */ + do { + struct asoc_simple_card_data adata; + struct device_node *codec; + struct device_node *np; + int num = of_get_child_count(node); + int ret; + + /* get codec */ + codec = of_get_child_by_name(node, is_top ? + PREFIX "codec" : "codec"); + if (!codec) + return -ENODEV; + + of_node_put(codec); + + /* get convert-xxx property */ + memset(&adata, 0, sizeof(adata)); + for_each_child_of_node(node, np) + simple_get_conversion(dev, np, &adata); + + /* loop for all CPU/Codec node */ + for_each_child_of_node(node, np) { + /* + * It is DPCM + * if it has many CPUs, + * or has convert-xxx property + */ + if (num > 2 || + adata.convert_rate || adata.convert_channels) + ret = func_dpcm(priv, np, codec, li, is_top); + /* else normal sound */ + else + ret = func_noml(priv, np, codec, li, is_top); + + if (ret < 0) + return ret; + } + + node = of_get_next_child(top, node); + } while (!is_top && node); + + return 0; +} + +static int simple_parse_aux_devs(struct device_node *node, + struct simple_priv *priv) { struct device *dev = simple_priv_to_dev(priv); struct device_node *aux_node; @@ -283,67 +530,151 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node, return 0; } -static int asoc_simple_card_parse_of(struct simple_card_data *priv) +static int simple_parse_of(struct simple_priv *priv) { struct device *dev = simple_priv_to_dev(priv); + struct device_node *top = dev->of_node; struct snd_soc_card *card = simple_priv_to_card(priv); - struct device_node *dai_link; - struct device_node *node = dev->of_node; + struct link_info li; int ret; - if (!node) + if (!top) return -EINVAL; - dai_link = of_get_child_by_name(node, PREFIX "dai-link"); - ret = asoc_simple_card_of_parse_widgets(card, PREFIX); if (ret < 0) - goto card_parse_end; + return ret; - ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1); + ret = asoc_simple_card_of_parse_routing(card, PREFIX); if (ret < 0) - goto card_parse_end; - - /* Factor to mclk, used in hw_params() */ - of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs); + return ret; /* Single/Muti DAI link(s) & New style of DT node */ - if (dai_link) { - struct device_node *np = NULL; - int i = 0; - - for_each_child_of_node(node, np) { - dev_dbg(dev, "\tlink %d:\n", i); - ret = asoc_simple_card_dai_link_of(np, priv, - i, false); - if (ret < 0) { - of_node_put(np); - goto card_parse_end; - } - i++; - } - } else { - /* For single DAI link & old style of DT node */ - ret = asoc_simple_card_dai_link_of(node, priv, 0, true); + memset(&li, 0, sizeof(li)); + for (li.cpu = 1; li.cpu >= 0; li.cpu--) { + /* + * Detect all CPU first, and Detect all Codec 2nd. + * + * In Normal sound case, all DAIs are detected + * as "CPU-Codec". + * + * In DPCM sound case, + * all CPUs are detected as "CPU-dummy", and + * all Codecs are detected as "dummy-Codec". + * To avoid random sub-device numbering, + * detect "dummy-Codec" in last; + */ + ret = simple_for_each_link(priv, &li, + simple_dai_link_of, + simple_dai_link_of_dpcm); if (ret < 0) - goto card_parse_end; + return ret; } ret = asoc_simple_card_parse_card_name(card, PREFIX); if (ret < 0) - goto card_parse_end; - - ret = asoc_simple_card_parse_aux_devs(node, priv); + return ret; -card_parse_end: - of_node_put(dai_link); + ret = simple_parse_aux_devs(top, priv); return ret; } -static int asoc_simple_soc_card_probe(struct snd_soc_card *card) +static int simple_count_noml(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top) { - struct simple_card_data *priv = snd_soc_card_get_drvdata(card); + li->dais++; /* CPU or Codec */ + if (np != codec) + li->link++; /* CPU-Codec */ + + return 0; +} + +static int simple_count_dpcm(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top) +{ + li->dais++; /* CPU or Codec */ + li->link++; /* CPU-dummy or dummy-Codec */ + if (np == codec) + li->conf++; + + return 0; +} + +static void simple_get_dais_count(struct simple_priv *priv, + struct link_info *li) +{ + struct device *dev = simple_priv_to_dev(priv); + struct device_node *top = dev->of_node; + + /* + * link_num : number of links. + * CPU-Codec / CPU-dummy / dummy-Codec + * dais_num : number of DAIs + * ccnf_num : number of codec_conf + * same number for "dummy-Codec" + * + * ex1) + * CPU0 --- Codec0 link : 5 + * CPU1 --- Codec1 dais : 7 + * CPU2 -/ ccnf : 1 + * CPU3 --- Codec2 + * + * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec + * => 7 DAIs = 4xCPU + 3xCodec + * => 1 ccnf = 1xdummy-Codec + * + * ex2) + * CPU0 --- Codec0 link : 5 + * CPU1 --- Codec1 dais : 6 + * CPU2 -/ ccnf : 1 + * CPU3 -/ + * + * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec + * => 6 DAIs = 4xCPU + 2xCodec + * => 1 ccnf = 1xdummy-Codec + * + * ex3) + * CPU0 --- Codec0 link : 6 + * CPU1 -/ dais : 6 + * CPU2 --- Codec1 ccnf : 2 + * CPU3 -/ + * + * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec + * => 6 DAIs = 4xCPU + 2xCodec + * => 2 ccnf = 2xdummy-Codec + * + * ex4) + * CPU0 --- Codec0 (convert-rate) link : 3 + * CPU1 --- Codec1 dais : 4 + * ccnf : 1 + * + * => 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec + * => 4 DAIs = 2xCPU + 2xCodec + * => 1 ccnf = 1xdummy-Codec + */ + if (!top) { + li->link = 1; + li->dais = 2; + li->conf = 0; + return; + } + + simple_for_each_link(priv, li, + simple_count_noml, + simple_count_dpcm); + + dev_dbg(dev, "link %d, dais %d, ccnf %d\n", + li->link, li->dais, li->conf); +} + +static int simple_soc_probe(struct snd_soc_card *card) +{ + struct simple_priv *priv = snd_soc_card_get_drvdata(card); int ret; ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX); @@ -357,30 +688,39 @@ static int asoc_simple_soc_card_probe(struct snd_soc_card *card) return 0; } -static int asoc_simple_card_probe(struct platform_device *pdev) +static int simple_probe(struct platform_device *pdev) { - struct simple_card_data *priv; + struct simple_priv *priv; struct snd_soc_dai_link *dai_link; struct simple_dai_props *dai_props; + struct asoc_simple_dai *dais; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct snd_soc_card *card; - int num, ret, i; - - /* Get the number of DAI links */ - if (np && of_get_child_by_name(np, PREFIX "dai-link")) - num = of_get_child_count(np); - else - num = 1; + struct snd_soc_codec_conf *cconf; + struct link_info li; + int ret, i; /* Allocate the private data and the DAI link array */ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL); - dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL); - if (!dai_props || !dai_link) + card = simple_priv_to_card(priv); + card->owner = THIS_MODULE; + card->dev = dev; + card->probe = simple_soc_probe; + + memset(&li, 0, sizeof(li)); + simple_get_dais_count(priv, &li); + if (!li.link || !li.dais) + return -EINVAL; + + dai_props = devm_kcalloc(dev, li.link, sizeof(*dai_props), GFP_KERNEL); + dai_link = devm_kcalloc(dev, li.link, sizeof(*dai_link), GFP_KERNEL); + dais = devm_kcalloc(dev, li.dais, sizeof(*dais), GFP_KERNEL); + cconf = devm_kcalloc(dev, li.conf, sizeof(*cconf), GFP_KERNEL); + if (!dai_props || !dai_link || !dais) return -ENOMEM; /* @@ -389,26 +729,25 @@ static int asoc_simple_card_probe(struct platform_device *pdev) * see * soc-core.c :: snd_soc_init_multicodec() */ - for (i = 0; i < num; i++) { + for (i = 0; i < li.link; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; dai_link[i].platform = &dai_props[i].platform; } - priv->dai_props = dai_props; - priv->dai_link = dai_link; + priv->dai_props = dai_props; + priv->dai_link = dai_link; + priv->dais = dais; + priv->codec_conf = cconf; - /* Init snd_soc_card */ - card = simple_priv_to_card(priv); - card->owner = THIS_MODULE; - card->dev = dev; card->dai_link = priv->dai_link; - card->num_links = num; - card->probe = asoc_simple_soc_card_probe; + card->num_links = li.link; + card->codec_conf = cconf; + card->num_configs = li.conf; if (np && of_device_is_available(np)) { - ret = asoc_simple_card_parse_of(priv); + ret = simple_parse_of(priv); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(dev, "parse error %d\n", ret); @@ -419,6 +758,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) struct asoc_simple_card_info *cinfo; struct snd_soc_dai_link_component *codecs; struct snd_soc_dai_link_component *platform; + int dai_idx = 0; cinfo = dev->platform_data; if (!cinfo) { @@ -435,6 +775,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) return -EINVAL; } + dai_props->cpu_dai = &priv->dais[dai_idx++]; + dai_props->codec_dai = &priv->dais[dai_idx++]; + codecs = dai_link->codecs; codecs->name = cinfo->codec; codecs->dai_name = cinfo->codec_dai.name; @@ -447,11 +790,11 @@ static int asoc_simple_card_probe(struct platform_device *pdev) dai_link->stream_name = cinfo->name; dai_link->cpu_dai_name = cinfo->cpu_dai.name; dai_link->dai_fmt = cinfo->daifmt; - dai_link->init = asoc_simple_card_dai_init; - memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai, - sizeof(priv->dai_props->cpu_dai)); - memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai, - sizeof(priv->dai_props->codec_dai)); + dai_link->init = simple_dai_init; + memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai, + sizeof(*priv->dai_props->cpu_dai)); + memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai, + sizeof(*priv->dai_props->codec_dai)); } snd_soc_card_set_drvdata(card, priv); @@ -467,27 +810,28 @@ static int asoc_simple_card_probe(struct platform_device *pdev) return ret; } -static int asoc_simple_card_remove(struct platform_device *pdev) +static int simple_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); return asoc_simple_card_clean_reference(card); } -static const struct of_device_id asoc_simple_of_match[] = { +static const struct of_device_id simple_of_match[] = { { .compatible = "simple-audio-card", }, + { .compatible = "simple-scu-audio-card", }, {}, }; -MODULE_DEVICE_TABLE(of, asoc_simple_of_match); +MODULE_DEVICE_TABLE(of, simple_of_match); static struct platform_driver asoc_simple_card = { .driver = { .name = "asoc-simple-card", .pm = &snd_soc_pm_ops, - .of_match_table = asoc_simple_of_match, + .of_match_table = simple_of_match, }, - .probe = asoc_simple_card_probe, - .remove = asoc_simple_card_remove, + .probe = simple_probe, + .remove = simple_remove, }; module_platform_driver(asoc_simple_card); diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c deleted file mode 100644 index 85b46f0eae0ff2..00000000000000 --- a/sound/soc/generic/simple-scu-card.c +++ /dev/null @@ -1,330 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// ASoC simple SCU sound card support -// -// Copyright (C) 2015 Renesas Solutions Corp. -// Kuninori Morimoto -// -// based on ${LINUX}/sound/soc/generic/simple-card.c - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct simple_card_data { - struct snd_soc_card snd_card; - struct snd_soc_codec_conf codec_conf; - struct simple_dai_props { - struct asoc_simple_dai dai; - struct snd_soc_dai_link_component codecs; - struct snd_soc_dai_link_component platform; - } *dai_props; - struct snd_soc_dai_link *dai_link; - struct asoc_simple_card_data adata; -}; - -#define simple_priv_to_card(priv) (&(priv)->snd_card) -#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i)) -#define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev) -#define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i)) - -#define DAI "sound-dai" -#define CELL "#sound-dai-cells" -#define PREFIX "simple-audio-card," - -static int asoc_simple_card_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = - simple_priv_to_props(priv, rtd->num); - - return asoc_simple_card_clk_enable(&dai_props->dai); -} - -static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = - simple_priv_to_props(priv, rtd->num); - - asoc_simple_card_clk_disable(&dai_props->dai); -} - -static const struct snd_soc_ops asoc_simple_card_ops = { - .startup = asoc_simple_card_startup, - .shutdown = asoc_simple_card_shutdown, -}; - -static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) -{ - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai; - struct snd_soc_dai_link *dai_link; - struct simple_dai_props *dai_props; - int num = rtd->num; - - dai_link = simple_priv_to_link(priv, num); - dai_props = simple_priv_to_props(priv, num); - dai = dai_link->dynamic ? - rtd->cpu_dai : - rtd->codec_dai; - - return asoc_simple_card_init_dai(dai, &dai_props->dai); -} - -static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - - asoc_simple_card_convert_fixup(&priv->adata, params); - - return 0; -} - -static int asoc_simple_card_dai_link_of(struct device_node *np, - struct simple_card_data *priv, - unsigned int daifmt, - int idx, bool is_fe) -{ - struct device *dev = simple_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); - struct snd_soc_card *card = simple_priv_to_card(priv); - int ret; - - if (is_fe) { - int is_single_links = 0; - struct snd_soc_dai_link_component *codecs; - - /* BE is dummy */ - codecs = dai_link->codecs; - codecs->of_node = NULL; - codecs->dai_name = "snd-soc-dummy-dai"; - codecs->name = "snd-soc-dummy"; - - /* FE settings */ - dai_link->dynamic = 1; - dai_link->dpcm_merged_format = 1; - - ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL, - &is_single_links); - if (ret) - return ret; - - ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, &dai_props->dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "fe.%s", - dai_link->cpu_dai_name); - if (ret < 0) - return ret; - - asoc_simple_card_canonicalize_cpu(dai_link, is_single_links); - } else { - /* FE is dummy */ - dai_link->cpu_of_node = NULL; - dai_link->cpu_dai_name = "snd-soc-dummy-dai"; - dai_link->cpu_name = "snd-soc-dummy"; - - /* BE settings */ - dai_link->no_pcm = 1; - dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup; - - ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL); - if (ret < 0) - return ret; - - ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, &dai_props->dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "be.%s", - dai_link->codecs->dai_name); - if (ret < 0) - return ret; - - snd_soc_of_parse_audio_prefix(card, - &priv->codec_conf, - dai_link->codecs->of_node, - PREFIX "prefix"); - } - - ret = asoc_simple_card_of_parse_tdm(np, &dai_props->dai); - if (ret) - return ret; - - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - return ret; - - dai_link->dai_fmt = daifmt; - dai_link->dpcm_playback = 1; - dai_link->dpcm_capture = 1; - dai_link->ops = &asoc_simple_card_ops; - dai_link->init = asoc_simple_card_dai_init; - - return 0; -} - -static int asoc_simple_card_parse_of(struct simple_card_data *priv) - -{ - struct device *dev = simple_priv_to_dev(priv); - struct device_node *np; - struct snd_soc_card *card = simple_priv_to_card(priv); - struct device_node *node = dev->of_node; - unsigned int daifmt = 0; - bool is_fe; - int ret, i; - - if (!node) - return -EINVAL; - - ret = asoc_simple_card_of_parse_widgets(card, PREFIX); - if (ret < 0) - return ret; - - ret = asoc_simple_card_of_parse_routing(card, PREFIX, 0); - if (ret < 0) - return ret; - - asoc_simple_card_parse_convert(dev, PREFIX, &priv->adata); - - /* find 1st codec */ - np = of_get_child_by_name(node, PREFIX "codec"); - if (!np) - return -ENODEV; - - ret = asoc_simple_card_parse_daifmt(dev, node, np, PREFIX, &daifmt); - if (ret < 0) - return ret; - - i = 0; - for_each_child_of_node(node, np) { - is_fe = false; - if (strcmp(np->name, PREFIX "cpu") == 0) - is_fe = true; - - ret = asoc_simple_card_dai_link_of(np, priv, daifmt, i, is_fe); - if (ret < 0) - return ret; - i++; - } - - ret = asoc_simple_card_parse_card_name(card, PREFIX); - if (ret < 0) - return ret; - - return 0; -} - -static int asoc_simple_card_probe(struct platform_device *pdev) -{ - struct simple_card_data *priv; - struct snd_soc_dai_link *dai_link; - struct simple_dai_props *dai_props; - struct snd_soc_card *card; - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - int num, ret, i; - - /* Allocate the private data */ - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - num = of_get_child_count(np); - - dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL); - dai_link = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL); - if (!dai_props || !dai_link) - return -ENOMEM; - - /* - * Use snd_soc_dai_link_component instead of legacy style - * It is codec only. but cpu/platform will be supported in the future. - * see - * soc-core.c :: snd_soc_init_multicodec() - */ - for (i = 0; i < num; i++) { - dai_link[i].codecs = &dai_props[i].codecs; - dai_link[i].num_codecs = 1; - dai_link[i].platform = &dai_props[i].platform; - } - - priv->dai_props = dai_props; - priv->dai_link = dai_link; - - /* Init snd_soc_card */ - card = simple_priv_to_card(priv); - card->owner = THIS_MODULE; - card->dev = dev; - card->dai_link = priv->dai_link; - card->num_links = num; - card->codec_conf = &priv->codec_conf; - card->num_configs = 1; - - ret = asoc_simple_card_parse_of(priv); - if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "parse error %d\n", ret); - goto err; - } - - snd_soc_card_set_drvdata(card, priv); - - ret = devm_snd_soc_register_card(dev, card); - if (ret < 0) - goto err; - - return 0; -err: - asoc_simple_card_clean_reference(card); - - return ret; -} - -static int asoc_simple_card_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - return asoc_simple_card_clean_reference(card); -} - -static const struct of_device_id asoc_simple_of_match[] = { - { .compatible = "renesas,rsrc-card", }, - { .compatible = "simple-scu-audio-card", }, - {}, -}; -MODULE_DEVICE_TABLE(of, asoc_simple_of_match); - -static struct platform_driver asoc_simple_card = { - .driver = { - .name = "simple-scu-audio-card", - .pm = &snd_soc_pm_ops, - .of_match_table = asoc_simple_of_match, - }, - .probe = asoc_simple_card_probe, - .remove = asoc_simple_card_remove, -}; - -module_platform_driver(asoc_simple_card); - -MODULE_ALIAS("platform:asoc-simple-scu-card"); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("ASoC Simple SCU Sound Card"); -MODULE_AUTHOR("Kuninori Morimoto "); From 1fb4587637d69b4bd8443e2302742ab9b9b89374 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:32 +0900 Subject: [PATCH 0690/1995] ASoC: soc-core: add .num_platform for dai_link Current snd_soc_dai_link is starting to use snd_soc_dai_link_component (= modern) style for Platform, but it is still assuming single Platform so far. We will need to have multi Platform support in the not far future. Currently only simple card is using it as sound card driver, and other drivers are converted to it from legacy style by snd_soc_init_platform(). To avoid future problem of multi Platform support, let's add num_platforms before it is too late. In the same time, to make it same naming mothed, "platform" should be "platforms". This patch fixup it too. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 910fdcabedd2354d161b1beab6ad7dc7e859651d) --- include/sound/simple_card_utils.h | 2 +- include/sound/soc.h | 3 ++- sound/soc/generic/audio-graph-card.c | 5 +++-- sound/soc/generic/simple-card-utils.c | 4 ++-- sound/soc/generic/simple-card.c | 7 ++++--- sound/soc/soc-core.c | 23 ++++++++++++++++------- 6 files changed, 28 insertions(+), 16 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 6d69ed2bd7b111..ab5a2ba09c0779 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -75,7 +75,7 @@ void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai); &dai_link->codec_dai_name, \ list_name, cells_name, NULL) #define asoc_simple_card_parse_platform(node, dai_link, list_name, cells_name) \ - asoc_simple_card_parse_dai(node, dai_link->platform, \ + asoc_simple_card_parse_dai(node, dai_link->platforms, \ &dai_link->platform_of_node, \ NULL, list_name, cells_name, NULL) int asoc_simple_card_parse_dai(struct device_node *node, diff --git a/include/sound/soc.h b/include/sound/soc.h index c31b6d122ff68c..3089257ead9544 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -961,7 +961,8 @@ struct snd_soc_dai_link { */ const char *platform_name; struct device_node *platform_of_node; - struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link_component *platforms; + unsigned int num_platforms; int id; /* optional ID for machine driver link identification */ diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 3ec96cdc683b5a..42b077c6be4c4a 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -26,7 +26,7 @@ struct graph_priv { struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; struct snd_soc_dai_link_component codecs; /* single codec */ - struct snd_soc_dai_link_component platform; + struct snd_soc_dai_link_component platforms; struct asoc_simple_card_data adata; struct snd_soc_codec_conf *codec_conf; unsigned int mclk_fs; @@ -687,7 +687,8 @@ static int graph_probe(struct platform_device *pdev) for (i = 0; i < li.link; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; - dai_link[i].platform = &dai_props[i].platform; + dai_link[i].platforms = &dai_props[i].platforms; + dai_link[i].num_platforms = 1; } priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 336895f7fd1e9e..3c0901df57960a 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -397,8 +397,8 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai); int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link) { /* Assumes platform == cpu */ - if (!dai_link->platform->of_node) - dai_link->platform->of_node = dai_link->cpu_of_node; + if (!dai_link->platforms->of_node) + dai_link->platforms->of_node = dai_link->cpu_of_node; return 0; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 479de236e694e2..d8a0d1ec256e06 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -21,7 +21,7 @@ struct simple_priv { struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; struct snd_soc_dai_link_component codecs; /* single codec */ - struct snd_soc_dai_link_component platform; + struct snd_soc_dai_link_component platforms; struct asoc_simple_card_data adata; struct snd_soc_codec_conf *codec_conf; unsigned int mclk_fs; @@ -732,7 +732,8 @@ static int simple_probe(struct platform_device *pdev) for (i = 0; i < li.link; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; - dai_link[i].platform = &dai_props[i].platform; + dai_link[i].platforms = &dai_props[i].platforms; + dai_link[i].num_platforms = 1; } priv->dai_props = dai_props; @@ -782,7 +783,7 @@ static int simple_probe(struct platform_device *pdev) codecs->name = cinfo->codec; codecs->dai_name = cinfo->codec_dai.name; - platform = dai_link->platform; + platform = dai_link->platforms; platform->name = cinfo->platform; card->name = (cinfo->card) ? cinfo->card : cinfo->name; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index de2851f1b3df3a..2c63921675d556 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -915,7 +915,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, /* find one from the set of registered platforms */ for_each_component(component) { - if (!snd_soc_is_matching_component(dai_link->platform, + if (!snd_soc_is_matching_component(dai_link->platforms, component)) continue; @@ -1026,7 +1026,7 @@ static void soc_remove_dai_links(struct snd_soc_card *card) static int snd_soc_init_platform(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { - struct snd_soc_dai_link_component *platform = dai_link->platform; + struct snd_soc_dai_link_component *platform = dai_link->platforms; /* * REMOVE ME @@ -1046,7 +1046,8 @@ static int snd_soc_init_platform(struct snd_soc_card *card, if (!platform) return -ENOMEM; - dai_link->platform = platform; + dai_link->platforms = platform; + dai_link->num_platforms = 1; dai_link->legacy_platform = 1; platform->name = dai_link->platform_name; platform->of_node = dai_link->platform_of_node; @@ -1136,11 +1137,19 @@ static int soc_init_dai_link(struct snd_soc_card *card, } } + /* FIXME */ + if (link->num_platforms > 1) { + dev_err(card->dev, + "ASoC: multi platform is not yet supported %s\n", + link->name); + return -EINVAL; + } + /* * Platform may be specified by either name or OF node, but * can be left unspecified, and a dummy platform will be used. */ - if (link->platform->name && link->platform->of_node) { + if (link->platforms->name && link->platforms->of_node) { dev_err(card->dev, "ASoC: Both platform name/of_node are set for %s\n", link->name); @@ -1151,8 +1160,8 @@ static int soc_init_dai_link(struct snd_soc_card *card, * Defer card registartion if platform dai component is not added to * component list. */ - if ((link->platform->of_node || link->platform->name) && - !soc_find_component(link->platform->of_node, link->platform->name)) + if ((link->platforms->of_node || link->platforms->name) && + !soc_find_component(link->platforms->of_node, link->platforms->name)) return -EPROBE_DEFER; /* @@ -1956,7 +1965,7 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) dev_err(card->dev, "init platform error"); continue; } - dai_link->platform->name = component->name; + dai_link->platforms->name = component->name; /* convert non BE into BE */ dai_link->no_pcm = 1; From d753e6e2c80199b66c48ee83944a4be3ad45f48f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:37 +0900 Subject: [PATCH 0691/1995] ASoC: soc-core: add new snd_soc_flush_all_delayed_work() soc-core is calling flush_delayed_work() many times for same purpose. Same code in many places makes code un-understandable. This patch adds new snd_soc_flush_all_delayed_work() for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 65462e445f78cb2f9378443be7ba8b7e07300694) --- sound/soc/soc-core.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 2c63921675d556..eeb794d8a26274 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -425,6 +425,14 @@ struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); +static void snd_soc_flush_all_delayed_work(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + + for_each_card_rtds(card, rtd) + flush_delayed_work(&rtd->delayed_work); +} + static void codec2codec_close_delayed_work(struct work_struct *work) { /* @@ -494,8 +502,7 @@ int snd_soc_suspend(struct device *dev) } /* close any waiting streams */ - for_each_card_rtds(card, rtd) - flush_delayed_work(&rtd->delayed_work); + snd_soc_flush_all_delayed_work(card); for_each_card_rtds(card, rtd) { @@ -2228,11 +2235,8 @@ static int soc_probe(struct platform_device *pdev) static int soc_cleanup_card_resources(struct snd_soc_card *card) { - struct snd_soc_pcm_runtime *rtd; - /* make sure any delayed work runs */ - for_each_card_rtds(card, rtd) - flush_delayed_work(&rtd->delayed_work); + snd_soc_flush_all_delayed_work(card); /* free the ALSA card at first; this syncs with pending operations */ snd_card_free(card->snd_card); @@ -2275,8 +2279,7 @@ int snd_soc_poweroff(struct device *dev) * Flush out pmdown_time work - we actually do want to run it * now, we're shutting down so no imminent restart. */ - for_each_card_rtds(card, rtd) - flush_delayed_work(&rtd->delayed_work); + snd_soc_flush_all_delayed_work(card); snd_soc_dapm_shutdown(card); From c69f11d0c9f4cfa55f63f4e805b3defd1129b67f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:42 +0900 Subject: [PATCH 0692/1995] ASoC: soc-core: merge card resources cleanup method We need to cleanup card resources when snd_soc_instantiate_card() was failed, or when snd_soc_unbind_card() was called. But they are cleanuping card resources on each way. Same code in many places makes code un-understandable. This patch reuses soc_cleanup_card_resources() for cleanuping code resource. Then, it makes avoiding cleanup order. It will be called from snd_soc_instantiate_card() and snd_soc_unbind_card(). Then, original soc_cleanup_card_resources() included snd_soc_flush_all_delayed_work(), but it is now separated. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 53e947a0e1f770b9707febb7054b856878945d50) --- sound/soc/soc-core.c | 103 ++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 60 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index eeb794d8a26274..d59b5ea9fa2540 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2008,6 +2008,29 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) } } +static int soc_cleanup_card_resources(struct snd_soc_card *card) +{ + /* free the ALSA card at first; this syncs with pending operations */ + if (card->snd_card) + snd_card_free(card->snd_card); + + /* remove and free each DAI */ + soc_remove_dai_links(card); + soc_remove_pcm_runtimes(card); + + /* remove auxiliary devices */ + soc_remove_aux_devices(card); + + snd_soc_dapm_free(&card->dapm); + soc_cleanup_card_debugfs(card); + + /* remove the card */ + if (card->remove) + card->remove(card); + + return 0; +} + static int snd_soc_instantiate_card(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; @@ -2017,6 +2040,11 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) mutex_lock(&client_mutex); mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT); + card->dapm.bias_level = SND_SOC_BIAS_OFF; + card->dapm.dev = card->dev; + card->dapm.card = card; + list_add(&card->dapm.list, &card->dapm_list); + /* check whether any platform is ignore machine FE and using topology */ soc_check_tplg_fes(card); @@ -2024,14 +2052,14 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) for_each_card_prelinks(card, i, dai_link) { ret = soc_bind_dai_link(card, dai_link); if (ret != 0) - goto base_error; + goto probe_end; } /* bind aux_devs too */ for (i = 0; i < card->num_aux_devs; i++) { ret = soc_bind_aux_dev(card, i); if (ret != 0) - goto base_error; + goto probe_end; } /* add predefined DAI links to the list */ @@ -2045,16 +2073,11 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dev_err(card->dev, "ASoC: can't create sound card for card %s: %d\n", card->name, ret); - goto base_error; + goto probe_end; } soc_init_card_debugfs(card); - card->dapm.bias_level = SND_SOC_BIAS_OFF; - card->dapm.dev = card->dev; - card->dapm.card = card; - list_add(&card->dapm.list, &card->dapm_list); - #ifdef CONFIG_DEBUG_FS snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root); #endif @@ -2076,7 +2099,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (card->probe) { ret = card->probe(card); if (ret < 0) - goto card_probe_error; + goto probe_end; } /* probe all components used by DAI links on this card */ @@ -2087,7 +2110,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dev_err(card->dev, "ASoC: failed to instantiate card %d\n", ret); - goto probe_dai_err; + goto probe_end; } } } @@ -2095,7 +2118,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* probe auxiliary components */ ret = soc_probe_aux_devices(card); if (ret < 0) - goto probe_dai_err; + goto probe_end; /* * Find new DAI links added during probing components and bind them. @@ -2107,10 +2130,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) ret = soc_init_dai_link(card, dai_link); if (ret) - goto probe_dai_err; + goto probe_end; ret = soc_bind_dai_link(card, dai_link); if (ret) - goto probe_dai_err; + goto probe_end; } /* probe all DAI links on this card */ @@ -2121,7 +2144,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dev_err(card->dev, "ASoC: failed to instantiate card %d\n", ret); - goto probe_dai_err; + goto probe_end; } } } @@ -2168,7 +2191,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (ret < 0) { dev_err(card->dev, "ASoC: %s late_probe() failed: %d\n", card->name, ret); - goto probe_aux_dev_err; + goto probe_end; } } @@ -2178,33 +2201,17 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (ret < 0) { dev_err(card->dev, "ASoC: failed to register soundcard %d\n", ret); - goto probe_aux_dev_err; + goto probe_end; } card->instantiated = 1; dapm_mark_endpoints_dirty(card); snd_soc_dapm_sync(&card->dapm); - mutex_unlock(&card->mutex); - mutex_unlock(&client_mutex); - - return 0; -probe_aux_dev_err: - soc_remove_aux_devices(card); - -probe_dai_err: - soc_remove_dai_links(card); - -card_probe_error: - if (card->remove) - card->remove(card); - - snd_soc_dapm_free(&card->dapm); - soc_cleanup_card_debugfs(card); - snd_card_free(card->snd_card); +probe_end: + if (ret < 0) + soc_cleanup_card_resources(card); -base_error: - soc_remove_pcm_runtimes(card); mutex_unlock(&card->mutex); mutex_unlock(&client_mutex); @@ -2233,31 +2240,6 @@ static int soc_probe(struct platform_device *pdev) return snd_soc_register_card(card); } -static int soc_cleanup_card_resources(struct snd_soc_card *card) -{ - /* make sure any delayed work runs */ - snd_soc_flush_all_delayed_work(card); - - /* free the ALSA card at first; this syncs with pending operations */ - snd_card_free(card->snd_card); - - /* remove and free each DAI */ - soc_remove_dai_links(card); - soc_remove_pcm_runtimes(card); - - /* remove auxiliary devices */ - soc_remove_aux_devices(card); - - snd_soc_dapm_free(&card->dapm); - soc_cleanup_card_debugfs(card); - - /* remove the card */ - if (card->remove) - card->remove(card); - - return 0; -} - /* removes a socdev */ static int soc_remove(struct platform_device *pdev) { @@ -2823,6 +2805,7 @@ static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) if (card->instantiated) { card->instantiated = false; snd_soc_dapm_shutdown(card); + snd_soc_flush_all_delayed_work(card); soc_cleanup_card_resources(card); if (!unregister) list_add(&card->list, &unbind_card_list); From 91f0bd9e22c2efe5a0ea554fe7f1f7c2974411cc Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:50 +0900 Subject: [PATCH 0693/1995] ASoC: soc-core: reduce if/else nest on soc_probe_link_dais Deep nested codec is not readable. Let's reduce if/else nest. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 52293596f5afff10d14e033aa3edfc801a31b3a1) --- sound/soc/soc-core.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d59b5ea9fa2540..7fc10a41e0e9d4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1612,27 +1612,24 @@ static int soc_probe_link_dais(struct snd_soc_card *card, dai_link->stream_name); return ret; } - } else { - - if (!dai_link->params) { - /* create the pcm */ - ret = soc_new_pcm(rtd, num); - if (ret < 0) { - dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", - dai_link->stream_name, ret); - return ret; - } - ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); - if (ret < 0) - return ret; - ret = soc_link_dai_pcm_new(rtd->codec_dais, - rtd->num_codecs, rtd); - if (ret < 0) - return ret; - } else { - INIT_DELAYED_WORK(&rtd->delayed_work, - codec2codec_close_delayed_work); + } else if (!dai_link->params) { + /* create the pcm */ + ret = soc_new_pcm(rtd, num); + if (ret < 0) { + dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", + dai_link->stream_name, ret); + return ret; } + ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); + if (ret < 0) + return ret; + ret = soc_link_dai_pcm_new(rtd->codec_dais, + rtd->num_codecs, rtd); + if (ret < 0) + return ret; + } else { + INIT_DELAYED_WORK(&rtd->delayed_work, + codec2codec_close_delayed_work); } return 0; From ae58ce0444a5205dc0912a0478b84b91775bea01 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:55 +0900 Subject: [PATCH 0694/1995] ASoC: soc-core: add soc_cleanup_component() We need to cleanup component when soc_probe_component() was failed, or when soc_remove_component() was called. But they are cleanuping component on each way. (And soc_probe_component() doesn't call snd_soc_dapm_free(), but it should). Same code in many places makes code un-understandable. This patch adds new soc_cleanup_component() and call it from snd_probe_component() and snd_remove_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 22d1423187e5b4d9d5a9851f24466fc0f585a36f) --- sound/soc/soc-core.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7fc10a41e0e9d4..8a58fa86675ac5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -937,21 +937,24 @@ static int soc_bind_dai_link(struct snd_soc_card *card, return -EPROBE_DEFER; } +static void soc_cleanup_component(struct snd_soc_component *component) +{ + list_del(&component->card_list); + snd_soc_dapm_free(snd_soc_component_get_dapm(component)); + soc_cleanup_component_debugfs(component); + component->card = NULL; + module_put(component->dev->driver->owner); +} + static void soc_remove_component(struct snd_soc_component *component) { if (!component->card) return; - list_del(&component->card_list); - if (component->driver->remove) component->driver->remove(component); - snd_soc_dapm_free(snd_soc_component_get_dapm(component)); - - soc_cleanup_component_debugfs(component); - component->card = NULL; - module_put(component->dev->driver->owner); + soc_cleanup_component(component); } static void soc_remove_dai(struct snd_soc_dai *dai, int order) @@ -1360,6 +1363,8 @@ static int soc_probe_component(struct snd_soc_card *card, component->card = card; dapm->card = card; + INIT_LIST_HEAD(&component->card_list); + INIT_LIST_HEAD(&dapm->list); soc_set_name_prefix(card, component); soc_init_component_debugfs(component); @@ -1422,12 +1427,9 @@ static int soc_probe_component(struct snd_soc_card *card, /* see for_each_card_components */ list_add(&component->card_list, &card->component_dev_list); - return 0; - err_probe: - soc_cleanup_component_debugfs(component); - component->card = NULL; - module_put(component->dev->driver->owner); + if (ret < 0) + soc_cleanup_component(component); return ret; } From 011797b7d70dece29f5712235f114c5921502b3d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:59 +0900 Subject: [PATCH 0695/1995] ASoC: soc-core: use for_each_link_codecs() for dai_link codecs We can use for_each_link_codecs() without waiting for_each_rtd_codec_dai() on soc_bind_dai_link(). Let's use for_each macro Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 10dff9b0ddf70bebe9523fc311ec77a872ce0a9c) --- sound/soc/soc-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 8a58fa86675ac5..1c92b4aff57b51 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -870,7 +870,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct snd_soc_dai_link_component *codecs; struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; struct snd_soc_dai **codec_dais; @@ -905,9 +905,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ - /* we can use for_each_rtd_codec_dai() after this */ codec_dais = rtd->codec_dais; - for (i = 0; i < rtd->num_codecs; i++) { + for_each_link_codecs(dai_link, i, codecs) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", From 58d0ead027639d025986e59112ef6c977e2b200a Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Tue, 22 Jan 2019 15:50:09 +0800 Subject: [PATCH 0696/1995] ASoC: rt5682: Correct the setting while select ASRC clk for AD/DA filter AD/DA ASRC function control two ASRC clock sources separately. Whether AD/DA filter select which clock source, we enable AD/DA ASRC function for all cases. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown (cherry picked from commit 8077ec011b1ea26abb7ca786f28ecccfb352717f) --- sound/soc/codecs/rt5682.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index bd45d0343913c0..9d5acd2d04abd4 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -1784,7 +1784,9 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = { {"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc}, {"DAC Stereo1 Filter", NULL, "DAC STO1 ASRC", is_using_asrc}, {"ADC STO1 ASRC", NULL, "AD ASRC"}, + {"ADC STO1 ASRC", NULL, "DA ASRC"}, {"ADC STO1 ASRC", NULL, "CLKDET"}, + {"DAC STO1 ASRC", NULL, "AD ASRC"}, {"DAC STO1 ASRC", NULL, "DA ASRC"}, {"DAC STO1 ASRC", NULL, "CLKDET"}, From a58ec8d2a6977ea61f6e5b5260f79015d1b2d8c0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 22 Jan 2019 17:36:11 +0000 Subject: [PATCH 0697/1995] ASoC: core: Fix multi-CODEC setups Revert 10dff9b0d (ASoC: soc-core: use for_each_link_codecs() for dai_link codecs) for now as Sylwester Nawrocki reports that it causes oopses on at least Odroid boards. Reported-by: Sylwester Nawrocki Signed-off-by: Mark Brown (cherry picked from commit 3f6a125230d8bfcbfe0c06ff0b8eaccbc727acd7) --- sound/soc/soc-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1c92b4aff57b51..8a58fa86675ac5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -870,7 +870,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai_link_component *codecs; + struct snd_soc_dai_link_component *codecs = dai_link->codecs; struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; struct snd_soc_dai **codec_dais; @@ -905,8 +905,9 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ + /* we can use for_each_rtd_codec_dai() after this */ codec_dais = rtd->codec_dais; - for_each_link_codecs(dai_link, i, codecs) { + for (i = 0; i < rtd->num_codecs; i++) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", From 4b6098670198ddbe25332b5039bccefb729efed8 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Tue, 22 Jan 2019 13:26:02 +0800 Subject: [PATCH 0698/1995] ASoC: sof: add comments for non-atomic pcm trigger Add the comments to why explain non-atomic is set in topology parsing. So it is safe to call sof_ipc_tx_message() in the trigger callback. Only FE need nonatomic = 1 Signed-off-by: Libin Yang Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pcm.c | 4 ++++ sound/soc/sof/topology.c | 13 ++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index cf3ce29c318996..3207d621d9aecd 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -224,6 +224,10 @@ static int sof_restore_hw_params(struct snd_pcm_substream *substream, return 0; } +/* + * FE dai link trigger actions are always executed in non-atomic context because + * they involve IPC's. + */ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index f013b1f8dc6b8a..5438461c026742 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2361,11 +2361,17 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, int ret = 0; link->platform_name = "sof-audio"; - link->nonatomic = true; - /* send BE configurations to DSP */ - if (!link->no_pcm) + /* + * Set nonatomic property for FE dai links as their trigger action + * involves IPC's. + */ + if (!link->no_pcm) { + link->nonatomic = true; + + /* nothing more to do for FE dai links */ return 0; + } /* check we have some tokens - we need at least DAI type */ if (le32_to_cpu(private->size) == 0) { @@ -2373,6 +2379,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, return -EINVAL; } + /* Send BE DAI link configurations to DSP */ memset(&config, 0, sizeof(config)); /* get any common DAI tokens */ From 0131cc35251a96d60449e5f03be4488a219f5192 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 23 Jan 2019 15:48:00 +0800 Subject: [PATCH 0699/1995] ASoC: SOF: fix a compiling warning Sof_nocodec_bes_setup should be a static function Signed-off-by: Rander Wang --- sound/soc/sof/nocodec.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index 9851ce7c1e8ec0..3f3b2a72c2cf6f 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -16,9 +16,10 @@ static struct snd_soc_card sof_nocodec_card = { .name = "nocodec", /* the sof- prefix is added by the core */ }; -int sof_nocodec_bes_setup(struct device *dev, const struct snd_sof_dsp_ops *ops, - struct snd_soc_dai_link *links, int link_num, - struct snd_soc_card *card) +static int sof_nocodec_bes_setup(struct device *dev, + const struct snd_sof_dsp_ops *ops, + struct snd_soc_dai_link *links, + int link_num, struct snd_soc_card *card) { int i; From 11bbb27b21b9da5dc1b62890628408ad3458e613 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 23 Jan 2019 10:41:41 +0800 Subject: [PATCH 0700/1995] ASoC: SOF: trace: Don't send trace IPC to FW if trace init fail If snd_sof_init_trace() failed, we will free trace DMA buffers/pages, so we need reset sdev->dma_trace_pages to 0. At trace resume(snd_sof_init_trace_ipc), if sdev->dma_trace_pages is 0, that means we don't have DMA buffers/pages for trace, so we can't resume trace, just return error. Signed-off-by: Keyon Jie --- sound/soc/sof/trace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index c2be44a39f63b0..3b861eb0bc806c 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -137,7 +137,7 @@ int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) struct sof_ipc_reply ipc_reply; int ret; - if (sdev->dtrace_is_enabled) + if (sdev->dtrace_is_enabled || !sdev->dma_trace_pages) return -EINVAL; /* set IPC parameters */ @@ -233,6 +233,7 @@ int snd_sof_init_trace(struct snd_sof_dev *sdev) return 0; table_err: + sdev->dma_trace_pages = 0; snd_dma_free_pages(&sdev->dmatb); page_err: snd_dma_free_pages(&sdev->dmatp); From e4fb585e96de3838849990362d52bf9fc1b0eec0 Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Thu, 17 Jan 2019 16:17:34 -0800 Subject: [PATCH 0701/1995] ASoC: SOF: add a parameter for polling delay value Remove hard-coded values and get one from a parameter. Longer delay is 10 times of initial dealy. Signed-off-by: Fred Oh --- sound/soc/sof/intel/hda-dsp.c | 12 ++++++++---- sound/soc/sof/intel/hda-loader-skl.c | 6 ++++-- sound/soc/sof/intel/hda-loader.c | 9 ++++++--- sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/ops.c | 8 +++++--- sound/soc/sof/ops.h | 3 ++- 6 files changed, 26 insertions(+), 13 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 8673e38666f830..92e5ce834161ac 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -40,7 +40,8 @@ int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask) HDA_DSP_REG_ADSPCS, HDA_DSP_ADSPCS_CRST_MASK(core_mask), HDA_DSP_ADSPCS_CRST_MASK(core_mask), - HDA_DSP_RESET_TIMEOUT); + HDA_DSP_RESET_TIMEOUT, + HDA_DSP_REG_POLL_INTERVAL_US); /* has core entered reset ? */ adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -71,7 +72,8 @@ int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask) ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, HDA_DSP_ADSPCS_CRST_MASK(core_mask), 0, - HDA_DSP_RESET_TIMEOUT); + HDA_DSP_RESET_TIMEOUT, + HDA_DSP_REG_POLL_INTERVAL_US); /* has core left reset ? */ adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -144,7 +146,8 @@ int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) HDA_DSP_REG_ADSPCS, HDA_DSP_ADSPCS_CPA_MASK(core_mask), HDA_DSP_ADSPCS_CPA_MASK(core_mask), - HDA_DSP_PU_TIMEOUT); + HDA_DSP_PU_TIMEOUT, + HDA_DSP_REG_POLL_INTERVAL_US); if (ret < 0) dev_err(sdev->dev, "error: timeout on core powerup\n"); @@ -172,7 +175,8 @@ int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask) /* poll with timeout to check if operation successful */ return snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, HDA_DSP_ADSPCS_CPA_MASK(core_mask), 0, - HDA_DSP_PD_TIMEOUT); + HDA_DSP_PD_TIMEOUT, + HDA_DSP_REG_POLL_INTERVAL_US); } bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 7a9cf5e46c8442..f6ec5ac6b76692 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -361,7 +361,8 @@ static int cl_dsp_init_skl(struct snd_sof_dev *sdev) ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, HDA_ADSP_FW_STATUS_SKL, HDA_DSP_ROM_STS_MASK, HDA_DSP_ROM_INIT, - HDA_DSP_INIT_TIMEOUT); + HDA_DSP_INIT_TIMEOUT, + HDA_DSP_REG_POLL_INTERVAL_US); if (ret < 0) goto err; @@ -462,7 +463,8 @@ static int cl_copy_fw_skl(struct snd_sof_dev *sdev) HDA_ADSP_FW_STATUS_SKL, HDA_DSP_ROM_STS_MASK, HDA_DSP_ROM_FW_FW_LOADED, - HDA_DSP_BASEFW_TIMEOUT); + HDA_DSP_BASEFW_TIMEOUT, + HDA_DSP_REG_POLL_INTERVAL_US); if (ret < 0) dev_err(sdev->dev, "error: firmware transfer timeout!"); diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index ef968a6b6d720d..2edf4ee7524120 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -108,7 +108,8 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, chip->ipc_ack, chip->ipc_ack_mask, chip->ipc_ack_mask, - HDA_DSP_INIT_TIMEOUT); + HDA_DSP_INIT_TIMEOUT, + HDA_DSP_REG_POLL_INTERVAL_US); if (ret < 0) { dev_err(sdev->dev, "error: waiting for HIPCIE done\n"); @@ -130,7 +131,8 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_ROM_STATUS, HDA_DSP_ROM_STS_MASK, HDA_DSP_ROM_INIT, - HDA_ROM_INIT_TIMEOUT); + HDA_ROM_INIT_TIMEOUT, + HDA_DSP_REG_POLL_INTERVAL_US); if (!ret) return 0; @@ -231,7 +233,8 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) HDA_DSP_SRAM_REG_ROM_STATUS, HDA_DSP_ROM_STS_MASK, HDA_DSP_ROM_FW_ENTERED, - HDA_DSP_BASEFW_TIMEOUT); + HDA_DSP_BASEFW_TIMEOUT, + HDA_DSP_REG_POLL_INTERVAL_US); ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_STOP); if (ret < 0) { diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 38ac2ccc3a4267..54b817358e3101 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -201,6 +201,7 @@ #define HDA_ROM_INIT_TIMEOUT 70 #define HDA_DSP_CTRL_RESET_TIMEOUT 100 #define HDA_DSP_WAIT_TIMEOUT 500 /* 500 msec */ +#define HDA_DSP_REG_POLL_INTERVAL_US 500 /* 0.5 msec */ #define HDA_DSP_ADSPIC_IPC 1 #define HDA_DSP_ADSPIS_IPC 1 diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index fb77499b89d66d..f7e05c6696a189 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -142,15 +142,17 @@ void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar, EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced); int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset, - u32 mask, u32 target, u32 timeout_ms) + u32 mask, u32 target, u32 timeout_ms, + u32 interval_us) { u32 reg; unsigned long tout_jiff; - int k = 0, s = 500; + int k = 0, s = interval_us; /* * Split the loop into 2 sleep stages with varying resolution. * To do it more accurately, the range of wakeups are: + * In case of interval_us = 500, * Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms. * Phase 2(beyond 5ms): min sleep 5ms; max sleep 10ms. */ @@ -163,7 +165,7 @@ int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset, /* Phase 2 after 5ms(500us * 10) */ if (++k > 10) - s = 5000; + s = interval_us * 10; usleep_range(s, 2 * s); } while (time_before(jiffies, tout_jiff)); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 2ae15025ed693c..30f1dc9bdb92bf 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -375,7 +375,8 @@ int snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset, u32 mask, u32 value); int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset, - u32 mask, u32 target, u32 timeout); + u32 mask, u32 target, u32 timeout_ms, + u32 interval_us); void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset); #endif From 49cddb8f46242fba6df90fc0d425e5a5976608ed Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Mon, 21 Jan 2019 14:11:31 +0800 Subject: [PATCH 0702/1995] ASoC: sof: Fix display power regression Now that the ASoC hdmi audio PM sequence issue has been fixed by: commit 687ae9e287b3 ("ASoC: intel: skl: Fix display power regression") SOF need the corresponding modifications. Now snd_hdac_display_power() to turn display power on/off is only used in probe and exit for controller. Signed-off-by: Libin Yang --- sound/soc/sof/intel/hda-dsp.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 92e5ce834161ac..df2ea5d55fca82 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -408,9 +408,6 @@ static int hda_resume(struct snd_sof_dev *sdev) int hda_dsp_resume(struct snd_sof_dev *sdev) { - /* turn display power on */ - hda_codec_i915_get(sdev); - /* init hda controller. DSP cores will be powered up during fw boot */ return hda_resume(sdev); } @@ -439,8 +436,5 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state) return ret; } - /* turn display power off */ - hda_codec_i915_put(sdev); - return 0; } From 8b72baae95b27a6a7a4b5e7da28b6ee76cff9a7e Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Thu, 24 Jan 2019 10:48:50 +0800 Subject: [PATCH 0703/1995] ASoC: sof: refine handling hda initialization failure When hda_dsp_ctrl_init_chip() fails, callback remove() will not be called. In this case, we need call hda_codec_i915_exit() to unbind i915. Signed-off-by: Libin Yang --- sound/soc/sof/intel/hda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 69e9d18bd30cc7..febef8283f2224 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -256,7 +256,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) ret = hda_dsp_ctrl_init_chip(sdev, true); if (ret < 0) { dev_err(bus->dev, "error: init chip failed with ret: %d\n", ret); - hda_codec_i915_put(sdev); + hda_codec_i915_exit(sdev); return ret; } From 359bf5157118077c75c9b7ab4d8500b74e552034 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 4 Jan 2019 11:33:29 +0100 Subject: [PATCH 0704/1995] sof: eliminate a large number of "goto" statements There are very few cases like jumping to the end of a function for error processing, that justify the use of a "goto" statement. Eliminate all the unjustified uses. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/ipc.c | 16 ++++++++-------- sound/soc/sof/loader.c | 4 ++-- sound/soc/sof/pcm.c | 3 +-- sound/soc/sof/trace.c | 10 ++++------ 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index b52fee9c6c482c..2e6516eb400931 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -292,16 +292,16 @@ static void ipc_tx_next_msg(struct work_struct *work) spin_lock_irq(&sdev->ipc_lock); /* send message if HW read and message in TX list */ - if (list_empty(&ipc->tx_list) || !snd_sof_dsp_is_ready(sdev)) - goto out; + if (!list_empty(&ipc->tx_list) && snd_sof_dsp_is_ready(sdev)) { + /* send first message in TX list */ + msg = list_first_entry(&ipc->tx_list, struct snd_sof_ipc_msg, + list); + list_move(&msg->list, &ipc->reply_list); + snd_sof_dsp_send_msg(sdev, msg); - /* send first message in TX list */ - msg = list_first_entry(&ipc->tx_list, struct snd_sof_ipc_msg, list); - list_move(&msg->list, &ipc->reply_list); - snd_sof_dsp_send_msg(sdev, msg); + ipc_log_header(sdev->dev, "ipc tx", msg->header); + } - ipc_log_header(sdev->dev, "ipc tx", msg->header); -out: spin_unlock_irq(&sdev->ipc_lock); } diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 7083d993e331aa..df6461ac4664ec 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -73,7 +73,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) if (ret < 0) { dev_err(sdev->dev, "error: failed to parse ext data type %d\n", ext_hdr->type); - goto out; + break; } /* move to next header */ @@ -82,7 +82,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) sizeof(*ext_hdr)); ext_hdr = (struct sof_ipc_ext_data_hdr *)ext_data; } -out: + kfree(ext_data); return ret; } diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 3207d621d9aecd..3c4526f15bf195 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -652,7 +652,7 @@ static int sof_pcm_probe(struct snd_soc_component *component) if (ret < 0) { dev_err(sdev->dev, "error: failed to load DSP topology %d\n", ret); - goto err; + return ret; } /* enable runtime PM with auto suspend */ @@ -666,7 +666,6 @@ static int sof_pcm_probe(struct snd_soc_component *component) if (err < 0) dev_err(sdev->dev, "error: failed to enter PM idle %d\n", err); -err: return ret; } diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 3b861eb0bc806c..97fd041b8ee1f1 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -37,14 +37,12 @@ static size_t sof_wait_trace_avail(struct snd_sof_dev *sdev, if (signal_pending(current)) { remove_wait_queue(&sdev->trace_sleep, &wait); - goto out; + } else { + /* set timeout to max value, no error code */ + schedule_timeout(MAX_SCHEDULE_TIMEOUT); + remove_wait_queue(&sdev->trace_sleep, &wait); } - /* set timeout to max value, no error code */ - schedule_timeout(MAX_SCHEDULE_TIMEOUT); - remove_wait_queue(&sdev->trace_sleep, &wait); - -out: /* return bytes available for copy */ if (sdev->host_offset < pos) return buffer_size - pos; From 481f83fe979d41af92e9de258358870040163a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Wed, 16 Jan 2019 14:59:00 +0100 Subject: [PATCH 0705/1995] ASoC: topology: Reduce number of dereferences when accessing dobj MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have passed dobj, there is no reason to access it through containing structs. Signed-off-by: Amadeusz SÅ‚awiÅ„ski Signed-off-by: Pierre-Louis Bossart --- sound/soc/soc-topology.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index ff84fe2a9c31db..0e725999ed921c 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -382,10 +382,10 @@ static void remove_mixer(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->control_unload) dobj->ops->control_unload(comp, dobj); - if (sm->dobj.control.kcontrol->tlv.p) - p = sm->dobj.control.kcontrol->tlv.p; - snd_ctl_remove(card, sm->dobj.control.kcontrol); - list_del(&sm->dobj.list); + if (dobj->control.kcontrol->tlv.p) + p = dobj->control.kcontrol->tlv.p; + snd_ctl_remove(card, dobj->control.kcontrol); + list_del(&dobj->list); kfree(sm); kfree(p); } @@ -404,12 +404,12 @@ static void remove_enum(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->control_unload) dobj->ops->control_unload(comp, dobj); - snd_ctl_remove(card, se->dobj.control.kcontrol); - list_del(&se->dobj.list); + snd_ctl_remove(card, dobj->control.kcontrol); + list_del(&dobj->list); - kfree(se->dobj.control.dvalues); + kfree(dobj->control.dvalues); for (i = 0; i < se->items; i++) - kfree(se->dobj.control.dtexts[i]); + kfree(dobj->control.dtexts[i]); kfree(se); } @@ -427,8 +427,8 @@ static void remove_bytes(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->control_unload) dobj->ops->control_unload(comp, dobj); - snd_ctl_remove(card, sb->dobj.control.kcontrol); - list_del(&sb->dobj.list); + snd_ctl_remove(card, dobj->control.kcontrol); + list_del(&dobj->list); kfree(sb); } @@ -481,9 +481,9 @@ static void remove_widget(struct snd_soc_component *comp, snd_ctl_remove(card, kcontrol); - kfree(se->dobj.control.dvalues); + kfree(dobj->control.dvalues); for (j = 0; j < se->items; j++) - kfree(se->dobj.control.dtexts[j]); + kfree(dobj->control.dtexts[j]); kfree(se); kfree(w->kcontrol_news[i].name); From 9959daa9f45478abb2f3d3bea7b676d068e5578a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Jan 2019 12:18:35 -0600 Subject: [PATCH 0706/1995] Revert "ASoC:topology:delete dynamic object during widget remove" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit d28e9af0a5df63d5a89fc9ad37c99085cfab4eb0. This functionality will be re-added by a following patch by Amadeusz SÅ‚awiÅ„ski Signed-off-by: Pierre-Louis Bossart --- sound/soc/soc-topology.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 0e725999ed921c..1e424c3d4a1469 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -508,7 +508,6 @@ static void remove_widget(struct snd_soc_component *comp, } free_news: - list_del(&dobj->list); kfree(w->kcontrol_news); /* widget w is freed by soc-dapm.c */ From b49b748012d31f242f25fa60e01064e1a8ade29e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Wed, 16 Jan 2019 14:59:13 +0100 Subject: [PATCH 0707/1995] ASoC: topology: Remove widgets from dobj list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently when we unload and reload machine driver few times we end with corrupted list and try to cleanup no longer existing objects. Fix this by removing dobj from the list. Signed-off-by: Amadeusz SÅ‚awiÅ„ski Signed-off-by: Pierre-Louis Bossart --- sound/soc/soc-topology.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 1e424c3d4a1469..f81c39aef12229 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -510,6 +510,8 @@ static void remove_widget(struct snd_soc_component *comp, free_news: kfree(w->kcontrol_news); + list_del(&dobj->list); + /* widget w is freed by soc-dapm.c */ } From c1b43e1bedf869b463610eebd64501aacd63ec4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Wed, 16 Jan 2019 14:59:17 +0100 Subject: [PATCH 0708/1995] ASoC: topology: Fix memory leak from soc_tplg_denum_create_texts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dtexts is two dimensional array, so we also need to free it after freeing its fields. Signed-off-by: Amadeusz SÅ‚awiÅ„ski Signed-off-by: Pierre-Louis Bossart --- sound/soc/soc-topology.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index f81c39aef12229..49e6fd76d9bcb2 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -410,6 +410,7 @@ static void remove_enum(struct snd_soc_component *comp, kfree(dobj->control.dvalues); for (i = 0; i < se->items; i++) kfree(dobj->control.dtexts[i]); + kfree(dobj->control.dtexts); kfree(se); } @@ -484,6 +485,7 @@ static void remove_widget(struct snd_soc_component *comp, kfree(dobj->control.dvalues); for (j = 0; j < se->items; j++) kfree(dobj->control.dtexts[j]); + kfree(dobj->control.dtexts); kfree(se); kfree(w->kcontrol_news[i].name); @@ -1446,6 +1448,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( kfree(se->dobj.control.dvalues); for (j = 0; j < ec->items; j++) kfree(se->dobj.control.dtexts[j]); + kfree(se->dobj.control.dtexts); kfree(se); kfree(kc[i].name); From 015f4145426c02c1e85dc6ceb2eddb1c6f5d2541 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 2 Jan 2019 11:15:52 -0600 Subject: [PATCH 0709/1995] ASoC: hdac_hdmi: use devm_kzalloc for all structures Loading/unloading modules exposes issues with memory allocation, which is a mix of devm_kzalloc and manual kzalloc. Move to devm_k routines everywhere to simplify all this. Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/hdac_hdmi.c | 87 ++++++++---------------------------- 1 file changed, 18 insertions(+), 69 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index b19d7a3e7a2cc0..5eeb0fe836a9a9 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1176,13 +1176,15 @@ static int hdac_hdmi_add_cvt(struct hdac_device *hdev, hda_nid_t nid) struct hdac_hdmi_cvt *cvt; char name[NAME_SIZE]; - cvt = kzalloc(sizeof(*cvt), GFP_KERNEL); + cvt = devm_kzalloc(&hdev->dev, sizeof(*cvt), GFP_KERNEL); if (!cvt) return -ENOMEM; cvt->nid = nid; sprintf(name, "cvt %d", cvt->nid); - cvt->name = kstrdup(name, GFP_KERNEL); + cvt->name = devm_kstrdup(&hdev->dev, name, GFP_KERNEL); + if (!cvt->name) + return -ENOMEM; list_add_tail(&cvt->head, &hdmi->cvt_list); hdmi->num_cvt++; @@ -1287,8 +1289,8 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, mutex_unlock(&hdmi->pin_mutex); } -static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi, - struct hdac_hdmi_pin *pin) +static int hdac_hdmi_add_ports(struct hdac_device *hdev, + struct hdac_hdmi_pin *pin) { struct hdac_hdmi_port *ports; int max_ports = HDA_MAX_PORTS; @@ -1300,7 +1302,7 @@ static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi, * implemented. */ - ports = kcalloc(max_ports, sizeof(*ports), GFP_KERNEL); + ports = devm_kcalloc(&hdev->dev, max_ports, sizeof(*ports), GFP_KERNEL); if (!ports) return -ENOMEM; @@ -1319,14 +1321,14 @@ static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid) struct hdac_hdmi_pin *pin; int ret; - pin = kzalloc(sizeof(*pin), GFP_KERNEL); + pin = devm_kzalloc(&hdev->dev, sizeof(*pin), GFP_KERNEL); if (!pin) return -ENOMEM; pin->nid = nid; pin->mst_capable = false; pin->hdev = hdev; - ret = hdac_hdmi_add_ports(hdmi, pin); + ret = hdac_hdmi_add_ports(hdev, pin); if (ret < 0) return ret; @@ -1468,8 +1470,6 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev, { hda_nid_t nid; int i, num_nodes; - struct hdac_hdmi_cvt *temp_cvt, *cvt_next; - struct hdac_hdmi_pin *temp_pin, *pin_next; struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); int ret; @@ -1497,51 +1497,35 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev, case AC_WID_AUD_OUT: ret = hdac_hdmi_add_cvt(hdev, nid); if (ret < 0) - goto free_widgets; + return ret; break; case AC_WID_PIN: ret = hdac_hdmi_add_pin(hdev, nid); if (ret < 0) - goto free_widgets; + return ret; break; } } if (!hdmi->num_pin || !hdmi->num_cvt) { ret = -EIO; - goto free_widgets; + dev_err(&hdev->dev, "Bad pin/cvt setup in %s\n", __func__); + return ret; } ret = hdac_hdmi_create_dais(hdev, dais, hdmi, hdmi->num_cvt); if (ret) { dev_err(&hdev->dev, "Failed to create dais with err: %d\n", - ret); - goto free_widgets; + ret); + return ret; } *num_dais = hdmi->num_cvt; ret = hdac_hdmi_init_dai_map(hdev); if (ret < 0) - goto free_widgets; - - return ret; - -free_widgets: - list_for_each_entry_safe(temp_cvt, cvt_next, &hdmi->cvt_list, head) { - list_del(&temp_cvt->head); - kfree(temp_cvt->name); - kfree(temp_cvt); - } - - list_for_each_entry_safe(temp_pin, pin_next, &hdmi->pin_list, head) { - for (i = 0; i < temp_pin->num_ports; i++) - temp_pin->ports[i].pin = NULL; - kfree(temp_pin->ports); - list_del(&temp_pin->head); - kfree(temp_pin); - } - + dev_err(&hdev->dev, "Failed to init DAI map with err: %d\n", + ret); return ret; } @@ -1782,7 +1766,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, * this is a new PCM device, create new pcm and * add to the pcm list */ - pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); + pcm = devm_kzalloc(&hdev->dev, sizeof(*pcm), GFP_KERNEL); if (!pcm) return -ENOMEM; pcm->pcm_id = device; @@ -1798,7 +1782,6 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, dev_err(&hdev->dev, "chmap control add failed with err: %d for pcm: %d\n", err, device); - kfree(pcm); return err; } } @@ -2075,42 +2058,8 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) static int hdac_hdmi_dev_remove(struct hdac_device *hdev) { - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); - struct hdac_hdmi_pin *pin, *pin_next; - struct hdac_hdmi_cvt *cvt, *cvt_next; - struct hdac_hdmi_pcm *pcm, *pcm_next; - struct hdac_hdmi_port *port, *port_next; - int i; - snd_hdac_display_power(hdev->bus, hdev->addr, false); - list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { - pcm->cvt = NULL; - if (list_empty(&pcm->port_list)) - continue; - - list_for_each_entry_safe(port, port_next, - &pcm->port_list, head) - list_del(&port->head); - - list_del(&pcm->head); - kfree(pcm); - } - - list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) { - list_del(&cvt->head); - kfree(cvt->name); - kfree(cvt); - } - - list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) { - for (i = 0; i < pin->num_ports; i++) - pin->ports[i].pin = NULL; - kfree(pin->ports); - list_del(&pin->head); - kfree(pin); - } - return 0; } From d502f1fe0bd3203790d5d4664e9965a0f422a736 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:59 +0900 Subject: [PATCH 0710/1995] ASoC: soc-core: use for_each_link_codecs() for dai_link codecs We can use for_each_link_codecs() without waiting for_each_rtd_codec_dai() on soc_bind_dai_link(). Let's use for_each macro Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 10dff9b0ddf70bebe9523fc311ec77a872ce0a9c) --- sound/soc/soc-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 8a58fa86675ac5..1c92b4aff57b51 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -870,7 +870,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct snd_soc_dai_link_component *codecs; struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; struct snd_soc_dai **codec_dais; @@ -905,9 +905,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ - /* we can use for_each_rtd_codec_dai() after this */ codec_dais = rtd->codec_dais; - for (i = 0; i < rtd->num_codecs; i++) { + for_each_link_codecs(dai_link, i, codecs) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", From 9dbaf2cb9a1c3e20fc406e74986a7a5f1c68c610 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 22 Jan 2019 17:36:11 +0000 Subject: [PATCH 0711/1995] ASoC: core: Fix multi-CODEC setups Revert 10dff9b0d (ASoC: soc-core: use for_each_link_codecs() for dai_link codecs) for now as Sylwester Nawrocki reports that it causes oopses on at least Odroid boards. Reported-by: Sylwester Nawrocki Signed-off-by: Mark Brown (cherry picked from commit 3f6a125230d8bfcbfe0c06ff0b8eaccbc727acd7) --- sound/soc/soc-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1c92b4aff57b51..8a58fa86675ac5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -870,7 +870,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai_link_component *codecs; + struct snd_soc_dai_link_component *codecs = dai_link->codecs; struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; struct snd_soc_dai **codec_dais; @@ -905,8 +905,9 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ + /* we can use for_each_rtd_codec_dai() after this */ codec_dais = rtd->codec_dais; - for_each_link_codecs(dai_link, i, codecs) { + for (i = 0; i < rtd->num_codecs; i++) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", From 100122dafef33b5d0e67fc15dae82b3d1a0a960c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 24 Jan 2019 17:37:35 +0000 Subject: [PATCH 0712/1995] ASoC: Intel: make const arrays static, reduces object code size Don't populate the const arrays on the stack but instead make it static. Makes the object code smaller, for example: Before: text data bss dec hex filename 14107 8832 224 23163 5a7b bytcht_es8316.o After: text data bss dec hex filename 14015 8896 224 23135 5a5f bytcht_es8316.o (gcc version 8.2.0 x86_64) Signed-off-by: Colin Ian King Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 4ffdca62e2deee7a27613571c9bd18c95b8eac84) --- sound/soc/intel/boards/bytcht_es8316.c | 2 +- sound/soc/intel/boards/bytcr_rt5640.c | 2 +- sound/soc/intel/boards/bytcr_rt5651.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index fa9c4cf97686d9..1364e4e601d837 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -437,7 +437,7 @@ static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = { static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { - const char * const mic_name[] = { "in1", "in2" }; + static const char * const mic_name[] = { "in1", "in2" }; struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index ca8b4d5ff70f9f..a79466c8fb2961 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1149,7 +1149,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { - const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; + static const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index b618d984e2d566..e6945d11c8abde 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -919,7 +919,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) { - const char * const mic_name[] = { "dmic", "in1", "in2", "in12" }; + static const char * const mic_name[] = { "dmic", "in1", "in2", "in12" }; struct byt_rt5651_private *priv; struct snd_soc_acpi_mach *mach; struct device *codec_dev; From f1cc6643b7a0d2f2b7efdee5d985d50502b5d070 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 25 Jan 2019 16:04:06 +0000 Subject: [PATCH 0713/1995] ASoC: core: Allow soc_find_component lookups to match parent of_node For devices implemented as a MFD it is common to only have a single node in devicetree representing the whole device. As such when looking up components in soc_find_components we should match against both the devices of_node and the devices parent's of_node, as is already done in the rest of the ASoC core. This causes regressions for some DAI links at the moment as soc_find_component was recently added as a check in soc_init_dai_link. Fixes: 8780cf1142a5 ("ASoC: soc-core: defer card probe until all component is added to list") Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit d0b95e6cd298a785c126e75a085af6dd7b7b1f60) --- sound/soc/soc-core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 8a58fa86675ac5..7f5e8abd5cb787 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -742,12 +742,17 @@ static struct snd_soc_component *soc_find_component( const struct device_node *of_node, const char *name) { struct snd_soc_component *component; + struct device_node *component_of_node; lockdep_assert_held(&client_mutex); for_each_component(component) { if (of_node) { - if (component->dev->of_node == of_node) + component_of_node = component->dev->of_node; + if (!component_of_node && component->dev->parent) + component_of_node = component->dev->parent->of_node; + + if (component_of_node == of_node) return component; } else if (name && strcmp(component->name, name) == 0) { return component; From 2c93e34e85debda0c86a03d268a5e7c68af5f4c2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 22 Jan 2019 18:53:43 -0600 Subject: [PATCH 0714/1995] ASoC: add helper to change platform name for all dailinks To reuse the same machine drivers with Atom/SST, Skylake and SOF, we need to change the default platform_name (or platforms->name in the "modern" representation). So far, this override was done with an automatic override, which was broken by a set of changes for DT platforms related to deferred probe handling. This automatic override is actually not really needed, the machine driver can already receive the platform name as a platform_data parameter. This is used e.g. for HDaudio support where we have different PCI aliases used for different platforms. We can reuse the same mechanism and modify the machine drivers to override the dailinks prior to registrating the card. This will require additional work for SOF, but with this helper it'll be just two lines of additional code per machine driver which is reused, not the end of the world. This helper can be simplified when all drivers have transitioned to the "modern" representation of dailinks. Signed-off-by: Pierre-Louis Bossart --- include/sound/soc.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index b71b05019c68c2..2b6b392556619b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1583,6 +1583,37 @@ struct snd_soc_dai *snd_soc_card_get_codec_dai(struct snd_soc_card *card, return NULL; } +static inline +int snd_soc_fixup_dai_links_platform_name(struct snd_soc_card *card, + const char *platform_name) +{ + struct snd_soc_dai_link *dai_link; + const char *name; + int i; + + if (!platform_name) /* nothing to do */ + return 0; + + /* set platform name for each dailink */ + for_each_card_prelinks(card, i, dai_link) { + name = devm_kstrdup(card->dev, platform_name, GFP_KERNEL); + if (!name) + return -ENOMEM; + + if (dai_link->platforms) + /* only single platform is supported for now */ + dai_link->platforms->name = name; + else + /* + * legacy mode, this case will be removed when all + * derivers are switched to modern style dai_link. + */ + dai_link->platform_name = name; + } + + return 0; +} + #ifdef CONFIG_DEBUG_FS extern struct dentry *snd_soc_debugfs_root; #endif From 1a48bc9f39d3f8a96083cd35008e1df86e312414 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Jan 2019 14:53:26 -0600 Subject: [PATCH 0715/1995] ASoC: Intel: haswell: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/haswell.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index 7d317de633d033..93eb691c9d494a 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "../common/sst-dsp.h" @@ -193,8 +194,22 @@ static struct snd_soc_card haswell_rt5640 = { static int haswell_audio_probe(struct platform_device *pdev) { + struct snd_soc_acpi_mach *mach; + const char *platform_name = NULL; + int ret; + haswell_rt5640.dev = &pdev->dev; + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + if (mach) /* extra check since legacy does not pass parameters */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&haswell_rt5640, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, &haswell_rt5640); } From 73e0974d590c8408100ae0764d963346b3cb8ba1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Jan 2019 14:08:16 -0600 Subject: [PATCH 0716/1995] ASoC: Intel: broadwell: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/broadwell.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index c5a0256e392608..0f18f8964f51fb 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "../common/sst-dsp.h" #include "../haswell/sst-haswell-ipc.h" @@ -271,7 +272,22 @@ static struct snd_soc_card broadwell_rt286 = { static int broadwell_audio_probe(struct platform_device *pdev) { + struct snd_soc_acpi_mach *mach; + const char *platform_name = NULL; + int ret; + broadwell_rt286.dev = &pdev->dev; + + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + if (mach) /* extra check since legacy does not pass parameters */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&broadwell_rt286, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286); } From 2c9b34f7f49203dbd4639a294b79e3e4b8a898ea Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Jan 2019 14:08:15 -0600 Subject: [PATCH 0717/1995] ASoC: Intel: bdw-rt5677: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bdw-rt5677.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index a61ab83c420fac..6520a8ea553758 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "../common/sst-dsp.h" #include "../haswell/sst-haswell-ipc.h" @@ -343,6 +344,9 @@ static struct snd_soc_card bdw_rt5677_card = { static int bdw_rt5677_probe(struct platform_device *pdev) { struct bdw_rt5677_priv *bdw_rt5677; + struct snd_soc_acpi_mach *mach; + const char *platform_name = NULL; + int ret; bdw_rt5677_card.dev = &pdev->dev; @@ -354,6 +358,16 @@ static int bdw_rt5677_probe(struct platform_device *pdev) return -ENOMEM; } + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + if (mach) /* extra check since legacy does not pass parameters */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&bdw_rt5677_card, + platform_name); + if (ret) + return ret; + snd_soc_card_set_drvdata(&bdw_rt5677_card, bdw_rt5677); return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5677_card); From 463201e2a6cb1a8bf94e7fb49c5de7335fd272ec Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Jan 2019 14:36:10 -0600 Subject: [PATCH 0718/1995] ASoC: Intel: bytcr_rt5640: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bytcr_rt5640.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index a79466c8fb2961..940eb27158da7e 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1153,6 +1153,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; + const char *platform_name; const char *i2c_name = NULL; int ret_val = 0; int dai_index = 0; @@ -1317,6 +1318,14 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); byt_rt5640_card.long_name = byt_rt5640_long_name; + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&byt_rt5640_card, + platform_name); + if (ret_val) + return ret_val; + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); if (ret_val) { From f241fc88786b66efaee11b640ddf8d40b158645d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Jan 2019 14:36:10 -0600 Subject: [PATCH 0719/1995] ASoC: Intel: bytcr_rt5651: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bytcr_rt5651.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index e6945d11c8abde..c3b7732929cc76 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -922,6 +922,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) static const char * const mic_name[] = { "dmic", "in1", "in2", "in12" }; struct byt_rt5651_private *priv; struct snd_soc_acpi_mach *mach; + const char *platform_name; struct device *codec_dev; const char *i2c_name = NULL; const char *hp_swapped; @@ -1137,6 +1138,14 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) mic_name[BYT_RT5651_MAP(byt_rt5651_quirk)], hp_swapped); byt_rt5651_card.long_name = byt_rt5651_long_name; + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&byt_rt5651_card, + platform_name); + if (ret_val) + return ret_val; + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card); if (ret_val) { From a532c8ca70aebd0804975e754d8aa2918727b636 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Jan 2019 14:21:19 -0600 Subject: [PATCH 0720/1995] ASoC: Intel: bytcht_da7213: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bytcht_da7213.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index 2179dedb28ad6d..b8e884803777b3 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -225,6 +225,7 @@ static int bytcht_da7213_probe(struct platform_device *pdev) { struct snd_soc_card *card; struct snd_soc_acpi_mach *mach; + const char *platform_name; const char *i2c_name = NULL; int dai_index = 0; int ret_val = 0; @@ -250,6 +251,13 @@ static int bytcht_da7213_probe(struct platform_device *pdev) dailink[dai_index].codec_name = codec_name; } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(card, platform_name); + if (ret_val) + return ret_val; + ret_val = devm_snd_soc_register_card(&pdev->dev, card); if (ret_val) { dev_err(&pdev->dev, From 9604a1449f10d2ca88c27406297780b4b3c6ddbf Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Jan 2019 14:27:19 -0600 Subject: [PATCH 0721/1995] ASoC: Intel: bytcht_es8316: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bytcht_es8316.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 1364e4e601d837..d2a7e6ba11aec1 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -441,6 +441,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; + const char *platform_name; const char *i2c_name = NULL; struct device *codec_dev; int dai_index = 0; @@ -469,6 +470,14 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_dais[dai_index].codec_name = codec_name; } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&byt_cht_es8316_card, + platform_name); + if (ret) + return ret; + /* Check for BYTCR or other platform and setup quirks */ if (x86_match_cpu(baytrail_cpu_ids) && mach->mach_params.acpi_ipc_irq_index == 0) { From b52eccfcf3014f45f6aec925c7454a364a7d2b42 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Jan 2019 14:36:11 -0600 Subject: [PATCH 0722/1995] ASoC: Intel: cht_bsw_max98090_ti: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 08a5152e635ac8..3263b0495853c2 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "../../codecs/max98090.h" #include "../atom/sst-atom-controls.h" @@ -420,6 +421,8 @@ static int snd_cht_mc_probe(struct platform_device *pdev) int ret_val = 0; struct cht_mc_private *drv; const char *mclk_name; + struct snd_soc_acpi_mach *mach; + const char *platform_name; int quirks = 0; dmi_id = dmi_first_match(cht_max98090_quirk_table); @@ -442,6 +445,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev) dev_dbg(dev, "Unable to add GPIO mapping table\n"); } + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, + platform_name); + if (ret_val) + return ret_val; + /* register the soc card */ snd_soc_card_cht.dev = &pdev->dev; snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); From e45c07c0131affab5cab09911312e86f19f9d49a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Jan 2019 14:40:46 -0600 Subject: [PATCH 0723/1995] ASoC: Intel: cht_bsw_nau8824: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/cht_bsw_nau8824.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c index 30c46977d53c28..02c2fa23933107 100644 --- a/sound/soc/intel/boards/cht_bsw_nau8824.c +++ b/sound/soc/intel/boards/cht_bsw_nau8824.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include "../atom/sst-atom-controls.h" @@ -246,6 +247,8 @@ static struct snd_soc_card snd_soc_card_cht = { static int snd_cht_mc_probe(struct platform_device *pdev) { struct cht_mc_private *drv; + struct snd_soc_acpi_mach *mach; + const char *platform_name; int ret_val; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); @@ -253,6 +256,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev) return -ENOMEM; snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, + platform_name); + if (ret_val) + return ret_val; + /* register the soc card */ snd_soc_card_cht.dev = &pdev->dev; ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); From a94fbbc15544af86a9d5cd091e5bbd189a325693 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Jan 2019 14:40:47 -0600 Subject: [PATCH 0724/1995] ASoC: Intel: cht_bsw_rt5645: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/cht_bsw_rt5645.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 250a356a0cbf08..cbc2d458483f3d 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -530,6 +530,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) { struct snd_soc_card *card = snd_soc_cards[0].soc_card; struct snd_soc_acpi_mach *mach; + const char *platform_name; struct cht_mc_private *drv; const char *i2c_name = NULL; bool found = false; @@ -663,6 +664,14 @@ static int snd_cht_mc_probe(struct platform_device *pdev) cht_rt5645_cpu_dai_name; } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(card, + platform_name); + if (ret_val) + return ret_val; + drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); if (IS_ERR(drv->mclk)) { dev_err(&pdev->dev, From 5410112ba4e809e93ff89515665552cc279f9fd4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Jan 2019 14:46:59 -0600 Subject: [PATCH 0725/1995] ASoC: Intel: cht_bsw_rt5672: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/cht_bsw_rt5672.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 9de64f447e7bed..f1c1f9dd5353db 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -400,6 +400,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) int ret_val = 0; struct cht_mc_private *drv; struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; + const char *platform_name; const char *i2c_name; int i; @@ -426,6 +427,14 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, + platform_name); + if (ret_val) + return ret_val; + drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); if (IS_ERR(drv->mclk)) { dev_err(&pdev->dev, From 6c0fa8794ca4465769ed12bd69f5d6127bbc70f7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Jan 2019 14:13:02 -0600 Subject: [PATCH 0726/1995] ASoC: Intel: bxt_da7219_max98357a: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 6f052fc8d1e25a..c00925f9da7340 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "../../codecs/hdac_hdmi.h" #include "../../codecs/da7219.h" #include "../../codecs/da7219-aad.h" @@ -584,6 +585,9 @@ static struct snd_soc_card broxton_audio_card = { static int broxton_audio_probe(struct platform_device *pdev) { struct bxt_card_private *ctx; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -594,6 +598,15 @@ static int broxton_audio_probe(struct platform_device *pdev) broxton_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&broxton_audio_card, ctx); + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&broxton_audio_card, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card); } From 610e13802752d936869fd4d6e70e008bec8ab381 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Jan 2019 14:15:13 -0600 Subject: [PATCH 0727/1995] ASoC: Intel: bxt_rt298: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bxt_rt298.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 27308337ab127a..e91057f83d2058 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include "../../codecs/hdac_hdmi.h" @@ -576,6 +577,9 @@ static int broxton_audio_probe(struct platform_device *pdev) struct bxt_rt286_private *ctx; struct snd_soc_card *card = (struct snd_soc_card *)pdev->id_entry->driver_data; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + int ret; int i; for (i = 0; i < ARRAY_SIZE(broxton_rt298_dais); i++) { @@ -602,6 +606,15 @@ static int broxton_audio_probe(struct platform_device *pdev) card->dev = &pdev->dev; snd_soc_card_set_drvdata(card, ctx); + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(card, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, card); } From 1408ac5402fed72328d265540c79e5b9192b865d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Jan 2019 14:47:00 -0600 Subject: [PATCH 0728/1995] ASoC: Intel: glk_rt5682_max98357a: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/glk_rt5682_max98357a.c | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index f6597c216fa8d3..d17126f7757cc6 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "../skylake/skl.h" #include "../../codecs/rt5682.h" #include "../../codecs/hdac_hdmi.h" @@ -571,6 +572,10 @@ static struct snd_soc_card glk_audio_card_rt5682_m98357a = { static int geminilake_audio_probe(struct platform_device *pdev) { struct glk_card_private *ctx; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + struct snd_soc_card *card; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -578,11 +583,19 @@ static int geminilake_audio_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - glk_audio_card_rt5682_m98357a.dev = &pdev->dev; - snd_soc_card_set_drvdata(&glk_audio_card_rt5682_m98357a, ctx); + card = &glk_audio_card_rt5682_m98357a; + card->dev = &pdev->dev; + snd_soc_card_set_drvdata(card, ctx); + + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(card, platform_name); + if (ret) + return ret; - return devm_snd_soc_register_card(&pdev->dev, - &glk_audio_card_rt5682_m98357a); + return devm_snd_soc_register_card(&pdev->dev, card); } static const struct platform_device_id glk_board_ids[] = { From ff0516d9ff64ca838f1094c4e13483e22e5602cd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 22 Jan 2019 18:12:32 -0600 Subject: [PATCH 0729/1995] ASoC: SOF: pass platform_name as machine parameter Use existing mechanism to pass platform_name and call helper to override platform_name, needed to avoid issues with overrides in ASoC core due to deferred probes on non-Intel platforms Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 1 + sound/soc/sof/sof-acpi-dev.c | 2 ++ sound/soc/sof/sof-pci-dev.c | 2 ++ sound/soc/sof/sof-spi-dev.c | 1 + 4 files changed, 6 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index febef8283f2224..f5ef2d52ce7553 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -304,6 +304,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) mach_params = (struct snd_soc_acpi_mach_params *) &pdata->machine->mach_params; mach_params->codec_mask = bus->codec_mask; + mach_params->platform = "sof-audio"; } /* create codec instances */ diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index f85c7046120711..56997d2400a865 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -206,6 +206,8 @@ static int sof_acpi_probe(struct platform_device *pdev) } #endif + mach->mach_params.platform = "sof-audio"; + sof_pdata->machine = mach; sof_pdata->desc = desc; priv->sof_pdata = sof_pdata; diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 198905bef358ad..8893ce224b0ecb 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -205,6 +205,8 @@ static int sof_pci_probe(struct pci_dev *pci, mach = snd_soc_acpi_find_machine(desc->machines); if (!mach) dev_warn(dev, "warning: No matching ASoC machine driver found\n"); + else + mach->mach_params.platform = "sof-audio"; #endif /* CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE */ sof_pdata->id = pci_id->device; diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index 16fc3c8bd2dad2..a949a61646ac40 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -121,6 +121,7 @@ static int sof_spi_probe(struct spi_device *spi) mach->sof_fw_filename = desc->nocodec_fw_filename; mach->sof_tplg_filename = desc->nocodec_tplg_filename; mach->asoc_plat_name = "sof-platform"; + mach->mach_params.platform = "sof-audio"; sof_pdata->id = -1; sof_pdata->name = dev_name(&spi->dev); From 9e80e8fb6d290929ee44a95f0b022b34e0d198b6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 22 Jan 2019 17:51:33 -0600 Subject: [PATCH 0730/1995] ASoC: Intel: bxt_pcm512x: move to "modern" platform dailink Use platforms->name instead of platform_name Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bxt_pcm512x.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/bxt_pcm512x.c b/sound/soc/intel/boards/bxt_pcm512x.c index 003159aa875c64..9e5eb39d22068f 100644 --- a/sound/soc/intel/boards/bxt_pcm512x.c +++ b/sound/soc/intel/boards/bxt_pcm512x.c @@ -165,6 +165,12 @@ static const struct snd_soc_ops aif1_ops = { .shutdown = aif1_shutdown, }; +static struct snd_soc_dai_link_component platform_component[] = { + { + .name = "0000:00:0e.0" + } +}; + static struct snd_soc_dai_link dailink[] = { /* CODEC<->CODEC link */ /* back ends */ @@ -172,7 +178,8 @@ static struct snd_soc_dai_link dailink[] = { .name = "SSP5-Codec", .id = 0, .cpu_dai_name = "SSP5 Pin", - .platform_name = "sof-audio", + .platforms = platform_component, + .num_platforms = ARRAY_SIZE(platform_component), .no_pcm = 1, .codec_dai_name = "pcm512x-hifi", .codec_name = "i2c-104C5122:00", @@ -191,7 +198,8 @@ static struct snd_soc_dai_link dailink[] = { .cpu_dai_name = "iDisp1 Pin", .codec_name = "ehdaudio0D2", .codec_dai_name = "intel-hdmi-hifi1", - .platform_name = "0000:00:0e.0", + .platforms = platform_component, + .num_platforms = ARRAY_SIZE(platform_component), .init = broxton_hdmi_init, .dpcm_playback = 1, .no_pcm = 1, @@ -202,7 +210,8 @@ static struct snd_soc_dai_link dailink[] = { .cpu_dai_name = "iDisp2 Pin", .codec_name = "ehdaudio0D2", .codec_dai_name = "intel-hdmi-hifi2", - .platform_name = "0000:00:0e.0", + .platforms = platform_component, + .num_platforms = ARRAY_SIZE(platform_component), .init = broxton_hdmi_init, .dpcm_playback = 1, .no_pcm = 1, @@ -213,7 +222,8 @@ static struct snd_soc_dai_link dailink[] = { .cpu_dai_name = "iDisp3 Pin", .codec_name = "ehdaudio0D2", .codec_dai_name = "intel-hdmi-hifi3", - .platform_name = "0000:00:0e.0", + .platforms = platform_component, + .num_platforms = ARRAY_SIZE(platform_component), .init = broxton_hdmi_init, .dpcm_playback = 1, .no_pcm = 1, From 2762d62d945d10ad8c5aafa5b7a24109b8253a84 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 22 Jan 2019 18:15:33 -0600 Subject: [PATCH 0731/1995] ASoC: Intel: bxt_pcm512x: use platform_name from mach_params Needed to avoid ASoC core platform overrides Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bxt_pcm512x.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bxt_pcm512x.c b/sound/soc/intel/boards/bxt_pcm512x.c index 9e5eb39d22068f..e2605df8b6efab 100644 --- a/sound/soc/intel/boards/bxt_pcm512x.c +++ b/sound/soc/intel/boards/bxt_pcm512x.c @@ -254,7 +254,8 @@ static int bxt_pcm512x_probe(struct platform_device *pdev) struct bxt_card_private *ctx; const char *i2c_name = NULL; int dai_index = 0; - int ret_val = 0, i; + int ret_val = 0; + int i; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -267,6 +268,12 @@ static int bxt_pcm512x_probe(struct platform_device *pdev) card = &bxt_pcm512x_card; card->dev = &pdev->dev; + /* set platform name for each dailink */ + ret_val = snd_soc_fixup_dai_links_platform_name(card, + mach->mach_params.platform); + if (ret_val) + return ret_val; + /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(dailink); i++) { if (!strcmp(dailink[i].codec_name, "i2c-104C5122:00")) { From c7932522eb5aa47eaf6f30580307fca10fc53b56 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 22 Jan 2019 19:31:32 -0600 Subject: [PATCH 0732/1995] ASoC: Intel: sof_rt5682: add platform component Since dailink override is broken, add platform component with "sof-audio" by default. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/sof_rt5682.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 935f8acbf5953e..2466487dbfaf9c 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -186,6 +186,12 @@ static struct snd_soc_ops sof_rt5682_ops = { .hw_params = sof_rt5682_hw_params, }; +static struct snd_soc_dai_link_component platform_component[] = { + { + .name = "sof-audio" + } +}; + /* sof digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link sof_rt5682_dais[] = { /* Back End DAI links */ @@ -195,6 +201,8 @@ static struct snd_soc_dai_link sof_rt5682_dais[] = { .cpu_dai_name = "SSP0 Pin", .codec_name = "i2c-10EC5682:00", .codec_dai_name = "rt5682-aif1", + .platforms = platform_component, + .num_platforms = ARRAY_SIZE(platform_component), .init = sof_rt5682_codec_init, .ops = &sof_rt5682_ops, .nonatomic = true, @@ -208,6 +216,8 @@ static struct snd_soc_dai_link sof_rt5682_dais[] = { .cpu_dai_name = "DMIC01 Pin", .codec_name = "dmic-codec", .codec_dai_name = "dmic-hifi", + .platforms = platform_component, + .num_platforms = ARRAY_SIZE(platform_component), .ignore_suspend = 1, .dpcm_capture = 1, .no_pcm = 1, @@ -218,6 +228,8 @@ static struct snd_soc_dai_link sof_rt5682_dais[] = { .cpu_dai_name = "iDisp1 Pin", .codec_name = "ehdaudio0D2", .codec_dai_name = "intel-hdmi-hifi1", + .platforms = platform_component, + .num_platforms = ARRAY_SIZE(platform_component), .init = sof_hdmi_init, .dpcm_playback = 1, .no_pcm = 1, @@ -228,6 +240,8 @@ static struct snd_soc_dai_link sof_rt5682_dais[] = { .cpu_dai_name = "iDisp2 Pin", .codec_name = "ehdaudio0D2", .codec_dai_name = "intel-hdmi-hifi2", + .platforms = platform_component, + .num_platforms = ARRAY_SIZE(platform_component), .init = sof_hdmi_init, .dpcm_playback = 1, .no_pcm = 1, @@ -238,6 +252,8 @@ static struct snd_soc_dai_link sof_rt5682_dais[] = { .cpu_dai_name = "iDisp3 Pin", .codec_name = "ehdaudio0D2", .codec_dai_name = "intel-hdmi-hifi3", + .platforms = platform_component, + .num_platforms = ARRAY_SIZE(platform_component), .init = sof_hdmi_init, .dpcm_playback = 1, .no_pcm = 1, From a4d5e3ebba2584dc6a5c9113103c43e7a9017bfd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Jan 2019 18:00:42 -0600 Subject: [PATCH 0733/1995] ASoC: SOF: acpi: add missing parameter for BYT/BYT-CR handling There are 4 machines drivers which select Baytrail-CR based on the value of mach->mach_params.acpi_ipc_irq_index. Set the relevant value. Tested on T100A. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-acpi-dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 56997d2400a865..1d5f19f109ae77 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -207,6 +207,7 @@ static int sof_acpi_probe(struct platform_device *pdev) #endif mach->mach_params.platform = "sof-audio"; + mach->mach_params.acpi_ipc_irq_index = desc->irqindex_host_ipc; sof_pdata->machine = mach; sof_pdata->desc = desc; From a85bb65715a1a353172693624f9ac83ace61ea8a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Jan 2019 18:07:00 -0600 Subject: [PATCH 0734/1995] ASoC: SOF: acpi: align Baytrail-CR detection with SST driver TODO: move to a common helper Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-acpi-dev.c | 65 +++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 1d5f19f109ae77..2ed3495a5520b6 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -84,39 +84,50 @@ static struct sof_dev_desc sof_acpi_baytrail_desc = { }; #ifdef CONFIG_X86 /* TODO: move this to common helper */ -static int is_byt_cr(struct device *dev) -{ - u32 bios_status; - int status; - - if (!iosf_mbi_available()) { - dev_info(dev, "IOSF_MBI not enabled - can't determine CPU variant\n"); - return -EIO; - } - - status = iosf_mbi_read(BT_MBI_UNIT_PMC, /* 0x04 PUNIT */ - MBI_REG_READ, /* 0x10 */ - 0x006, /* BIOS_CONFIG */ - &bios_status); - if (status) { - dev_err(dev, "error: could not read PUNIT BIOS_CONFIG\n"); - return -EIO; +static bool is_byt_cr(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + int status = 0; + + if (iosf_mbi_available()) { + u32 bios_status; + status = iosf_mbi_read(BT_MBI_UNIT_PMC, /* 0x04 PUNIT */ + MBI_REG_READ, /* 0x10 */ + 0x006, /* BIOS_CONFIG */ + &bios_status); + + if (status) { + dev_err(dev, "could not read PUNIT BIOS_CONFIG\n"); + } else { + /* bits 26:27 mirror PMIC options */ + bios_status = (bios_status >> 26) & 3; + + if (bios_status == 1 || bios_status == 3) { + dev_info(dev, "Detected Baytrail-CR platform\n"); + return true; + } + + dev_info(dev, "BYT-CR not detected\n"); + } + } else { + dev_info(dev, "IOSF_MBI not available, no BYT-CR detection\n"); } - /* bits 26:27 mirror PMIC options */ - bios_status = (bios_status >> 26) & 3; - - if (bios_status == 1 || bios_status == 3) { - dev_info(dev, "BYT-CR detected\n"); - return 1; + if (platform_get_resource(pdev, IORESOURCE_IRQ, 5) == NULL) { + /* + * Some devices detected as BYT-T have only a single IRQ listed, + * causing platform_get_irq with index 5 to return -ENXIO. + * The correct IRQ in this case is at index 0, as on BYT-CR. + */ + dev_info(dev, "Falling back to Baytrail-CR platform\n"); + return true; } - dev_info(dev, "BYT-CR not detected\n"); - return 0; + return false; } #else -static int is_byt_cr(struct device *dev) +static int is_byt_cr(struct platform_device *pdev) { return 0; } @@ -168,7 +179,7 @@ static int sof_acpi_probe(struct platform_device *pdev) return -ENODEV; #if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - if (desc == &sof_acpi_baytrail_desc && is_byt_cr(dev)) + if (desc == &sof_acpi_baytrail_desc && is_byt_cr(pdev)) desc = &sof_acpi_baytrailcr_desc; #endif From 7b67e0bba6c656eb1be725df1c09dfb68b3c8285 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 15:19:22 -0600 Subject: [PATCH 0735/1995] ASoC: SOF: core: fix missing line before sof_probe Make checkpatch happy. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 4b794575ec7693..1eff06acb9f057 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -253,6 +253,7 @@ static int sof_machine_check(struct snd_sof_dev *sdev) return 0; } + static int sof_probe(struct platform_device *pdev) { struct snd_sof_pdata *plat_data = dev_get_platdata(&pdev->dev); From af8af763b7338b7e6149dce6f073b118b3b47bc3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 30 Jan 2019 10:16:22 -0600 Subject: [PATCH 0736/1995] ASoC: SOF: loader: remove cl_bar field This field is set but not used. It's been unused for more than a year. Remove. Reported-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/bdw.c | 3 --- sound/soc/sof/intel/byt.c | 6 ------ sound/soc/sof/intel/hsw.c | 3 --- sound/soc/sof/sof-priv.h | 1 - 4 files changed, 13 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index f6eb51605f7a6d..95a7d250e71e4f 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -618,9 +618,6 @@ static int bdw_probe(struct snd_sof_dev *sdev) return ret; } - /* set BARS */ - sdev->cl_bar = BDW_DSP_BAR; - /* set default mailbox */ snd_sof_dsp_mailbox_init(sdev, MBOX_OFFSET, MBOX_SIZE, 0, 0); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index a6a2dfecf820ce..3455ac42f7b69c 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -578,9 +578,6 @@ static int byt_pci_probe(struct snd_sof_dev *sdev) snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRX, 0x3, 0x0); snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRD, 0x3, 0x0); - /* set BARS */ - sdev->cl_bar = BYT_DSP_BAR; - /* set default mailbox offset for FW ready message */ sdev->dsp_box.offset = MBOX_OFFSET; @@ -742,9 +739,6 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRX, 0x3, 0x0); snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRD, 0x3, 0x0); - /* set BARS */ - sdev->cl_bar = BYT_DSP_BAR; - /* set default mailbox offset for FW ready message */ sdev->dsp_box.offset = MBOX_OFFSET; diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index d1c3ed9b0247d7..d61e1af503dad5 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -618,9 +618,6 @@ static int hsw_probe(struct snd_sof_dev *sdev) return ret; } - /* set BARS */ - sdev->cl_bar = HSW_DSP_BAR; - /* set default mailbox */ snd_sof_dsp_mailbox_init(sdev, MBOX_OFFSET, MBOX_SIZE, 0, 0); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index d704cc5c0969ab..bdaad14981cec7 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -337,7 +337,6 @@ struct snd_sof_dev { struct dentry *debugfs_root; /* firmware loader */ - int cl_bar; struct snd_dma_buffer dmab; struct snd_dma_buffer dmab_bdl; struct sof_ipc_fw_ready fw_ready; From 6134641d160ebe84fcb91d4637f2989a340188e4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 30 Jan 2019 10:31:52 -0600 Subject: [PATCH 0737/1995] ASoC: SOF: ipc: fix trivial typo s/HW read/HW ready/ Daniel Baluta Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 2e6516eb400931..103a9180dc1f81 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -291,7 +291,7 @@ static void ipc_tx_next_msg(struct work_struct *work) spin_lock_irq(&sdev->ipc_lock); - /* send message if HW read and message in TX list */ + /* send message if HW ready and message in TX list */ if (!list_empty(&ipc->tx_list) && snd_sof_dsp_is_ready(sdev)) { /* send first message in TX list */ msg = list_first_entry(&ipc->tx_list, struct snd_sof_ipc_msg, From 937cff15d4133659084cd7f399c628e8137ae74c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 30 Jan 2019 10:34:12 -0600 Subject: [PATCH 0738/1995] ASoC: SOF: trace: fix trivial typo s/craete/create Reported-by: Daniel Baluta Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 97fd041b8ee1f1..603c2ac282e3d4 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -208,7 +208,7 @@ int snd_sof_init_trace(struct snd_sof_dev *sdev) goto page_err; } - /* craete compressed page table for audio firmware */ + /* create compressed page table for audio firmware */ ret = snd_sof_create_page_table(sdev, &sdev->dmatb, sdev->dmatp.area, sdev->dmatb.bytes); if (ret < 0) From cfab822548d18d0762bdf07e23b01045d84a9c12 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 22 Jan 2019 23:39:38 -0800 Subject: [PATCH 0739/1995] ASoC: SOF: pm: set restore_stream for all streams during suspend. The machine driver pm ops suspends all streams during system suspend. So it is not needed to suspend streams in the SOF driver suspend callback. But since all streams are suspended, set restore_stream so that hw_params can be restored upon resuming. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pm.c | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 93102993b508dc..fd9d07892201f7 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -194,35 +194,16 @@ static int sof_send_pm_ipc(struct snd_sof_dev *sdev, int cmd) sizeof(pm_ctx), &reply, sizeof(reply)); } -static void sof_suspend_streams(struct snd_sof_dev *sdev) +static void sof_set_restore_stream(struct snd_sof_dev *sdev) { struct snd_sof_pcm *spcm; - struct snd_pcm_substream *substream; - int dir, playback_dir, capture_dir; /* suspend all running streams */ list_for_each_entry(spcm, &sdev->pcm_list, list) { - mutex_lock(&spcm->mutex); - playback_dir = SNDRV_PCM_STREAM_PLAYBACK; - capture_dir = SNDRV_PCM_STREAM_CAPTURE; - - /* suspend running streams in both directions */ - for (dir = playback_dir; dir <= capture_dir; dir++) { - substream = spcm->stream[dir].substream; - - if (substream && substream->runtime) { - - snd_pcm_suspend(substream); - - /* - * set restore_stream so that hw_params can be - * restored during resume - */ - spcm->restore_stream[dir] = 1; - } - } + spcm->restore_stream[0] = 1; + spcm->restore_stream[1] = 1; mutex_unlock(&spcm->mutex); } @@ -311,11 +292,9 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) /* release trace */ snd_sof_release_trace(sdev); - /* - * Suspend running pcm streams. - * They will be restarted by ALSA resume trigger call. - */ - sof_suspend_streams(sdev); + /* set restore_stream for all streams during system suspend */ + if (!runtime_suspend) + sof_set_restore_stream(sdev); /* notify DSP of upcoming power down */ ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_SAVE); From b145db03cadcc8e182808ea12ddc5440b43b6c86 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 22 Jan 2019 23:40:36 -0800 Subject: [PATCH 0740/1995] ASoC: SOF: send IPC to stop stream during SUSPEND trigger When a suspend trigger is received, send the stop IPC to the DSP to stop the stream. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pcm.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 3c4526f15bf195..eb6eeaeb3f0cb6 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -252,22 +252,6 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) stream.comp_id = spcm->stream[substream->stream].comp_id; switch (cmd) { - case SNDRV_PCM_TRIGGER_STOP: - - /* - * Check if stream was marked for restore before suspend - */ - if (spcm->restore_stream[substream->stream]) { - - /* unset restore_stream */ - spcm->restore_stream[substream->stream] = 0; - - /* do not send ipc as the stream hasn't been set up */ - return 0; - } - - stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; - break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_PAUSE; break; @@ -313,6 +297,20 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) break; case SNDRV_PCM_TRIGGER_SUSPEND: + /* fallthrough */ + case SNDRV_PCM_TRIGGER_STOP: + + /* Check if stream was marked for restore before suspend */ + if (spcm->restore_stream[substream->stream]) { + + /* unset restore_stream */ + spcm->restore_stream[substream->stream] = 0; + + /* do not send ipc as the stream hasn't been set up */ + return 0; + } + + stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; break; default: dev_err(sdev->dev, "error: unhandled trigger cmd %d\n", cmd); From c657ae10dd29f0ecbc26381981202da7d35424a4 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 23 Jan 2019 13:01:32 -0800 Subject: [PATCH 0741/1995] ASoC: SOF: unset restore_stream after hw_params With the use of snd_pcm_suspend_all(), all streams in a pcm will be marked for restoring. So unset restore_stream after hw_params to avoid duplicating the call to hw_params. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pcm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index eb6eeaeb3f0cb6..cea7601d16b1ff 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -163,6 +163,9 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, /* save pcm hw_params */ memcpy(&spcm->params[substream->stream], params, sizeof(*params)); + /* unset restore_stream */ + spcm->restore_stream[substream->stream] = 0; + return ret; } From 635697fbdd1ff68135616c414af530578a4154e3 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 24 Jan 2019 09:01:35 -0800 Subject: [PATCH 0742/1995] ASoC: intel: bxt_pcm512x: set pm ops Set pm ops for the bxt_pcm512x machine driver. Signed-off-by: Ranjani Sridharan --- sound/soc/intel/boards/bxt_pcm512x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/boards/bxt_pcm512x.c b/sound/soc/intel/boards/bxt_pcm512x.c index e2605df8b6efab..47e21e26c0084b 100644 --- a/sound/soc/intel/boards/bxt_pcm512x.c +++ b/sound/soc/intel/boards/bxt_pcm512x.c @@ -305,6 +305,7 @@ static int bxt_pcm512x_probe(struct platform_device *pdev) static struct platform_driver bxt_pcm521x_driver = { .driver = { .name = "bxt-pcm512x", + .pm = &snd_soc_pm_ops, }, .probe = bxt_pcm512x_probe, }; From 654ff14886be2f299d9c77efb62be3a189f0daf5 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 24 Jan 2019 09:02:22 -0800 Subject: [PATCH 0743/1995] ALSA: PCM: check if ops are defined before suspending PCM BE dai links only have internal PCM's and their substream ops may not be set. Suspending these PCM's will result in their ops->trigger() being invoked and cause a kernel oops. So skip suspending PCM's if their ops are NULL. Signed-off-by: Ranjani Sridharan --- sound/core/pcm_native.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 818dff1de545fa..b6e158ce6650de 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1506,6 +1506,14 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm) /* FIXME: the open/close code should lock this as well */ if (substream->runtime == NULL) continue; + + /* + * Skip BE dai link PCM's that are internal and may + * not have their substream ops set. + */ + if (!substream->ops) + continue; + err = snd_pcm_suspend(substream); if (err < 0 && err != -EBUSY) return err; From dfc093b1d84cd588be7858a355d3a2a2ebb09340 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Wed, 23 Jan 2019 01:02:03 +0800 Subject: [PATCH 0744/1995] ASoC: SOF: add byt/cht support on sof_rt5682 machine driver add byt/cht support on sof_rt5682 machine driver. Tested on minnow board. Signed-off-by: Bard liao --- sound/soc/intel/boards/Kconfig | 10 +- sound/soc/intel/boards/sof_rt5682.c | 205 ++++++++++-------- .../intel/common/soc-acpi-intel-byt-match.c | 7 + .../intel/common/soc-acpi-intel-cht-match.c | 7 + 4 files changed, 135 insertions(+), 94 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 25796ef5a15602..b4f773bfaea59a 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -377,18 +377,20 @@ config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC -if SND_SOC_SOF_HDA_COMMON +if SND_SOC_SOF_HDA_COMMON || SND_SOC_SOF_BAYTRAIL config SND_SOC_INTEL_SOF_RT5682_MACH tristate "SOF with rt5682 codec in I2S Mode" - depends on MFD_INTEL_LPSS && I2C && ACPI + depends on I2C && ACPI + depends on (SND_SOC_SOF_HDA_COMMON && MFD_INTEL_LPSS) ||\ + (SND_SOC_SOF_BAYTRAIL && X86_INTEL_LPSS) select SND_SOC_RT5682 select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI + select SND_SOC_HDAC_HDMI if SND_SOC_SOF_HDA_COMMON help This adds support for ASoC machine driver for SOF platforms with rt5682 codec. Say Y if you have such a device. If unsure select "N". -endif ## SND_SOC_SOF_HDA_COMMON +endif ## SND_SOC_SOF_HDA_COMMON || SND_SOC_SOF_BAYTRAIL endif ## SND_SOC_INTEL_MACH diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 2466487dbfaf9c..32065082b9527f 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include @@ -22,17 +24,16 @@ #define QUAD_CHANNEL 4 #define NAME_SIZE 32 -#define SOF_RT5682_MCLK_EN BIT(0) -#define SOF_RT5682_MCLK_24MHZ BIT(1) -#define SOF_RT5682_SSP0 BIT(2) -#define SOF_RT5682_SSP1 BIT(3) - -static char sof_rt5682_cpu_dai_name[9]; /* = "SSP[0/1] Pin" */ -static char sof_rt5682_dai_link_name[11]; /* = "SSP[0/1]-Codec" */ +#define SOF_RT5682_SSP(quirk) ((quirk) & GENMASK(2, 0)) +#define SOF_RT5682_SSP_MASK (GENMASK(2, 0)) +#define SOF_RT5682_MCLK_EN BIT(3) +#define SOF_RT5682_MCLK_24MHZ BIT(4) /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP0; + SOF_RT5682_SSP(0); + +static int is_legacy_cpu; static struct snd_soc_jack sof_hdmi[3]; @@ -62,7 +63,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | SOF_RT5682_MCLK_24MHZ | - SOF_RT5682_SSP1), + SOF_RT5682_SSP(1)), }, { .callback = sof_rt5682_quirk_cb, @@ -71,7 +72,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"), }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP0), + SOF_RT5682_SSP(0)), }, {} }; @@ -192,74 +193,6 @@ static struct snd_soc_dai_link_component platform_component[] = { } }; -/* sof digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link sof_rt5682_dais[] = { - /* Back End DAI links */ - { - .name = "SSP0-Codec", - .id = 0, - .cpu_dai_name = "SSP0 Pin", - .codec_name = "i2c-10EC5682:00", - .codec_dai_name = "rt5682-aif1", - .platforms = platform_component, - .num_platforms = ARRAY_SIZE(platform_component), - .init = sof_rt5682_codec_init, - .ops = &sof_rt5682_ops, - .nonatomic = true, - .dpcm_playback = 1, - .dpcm_capture = 1, - .no_pcm = 1, - }, - { - .name = "dmic01", - .id = 1, - .cpu_dai_name = "DMIC01 Pin", - .codec_name = "dmic-codec", - .codec_dai_name = "dmic-hifi", - .platforms = platform_component, - .num_platforms = ARRAY_SIZE(platform_component), - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - }, - { - .name = "iDisp1", - .id = 2, - .cpu_dai_name = "iDisp1 Pin", - .codec_name = "ehdaudio0D2", - .codec_dai_name = "intel-hdmi-hifi1", - .platforms = platform_component, - .num_platforms = ARRAY_SIZE(platform_component), - .init = sof_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - }, - { - .name = "iDisp2", - .id = 3, - .cpu_dai_name = "iDisp2 Pin", - .codec_name = "ehdaudio0D2", - .codec_dai_name = "intel-hdmi-hifi2", - .platforms = platform_component, - .num_platforms = ARRAY_SIZE(platform_component), - .init = sof_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - }, - { - .name = "iDisp3", - .id = 4, - .cpu_dai_name = "iDisp3 Pin", - .codec_name = "ehdaudio0D2", - .codec_dai_name = "intel-hdmi-hifi3", - .platforms = platform_component, - .num_platforms = ARRAY_SIZE(platform_component), - .init = sof_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - }, -}; - static int sof_card_late_probe(struct snd_soc_card *card) { struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); @@ -269,6 +202,10 @@ static int sof_card_late_probe(struct snd_soc_card *card) int err = 0; int i = 0; + /* HDMI is not supported by SOF on Baytrail/CherryTrail */ + if (is_legacy_cpu) + return 0; + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { component = pcm->codec_dai->component; snprintf(jack_name, sizeof(jack_name), @@ -318,8 +255,6 @@ static const struct snd_soc_dapm_route sof_map[] = { static struct snd_soc_card sof_audio_card_rt5682 = { .name = "sof_rt5682", .owner = THIS_MODULE, - .dai_link = sof_rt5682_dais, - .num_links = ARRAY_SIZE(sof_rt5682_dais), .controls = sof_controls, .num_controls = ARRAY_SIZE(sof_controls), .dapm_widgets = sof_widgets, @@ -330,26 +265,116 @@ static struct snd_soc_card sof_audio_card_rt5682 = { .late_probe = sof_card_late_probe, }; +static const struct x86_cpu_id legacy_cpi_ids[] = { + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT }, /* Baytrail */ + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT }, /* Cherrytrail */ + {} +}; + +static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, + int ssp_port, + int dmic_num, + int hdmi_num) +{ + struct snd_soc_dai_link *links; + int i, id = 0; + + links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * + (1 + dmic_num + hdmi_num), GFP_KERNEL); + /* SSP */ + links[id].name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d-Codec", ssp_port); + links[id].id = id; + links[id].codec_name = "i2c-10EC5682:00"; + links[id].codec_dai_name = "rt5682-aif1"; + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].init = sof_rt5682_codec_init; + links[id].ops = &sof_rt5682_ops; + links[id].nonatomic = true; + links[id].dpcm_playback = 1; + links[id].dpcm_capture = 1; + links[id].no_pcm = 1; + if (is_legacy_cpu) { + links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, + "ssp%d-port", ssp_port); + } else { + links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", ssp_port); + } + id++; + + /* dmic */ + for (i = 1; i <= dmic_num; i++) { + links[id].name = devm_kasprintf(dev, GFP_KERNEL, + "dmic%02d", i); + links[id].id = id; + links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, + "DMIC%02d Pin", i); + links[id].codec_name = "dmic-codec"; + links[id].codec_dai_name = "dmic-hifi"; + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].ignore_suspend = 1; + links[id].dpcm_capture = 1; + links[id].no_pcm = 1; + id++; + } + + /* HDMI */ + for (i = 1; i <= hdmi_num; i++) { + links[id].name = devm_kasprintf(dev, GFP_KERNEL, + "iDisp%d", i); + links[id].id = id; + links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, + "iDisp%d Pin", i); + links[id].codec_name = "ehdaudio0D2"; + links[id].codec_dai_name = devm_kasprintf(dev, GFP_KERNEL, + "intel-hdmi-hifi%d", + i); + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].init = sof_hdmi_init; + links[id].dpcm_playback = 1; + links[id].no_pcm = 1; + id++; + } + + return links; +} + static int sof_audio_probe(struct platform_device *pdev) { + struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; + int dmic_num, hdmi_num; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); if (!ctx) return -ENOMEM; + if (x86_match_cpu(legacy_cpi_ids)) { + is_legacy_cpu = 1; + dmic_num = 0; + hdmi_num = 0; + /* default quirk for legacy cpu */ + sof_rt5682_quirk = SOF_RT5682_SSP(2); + } else { + dmic_num = 1; + hdmi_num = 3; + } + dmi_check_system(sof_rt5682_quirk_table); - if (sof_rt5682_quirk & SOF_RT5682_SSP1) { - snprintf(sof_rt5682_dai_link_name, - sizeof(sof_rt5682_dai_link_name), - "%s", "SSP1-Codec"); - snprintf(sof_rt5682_cpu_dai_name, - sizeof(sof_rt5682_cpu_dai_name), - "%s", "SSP1 Pin"); - sof_rt5682_dais[0].name = sof_rt5682_dai_link_name; - sof_rt5682_dais[0].cpu_dai_name = sof_rt5682_cpu_dai_name; - } + dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", + sof_rt5682_quirk); + + dai_links = sof_card_dai_links_create(&pdev->dev, sof_rt5682_quirk & + SOF_RT5682_SSP_MASK, + dmic_num, hdmi_num); + sof_audio_card_rt5682.dai_link = dai_links; + sof_audio_card_rt5682.num_links = 1 + dmic_num + hdmi_num; + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); sof_audio_card_rt5682.dev = &pdev->dev; diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 96f9c553fe6c9f..a4ffad0c91aa8e 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -194,6 +194,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .sof_tplg_filename = "intel/sof-byt-es8316.tplg", .asoc_plat_name = "sst-mfld-platform", }, + { + .id = "10EC5682", + .drv_name = "sof_rt5682", + .sof_fw_filename = "intel/sof-byt.ri", + .sof_tplg_filename = "intel/sof-byt-rt5682.tplg", + .asoc_plat_name = "sst-mfld-platform", + }, /* some Baytrail platforms rely on RT5645, use CHT machine driver */ { .id = "10EC5645", diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c index 91bb99b69601dd..2038dba88144c3 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -173,6 +173,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .sof_tplg_filename = "intel/sof-cht-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, + { + .id = "10EC5682", + .drv_name = "sof_rt5682", + .sof_fw_filename = "intel/sof-cht.ri", + .sof_tplg_filename = "intel/sof-cht-rt5682.tplg", + .asoc_plat_name = "sst-mfld-platform", + }, /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */ { .id = "10EC5651", From 95a0bc34a833e8c414cac4a093067b7679f5eac2 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Fri, 1 Feb 2019 16:20:23 +0200 Subject: [PATCH 0745/1995] ASoC: SOF: Cleanup DMIC FIFO B related IPC This patch renames the FIFO B related fields from the IPC struct into reserved and renames FIFO A related to just FIFO. The DMIC FW driver now abstracts from kernel the dependencies so the FIFOs can be treated as separate DAIs. The corresponding patch for FW side has been merged. Since the FIFO B was not supported earlier only the SOF ABI minor version is incremented due to this change. Signed-off-by: Seppo Ingalsuo --- include/sound/sof/dai-intel.h | 8 ++++---- include/uapi/sound/sof/abi.h | 3 +-- sound/soc/sof/topology.c | 15 ++++++--------- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h index 700e1ed2345026..11e6fec8ec21a8 100644 --- a/include/sound/sof/dai-intel.h +++ b/include/sound/sof/dai-intel.h @@ -152,10 +152,10 @@ struct sof_ipc_dai_dmic_params { uint32_t pdmclk_min; /**< Minimum microphone clock in Hz (100000..N) */ uint32_t pdmclk_max; /**< Maximum microphone clock in Hz (min...N) */ - uint32_t fifo_fs_a; /**< FIFO A sample rate in Hz (8000..96000) */ - uint32_t fifo_fs_b; /**< FIFO B sample rate in Hz (8000..96000) */ - uint16_t fifo_bits_a; /**< FIFO A word length (16 or 32) */ - uint16_t fifo_bits_b; /**< FIFO B word length (16 or 32) */ + uint32_t fifo_fs; /**< FIFO sample rate in Hz (8000..96000) */ + uint32_t reserved_1; /**< Reserved */ + uint16_t fifo_bits; /**< FIFO word length (16 or 32) */ + uint16_t reserved_2; /**< Reserved */ uint16_t duty_min; /**< Min. mic clock duty cycle in % (20..80) */ uint16_t duty_max; /**< Max. mic clock duty cycle in % (min..80) */ diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index cc0d3d2a47a74b..65ce9ee51835f4 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 0 +#define SOF_ABI_MINOR 1 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ @@ -60,4 +60,3 @@ #define SOF_ABI_MAGIC 0x00464F53 #endif - diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 5438461c026742..c6a5dbd14a4784 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -538,7 +538,7 @@ static const struct sof_topology_token dmic_tokens[] = { offsetof(struct sof_ipc_dai_dmic_params, pdmclk_max), 0}, {SOF_TKN_INTEL_DMIC_SAMPLE_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_dai_dmic_params, fifo_fs_a), 0}, + offsetof(struct sof_ipc_dai_dmic_params, fifo_fs), 0}, {SOF_TKN_INTEL_DMIC_DUTY_MIN, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, offsetof(struct sof_ipc_dai_dmic_params, duty_min), 0}, @@ -551,7 +551,7 @@ static const struct sof_topology_token dmic_tokens[] = { num_pdm_active), 0}, {SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, - offsetof(struct sof_ipc_dai_dmic_params, fifo_bits_a), 0}, + offsetof(struct sof_ipc_dai_dmic_params, fifo_bits), 0}, }; /* @@ -2168,10 +2168,10 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, ipc_config->dmic.pdmclk_min, ipc_config->dmic.pdmclk_max, ipc_config->dmic.duty_min); dev_dbg(sdev->dev, "duty_max %hd fifo_fs %d num_pdms active %d\n", - ipc_config->dmic.duty_max, ipc_config->dmic.fifo_fs_a, + ipc_config->dmic.duty_max, ipc_config->dmic.fifo_fs, ipc_config->dmic.num_pdm_active); dev_dbg(sdev->dev, "fifo word length %hd\n", - ipc_config->dmic.fifo_bits_a); + ipc_config->dmic.fifo_bits); for (j = 0; j < ipc_config->dmic.num_pdm_active; j++) { dev_dbg(sdev->dev, "pdm %hd mic a %hd mic b %hd\n", @@ -2188,16 +2188,14 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, ipc_config->dmic.pdm[j].skew); } - /* TODO: check if fifo_b word length is needed */ - ipc_config->dmic.fifo_bits_b = ipc_config->dmic.fifo_bits_a; - /* send message to DSP */ ret = sof_ipc_tx_message(sdev->ipc, ipc_config->hdr.cmd, ipc_config, size, &reply, sizeof(reply)); if (ret < 0) { - dev_err(sdev->dev, "error: failed to set DAI config for DMIC%d\n", + dev_err(sdev->dev, + "error: failed to set DAI config for DMIC%d\n", config->dai_index); goto err; } @@ -2801,4 +2799,3 @@ int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file) return ret; } EXPORT_SYMBOL(snd_sof_load_topology); - From 94d878676d50b0ae3a8836e243a2d87e37313dbd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Feb 2019 06:29:49 -0600 Subject: [PATCH 0746/1995] ASoC: dapm: fix out-of-bounds accesses to DAPM lookup tables KASAN reports and additional traces point to out-of-bounds accesses to the dapm_up_seq and dapm_down_seq lookup tables. The indices used are larger than the array definition. Fix by adding missing entries for the new widget types in these two lookup tables. The value of 10 was chosen since these widgets are not too critical for pop/click removals. Also the sequences for the following widgets were not defined snd_soc_dapm_input snd_soc_dapm_output snd_soc_dapm_mic snd_soc_dapm_vmid snd_soc_dapm_siggen snd_soc_dapm_sink Since their values defaulted to zero, use a more reasonable mid-level value of 10. Fixes: 8a70b4544ef4 ('ASoC: dapm: Add new widget type for constructing DAPM graphs on DSPs.'). Signed-off-by: Pierre-Louis Bossart --- sound/soc/soc-dapm.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index e6072c38eb8f3f..c3f5e11dd9fde5 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -84,6 +84,19 @@ static int dapm_up_seq[] = { [snd_soc_dapm_mixer_named_ctl] = 8, [snd_soc_dapm_pga] = 9, [snd_soc_dapm_adc] = 10, + [snd_soc_dapm_input] = 10, + [snd_soc_dapm_output] = 10, + [snd_soc_dapm_mic] = 10, + [snd_soc_dapm_vmid] = 10, + [snd_soc_dapm_siggen] = 10, + [snd_soc_dapm_sink] = 10, + [snd_soc_dapm_buffer] = 10, + [snd_soc_dapm_scheduler] = 10, + [snd_soc_dapm_effect] = 10, + [snd_soc_dapm_src] = 10, + [snd_soc_dapm_asrc] = 10, + [snd_soc_dapm_encoder] = 10, + [snd_soc_dapm_decoder] = 10, [snd_soc_dapm_out_drv] = 11, [snd_soc_dapm_hp] = 11, [snd_soc_dapm_spk] = 11, @@ -113,6 +126,19 @@ static int dapm_down_seq[] = { [snd_soc_dapm_aif_out] = 10, [snd_soc_dapm_dai_in] = 10, [snd_soc_dapm_dai_out] = 10, + [snd_soc_dapm_input] = 10, + [snd_soc_dapm_output] = 10, + [snd_soc_dapm_mic] = 10, + [snd_soc_dapm_vmid] = 10, + [snd_soc_dapm_siggen] = 10, + [snd_soc_dapm_sink] = 10, + [snd_soc_dapm_buffer] = 10, + [snd_soc_dapm_scheduler] = 10, + [snd_soc_dapm_effect] = 10, + [snd_soc_dapm_src] = 10, + [snd_soc_dapm_asrc] = 10, + [snd_soc_dapm_encoder] = 10, + [snd_soc_dapm_decoder] = 10, [snd_soc_dapm_dai_link] = 11, [snd_soc_dapm_supply] = 12, [snd_soc_dapm_clock_supply] = 13, From 88ac7b0d57b930319e7deeb65a483c5132abdd18 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Feb 2019 05:42:48 -0600 Subject: [PATCH 0747/1995] ASoC: dapm: fix use-after-free issue with dailink sname Commit 7620fe9161ce ("ASoC: topology: fix memory leak in soc_tplg_dapm_widget_create") fixed a memory leak issue, but additional tests and KASAN reports show a use-after-free in soc-dapm. The widgets are created with a kmemdup operating on a template. The "name" string is also duplicated, but the "sname" string is not. As a result, when the template is freed after widget creation, its sname string is still used. Fix by explicitly duplicating the "sname" string, and freeing it when required. Signed-off-by: Pierre-Louis Bossart --- sound/soc/soc-dapm.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c3f5e11dd9fde5..2dbd64693a68f4 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -321,7 +321,22 @@ EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty); static inline struct snd_soc_dapm_widget *dapm_cnew_widget( const struct snd_soc_dapm_widget *_widget) { - return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); + struct snd_soc_dapm_widget *w; + + w = kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); + if (!w) + return NULL; + + /* + * w->name is duplicated in caller, but w->sname isn't. + * Duplicate it here if defined + */ + if (_widget->sname) { + w->sname = kstrdup_const(_widget->sname, GFP_KERNEL); + if (!w->sname) + return NULL; + } + return w; } struct dapm_kcontrol_data { @@ -2440,6 +2455,7 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) kfree(w->kcontrols); kfree_const(w->name); + kfree_const(w->sname); kfree(w); } @@ -3498,6 +3514,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, else w->name = kstrdup_const(widget->name, GFP_KERNEL); if (w->name == NULL) { + kfree_const(w->sname); kfree(w); return ERR_PTR(-ENOMEM); } From 26844058462fc81cc56034a0d0eba11143b419ae Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 20 Sep 2018 15:42:14 +0200 Subject: [PATCH 0748/1995] ASoC: topology: fix oops/use-after-free case with dai driver rmmod/modprobe tests expose a kernel oops when accessing the dai driver pointer. This comes from the topology design which operates in multiple passes. Each object removal happens at a specific iteration, and the code checks for the iteration (order) number after the memory containing the order was freed. Fix this be clearing a reference to the dai driver and check its validity to avoid dereferences. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart --- sound/soc/soc-core.c | 2 +- sound/soc/soc-topology.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index cfc5f3bbc57a3b..0bf624da1df7f0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -966,7 +966,7 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order) { int err; - if (!dai || !dai->probed || + if (!dai || !dai->probed || !dai->driver || dai->driver->remove_order != order) return; diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 49e6fd76d9bcb2..67ce85bdad50d9 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -523,6 +523,7 @@ static void remove_dai(struct snd_soc_component *comp, { struct snd_soc_dai_driver *dai_drv = container_of(dobj, struct snd_soc_dai_driver, dobj); + struct snd_soc_dai *dai; if (pass != SOC_TPLG_PASS_PCM_DAI) return; @@ -530,6 +531,10 @@ static void remove_dai(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->dai_unload) dobj->ops->dai_unload(comp, dobj); + list_for_each_entry(dai, &comp->dai_list, list) + if (dai->driver == dai_drv) + dai->driver = NULL; + kfree(dai_drv->name); list_del(&dobj->list); kfree(dai_drv); From b6fa1cd8b1ddcb45aec6a8eb688e907334844ac6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Feb 2019 06:58:29 -0600 Subject: [PATCH 0749/1995] Revert "ASoC: topology: unload physical dai link in remove" This reverts commit e9cc0205ea6df4113bf286d4279fad7e6a6a4dae. Signed-off-by: Pierre-Louis Bossart --- include/sound/soc-topology.h | 1 - sound/soc/soc-topology.c | 31 ------------------------------- 2 files changed, 32 deletions(-) diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index 5223896de26f51..8c43cfc240fa33 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -45,7 +45,6 @@ enum snd_soc_dobj_type { SND_SOC_DOBJ_DAI_LINK, SND_SOC_DOBJ_PCM, SND_SOC_DOBJ_CODEC_LINK, - SND_SOC_DOBJ_BACKEND_LINK, }; /* dynamic control object */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 67ce85bdad50d9..bb7e5422a419f8 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -562,24 +562,6 @@ static void remove_link(struct snd_soc_component *comp, kfree(link); } -/* unload dai link */ -static void remove_backend_link(struct snd_soc_component *comp, - struct snd_soc_dobj *dobj, int pass) -{ - if (pass != SOC_TPLG_PASS_LINK) - return; - - if (dobj->ops && dobj->ops->link_unload) - dobj->ops->link_unload(comp, dobj); - - /* - * We don't free the link here as what remove_link() do since BE - * links are not allocated by topology. - */ - - list_del(&dobj->list); -} - /* bind a kcontrol to it's IO handlers */ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, struct snd_kcontrol_new *k, @@ -2186,12 +2168,6 @@ static int soc_tplg_link_config(struct soc_tplg *tplg, return ret; } - /* for unloading it in snd_soc_tplg_component_remove */ - link->dobj.index = tplg->index; - link->dobj.ops = tplg->ops; - link->dobj.type = SND_SOC_DOBJ_BACKEND_LINK; - list_add(&link->dobj.list, &tplg->comp->dobj_list); - return 0; } @@ -2678,13 +2654,6 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) case SND_SOC_DOBJ_DAI_LINK: remove_link(comp, dobj, pass); break; - case SND_SOC_DOBJ_BACKEND_LINK: - /* - * call link_unload ops if extra - * deinitialization is needed. - */ - remove_backend_link(comp, dobj, pass); - break; default: dev_err(comp->dev, "ASoC: invalid component type %d for removal\n", dobj->type); From c4575fb53723f834a729bbf662b28db3a6c6a04d Mon Sep 17 00:00:00 2001 From: Bard liao Date: Mon, 7 Jan 2019 06:24:02 +0800 Subject: [PATCH 0750/1995] ASoC: topology: unload physical dai link in remove soc_tplg_link_config() will find the physical dai link and call soc_tplg_dai_link_load() to load the BE dai link. Currently remove_link() is only used to remove the FE dai link which is created by the topology. The BE dai link cannot however be unloaded in snd_soc_tplg_component _remove(), which is problematic if anything needs to be released or reinitialized. This patch aligns the definitions of dynamic types with the existing UAPI and adds a new remove_backend_link() routine to unload the the BE dai link when snd_soc_tplg_component_remove() is invoked. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart --- include/sound/soc-topology.h | 1 + sound/soc/soc-topology.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index 8c43cfc240fa33..5223896de26f51 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -45,6 +45,7 @@ enum snd_soc_dobj_type { SND_SOC_DOBJ_DAI_LINK, SND_SOC_DOBJ_PCM, SND_SOC_DOBJ_CODEC_LINK, + SND_SOC_DOBJ_BACKEND_LINK, }; /* dynamic control object */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index bb7e5422a419f8..c5638e15a2ddfb 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -562,6 +562,25 @@ static void remove_link(struct snd_soc_component *comp, kfree(link); } +/* unload dai link */ +static void remove_backend_link(struct snd_soc_component *comp, + struct snd_soc_dobj *dobj, int pass) +{ + if (pass != SOC_TPLG_PASS_LINK) + return; + + if (dobj->ops && dobj->ops->link_unload) + dobj->ops->link_unload(comp, dobj); + + /* + * We don't free the link here as what remove_link() do since BE + * links are not allocated by topology. + * We however need to reset the dobj type to its initial values + */ + dobj->type = SND_SOC_DOBJ_NONE; + list_del(&dobj->list); +} + /* bind a kcontrol to it's IO handlers */ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, struct snd_kcontrol_new *k, @@ -2168,6 +2187,12 @@ static int soc_tplg_link_config(struct soc_tplg *tplg, return ret; } + /* for unloading it in snd_soc_tplg_component_remove */ + link->dobj.index = tplg->index; + link->dobj.ops = tplg->ops; + link->dobj.type = SND_SOC_DOBJ_BACKEND_LINK; + list_add(&link->dobj.list, &tplg->comp->dobj_list); + return 0; } @@ -2654,6 +2679,13 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) case SND_SOC_DOBJ_DAI_LINK: remove_link(comp, dobj, pass); break; + case SND_SOC_DOBJ_BACKEND_LINK: + /* + * call link_unload ops if extra + * deinitialization is needed. + */ + remove_backend_link(comp, dobj, pass); + break; default: dev_err(comp->dev, "ASoC: invalid component type %d for removal\n", dobj->type); From 89cd76e8db6ed6b5c914c5552a09447348b00f91 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 28 Jan 2019 18:50:44 -0600 Subject: [PATCH 0751/1995] ASoC: SOF: core: move release_firmware No need to do this multiple times in parent drivers. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 5 ++++- sound/soc/sof/sof-acpi-dev.c | 2 -- sound/soc/sof/sof-pci-dev.c | 4 ---- sound/soc/sof/sof-spi-dev.c | 2 -- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 1eff06acb9f057..1abe6a704f1b9f 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -8,6 +8,7 @@ // Author: Liam Girdwood // +#include #include #include #include @@ -415,7 +416,6 @@ static int sof_remove(struct platform_device *pdev) snd_sof_free_debug(sdev); snd_sof_free_trace(sdev); snd_sof_remove(sdev); - /* * platform_device_unregister() frees the card and its resources. * So it should be called after unregistering the comp driver @@ -424,6 +424,9 @@ static int sof_remove(struct platform_device *pdev) if (pdata && !IS_ERR_OR_NULL(pdata->pdev_mach)) platform_device_unregister(pdata->pdev_mach); + /* release firmware */ + release_firmware(pdata->fw); + return 0; } diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 2ed3495a5520b6..24dbad20a4e376 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -245,11 +245,9 @@ static int sof_acpi_probe(struct platform_device *pdev) static int sof_acpi_remove(struct platform_device *pdev) { struct sof_platform_priv *priv = dev_get_drvdata(&pdev->dev); - struct snd_sof_pdata *sof_pdata = priv->sof_pdata; if (!IS_ERR_OR_NULL(priv->pdev_pcm)) platform_device_unregister(priv->pdev_pcm); - release_firmware(sof_pdata->fw); return 0; } diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 8893ce224b0ecb..62435e78196694 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -248,15 +248,11 @@ static int sof_pci_probe(struct pci_dev *pci, static void sof_pci_remove(struct pci_dev *pci) { struct sof_platform_priv *priv = pci_get_drvdata(pci); - struct snd_sof_pdata *sof_pdata = priv->sof_pdata; /* unregister sof-audio platform driver */ if (!IS_ERR_OR_NULL(priv->pdev_pcm)) platform_device_unregister(priv->pdev_pcm); - /* release firmware */ - release_firmware(sof_pdata->fw); - /* follow recommendation in pci-driver.c to increment usage counter */ pm_runtime_get_noresume(&pci->dev); diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index a949a61646ac40..ad2255a7e96dc9 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -150,11 +150,9 @@ static int sof_spi_probe(struct spi_device *spi) static int sof_spi_remove(struct spi_device *spi) { struct sof_platform_priv *priv = spi_get_drvdata(spi); - struct snd_sof_pdata *sof_pdata = priv->sof_pdata; if (!IS_ERR_OR_NULL(priv->pdev_pcm)) platform_device_unregister(priv->pdev_pcm); - release_firmware(sof_pdata->fw); return 0; } From fa037413506b42bb3b9145dc45bb24737b329565 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 16:07:25 -0600 Subject: [PATCH 0752/1995] ASoC: SOF: add probe_complete callback definition With the device model, there is no guarantee that the driver probe of the child platform device will complete synchronously. The errors are also squelched so that e.g. the pci driver has no way of knowing that the firmware boot failed. Also the probe might be implemented in a workqueue (e.g. if there are any dependencies on modules or long hardware initialization times), so we really need an asynchronous way of notifying the parent device that all probe-related functionality completed successfully in the "sof-audio" device. The simplest possible implementation is a callback added to the sof_pdata structure. Signed-off-by: Pierre-Louis Bossart --- include/sound/sof.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/sound/sof.h b/include/sound/sof.h index 7c11d16207e478..251103f46fe51a 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -30,6 +30,16 @@ struct snd_sof_pdata { /* parent device */ struct device *dev; + /* + * notification callback used if the hardware initialization + * can take time or is handled in a workqueue. This callback + * can be used by the parent device to e.g. enable runtime_pm + * or limit functionality until all low-level inits are + * complete. The device argument refers to the parent, not the + * "sof-audio" device. + */ + void (*sof_probe_complete)(struct device *dev); + /* descriptor */ const struct sof_dev_desc *desc; From edc331f727f0f24171a5ebcaba912ceb8914b78c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 28 Jan 2019 18:30:48 -0600 Subject: [PATCH 0753/1995] ASoC: SOF: core: move probe/remove to exported functions Prepare for removal of platform:sof-audio device Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 33 +++++++++++++++++++++++---------- sound/soc/sof/sof-priv.h | 4 ++++ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 1abe6a704f1b9f..c579d5350cbc24 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -255,23 +255,22 @@ static int sof_machine_check(struct snd_sof_dev *sdev) return 0; } -static int sof_probe(struct platform_device *pdev) +int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) { - struct snd_sof_pdata *plat_data = dev_get_platdata(&pdev->dev); struct snd_sof_dev *sdev; const char *drv_name; const void *mach; int size; int ret; - sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL); + sdev = devm_kzalloc(dev, sizeof(*sdev), GFP_KERNEL); if (!sdev) return -ENOMEM; - dev_dbg(&pdev->dev, "probing SOF DSP device....\n"); + dev_dbg(dev, "probing SOF DSP device....\n"); /* initialize sof device */ - sdev->dev = &pdev->dev; + sdev->dev = dev; sdev->parent = plat_data->dev; if dev_is_pci(plat_data->dev) sdev->pci = to_pci_dev(plat_data->dev); @@ -363,7 +362,7 @@ static int sof_probe(struct platform_device *pdev) sdev->first_boot = false; /* now register audio DSP platform driver and dai */ - ret = snd_soc_register_component(&pdev->dev, &sdev->plat_drv, + ret = snd_soc_register_component(dev, &sdev->plat_drv, sof_ops(sdev)->drv, sof_ops(sdev)->num_drv); if (ret < 0) { @@ -392,7 +391,7 @@ static int sof_probe(struct platform_device *pdev) return 0; comp_err: - snd_soc_unregister_component(&pdev->dev); + snd_soc_unregister_component(dev); fw_run_err: snd_sof_fw_unload(sdev); fw_load_err: @@ -404,13 +403,21 @@ static int sof_probe(struct platform_device *pdev) return ret; } +EXPORT_SYMBOL(snd_sof_device_probe); -static int sof_remove(struct platform_device *pdev) +static int sof_probe(struct platform_device *pdev) { - struct snd_sof_dev *sdev = dev_get_drvdata(&pdev->dev); + struct snd_sof_pdata *plat_data = dev_get_platdata(&pdev->dev); + + return snd_sof_device_probe(&pdev->dev, plat_data); +} + +int snd_sof_device_remove(struct device *dev) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(dev); struct snd_sof_pdata *pdata = sdev->pdata; - snd_soc_unregister_component(&pdev->dev); + snd_soc_unregister_component(dev); snd_sof_fw_unload(sdev); snd_sof_ipc_free(sdev); snd_sof_free_debug(sdev); @@ -429,6 +436,12 @@ static int sof_remove(struct platform_device *pdev) return 0; } +EXPORT_SYMBOL(snd_sof_device_remove); + +static int sof_remove(struct platform_device *pdev) +{ + return snd_sof_device_remove(&pdev->dev); +} static struct platform_driver sof_driver = { .driver = { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index bdaad14981cec7..dec05231610af5 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -388,6 +388,10 @@ struct sof_platform_priv { /* * Device Level. */ + +int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data); +int snd_sof_device_remove(struct device *dev); + int snd_sof_runtime_suspend(struct device *dev); int snd_sof_runtime_resume(struct device *dev); int snd_sof_resume(struct device *dev); From ab8f970cfc1c1b3b22ecabbaab732cd90eefc40d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 31 Jan 2019 14:09:17 -0600 Subject: [PATCH 0754/1995] ASoC: SOF: remove unnecessary use of plat_data Make the following patch less complex Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/hw-spi.c | 8 +++----- sound/soc/sof/intel/hda-loader-skl.c | 2 +- sound/soc/sof/intel/hda-loader.c | 4 ++-- sound/soc/sof/loader.c | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index 02dab65b2cbe1f..75fb0518cfbf32 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -152,9 +152,7 @@ static void spi_mailbox_read(struct snd_sof_dev *sdev __maybe_unused, static irqreturn_t spi_irq_handler(int irq __maybe_unused, void *context) { const struct snd_sof_dev *sdev = context; - const struct platform_device *pdev = - container_of(sdev->parent, struct platform_device, dev); - struct snd_sof_pdata *sof_pdata = dev_get_platdata(&pdev->dev); + struct snd_sof_pdata *sof_pdata = sdev->pdata; struct sof_spi_dev *sof_spi = (struct sof_spi_dev *)sof_pdata->hw_pdata; @@ -237,8 +235,8 @@ static int spi_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) static int spi_sof_probe(struct snd_sof_dev *sdev) { struct platform_device *pdev = - container_of(sdev->parent, struct platform_device, dev); - struct snd_sof_pdata *sof_pdata = dev_get_platdata(&pdev->dev); + container_of(sdev->dev, struct platform_device, dev); + struct snd_sof_pdata *sof_pdata = sdev->pdata; struct sof_spi_dev *sof_spi = (struct sof_spi_dev *)sof_pdata->hw_pdata; /* get IRQ from Device tree or ACPI - register our IRQ */ diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index f6ec5ac6b76692..da250ad8fdc755 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -445,7 +445,7 @@ cl_skl_cldma_copy_to_buf(struct snd_sof_dev *sdev, const void *bin, static int cl_copy_fw_skl(struct snd_sof_dev *sdev) { - struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev); + struct snd_sof_pdata *plat_data = sdev->pdata; const struct firmware *fw = plat_data->fw; unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; int ret = 0; diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 2edf4ee7524120..68a27810520a50 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -247,7 +247,7 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev) { - struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev); + struct snd_sof_pdata *plat_data = sdev->pdata; const char *fw_filename; /* set code loading condition to true */ @@ -259,7 +259,7 @@ int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev) int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) { - struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev); + struct snd_sof_pdata *plat_data = sdev->pdata; struct hdac_ext_stream *stream; struct firmware stripped_firmware; int ret, ret1, tag, i; diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index df6461ac4664ec..d3a3f7b29d3380 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -228,7 +228,7 @@ static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw) int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev) { - struct snd_sof_pdata *plat_data = dev_get_platdata(sdev->dev); + struct snd_sof_pdata *plat_data = sdev->pdata; const char *fw_filename; int ret; From a58c97c2679e07454ef637ea1fa6b44f02821378 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 31 Jan 2019 14:10:46 -0600 Subject: [PATCH 0755/1995] ASoC: SOF: remove "sof-audio" device Very intrusive patch with changes the module hierarchy Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/compressed.c | 2 +- sound/soc/sof/core.c | 23 ----------------------- sound/soc/sof/intel/bdw.c | 2 +- sound/soc/sof/intel/byt.c | 2 +- sound/soc/sof/intel/hda.c | 2 +- sound/soc/sof/intel/hsw.c | 2 +- sound/soc/sof/nocodec.c | 2 +- sound/soc/sof/pcm.c | 15 ++++++--------- sound/soc/sof/pm.c | 6 ++---- sound/soc/sof/sof-acpi-dev.c | 23 +++++++---------------- sound/soc/sof/sof-pci-dev.c | 27 ++++++++------------------- sound/soc/sof/sof-priv.h | 11 ----------- sound/soc/sof/sof-spi-dev.c | 21 ++++++--------------- sound/soc/sof/topology.c | 6 +++--- sound/soc/sof/trace.c | 4 ++-- sound/soc/sof/utils.c | 20 -------------------- 16 files changed, 40 insertions(+), 128 deletions(-) diff --git a/sound/soc/sof/compressed.c b/sound/soc/sof/compressed.c index e85ad4727d9e8b..701d204cabf708 100644 --- a/sound/soc/sof/compressed.c +++ b/sound/soc/sof/compressed.c @@ -15,7 +15,7 @@ #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) -#define DRV_NAME "sof-audio" +#define DRV_NAME "sof-audio-component" static int sof_compressed_open(struct snd_compr_stream *cstream) { diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index c579d5350cbc24..a37b42a4849e38 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -271,7 +271,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) /* initialize sof device */ sdev->dev = dev; - sdev->parent = plat_data->dev; if dev_is_pci(plat_data->dev) sdev->pci = to_pci_dev(plat_data->dev); @@ -405,13 +404,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) } EXPORT_SYMBOL(snd_sof_device_probe); -static int sof_probe(struct platform_device *pdev) -{ - struct snd_sof_pdata *plat_data = dev_get_platdata(&pdev->dev); - - return snd_sof_device_probe(&pdev->dev, plat_data); -} - int snd_sof_device_remove(struct device *dev) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); @@ -438,21 +430,6 @@ int snd_sof_device_remove(struct device *dev) } EXPORT_SYMBOL(snd_sof_device_remove); -static int sof_remove(struct platform_device *pdev) -{ - return snd_sof_device_remove(&pdev->dev); -} - -static struct platform_driver sof_driver = { - .driver = { - .name = "sof-audio", - }, - - .probe = sof_probe, - .remove = sof_remove, -}; -module_platform_driver(sof_driver); - MODULE_AUTHOR("Liam Girdwood"); MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 95a7d250e71e4f..1ed813f244224f 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -533,7 +533,7 @@ static int bdw_probe(struct snd_sof_dev *sdev) struct snd_sof_pdata *pdata = sdev->pdata; const struct sof_dev_desc *desc = pdata->desc; struct platform_device *pdev = - container_of(sdev->parent, struct platform_device, dev); + container_of(sdev->dev, struct platform_device, dev); struct resource *mmio; u32 base, size; int ret = 0; diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 3455ac42f7b69c..5dfa73e7ec660e 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -649,7 +649,7 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) struct snd_sof_pdata *pdata = sdev->pdata; const struct sof_dev_desc *desc = pdata->desc; struct platform_device *pdev = - container_of(sdev->parent, struct platform_device, dev); + container_of(sdev->dev, struct platform_device, dev); struct resource *mmio; u32 base, size; int ret = 0; diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index f5ef2d52ce7553..e7c14cb002e8ef 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -304,7 +304,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) mach_params = (struct snd_soc_acpi_mach_params *) &pdata->machine->mach_params; mach_params->codec_mask = bus->codec_mask; - mach_params->platform = "sof-audio"; + mach_params->platform = dev_name(sdev->dev); } /* create codec instances */ diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index d61e1af503dad5..282b21a26e4875 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -533,7 +533,7 @@ static int hsw_probe(struct snd_sof_dev *sdev) struct snd_sof_pdata *pdata = sdev->pdata; const struct sof_dev_desc *desc = pdata->desc; struct platform_device *pdev = - container_of(sdev->parent, struct platform_device, dev); + container_of(sdev->dev, struct platform_device, dev); struct resource *mmio; u32 base, size; int ret = 0; diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index 3f3b2a72c2cf6f..fa5b2d5904e126 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -36,7 +36,7 @@ static int sof_nocodec_bes_setup(struct device *dev, links[i].id = i; links[i].no_pcm = 1; links[i].cpu_dai_name = ops->drv[i].name; - links[i].platform_name = "sof-audio"; + links[i].platform_name = dev_name(dev); links[i].codec_dai_name = "snd-soc-dummy-dai"; links[i].codec_name = "snd-soc-dummy"; links[i].dpcm_playback = 1; diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index cea7601d16b1ff..ae66b8fd5238cf 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -16,7 +16,7 @@ #include "sof-priv.h" #include "ops.h" -#define DRV_NAME "sof-audio" +#define DRV_NAME "sof-audio-component" /* Create DMA buffer page table for DSP */ static int create_page_table(struct snd_pcm_substream *substream, @@ -513,7 +513,7 @@ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) caps->name, caps->buffer_size_min, caps->buffer_size_max); ret = snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream, - SNDRV_DMA_TYPE_DEV_SG, sdev->parent, + SNDRV_DMA_TYPE_DEV_SG, sdev->dev, le32_to_cpu(caps->buffer_size_min), le32_to_cpu(caps->buffer_size_max)); if (ret) { @@ -537,7 +537,7 @@ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) caps->name, caps->buffer_size_min, caps->buffer_size_max); ret = snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream, - SNDRV_DMA_TYPE_DEV_SG, sdev->parent, + SNDRV_DMA_TYPE_DEV_SG, sdev->dev, le32_to_cpu(caps->buffer_size_min), le32_to_cpu(caps->buffer_size_max)); if (ret) @@ -641,7 +641,7 @@ static int sof_pcm_probe(struct snd_soc_component *component) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - struct snd_sof_pdata *plat_data = dev_get_platdata(component->dev); + struct snd_sof_pdata *plat_data = sdev->pdata; const char *tplg_filename; int ret, err; @@ -679,14 +679,11 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) { struct snd_soc_component_driver *pd = &sdev->plat_drv; struct snd_sof_pdata *plat_data = sdev->pdata; - const char *plat_name, *drv_name; + const char *drv_name; - plat_name = plat_data->machine->asoc_plat_name; drv_name = plat_data->machine->drv_name; - dev_dbg(sdev->dev, "using platform alias %s\n", plat_name); - - pd->name = "sof-audio"; + pd->name = "sof-audio-component"; pd->probe = sof_pcm_probe; pd->remove = sof_pcm_remove; pd->ops = &sof_pcm_ops; diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index fd9d07892201f7..96af5cdee05b90 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -211,8 +211,7 @@ static void sof_set_restore_stream(struct snd_sof_dev *sdev) static int sof_resume(struct device *dev, bool runtime_resume) { - struct sof_platform_priv *priv = dev_get_drvdata(dev); - struct snd_sof_dev *sdev = dev_get_drvdata(&priv->pdev_pcm->dev); + struct snd_sof_dev *sdev = dev_get_drvdata(dev); int ret = 0; /* do nothing if dsp resume callbacks are not set */ @@ -281,8 +280,7 @@ static int sof_resume(struct device *dev, bool runtime_resume) static int sof_suspend(struct device *dev, bool runtime_suspend) { - struct sof_platform_priv *priv = dev_get_drvdata(dev); - struct snd_sof_dev *sdev = dev_get_drvdata(&priv->pdev_pcm->dev); + struct snd_sof_dev *sdev = dev_get_drvdata(dev); int ret = 0; /* do nothing if dsp suspend callback is not set */ diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 24dbad20a4e376..b0ee8ea00dc4d0 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -160,16 +160,11 @@ static int sof_acpi_probe(struct platform_device *pdev) const struct sof_dev_desc *desc; struct snd_soc_acpi_mach *mach; struct snd_sof_pdata *sof_pdata; - struct sof_platform_priv *priv; const struct snd_sof_dsp_ops *ops; int ret = 0; dev_dbg(&pdev->dev, "ACPI DSP detected"); - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); if (!sof_pdata) return -ENOMEM; @@ -217,20 +212,18 @@ static int sof_acpi_probe(struct platform_device *pdev) } #endif - mach->mach_params.platform = "sof-audio"; + mach->mach_params.platform = dev_name(dev); mach->mach_params.acpi_ipc_irq_index = desc->irqindex_host_ipc; sof_pdata->machine = mach; sof_pdata->desc = desc; - priv->sof_pdata = sof_pdata; sof_pdata->dev = &pdev->dev; - sof_pdata->platform = "sof-audio"; - dev_set_drvdata(&pdev->dev, priv); + sof_pdata->platform = dev_name(dev); - /* register sof-audio platform driver */ - ret = sof_create_platform_device(priv); + /* call sof helper for DSP hardware probe */ + ret = snd_sof_device_probe(dev, sof_pdata); if (ret) { - dev_err(dev, "error: failed to create platform device!\n"); + dev_err(dev, "error: failed to probe DSP hardware!\n"); return ret; } @@ -244,10 +237,8 @@ static int sof_acpi_probe(struct platform_device *pdev) static int sof_acpi_remove(struct platform_device *pdev) { - struct sof_platform_priv *priv = dev_get_drvdata(&pdev->dev); - - if (!IS_ERR_OR_NULL(priv->pdev_pcm)) - platform_device_unregister(priv->pdev_pcm); + /* call sof helper for DSP hardware remove */ + snd_sof_device_remove(&pdev->dev); return 0; } diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 62435e78196694..3e383d867464bf 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -158,7 +158,6 @@ static int sof_pci_probe(struct pci_dev *pci, (const struct sof_dev_desc *)pci_id->driver_data; struct snd_soc_acpi_mach *mach; struct snd_sof_pdata *sof_pdata; - struct sof_platform_priv *priv; const struct snd_sof_dsp_ops *ops; int ret = 0; @@ -171,12 +170,6 @@ static int sof_pci_probe(struct pci_dev *pci, return -ENODEV; } - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - pci_set_drvdata(pci, priv); - sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); if (!sof_pdata) return -ENOMEM; @@ -206,21 +199,20 @@ static int sof_pci_probe(struct pci_dev *pci, if (!mach) dev_warn(dev, "warning: No matching ASoC machine driver found\n"); else - mach->mach_params.platform = "sof-audio"; + mach->mach_params.platform = dev_name(dev); #endif /* CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE */ sof_pdata->id = pci_id->device; sof_pdata->name = pci_name(pci); sof_pdata->machine = mach; sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data; - priv->sof_pdata = sof_pdata; - sof_pdata->dev = &pci->dev; - sof_pdata->platform = "sof-audio"; + sof_pdata->dev = dev; + sof_pdata->platform = dev_name(dev); - /* register sof-audio platform driver */ - ret = sof_create_platform_device(priv); + /* call sof helper for DSP hardware probe */ + ret = snd_sof_device_probe(dev, sof_pdata); if (ret) { - dev_err(dev, "error: failed to create platform device!\n"); + dev_err(dev, "error: failed to probe DSP hardware!\n"); goto release_regions; } @@ -247,11 +239,8 @@ static int sof_pci_probe(struct pci_dev *pci, static void sof_pci_remove(struct pci_dev *pci) { - struct sof_platform_priv *priv = pci_get_drvdata(pci); - - /* unregister sof-audio platform driver */ - if (!IS_ERR_OR_NULL(priv->pdev_pcm)) - platform_device_unregister(priv->pdev_pcm); + /* call sof helper for DSP hardware remove */ + snd_sof_device_remove(&pci->dev); /* follow recommendation in pci-driver.c to increment usage counter */ pm_runtime_get_noresume(&pci->dev); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index dec05231610af5..b229949a286ec7 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -302,7 +302,6 @@ struct snd_sof_dai { */ struct snd_sof_dev { struct device *dev; - struct device *parent; spinlock_t ipc_lock; /* lock for IPC users */ spinlock_t hw_lock; /* lock for HW IO access */ struct pci_dev *pci; @@ -376,15 +375,6 @@ struct snd_sof_dev { void *private; /* core does not touch this */ }; -/* - * SOF platform private struct used as drvdata of - * platform dev (e.g. pci/acpi/spi...) drvdata. - */ -struct sof_platform_priv { - struct snd_sof_pdata *sof_pdata; - struct platform_device *pdev_pcm; -}; - /* * Device Level. */ @@ -547,7 +537,6 @@ extern const struct sof_arch_ops sof_xtensa_arch_ops; /* * Utilities */ -int sof_create_platform_device(struct sof_platform_priv *priv); void sof_io_write(struct snd_sof_dev *sdev, void __iomem *addr, u32 value); void sof_io_write64(struct snd_sof_dev *sdev, void __iomem *addr, u64 value); u32 sof_io_read(struct snd_sof_dev *sdev, void __iomem *addr); diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index ad2255a7e96dc9..ae06fa18acb1ce 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -53,7 +53,6 @@ static int sof_spi_probe(struct spi_device *spi) const struct sof_dev_desc *desc = of_device_get_match_data(dev); struct snd_soc_acpi_mach *machines, *mach; struct snd_sof_pdata *sof_pdata; - struct sof_platform_priv *priv; struct sof_spi_dev *sof_spi; const char *tplg, *fw; struct gpio_desc *gpiod; @@ -68,11 +67,6 @@ static int sof_spi_probe(struct spi_device *spi) dev_dbg(&spi->dev, "SPI DSP detected"); - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - spi_set_drvdata(spi, priv); - sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); if (!sof_pdata) return -ENOMEM; @@ -121,19 +115,18 @@ static int sof_spi_probe(struct spi_device *spi) mach->sof_fw_filename = desc->nocodec_fw_filename; mach->sof_tplg_filename = desc->nocodec_tplg_filename; mach->asoc_plat_name = "sof-platform"; - mach->mach_params.platform = "sof-audio"; + mach->mach_params.platform = dev_name(dev); sof_pdata->id = -1; sof_pdata->name = dev_name(&spi->dev); sof_pdata->machine = mach; sof_pdata->desc = desc; - priv->sof_pdata = sof_pdata; sof_pdata->dev = dev; - /* register sof-audio platform driver */ - ret = sof_create_platform_device(priv); + /* call sof helper for DSP hardware probe */ + ret = snd_sof_device_probe(dev, sof_pdata); if (ret) { - dev_err(dev, "error: failed to create platform device!\n"); + dev_err(dev, "error: failed to probe DSP hardware!\n"); return ret; } @@ -149,10 +142,8 @@ static int sof_spi_probe(struct spi_device *spi) static int sof_spi_remove(struct spi_device *spi) { - struct sof_platform_priv *priv = spi_get_drvdata(spi); - - if (!IS_ERR_OR_NULL(priv->pdev_pcm)) - platform_device_unregister(priv->pdev_pcm); + /* call sof helper for DSP hardware remove */ + snd_sof_device_remove(&spi->dev); return 0; } diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index c6a5dbd14a4784..b6a65c149f6618 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1908,7 +1908,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, caps = &spcm->pcm.caps[stream]; /* allocate playback page table buffer */ - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->parent, + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev, PAGE_SIZE, &spcm->stream[stream].page_table); if (ret < 0) { dev_err(sdev->dev, "error: can't alloc page table for %s %d\n", @@ -1927,7 +1927,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, caps = &spcm->pcm.caps[stream]; /* allocate capture page table buffer */ - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->parent, + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev, PAGE_SIZE, &spcm->stream[stream].page_table); if (ret < 0) { dev_err(sdev->dev, "error: can't alloc page table for %s %d\n", @@ -2358,7 +2358,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_hw_config *hw_config; int ret = 0; - link->platform_name = "sof-audio"; + link->platform_name = dev_name(sdev->dev); /* * Set nonatomic property for FE dai links as their trigger action diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 603c2ac282e3d4..157b01dc237894 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -191,7 +191,7 @@ int snd_sof_init_trace(struct snd_sof_dev *sdev) sdev->dtrace_is_enabled = false; /* allocate trace page table buffer */ - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->parent, + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev, PAGE_SIZE, &sdev->dmatp); if (ret < 0) { dev_err(sdev->dev, @@ -200,7 +200,7 @@ int snd_sof_init_trace(struct snd_sof_dev *sdev) } /* allocate trace data buffer */ - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, sdev->parent, + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, sdev->dev, DMA_BUF_SIZE_FOR_TRACE, &sdev->dmatb); if (ret < 0) { dev_err(sdev->dev, diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index 6167e05d5a6dea..73c5900319d338 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -14,26 +14,6 @@ #include #include "sof-priv.h" -/* register sof platform device */ -int sof_create_platform_device(struct sof_platform_priv *priv) -{ - struct snd_sof_pdata *sof_pdata = priv->sof_pdata; - struct device *dev = sof_pdata->dev; - - priv->pdev_pcm = - platform_device_register_data(dev, "sof-audio", - PLATFORM_DEVID_NONE, - sof_pdata, sizeof(*sof_pdata)); - if (IS_ERR(priv->pdev_pcm)) { - dev_err(dev, "error: cannot register device sof-audio. Error %ld\n", - PTR_ERR(priv->pdev_pcm)); - return PTR_ERR(priv->pdev_pcm); - } - - return 0; -} -EXPORT_SYMBOL(sof_create_platform_device); - /* * Register IO */ From bf9b30d2ce6c8e665e4ecc67f56a6177e398dbcd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 28 Jan 2019 12:07:09 -0600 Subject: [PATCH 0756/1995] ASoC: SOF: only enable/allow pm_runtime in parent Remove all inits to pm_runtime from pcm.c, this needs to be done at a higher level. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 3 ++- sound/soc/sof/pcm.c | 12 ------------ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index a37b42a4849e38..e5b5cdce4df18a 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -276,12 +276,13 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) sdev->pdata = plat_data; sdev->first_boot = true; + dev_set_drvdata(dev, sdev); + INIT_LIST_HEAD(&sdev->pcm_list); INIT_LIST_HEAD(&sdev->kcontrol_list); INIT_LIST_HEAD(&sdev->widget_list); INIT_LIST_HEAD(&sdev->dai_list); INIT_LIST_HEAD(&sdev->route_list); - dev_set_drvdata(&pdev->dev, sdev); spin_lock_init(&sdev->ipc_lock); spin_lock_init(&sdev->hw_lock); diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index ae66b8fd5238cf..c55f3224e31300 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -656,23 +656,11 @@ static int sof_pcm_probe(struct snd_soc_component *component) return ret; } - /* enable runtime PM with auto suspend */ - pm_runtime_set_autosuspend_delay(component->dev, - SND_SOF_SUSPEND_DELAY_MS); - pm_runtime_use_autosuspend(component->dev); - pm_runtime_enable(component->dev); - - pm_runtime_mark_last_busy(component->dev); - err = pm_runtime_put_autosuspend(component->dev); - if (err < 0) - dev_err(sdev->dev, "error: failed to enter PM idle %d\n", err); - return ret; } static void sof_pcm_remove(struct snd_soc_component *component) { - pm_runtime_disable(component->dev); } void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) From 56bfbfbe3ac2e84a50df20f3e65a0874eb1e75c6 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 31 Jan 2019 12:17:54 -0800 Subject: [PATCH 0757/1995] ASoC: SOF: fix PM flow This patch does the following: 1. Fix the runtime PM call in ACPI device probe to enable runtime PM. 2. The machine driver resumes its parent device before it's probe() gets invoked. But snd_soc_register_card() call in the machine driver's probe also increments the parent device's usage count. So decrement the usage count after the component driver's probe is complete. This will enable the device to enter runtime suspend after the machine driver probe is finished. 3. Lastly, in SOF some platforms ex:BYT do not have their platform PM callbacks enabled. In order to prevent them from entering runtime suspend, skip decrementing the usage count in the component probe. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pcm.c | 16 +++++++++++++++- sound/soc/sof/sof-acpi-dev.c | 4 +++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index c55f3224e31300..a6d6269a5c4b7b 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -643,7 +643,7 @@ static int sof_pcm_probe(struct snd_soc_component *component) snd_soc_component_get_drvdata(component); struct snd_sof_pdata *plat_data = sdev->pdata; const char *tplg_filename; - int ret, err; + int ret; /* load the default topology */ sdev->component = component; @@ -656,6 +656,20 @@ static int sof_pcm_probe(struct snd_soc_component *component) return ret; } + /* + * Some platforms in SOF, ex: BYT, may not have their platform PM + * callbacks set. Skip decrementing the usage count so as to + * prevent their runtime PM callbacks from being invoked. + */ + if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume) + return ret; + + /* + * Decrement the usage count to enable the device to enter + * runtime suspend after probe() completes. + */ + pm_runtime_put_noidle(sdev->dev); + return ret; } diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index b0ee8ea00dc4d0..f200ff877c55ae 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -230,13 +230,15 @@ static int sof_acpi_probe(struct platform_device *pdev) /* allow runtime_pm */ pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); pm_runtime_use_autosuspend(dev); - pm_runtime_allow(dev); + pm_runtime_enable(dev); return ret; } static int sof_acpi_remove(struct platform_device *pdev) { + pm_runtime_disable(&pdev->dev); + /* call sof helper for DSP hardware remove */ snd_sof_device_remove(&pdev->dev); From e0526424b39cc231b49773084fb5c13639d9cf8b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 30 Jan 2019 13:03:24 -0600 Subject: [PATCH 0758/1995] ASoC: core: don't increase component module refcount unconditionally The ASoC core has for the longest time increased the module reference counts, even before the transition to the component model. This is probably fine on most platforms, but it introduces a deadlock case on Intel devices with the Skylake and SOF drivers which cannot be removed due to their reference counts being modified by the core. In these 2 cases, the PCI or ACPI driver .probe creates a platform device to let the machine driver .probe register the audio card. Conversely the PCI or ACPI driver .remove will unregister the platform device which results in the card being removed by the machine driver .remove. With ascii art, this can be represented as modprobe snd_soc_skl/ soc-pci-dev/sof-acpci-dev ----------> pci/acpi probe ^ | | ---------------| | | | | V V increase register register machine refcount component platform_device ^ | | | | V component <---- register card <---- probe probe The issue is that by playing with the component's module reference counts during the card registration, it's no longer possible to remove the module which controls the component. This can be shown, e.g. with the following error: root@plb-XPS-13-9350:~# lsmod | grep snd_soc_skl snd_soc_skl 110592 1 root@plb-XPS-13-9350:~# rmmod snd_soc_skl rmmod: ERROR: Module snd_soc_skl is in use Increasing the reference count during the component probe is not useful. If the PCI/ACPI module is removed, the card will be removed anyway. To avoid breaking existing platforms and allowing Intel platforms to safely deal with module load/unload cases, this patch introduces a flag which needs to be set during the component initialization. This is a strictly opt-in capability that should only be used when the handling of the component module does not require a reference count increase to prevent removal during use. Note that this solution does is not applicable to the legacy Atom/SST driver, which uses a different device hierarchy. There are however additional refcount issues which prevent the ACPI driver from being removed. This is a different issue which would need a different patch. Signed-off-by: Pierre-Louis Bossart --- include/sound/soc.h | 3 +++ sound/soc/soc-core.c | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 2b6b392556619b..da3c1318526341 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -802,6 +802,9 @@ struct snd_soc_component_driver { int probe_order; int remove_order; + /* signal if the module handling the component cannot be removed */ + unsigned int ignore_module_refcount:1; + /* bits */ unsigned int idle_bias_on:1; unsigned int suspend_bias_off:1; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0bf624da1df7f0..0d8064a21975b2 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -948,7 +948,8 @@ static void soc_cleanup_component(struct snd_soc_component *component) snd_soc_dapm_free(snd_soc_component_get_dapm(component)); soc_cleanup_component_debugfs(component); component->card = NULL; - module_put(component->dev->driver->owner); + if (!component->driver->ignore_module_refcount) + module_put(component->dev->driver->owner); } static void soc_remove_component(struct snd_soc_component *component) @@ -1363,7 +1364,8 @@ static int soc_probe_component(struct snd_soc_card *card, return 0; } - if (!try_module_get(component->dev->driver->owner)) + if (!component->driver->ignore_module_refcount && + !try_module_get(component->dev->driver->owner)) return -ENODEV; component->card = card; From 87f8fe0368db0611a1a4e2910514d173c99bb052 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 30 Jan 2019 13:29:52 -0600 Subject: [PATCH 0759/1995] ASoC: Intel: Skylake: set .ignore_module_refcount field in component There is no risk of the module being removed while the platform components are in use. This solves the problem of the snd_soc_skl module not being removable with rmmod Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/skylake/skl-pcm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 8e589d698c588e..a4284778f117d6 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1464,6 +1464,7 @@ static const struct snd_soc_component_driver skl_component = { .ops = &skl_platform_ops, .pcm_new = skl_pcm_new, .pcm_free = skl_pcm_free, + .ignore_module_refcount = 1, /* do not increase the refcount in core */ }; int skl_platform_register(struct device *dev) From 3713d0d203f58197542d9b6922e1df56a50d4121 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 31 Jan 2019 15:07:15 -0600 Subject: [PATCH 0760/1995] ASoC: SOF: pcm: set .ignore_module_refcount field in component There is no risk of the sof-pci/acpi-dev module being removed while the platform components are in use. This solves the problem of the soc-pci/acpi-dev module not being removable with rmmod Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pcm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index a6d6269a5c4b7b..82c3d8a20aca10 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -698,5 +698,8 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) pd->be_pcm_base = SOF_BE_PCM_BASE; pd->use_dai_pcm_id = true; pd->topology_name_prefix = "sof"; + + /* do not increase the refcount in core */ + pd->ignore_module_refcount = 1; } From 746ced27801a8274072c3a00e3563f236364b2c9 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 1 Feb 2019 15:25:46 +0000 Subject: [PATCH 0761/1995] ASoC: SOF: pm: Fix ops when restoring pipelines. DAI config can be NULL, complain and let user know topology is bad. Signed-off-by: Liam Girdwood --- sound/soc/sof/pm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 96af5cdee05b90..bb199eb014df10 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -143,6 +143,12 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev) struct sof_ipc_reply reply; struct sof_ipc_dai_config *config = dai->dai_config; + if (!config) { + dev_err(sdev->dev, "error: no config for DAI %s\n", + dai->name); + continue; + } + ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size, From 58fdeaf066e955d0390f2e69312957d968052a72 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 1 Feb 2019 18:35:52 +0200 Subject: [PATCH 0762/1995] ASoC: fw: Sync fw.h interface file with FW Block type specifies now the type of memory where that given block will be loaded. Anyhow, Linux doesn't make use of this information yet. This change is only to algin fw.h with the corresponding file from FW. Signed-off-by: Daniel Baluta --- include/uapi/sound/sof/fw.h | 27 +++++++++++++++++++-------- sound/soc/sof/loader.c | 11 ++++------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/include/uapi/sound/sof/fw.h b/include/uapi/sound/sof/fw.h index 37dd159c955b01..1afca973eb0972 100644 --- a/include/uapi/sound/sof/fw.h +++ b/include/uapi/sound/sof/fw.h @@ -23,14 +23,25 @@ * DSP/host memory space. */ enum snd_sof_fw_blk_type { - SOF_BLK_IMAGE = 0, /* whole image - parsed by ROMs */ - SOF_BLK_TEXT = 1, - SOF_BLK_DATA = 2, - SOF_BLK_CACHE = 3, - SOF_BLK_REGS = 4, - SOF_BLK_SIG = 5, - SOF_BLK_ROM = 6, - /* add new block types here */ + SOF_FW_BLK_TYPE_INVALID = -1, + SOF_FW_BLK_TYPE_START = 0, + SOF_FW_BLK_TYPE_RSRVD0 = SOF_FW_BLK_TYPE_START, + SOF_FW_BLK_TYPE_IRAM = 1, /* local instruction RAM */ + SOF_FW_BLK_TYPE_DRAM = 2, /* local data RAM */ + SOF_FW_BLK_TYPE_SRAM = 3, /* system RAM */ + SOF_FW_BLK_TYPE_ROM = 4, + SOF_FW_BLK_TYPE_IMR = 5, + SOF_FW_BLK_TYPE_RSRVD6 = 6, + SOF_FW_BLK_TYPE_RSRVD7 = 7, + SOF_FW_BLK_TYPE_RSRVD8 = 8, + SOF_FW_BLK_TYPE_RSRVD9 = 9, + SOF_FW_BLK_TYPE_RSRVD10 = 10, + SOF_FW_BLK_TYPE_RSRVD11 = 11, + SOF_FW_BLK_TYPE_RSRVD12 = 12, + SOF_FW_BLK_TYPE_RSRVD13 = 13, + SOF_FW_BLK_TYPE_RSRVD14 = 14, + /* use SOF_FW_BLK_TYPE_RSVRDX for new block types */ + SOF_FW_BLK_TYPE_NUM }; struct snd_sof_blk_hdr { diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index d3a3f7b29d3380..edd7b77c217a16 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -121,14 +121,11 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, } switch (block->type) { - case SOF_BLK_IMAGE: - case SOF_BLK_CACHE: - case SOF_BLK_REGS: - case SOF_BLK_SIG: - case SOF_BLK_ROM: + case SOF_FW_BLK_TYPE_RSRVD0: + case SOF_FW_BLK_TYPE_SRAM...SOF_FW_BLK_TYPE_RSRVD14: continue; /* not handled atm */ - case SOF_BLK_TEXT: - case SOF_BLK_DATA: + case SOF_FW_BLK_TYPE_IRAM: + case SOF_FW_BLK_TYPE_DRAM: offset = block->offset; break; default: From 6e3216457cf3ba95debd2c83d85955f192cda7da Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Feb 2019 16:52:44 -0600 Subject: [PATCH 0763/1995] ASoC: SOF: core: fix dev usage Minor fix to avoid messing with diff in later patch. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index e5b5cdce4df18a..026c0933bff2c7 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -362,7 +362,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) sdev->first_boot = false; /* now register audio DSP platform driver and dai */ - ret = snd_soc_register_component(dev, &sdev->plat_drv, + ret = snd_soc_register_component(sdev->dev, &sdev->plat_drv, sof_ops(sdev)->drv, sof_ops(sdev)->num_drv); if (ret < 0) { @@ -391,7 +391,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) return 0; comp_err: - snd_soc_unregister_component(dev); + snd_soc_unregister_component(sdev->dev); fw_run_err: snd_sof_fw_unload(sdev); fw_load_err: From 0ba87a265e79e8752f7f060349fa3f7f11bc662f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Feb 2019 17:05:11 -0600 Subject: [PATCH 0764/1995] ASoC: SOF: core: introduce sof_probe_continue() Since we may need to do the probe in two steps, move the bulk of the hardware setup to sof_probe_continue. No functional change here. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 77 ++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 026c0933bff2c7..ce7eca71e3be9d 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -255,47 +255,14 @@ static int sof_machine_check(struct snd_sof_dev *sdev) return 0; } -int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) +static int sof_probe_continue(struct snd_sof_dev *sdev) { - struct snd_sof_dev *sdev; + struct snd_sof_pdata *plat_data = sdev->pdata; const char *drv_name; const void *mach; int size; int ret; - sdev = devm_kzalloc(dev, sizeof(*sdev), GFP_KERNEL); - if (!sdev) - return -ENOMEM; - - dev_dbg(dev, "probing SOF DSP device....\n"); - - /* initialize sof device */ - sdev->dev = dev; - if dev_is_pci(plat_data->dev) - sdev->pci = to_pci_dev(plat_data->dev); - - sdev->pdata = plat_data; - sdev->first_boot = true; - dev_set_drvdata(dev, sdev); - - INIT_LIST_HEAD(&sdev->pcm_list); - INIT_LIST_HEAD(&sdev->kcontrol_list); - INIT_LIST_HEAD(&sdev->widget_list); - INIT_LIST_HEAD(&sdev->dai_list); - INIT_LIST_HEAD(&sdev->route_list); - spin_lock_init(&sdev->ipc_lock); - spin_lock_init(&sdev->hw_lock); - - /* set default timeouts if none provided */ - if (plat_data->desc->ipc_timeout == 0) - sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC_MS; - else - sdev->ipc_timeout = plat_data->desc->ipc_timeout; - if (plat_data->desc->boot_timeout == 0) - sdev->boot_timeout = TIMEOUT_DEFAULT_BOOT_MS; - else - sdev->boot_timeout = plat_data->desc->boot_timeout; - /* probe the DSP hardware */ ret = snd_sof_probe(sdev); if (ret < 0) { @@ -403,6 +370,46 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) return ret; } + +int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) +{ + struct snd_sof_dev *sdev; + + sdev = devm_kzalloc(dev, sizeof(*sdev), GFP_KERNEL); + if (!sdev) + return -ENOMEM; + + dev_dbg(dev, "probing SOF DSP device....\n"); + + /* initialize sof device */ + sdev->dev = dev; + if dev_is_pci(plat_data->dev) + sdev->pci = to_pci_dev(plat_data->dev); + + sdev->pdata = plat_data; + sdev->first_boot = true; + dev_set_drvdata(dev, sdev); + + INIT_LIST_HEAD(&sdev->pcm_list); + INIT_LIST_HEAD(&sdev->kcontrol_list); + INIT_LIST_HEAD(&sdev->widget_list); + INIT_LIST_HEAD(&sdev->dai_list); + INIT_LIST_HEAD(&sdev->route_list); + spin_lock_init(&sdev->ipc_lock); + spin_lock_init(&sdev->hw_lock); + + /* set default timeouts if none provided */ + if (plat_data->desc->ipc_timeout == 0) + sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC_MS; + else + sdev->ipc_timeout = plat_data->desc->ipc_timeout; + if (plat_data->desc->boot_timeout == 0) + sdev->boot_timeout = TIMEOUT_DEFAULT_BOOT_MS; + else + sdev->boot_timeout = plat_data->desc->boot_timeout; + + return sof_probe_continue(sdev); +} EXPORT_SYMBOL(snd_sof_device_probe); int snd_sof_device_remove(struct device *dev) From de67df2c43c799071fcac313ddf2348ed4e4351c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Feb 2019 17:22:07 -0600 Subject: [PATCH 0765/1995] ASoC: SOF: core: add support for probe workqueue Schedule sof_probe_continue() at a later time if so desired Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 28 ++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 3 +++ 2 files changed, 31 insertions(+) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index ce7eca71e3be9d..89f345ddef4c31 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -371,6 +371,22 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) return ret; } +#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) +static void sof_probe_work(struct work_struct *work) +{ + struct snd_sof_dev *sdev = + container_of(work, struct snd_sof_dev, probe_work); + int ret; + + dev_dbg(sdev->dev, "%s entry\n", __func__); + ret = sof_probe_continue(sdev); + if (ret < 0) { + /* errors cannot be propagated, log */ + dev_err(sdev->dev, "error: %s failed err: %d\n", __func__, ret); + } +} +#endif + int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) { struct snd_sof_dev *sdev; @@ -398,6 +414,10 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) spin_lock_init(&sdev->ipc_lock); spin_lock_init(&sdev->hw_lock); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) + INIT_WORK(&sdev->probe_work, sof_probe_work); +#endif + /* set default timeouts if none provided */ if (plat_data->desc->ipc_timeout == 0) sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC_MS; @@ -408,6 +428,11 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) else sdev->boot_timeout = plat_data->desc->boot_timeout; + if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) { + schedule_work(&sdev->probe_work); + return 0; + } + return sof_probe_continue(sdev); } EXPORT_SYMBOL(snd_sof_device_probe); @@ -417,6 +442,9 @@ int snd_sof_device_remove(struct device *dev) struct snd_sof_dev *sdev = dev_get_drvdata(dev); struct snd_sof_pdata *pdata = sdev->pdata; + if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) + cancel_work_sync(&sdev->probe_work); + snd_soc_unregister_component(dev); snd_sof_fw_unload(sdev); snd_sof_ipc_free(sdev); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index b229949a286ec7..ed865c794306ab 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -314,6 +314,9 @@ struct snd_sof_dev { u32 boot_complete; u32 first_boot; + /* work queue in case the probe is implemented in two steps */ + struct work_struct probe_work; + /* DSP HW differentiation */ struct snd_sof_pdata *pdata; From c83eeb4ace402041438ef489fe1b9b8b57958a46 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 17 Jan 2019 16:58:30 -0600 Subject: [PATCH 0766/1995] ASoC: SOF: Intel: enable workqueue-based probe for HDaudio HDaudio initialization relies on request_module (for HDaudio codecs and i915 inits). To avoid any lockups select the option to split the probe in two. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/Kconfig | 8 ++++++++ sound/soc/sof/intel/Kconfig | 1 + 2 files changed, 9 insertions(+) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index e8382eb8e1bb35..06b237f726e17d 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -144,6 +144,14 @@ config SND_SOC_SOF module dependencies but since the module or built-in type is decided at the top level it doesn't matter. +config SND_SOC_SOF_PROBE_WORK_QUEUE + bool + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + When selected, the probe is handled in two steps, for example to + avoid lockdeps if request_module is used in the probe. + source "sound/soc/sof/intel/Kconfig" source "sound/soc/sof/xtensa/Kconfig" diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index a5b8b47b9deb2e..50cb06b160a87d 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -215,6 +215,7 @@ if SND_SOC_SOF_HDA_COMMON config SND_SOC_SOF_HDA_LINK bool "SOF support for HDA Links(HDA/HDMI)" + select SND_SOC_SOF_PROBE_WORK_QUEUE help This adds support for HDA links(HDA/HDMI) with Sound Open Firmware for Intel(R) platforms. From c9279df3a254b1e86c774635406390ebfb978a61 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 16:11:57 -0600 Subject: [PATCH 0767/1995] ASoC: SOF: core: invoke notification callback If the second part of the probe completes successfully, invoke the sof_probe_complete notification callback, if desired by the caller Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 89f345ddef4c31..af5dadee9c399d 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -355,6 +355,9 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) dev_dbg(sdev->dev, "created machine %s\n", dev_name(&plat_data->pdev_mach->dev)); + if (plat_data->sof_probe_complete) + plat_data->sof_probe_complete(sdev->dev); + return 0; comp_err: From 268dbef7467d7a6d024cb60d771411eb9f7e4642 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 16:13:36 -0600 Subject: [PATCH 0768/1995] ASoC: SOF: pci: enable sof_probe_complete callback We have no way of knowing if low-level layers probed successfully when a workqueue is enabled. Move all the runtime_pm enablement to the sof_probe_complete callback to avoid any possible race conditions. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-pci-dev.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 3e383d867464bf..9fcb8087898e90 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -150,6 +150,24 @@ static const struct dev_pm_ops sof_pci_pm = { NULL) }; +static void sof_pci_probe_complete(struct device *dev) +{ + dev_dbg(dev, "Completing SOF PCI probe"); + + /* allow runtime_pm */ + pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(dev); + + /* + * runtime pm for pci device is "forbidden" by default. + * so call pm_runtime_allow() to enable it. + */ + pm_runtime_allow(dev); + + /* follow recommendation in pci-driver.c to decrement usage counter */ + pm_runtime_put_noidle(dev); +} + static int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -209,6 +227,10 @@ static int sof_pci_probe(struct pci_dev *pci, sof_pdata->dev = dev; sof_pdata->platform = dev_name(dev); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) + /* set callback to enable runtime_pm */ + sof_pdata->sof_probe_complete = sof_pci_probe_complete; +#endif /* call sof helper for DSP hardware probe */ ret = snd_sof_device_probe(dev, sof_pdata); if (ret) { @@ -216,18 +238,9 @@ static int sof_pci_probe(struct pci_dev *pci, goto release_regions; } - /* allow runtime_pm */ - pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); - pm_runtime_use_autosuspend(dev); - - /* - * runtime pm for pci device is "forbidden" by default. - * so call pm_runtime_allow() to enable it. - */ - pm_runtime_allow(dev); - - /* follow recommendation in pci-driver.c to decrement usage counter */ - pm_runtime_put_noidle(dev); +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) + sof_pci_probe_complete(dev); +#endif return ret; From d7c0864128eca2c9f70ebba8b207ea0efb48cadd Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Mon, 4 Feb 2019 14:26:23 +0200 Subject: [PATCH 0769/1995] ASoC: SOF: Pass bar to snd_sof_fw_parse_ext_data This allows platform specific drivers to read extended data from any given bar not just mmio_bar as it is now. Signed-off-by: Daniel Baluta --- sound/soc/sof/intel/bdw.c | 2 +- sound/soc/sof/intel/byt.c | 2 +- sound/soc/sof/intel/hda-ipc.c | 3 ++- sound/soc/sof/intel/hsw.c | 2 +- sound/soc/sof/loader.c | 8 ++++---- sound/soc/sof/sof-priv.h | 2 +- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 1ed813f244224f..14b2b5511a1a3a 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -437,7 +437,7 @@ static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return ret; /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + + snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + sizeof(struct sof_ipc_fw_ready)); bdw_get_windows(sdev); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 5dfa73e7ec660e..86b2ee4e3fbfc7 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -218,7 +218,7 @@ static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return ret; /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + + snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + sizeof(struct sof_ipc_fw_ready)); byt_get_windows(sdev); diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 9ddfa9e1f96868..af67cf3ca9de2f 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -379,7 +379,8 @@ int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return ret; /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, HDA_DSP_MBOX_UPLINK_OFFSET + + snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, + HDA_DSP_MBOX_UPLINK_OFFSET + sizeof(struct sof_ipc_fw_ready)); ipc_get_windows(sdev); diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 282b21a26e4875..a88918d5b0fed6 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -438,7 +438,7 @@ static int hsw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return ret; /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + + snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + sizeof(struct sof_ipc_fw_ready)); hsw_get_windows(sdev); diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index edd7b77c217a16..5005d1dc4513ef 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -34,7 +34,7 @@ static int get_ext_windows(struct snd_sof_dev *sdev, } /* parse the extended FW boot data structures from FW boot message */ -int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) +int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) { struct sof_ipc_ext_data_hdr *ext_hdr; void *ext_data; @@ -45,14 +45,14 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) return -ENOMEM; /* get first header */ - snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, ext_data, + snd_sof_dsp_block_read(sdev, bar, offset, ext_data, sizeof(*ext_hdr)); ext_hdr = (struct sof_ipc_ext_data_hdr *)ext_data; while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) { /* read in ext structure */ offset += sizeof(*ext_hdr); - snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, + snd_sof_dsp_block_read(sdev, bar, offset, ext_data + sizeof(*ext_hdr), ext_hdr->hdr.size - sizeof(*ext_hdr)); @@ -78,7 +78,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) /* move to next header */ offset += ext_hdr->hdr.size; - snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, ext_data, + snd_sof_dsp_block_read(sdev, bar, offset, ext_data, sizeof(*ext_hdr)); ext_hdr = (struct sof_ipc_ext_data_hdr *)ext_data; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index ed865c794306ab..79adcc01b68ad8 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -405,7 +405,7 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev); int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, struct snd_sof_mod_hdr *module); void snd_sof_fw_unload(struct snd_sof_dev *sdev); -int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset); +int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset); /* * IPC low level APIs. From 6c747e58a8f02185e84f5979d1cb8846a2d1d090 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 6 Feb 2019 18:13:36 -0600 Subject: [PATCH 0770/1995] ASoC: SOF: acpi: add support for probe workqueue/completion When both ACPI and PCI/HDaudio devices are compiled in, the Kconfig dependencies enable the workqueue support, even if this is not needed when testing on ACPI devices. Mirror the PCI implementation and only do the PM enablement when the probe succeeds. In a future evolution we may want to signal at run-time that a workqueue is not necessary instead of doing a build selection. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-acpi-dev.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index f200ff877c55ae..150053ef9330c1 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -154,6 +154,14 @@ static const struct dev_pm_ops sof_acpi_pm = { NULL) }; +static void sof_acpi_probe_complete(struct device *dev) +{ + /* allow runtime_pm */ + pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); +} + static int sof_acpi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -220,6 +228,11 @@ static int sof_acpi_probe(struct platform_device *pdev) sof_pdata->dev = &pdev->dev; sof_pdata->platform = dev_name(dev); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) + /* set callback to enable runtime_pm */ + sof_pdata->sof_probe_complete = sof_acpi_probe_complete; +#endif + /* call sof helper for DSP hardware probe */ ret = snd_sof_device_probe(dev, sof_pdata); if (ret) { @@ -227,10 +240,9 @@ static int sof_acpi_probe(struct platform_device *pdev) return ret; } - /* allow runtime_pm */ - pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); - pm_runtime_use_autosuspend(dev); - pm_runtime_enable(dev); +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) + sof_acpi_probe_complete(dev); +#endif return ret; } From 25255a47cd8fc92dd686a7670314446d08130210 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 6 Feb 2019 21:11:56 -0800 Subject: [PATCH 0771/1995] ASoC: SOF: check if mandatory ops required for ipc are defined Initialize ipc only if the madatory ops required are defined. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/ipc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 103a9180dc1f81..b8b31c365bc5d0 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -761,6 +761,12 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) struct snd_sof_ipc_msg *msg; int i; + /* check if mandatory ops required for ipc are defined */ + if (!sof_ops(sdev)->is_ipc_ready || !sof_ops(sdev)->fw_ready) { + dev_err(sdev->dev, "error: ipc mandatory ops not defined\n"); + return NULL; + } + ipc = devm_kzalloc(sdev->dev, sizeof(*ipc), GFP_KERNEL); if (!ipc) return NULL; From 4387448948b9c03aefb54c87fbbb6651b25c6c64 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 14 Jan 2019 09:19:16 -0800 Subject: [PATCH 0772/1995] ASoC: SOF: update processing of fw ready message from DSP Fix the logic to process the fw_ready message from DSP. A failure in fw_ready() indicates that there is a mismatch in ABI between the driver and FW. So, set the flag to indicate this error and notify the thread that is waiting for fw boot completion. Without this change, ABI mismatch will not get caught. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/hw-spi.c | 1 + sound/soc/sof/intel/bdw.c | 1 + sound/soc/sof/intel/byt.c | 1 + sound/soc/sof/intel/hda-ipc.c | 1 + sound/soc/sof/intel/hsw.c | 1 + sound/soc/sof/ipc.c | 16 ++++++++++------ sound/soc/sof/loader.c | 2 +- sound/soc/sof/sof-priv.h | 5 +++++ 8 files changed, 21 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index 75fb0518cfbf32..9b937453f75b7b 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -98,6 +98,7 @@ static void spi_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, /* * IPC Firmware ready. + * TODO: check for ABI compatibility */ static int spi_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) { diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 14b2b5511a1a3a..554ceab298351e 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -406,6 +406,7 @@ static void bdw_get_windows(struct snd_sof_dev *sdev) stream_offset, stream_size); } +/* check for ABI compatibility and create memory windows on first boot */ static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) { struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 86b2ee4e3fbfc7..5f05651a89a4de 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -187,6 +187,7 @@ static void byt_get_windows(struct snd_sof_dev *sdev) stream_offset, stream_size); } +/* check for ABI compatibility and create memory windows on first boot */ static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) { struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index af67cf3ca9de2f..934a0979a87560 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -353,6 +353,7 @@ static void ipc_get_windows(struct snd_sof_dev *sdev) stream_offset, stream_size); } +/* check for ABI compatibility and create memory windows on first boot */ int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) { struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index a88918d5b0fed6..5bd79a56994ba2 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -407,6 +407,7 @@ static void hsw_get_windows(struct snd_sof_dev *sdev) stream_offset, stream_size); } +/* check for ABI compatibility and create memory windows on first boot */ static int hsw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) { struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index b8b31c365bc5d0..a44cec01753c8e 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -381,7 +381,7 @@ static void ipc_msgs_rx(struct work_struct *work) struct snd_sof_dev *sdev = ipc->sdev; struct sof_ipc_cmd_hdr hdr; u32 cmd, type; - int err = -EINVAL; + int err = 0; /* read back header */ snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &hdr, sizeof(hdr)); @@ -398,17 +398,21 @@ static void ipc_msgs_rx(struct work_struct *work) case SOF_IPC_FW_READY: /* check for FW boot completion */ if (!sdev->boot_complete) { - if (sof_ops(sdev)->fw_ready) - err = sof_ops(sdev)->fw_ready(sdev, cmd); + err = sof_ops(sdev)->fw_ready(sdev, cmd); if (err < 0) { - dev_err(sdev->dev, "error: DSP firmware boot timeout %d\n", + /* + * this indicates a mismatch in ABI + * between the driver and fw + */ + dev_err(sdev->dev, "error: ABI mismatch %d\n", err); } else { /* firmware boot completed OK */ sdev->boot_complete = true; - dev_dbg(sdev->dev, "booting DSP firmware completed\n"); - wake_up(&sdev->boot_wait); } + + /* wake up firmware loader */ + wake_up(&sdev->boot_wait); } break; case SOF_IPC_GLB_COMPOUND: diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 5005d1dc4513ef..443764e59dd939 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -320,7 +320,7 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) ret = wait_event_timeout(sdev->boot_wait, sdev->boot_complete, msecs_to_jiffies(sdev->boot_timeout)); if (ret == 0) { - dev_err(sdev->dev, "error: firmware boot timeout\n"); + dev_err(sdev->dev, "error: firmware boot failure\n"); snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX | SOF_DBG_TEXT | SOF_DBG_PCI); return -EIO; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 79adcc01b68ad8..32cb032621c265 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -155,6 +155,11 @@ struct snd_sof_dsp_ops { int (*load_firmware)(struct snd_sof_dev *sof_dev); int (*load_module)(struct snd_sof_dev *sof_dev, struct snd_sof_mod_hdr *hdr); + + /* + * FW ready checks for ABI compatibility and creates + * memory windows at first boot + */ int (*fw_ready)(struct snd_sof_dev *sdev, u32 msg_id); /* host DMA trace initialization */ From 6250420d69b2b371f112f7d0d7eb7be97f623ed3 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 14 Jan 2019 10:22:30 -0800 Subject: [PATCH 0773/1995] ASoC: SOF: add flag to disable ipc queueing Add a flag to disable ipc queueing to avoid race conditions. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/ipc.c | 11 ++++++++--- sound/soc/sof/sof-priv.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index a44cec01753c8e..3bedc64bca673b 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -272,7 +272,7 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, /* schedule the message if not busy */ if (snd_sof_dsp_is_ready(sdev)) - schedule_work(&ipc->tx_kwork); + snd_sof_ipc_msgs_tx(sdev); spin_unlock_irq(&sdev->ipc_lock); @@ -441,14 +441,16 @@ static void ipc_msgs_rx(struct work_struct *work) /* schedule work to transmit any IPC in queue */ void snd_sof_ipc_msgs_tx(struct snd_sof_dev *sdev) { - schedule_work(&sdev->ipc->tx_kwork); + if (!sdev->disable_ipc_queue) + schedule_work(&sdev->ipc->tx_kwork); } EXPORT_SYMBOL(snd_sof_ipc_msgs_tx); /* schedule work to handle IPC from DSP */ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) { - schedule_work(&sdev->ipc->rx_kwork); + if (!sdev->disable_ipc_queue) + schedule_work(&sdev->ipc->rx_kwork); } EXPORT_SYMBOL(snd_sof_ipc_msgs_rx); @@ -813,6 +815,9 @@ EXPORT_SYMBOL(snd_sof_ipc_init); void snd_sof_ipc_free(struct snd_sof_dev *sdev) { + /* disable queueing of ipc's */ + sdev->disable_ipc_queue = true; + cancel_work_sync(&sdev->ipc->tx_kwork); cancel_work_sync(&sdev->ipc->rx_kwork); } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 32cb032621c265..f836591cedce28 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -333,6 +333,7 @@ struct snd_sof_dev { u64 irq_status; int ipc_irq; u32 next_comp_id; /* monotonic - reset during S3 */ + u32 disable_ipc_queue; /* disables further queueing of ipc's */ /* memory bases for mmaped DSPs - set by dsp_init() */ void __iomem *bar[SND_SOF_BARS]; /* DSP base address */ From b67bd364ca1c1567db273d8e445dda76f1255492 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 14 Jan 2019 10:31:50 -0800 Subject: [PATCH 0774/1995] ASoC: SOF: rename snd_sof_dsp_is_ready() to snd_sof_dsp_is_ipc_ready() Rename snd_sof_dsp_is_ready() to snd_sof_dsp_is_ipc_ready() as it is more intuitive in indicating that the DSP is ready to accept IPC's and update all the users. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/hw-spi.c | 4 ++-- sound/soc/sof/intel/apl.c | 2 +- sound/soc/sof/intel/bdw.c | 4 ++-- sound/soc/sof/intel/byt.c | 8 ++++---- sound/soc/sof/intel/cnl.c | 4 ++-- sound/soc/sof/intel/hda-ipc.c | 2 +- sound/soc/sof/intel/hda.h | 2 +- sound/soc/sof/intel/hsw.c | 4 ++-- sound/soc/sof/intel/skl.c | 2 +- sound/soc/sof/ipc.c | 4 ++-- sound/soc/sof/ops.h | 6 +++--- sound/soc/sof/sof-priv.h | 2 +- 12 files changed, 22 insertions(+), 22 deletions(-) diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index 9b937453f75b7b..426f276d2c232c 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -181,7 +181,7 @@ static irqreturn_t spi_irq_thread(int irq __maybe_unused, void *context __maybe_ return IRQ_HANDLED; } -static int spi_is_ready(struct snd_sof_dev *sdev __maybe_unused) +static int spi_is_ipc_ready(struct snd_sof_dev *sdev __maybe_unused) { // use local variable to store DSP command state. either DSP is ready // for new cmd or still processing current cmd. @@ -300,7 +300,7 @@ const struct snd_sof_dsp_ops snd_sof_spi_ops = { .send_msg = spi_send_msg, .get_reply = spi_get_reply, .fw_ready = spi_fw_ready, - .is_ready = spi_is_ready, + .is_ipc_ready = spi_is_ipc_ready, .cmd_done = spi_cmd_done, /* debug */ diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 054baf27abc08b..bcad8edb079d98 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -52,7 +52,7 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .send_msg = hda_dsp_ipc_send_msg, .get_reply = hda_dsp_ipc_get_reply, .fw_ready = hda_dsp_ipc_fw_ready, - .is_ready = hda_dsp_ipc_is_ready, + .is_ipc_ready = hda_dsp_is_ipc_ready, .cmd_done = hda_dsp_ipc_cmd_done, /* debug */ diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 554ceab298351e..ec4aa750b09a7d 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -450,7 +450,7 @@ static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) * IPC Mailbox IO */ -static int bdw_is_ready(struct snd_sof_dev *sdev) +static int bdw_is_ipc_ready(struct snd_sof_dev *sdev) { u32 val; @@ -673,7 +673,7 @@ const struct snd_sof_dsp_ops sof_bdw_ops = { .send_msg = bdw_send_msg, .get_reply = bdw_get_reply, .fw_ready = bdw_fw_ready, - .is_ready = bdw_is_ready, + .is_ipc_ready = bdw_is_ipc_ready, .cmd_done = bdw_cmd_done, /* debug */ diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 5f05651a89a4de..2f59d6672e10aa 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -333,7 +333,7 @@ static irqreturn_t byt_irq_thread(int irq, void *context) return IRQ_HANDLED; } -static int byt_is_ready(struct snd_sof_dev *sdev) +static int byt_is_ipc_ready(struct snd_sof_dev *sdev) { u64 ipcx; @@ -615,7 +615,7 @@ const struct snd_sof_dsp_ops sof_tng_ops = { .send_msg = byt_send_msg, .get_reply = byt_get_reply, .fw_ready = byt_fw_ready, - .is_ready = byt_is_ready, + .is_ipc_ready = byt_is_ipc_ready, .cmd_done = byt_cmd_done, /* debug */ @@ -777,7 +777,7 @@ const struct snd_sof_dsp_ops sof_byt_ops = { .send_msg = byt_send_msg, .get_reply = byt_get_reply, .fw_ready = byt_fw_ready, - .is_ready = byt_is_ready, + .is_ipc_ready = byt_is_ipc_ready, .cmd_done = byt_cmd_done, /* debug */ @@ -834,7 +834,7 @@ const struct snd_sof_dsp_ops sof_cht_ops = { .send_msg = byt_send_msg, .get_reply = byt_get_reply, .fw_ready = byt_fw_ready, - .is_ready = byt_is_ready, + .is_ipc_ready = byt_is_ipc_ready, .cmd_done = byt_cmd_done, /* debug */ diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index bcc9820d57968c..6b3bda8c5e17f2 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -147,7 +147,7 @@ static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev, int dir) return 0; } -static int cnl_ipc_is_ready(struct snd_sof_dev *sdev) +static int cnl_is_ipc_ready(struct snd_sof_dev *sdev) { u64 busy, done; @@ -202,7 +202,7 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .send_msg = cnl_ipc_send_msg, .get_reply = hda_dsp_ipc_get_reply, .fw_ready = hda_dsp_ipc_fw_ready, - .is_ready = cnl_ipc_is_ready, + .is_ipc_ready = cnl_is_ipc_ready, .cmd_done = cnl_ipc_cmd_done, /* debug */ diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 934a0979a87560..03e8e3e1dca84e 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -55,7 +55,7 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir) return 0; } -int hda_dsp_ipc_is_ready(struct snd_sof_dev *sdev) +int hda_dsp_is_ipc_ready(struct snd_sof_dev *sdev) { u64 busy, done; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 54b817358e3101..79953d05d020c5 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -466,7 +466,7 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, /* * DSP IPC Operations. */ -int hda_dsp_ipc_is_ready(struct snd_sof_dev *sdev); +int hda_dsp_is_ipc_ready(struct snd_sof_dev *sdev); int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 5bd79a56994ba2..174f8dabca93fa 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -451,7 +451,7 @@ static int hsw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) * IPC Mailbox IO */ -static int hsw_is_ready(struct snd_sof_dev *sdev) +static int hsw_is_ipc_ready(struct snd_sof_dev *sdev) { u32 val; @@ -673,7 +673,7 @@ const struct snd_sof_dsp_ops sof_hsw_ops = { .send_msg = hsw_send_msg, .get_reply = hsw_get_reply, .fw_ready = hsw_fw_ready, - .is_ready = hsw_is_ready, + .is_ipc_ready = hsw_is_ipc_ready, .cmd_done = hsw_cmd_done, /* debug */ diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 433b9ed0ffee51..014720aefdb166 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -52,7 +52,7 @@ const struct snd_sof_dsp_ops sof_skl_ops = { .send_msg = hda_dsp_ipc_send_msg, .get_reply = hda_dsp_ipc_get_reply, .fw_ready = hda_dsp_ipc_fw_ready, - .is_ready = hda_dsp_ipc_is_ready, + .is_ipc_ready = hda_dsp_is_ipc_ready, .cmd_done = hda_dsp_ipc_cmd_done, /* debug */ diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 3bedc64bca673b..1a31492b10fb57 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -271,7 +271,7 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, list_add_tail(&msg->list, &ipc->tx_list); /* schedule the message if not busy */ - if (snd_sof_dsp_is_ready(sdev)) + if (snd_sof_dsp_is_ipc_ready(sdev)) snd_sof_ipc_msgs_tx(sdev); spin_unlock_irq(&sdev->ipc_lock); @@ -292,7 +292,7 @@ static void ipc_tx_next_msg(struct work_struct *work) spin_lock_irq(&sdev->ipc_lock); /* send message if HW ready and message in TX list */ - if (!list_empty(&ipc->tx_list) && snd_sof_dsp_is_ready(sdev)) { + if (!list_empty(&ipc->tx_list) && snd_sof_dsp_is_ipc_ready(sdev)) { /* send first message in TX list */ msg = list_first_entry(&ipc->tx_list, struct snd_sof_ipc_msg, list); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 30f1dc9bdb92bf..b0b7cc1e49392f 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -232,10 +232,10 @@ static inline int snd_sof_dsp_get_reply(struct snd_sof_dev *sdev, return 0; } -static inline int snd_sof_dsp_is_ready(struct snd_sof_dev *sdev) +static inline int snd_sof_dsp_is_ipc_ready(struct snd_sof_dev *sdev) { - if (sof_ops(sdev)->is_ready) - return sof_ops(sdev)->is_ready(sdev); + if (sof_ops(sdev)->is_ipc_ready) + return sof_ops(sdev)->is_ipc_ready(sdev); return 0; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index f836591cedce28..ed0a35d680c488 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -122,7 +122,7 @@ struct snd_sof_dsp_ops { struct snd_sof_ipc_msg *msg); int (*get_reply)(struct snd_sof_dev *sof_dev, struct snd_sof_ipc_msg *msg); - int (*is_ready)(struct snd_sof_dev *sof_dev); + int (*is_ipc_ready)(struct snd_sof_dev *sof_dev); int (*cmd_done)(struct snd_sof_dev *sof_dev, int dir); /* debug */ From cf16ba324fddffa20111a0987a33bccf239f3735 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 14 Jan 2019 12:56:21 -0800 Subject: [PATCH 0775/1995] ASoC: SOF: move msg to reply list only if doorbell succeeds There is a possibility of DSP message doorbell failing. So move the msg to the reply list only if it succeeds. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/ipc.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 1a31492b10fb57..126febbf4fad4b 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -288,6 +288,7 @@ static void ipc_tx_next_msg(struct work_struct *work) container_of(work, struct snd_sof_ipc, tx_kwork); struct snd_sof_dev *sdev = ipc->sdev; struct snd_sof_ipc_msg *msg; + int ret; spin_lock_irq(&sdev->ipc_lock); @@ -296,10 +297,27 @@ static void ipc_tx_next_msg(struct work_struct *work) /* send first message in TX list */ msg = list_first_entry(&ipc->tx_list, struct snd_sof_ipc_msg, list); - list_move(&msg->list, &ipc->reply_list); - snd_sof_dsp_send_msg(sdev, msg); - - ipc_log_header(sdev->dev, "ipc tx", msg->header); + ret = snd_sof_dsp_send_msg(sdev, msg); + if (ret < 0) { + + /* + * if ipc tx fails, the msg will be retained in the + * msg_list, so that it can be re-tried until it + * succeeds or times-out. The ipc re-try mechanism in + * SOF currently relies upon tx_kwork being + * rescheduled, which is not guaranteed. This needs + * to be enhanced with a better mechanism. + */ + dev_err_ratelimited(sdev->dev, + "error: ipc tx failed with error %d\n", + ret); + } else { + + /* message sent. move it to the reply list */ + list_move(&msg->list, &ipc->reply_list); + + ipc_log_header(sdev->dev, "ipc tx", msg->header); + } } spin_unlock_irq(&sdev->ipc_lock); From aa502c7df1135676e78e3355002ed652b638edb4 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 15 Jan 2019 14:40:45 -0800 Subject: [PATCH 0776/1995] ASoC: SOF: tx_kwork scheduling doesn't have to be in locked context Move the call to schedule ipc tx_kwork outside the ipc_lock context. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/ipc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 126febbf4fad4b..bcd56f5a5fa907 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -270,12 +270,12 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, /* add message to transmit list */ list_add_tail(&msg->list, &ipc->tx_list); + spin_unlock_irq(&sdev->ipc_lock); + /* schedule the message if not busy */ if (snd_sof_dsp_is_ipc_ready(sdev)) snd_sof_ipc_msgs_tx(sdev); - spin_unlock_irq(&sdev->ipc_lock); - /* now wait for completion */ return tx_wait_done(ipc, msg, reply_data); } From 216cb93885c2f24a588c11ac705040f1c5fb4b43 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 6 Feb 2019 18:25:50 -0800 Subject: [PATCH 0777/1995] ASoC: intel: sof_rt5682: set platform name for dai links Set platform name for dai links. Signed-off-by: Ranjani Sridharan --- sound/soc/intel/boards/sof_rt5682.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 32065082b9527f..92581a192bc2cc 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "../../codecs/rt5682.h" #include "../../codecs/hdac_hdmi.h" @@ -189,7 +190,8 @@ static struct snd_soc_ops sof_rt5682_ops = { static struct snd_soc_dai_link_component platform_component[] = { { - .name = "sof-audio" + /* name might be overridden during probe */ + .name = "0000:00:1f.3" } }; @@ -346,8 +348,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, static int sof_audio_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_links; + struct snd_soc_acpi_mach *mach; struct sof_card_private *ctx; int dmic_num, hdmi_num; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); if (!ctx) @@ -378,6 +382,14 @@ static int sof_audio_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ctx->hdmi_pcm_list); sof_audio_card_rt5682.dev = &pdev->dev; + mach = (&pdev->dev)->platform_data; + + /* set platform name for each dailink */ + ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_rt5682, + mach->mach_params.platform); + if (ret) + return ret; + snd_soc_card_set_drvdata(&sof_audio_card_rt5682, ctx); return devm_snd_soc_register_card(&pdev->dev, From 40660634c69d975ea560f0973b3d030c6063fd0b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 14 Jan 2019 12:27:12 -0800 Subject: [PATCH 0778/1995] ASoC: SOF: fix return values for mandatory ops Clarify the mandatory and optional dsp ops and fix return value for mandatory ops. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/ops.h | 60 +++++++++++++++----- sound/soc/sof/sof-priv.h | 119 +++++++++++++++++++++------------------ 2 files changed, 110 insertions(+), 69 deletions(-) diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index b0b7cc1e49392f..c6374f0210e987 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -27,7 +27,8 @@ static inline int snd_sof_probe(struct snd_sof_dev *sdev) if (sof_ops(sdev)->probe) return sof_ops(sdev)->probe(sdev); - return 0; + dev_err(sdev->dev, "error: %s not defined\n", __func__); + return -ENOTSUPP; } static inline int snd_sof_remove(struct snd_sof_dev *sdev) @@ -44,7 +45,8 @@ static inline int snd_sof_dsp_run(struct snd_sof_dev *sdev) if (sof_ops(sdev)->run) return sof_ops(sdev)->run(sdev); - return 0; + dev_err(sdev->dev, "error: %s not defined\n", __func__); + return -ENOTSUPP; } static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev) @@ -152,15 +154,23 @@ static inline void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, u32 flags) static inline void snd_sof_dsp_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 value) { - if (sof_ops(sdev)->write) + if (sof_ops(sdev)->write) { sof_ops(sdev)->write(sdev, sdev->bar[bar] + offset, value); + return; + } + + dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__); } static inline void snd_sof_dsp_write64(struct snd_sof_dev *sdev, u32 bar, u32 offset, u64 value) { - if (sof_ops(sdev)->write64) + if (sof_ops(sdev)->write64) { sof_ops(sdev)->write64(sdev, sdev->bar[bar] + offset, value); + return; + } + + dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__); } static inline u32 snd_sof_dsp_read(struct snd_sof_dev *sdev, u32 bar, @@ -169,7 +179,8 @@ static inline u32 snd_sof_dsp_read(struct snd_sof_dev *sdev, u32 bar, if (sof_ops(sdev)->read) return sof_ops(sdev)->read(sdev, sdev->bar[bar] + offset); - return 0; + dev_err(sdev->dev, "error: %s not defined\n", __func__); + return -ENOTSUPP; } static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar, @@ -178,22 +189,31 @@ static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar, if (sof_ops(sdev)->read64) return sof_ops(sdev)->read64(sdev, sdev->bar[bar] + offset); - return 0; + dev_err(sdev->dev, "error: %s not defined\n", __func__); + return -ENOTSUPP; } /* block IO */ static inline void snd_sof_dsp_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, size_t bytes) { - if (sof_ops(sdev)->block_read) + if (sof_ops(sdev)->block_read) { sof_ops(sdev)->block_read(sdev, bar, offset, dest, bytes); + return; + } + + dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__); } static inline void snd_sof_dsp_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, size_t bytes) { - if (sof_ops(sdev)->block_write) + if (sof_ops(sdev)->block_write) { sof_ops(sdev)->block_write(sdev, bar, offset, src, bytes); + return; + } + + dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__); } /* mailbox */ @@ -201,16 +221,24 @@ static inline void snd_sof_dsp_mailbox_read(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes) { - if (sof_ops(sdev)->mailbox_read) + if (sof_ops(sdev)->mailbox_read) { sof_ops(sdev)->mailbox_read(sdev, offset, message, bytes); + return; + } + + dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__); } static inline void snd_sof_dsp_mailbox_write(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes) { - if (sof_ops(sdev)->mailbox_write) + if (sof_ops(sdev)->mailbox_write) { sof_ops(sdev)->mailbox_write(sdev, offset, message, bytes); + return; + } + + dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__); } /* ipc */ @@ -220,7 +248,8 @@ static inline int snd_sof_dsp_send_msg(struct snd_sof_dev *sdev, if (sof_ops(sdev)->send_msg) return sof_ops(sdev)->send_msg(sdev, msg); - return 0; + dev_err(sdev->dev, "error: %s not defined\n", __func__); + return -ENOTSUPP; } static inline int snd_sof_dsp_get_reply(struct snd_sof_dev *sdev, @@ -229,7 +258,8 @@ static inline int snd_sof_dsp_get_reply(struct snd_sof_dev *sdev, if (sof_ops(sdev)->get_reply) return sof_ops(sdev)->get_reply(sdev, msg); - return 0; + dev_err(sdev->dev, "error: %s not defined\n", __func__); + return -ENOTSUPP; } static inline int snd_sof_dsp_is_ipc_ready(struct snd_sof_dev *sdev) @@ -237,7 +267,8 @@ static inline int snd_sof_dsp_is_ipc_ready(struct snd_sof_dev *sdev) if (sof_ops(sdev)->is_ipc_ready) return sof_ops(sdev)->is_ipc_ready(sdev); - return 0; + dev_err(sdev->dev, "error: %s not defined\n", __func__); + return -ENOTSUPP; } static inline int snd_sof_dsp_cmd_done(struct snd_sof_dev *sdev, @@ -246,7 +277,8 @@ static inline int snd_sof_dsp_cmd_done(struct snd_sof_dev *sdev, if (sof_ops(sdev)->cmd_done) return sof_ops(sdev)->cmd_done(sdev, dir); - return 0; + dev_err(sdev->dev, "error: %s not defined\n", __func__); + return -ENOTSUPP; } /* host DMA trace */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index ed0a35d680c488..f0cd75213d5a3b 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -67,105 +67,114 @@ struct snd_sof_pdata; * and DSP device(s). */ struct snd_sof_dsp_ops { + /* probe and remove */ - int (*remove)(struct snd_sof_dev *sof_dev); - int (*probe)(struct snd_sof_dev *sof_dev); + int (*probe)(struct snd_sof_dev *sof_dev); /* mandatory */ + int (*remove)(struct snd_sof_dev *sof_dev); /* optional */ /* DSP core boot / reset */ - int (*run)(struct snd_sof_dev *sof_dev); - int (*stall)(struct snd_sof_dev *sof_dev); - int (*reset)(struct snd_sof_dev *sof_dev); + int (*run)(struct snd_sof_dev *sof_dev); /* mandatory */ + int (*stall)(struct snd_sof_dev *sof_dev); /* optional */ + int (*reset)(struct snd_sof_dev *sof_dev); /* optional */ int (*core_power_up)(struct snd_sof_dev *sof_dev, - unsigned int core_mask); + unsigned int core_mask); /* optional */ int (*core_power_down)(struct snd_sof_dev *sof_dev, - unsigned int core_mask); - - /* pre/post firmware run */ - int (*pre_fw_run)(struct snd_sof_dev *sof_dev); - int (*post_fw_run)(struct snd_sof_dev *sof_dev); - - /* DSP PM */ - int (*suspend)(struct snd_sof_dev *sof_dev, int state); - int (*resume)(struct snd_sof_dev *sof_dev); - int (*runtime_suspend)(struct snd_sof_dev *sof_dev, int state); - int (*runtime_resume)(struct snd_sof_dev *sof_dev); - - /* DSP clocking */ - int (*set_clk)(struct snd_sof_dev *sof_dev, u32 freq); + unsigned int core_mask); /* optional */ /* Register IO */ void (*write)(struct snd_sof_dev *sof_dev, void __iomem *addr, - u32 value); - u32 (*read)(struct snd_sof_dev *sof_dev, void __iomem *addr); + u32 value); /* mandatory */ + u32 (*read)(struct snd_sof_dev *sof_dev, + void __iomem *addr); /* mandatory */ void (*write64)(struct snd_sof_dev *sof_dev, void __iomem *addr, - u64 value); - u64 (*read64)(struct snd_sof_dev *sof_dev, void __iomem *addr); + u64 value); /* mandatory */ + u64 (*read64)(struct snd_sof_dev *sof_dev, + void __iomem *addr); /* mandatory */ /* memcpy IO */ void (*block_read)(struct snd_sof_dev *sof_dev, u32 bar, - u32 offset, void *dest, size_t size); + u32 offset, void *dest, + size_t size); /* mandatory */ void (*block_write)(struct snd_sof_dev *sof_dev, u32 bar, - u32 offset, void *src, size_t size); + u32 offset, void *src, + size_t size); /* mandatory */ /* doorbell */ - irqreturn_t (*irq_handler)(int irq, void *context); - irqreturn_t (*irq_thread)(int irq, void *context); + irqreturn_t (*irq_handler)(int irq, void *context); /* mandatory */ + irqreturn_t (*irq_thread)(int irq, void *context); /* mandatory */ /* mailbox */ void (*mailbox_read)(struct snd_sof_dev *sof_dev, u32 offset, - void *addr, size_t bytes); + void *addr, size_t bytes); /* mandatory */ void (*mailbox_write)(struct snd_sof_dev *sof_dev, u32 offset, - void *addr, size_t bytes); + void *addr, size_t bytes); /* mandatory */ /* ipc */ int (*send_msg)(struct snd_sof_dev *sof_dev, - struct snd_sof_ipc_msg *msg); + struct snd_sof_ipc_msg *msg); /* mandatory */ int (*get_reply)(struct snd_sof_dev *sof_dev, - struct snd_sof_ipc_msg *msg); - int (*is_ipc_ready)(struct snd_sof_dev *sof_dev); - int (*cmd_done)(struct snd_sof_dev *sof_dev, int dir); + struct snd_sof_ipc_msg *msg); /* mandatory */ + int (*is_ipc_ready)(struct snd_sof_dev *sof_dev); /* mandatory */ + int (*cmd_done)(struct snd_sof_dev *sof_dev, int dir); /* mandatory */ - /* debug */ - const struct snd_sof_debugfs_map *debug_map; - int debug_map_count; - void (*dbg_dump)(struct snd_sof_dev *sof_dev, u32 flags); + /* FW loading */ + int (*load_firmware)(struct snd_sof_dev *sof_dev); /* mandatory */ + int (*load_module)(struct snd_sof_dev *sof_dev, + struct snd_sof_mod_hdr *hdr); /* optional */ + /* + * FW ready checks for ABI compatibility and creates + * memory windows at first boot + */ + int (*fw_ready)(struct snd_sof_dev *sdev, u32 msg_id); /* mandatory */ /* connect pcm substream to a host stream */ int (*pcm_open)(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream); + struct snd_pcm_substream *substream); /* optional */ /* disconnect pcm substream to a host stream */ int (*pcm_close)(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream); + struct snd_pcm_substream *substream); /* optional */ /* host stream hw params */ int (*pcm_hw_params)(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, - struct sof_ipc_stream_params *ipc_params); + struct sof_ipc_stream_params *ipc_params); /* optional */ /* host stream trigger */ int (*pcm_trigger)(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, int cmd); + struct snd_pcm_substream *substream, + int cmd); /* optional */ /* host stream pointer */ snd_pcm_uframes_t (*pcm_pointer)(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream); + struct snd_pcm_substream *substream); /* optional */ - /* FW loading */ - int (*load_firmware)(struct snd_sof_dev *sof_dev); - int (*load_module)(struct snd_sof_dev *sof_dev, - struct snd_sof_mod_hdr *hdr); + /* pre/post firmware run */ + int (*pre_fw_run)(struct snd_sof_dev *sof_dev); /* optional */ + int (*post_fw_run)(struct snd_sof_dev *sof_dev); /* optional */ - /* - * FW ready checks for ABI compatibility and creates - * memory windows at first boot - */ - int (*fw_ready)(struct snd_sof_dev *sdev, u32 msg_id); + /* DSP PM */ + int (*suspend)(struct snd_sof_dev *sof_dev, int state); /* optional */ + int (*resume)(struct snd_sof_dev *sof_dev); /* optional */ + int (*runtime_suspend)(struct snd_sof_dev *sof_dev, + int state); /* optional */ + int (*runtime_resume)(struct snd_sof_dev *sof_dev); /* optional */ + + /* DSP clocking */ + int (*set_clk)(struct snd_sof_dev *sof_dev, u32 freq); /* optional */ + + /* debug */ + const struct snd_sof_debugfs_map *debug_map; /* optional */ + int debug_map_count; /* optional */ + void (*dbg_dump)(struct snd_sof_dev *sof_dev, + u32 flags); /* optional */ /* host DMA trace initialization */ - int (*trace_init)(struct snd_sof_dev *sdev, u32 *stream_tag); - int (*trace_release)(struct snd_sof_dev *sdev); - int (*trace_trigger)(struct snd_sof_dev *sdev, int cmd); + int (*trace_init)(struct snd_sof_dev *sdev, + u32 *stream_tag); /* optional */ + int (*trace_release)(struct snd_sof_dev *sdev); /* optional */ + int (*trace_trigger)(struct snd_sof_dev *sdev, + int cmd); /* optional */ /* DAI ops */ struct snd_soc_dai_driver *drv; From fc004c56e27cc6c0922a2c91d3ffa7afc9f6c0e6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 25 Jan 2019 17:11:32 +0100 Subject: [PATCH 0779/1995] ALSA: pcm: Fix tight loop of OSS capture stream When the trigger=off is passed for a PCM OSS stream, it sets the start_threshold of the given substream to the boundary size, so that it won't be automatically started. This can be problematic for a capture stream, unfortunately, as detected by syzkaller. The scenario is like the following: - In __snd_pcm_lib_xfer() that is invoked from snd_pcm_oss_read() loop, we have a check whether the stream was already started or the stream can be auto-started. - The function at this check returns 0 with trigger=off since we explicitly disable the auto-start. - The loop continues and repeats calling __snd_pcm_lib_xfer() tightly, which may lead to an RCU stall. This patch fixes the bug by simply allowing the wait for non-started stream in the case of OSS capture. For native usages, it's supposed to be done by the caller side (which is user-space), hence it returns zero like before. (In theory, __snd_pcm_lib_xfer() could wait even for the native API usage cases, too; but I'd like to stay in a safer side for not breaking the existing stuff for now.) Reported-by: syzbot+fbe0496f92a0ce7b786c@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai (cherry picked from commit e190161f96b88ffae870405fd6c3fdd1d2e7f98d) --- sound/core/pcm_lib.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 40013b26f67196..6c99fa8ac5fa18 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2112,6 +2112,13 @@ int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream, return 0; } +/* allow waiting for a capture stream that hasn't been started */ +#if IS_ENABLED(CONFIG_SND_PCM_OSS) +#define wait_capture_start(substream) ((substream)->oss.oss) +#else +#define wait_capture_start(substream) false +#endif + /* the common loop for read/write data */ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, void *data, bool interleaved, @@ -2182,7 +2189,7 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, err = snd_pcm_start(substream); if (err < 0) goto _end_unlock; - } else { + } else if (!wait_capture_start(substream)) { /* nothing to do */ err = 0; goto _end_unlock; From 1bc6ca5d416f7eab120b148764df855c8a854c18 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 28 Jan 2019 10:40:24 +0900 Subject: [PATCH 0780/1995] ASoC: soc-core: use for_each_link_codecs() for dai_link codecs V2 We can use for_each_link_codecs() without waiting for_each_rtd_codec_dai() on soc_bind_dai_link(). Let's use for_each macro. Fixes: 50acc7e49 ("ASoC: core: Fix multi-CODEC setups") Fixes: 10dff9b0d ("ASoC: soc-core: use for_each_link_codecs() for dai_link codecs") Signed-off-by: Kuninori Morimoto Tested-by: Sylwester Nawrocki Signed-off-by: Mark Brown (cherry picked from commit 720734a0b66f9ca42ec6663a48702b16e49552ee) --- sound/soc/soc-core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7f5e8abd5cb787..d6b5edba8d2d6f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -875,7 +875,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct snd_soc_dai_link_component *codecs; struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; struct snd_soc_dai **codec_dais; @@ -910,13 +910,12 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ - /* we can use for_each_rtd_codec_dai() after this */ codec_dais = rtd->codec_dais; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dais[i] = snd_soc_find_dai(&codecs[i]); + for_each_link_codecs(dai_link, i, codecs) { + codec_dais[i] = snd_soc_find_dai(codecs); if (!codec_dais[i]) { dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", - codecs[i].dai_name); + codecs->dai_name); goto _err_defer; } snd_soc_rtdcom_add(rtd, codec_dais[i]->component); From 9fdc017e48dcb40bc50409b2304b86557ea64097 Mon Sep 17 00:00:00 2001 From: Dimitris Papavasiliou Date: Sat, 26 Jan 2019 15:17:01 +0200 Subject: [PATCH 0781/1995] ASoC: pcm512x: Implement the set_bclk_ratio interface Some boards, such as the HiFiBerry DAC+ Pro, use a pair of external oscillators, to generate 44.1 or 48kHz multiples and are forced to resort to hacks [1] in order to support 24-bit data without ending up with fractional dividers. This patch allows the machine driver to use 32-bit frames for 24-bit data to avoid such issues. Although the datasheet (p. 15) seems to suggest that only a handful of ratios are supported, it's not very explicit about it, so we allow the full range of values supported by the underlying register in the callback, to avoid needlessly rejecting potentially usable configurations. [1] http://mailman.alsa-project.org/pipermail/alsa-devel/2018-December/143442.html Signed-off-by: Dimitris Papavasiliou Signed-off-by: Mark Brown (cherry picked from commit ccc8d6c7b6d2f521a4b10c7f6d027f46c7a686bf) --- sound/soc/codecs/pcm512x.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 4cc24a5d5c3167..ce8c5dbd21641e 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -55,6 +55,7 @@ struct pcm512x_priv { unsigned long overclock_dsp; int mute; struct mutex mutex; + unsigned int bclk_ratio; }; /* @@ -915,10 +916,15 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, int fssp; int gpio; - lrclk_div = snd_soc_params_to_frame_size(params); - if (lrclk_div == 0) { - dev_err(dev, "No LRCLK?\n"); - return -EINVAL; + if (pcm512x->bclk_ratio > 0) { + lrclk_div = pcm512x->bclk_ratio; + } else { + lrclk_div = snd_soc_params_to_frame_size(params); + + if (lrclk_div == 0) { + dev_err(dev, "No LRCLK?\n"); + return -EINVAL; + } } if (!pcm512x->pll_out) { @@ -1383,6 +1389,19 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static int pcm512x_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + struct snd_soc_component *component = dai->component; + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + + if (ratio > 256) + return -EINVAL; + + pcm512x->bclk_ratio = ratio; + + return 0; +} + static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_component *component = dai->component; @@ -1435,6 +1454,7 @@ static const struct snd_soc_dai_ops pcm512x_dai_ops = { .hw_params = pcm512x_hw_params, .set_fmt = pcm512x_set_fmt, .digital_mute = pcm512x_digital_mute, + .set_bclk_ratio = pcm512x_set_bclk_ratio, }; static struct snd_soc_dai_driver pcm512x_dai = { From a9fc9c548955c034c75db94f9ade2c2989e694f5 Mon Sep 17 00:00:00 2001 From: Dimitris Papavasiliou Date: Sat, 26 Jan 2019 15:23:45 +0200 Subject: [PATCH 0782/1995] ASoC: pcm512x: Fix clocking calculations when not using the PLL The rationale behind the current calculation is somewhat obscure [1] and can yield slightly wrong dividers in certain cases, which the machine drivers for some boards (like the HiFiBerry DAC+ Pro) seemingly try to circumvent, by updating the rate fraction so as to suit this calculation. The updated calculation should correctly yield the smallest bit clock rate that would fit the frame. [1] http://mailman.alsa-project.org/pipermail/alsa-devel/2019-January/144219.html Signed-off-by: Dimitris Papavasiliou Signed-off-by: Mark Brown (cherry picked from commit 51b033c2608147efe3a5368bfa64837e772d8c55) --- sound/soc/codecs/pcm512x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index ce8c5dbd21641e..ae3bd533eadb5a 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -929,8 +929,8 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, if (!pcm512x->pll_out) { sck_rate = clk_get_rate(pcm512x->sclk); - bclk_div = params->rate_den * 64 / lrclk_div; - bclk_rate = DIV_ROUND_CLOSEST(sck_rate, bclk_div); + bclk_rate = params_rate(params) * lrclk_div; + bclk_div = DIV_ROUND_CLOSEST(sck_rate, bclk_rate); mck_rate = sck_rate; } else { From 1d2314f5fde28a6a8631c04cea5a453579617b63 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:16:17 -0600 Subject: [PATCH 0783/1995] ASoC: soc-acpi: add static inline fallbacks when CONFIG_ACPI=n Fix compilation issues reported by 0day-Kbuild with sparc64 w/ SOF. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 5e484ec1758b95e6420787fc17f0e8c5e152c264) --- include/sound/soc-acpi.h | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 266e64e3c24c4f..6cbbeed9cdd0c8 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -22,20 +22,37 @@ struct snd_soc_acpi_package_context { #define SND_ACPI_I2C_ID_LEN (4 + ACPI_ID_LEN + 3 + 1) #if IS_ENABLED(CONFIG_ACPI) +/* acpi match */ +struct snd_soc_acpi_mach * +snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines); + bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], struct snd_soc_acpi_package_context *ctx); + +/* check all codecs */ +struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg); + #else +/* acpi match */ +static inline struct snd_soc_acpi_mach * +snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines) +{ + return NULL; +} + static inline bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], struct snd_soc_acpi_package_context *ctx) { return false; } -#endif -/* acpi match */ -struct snd_soc_acpi_mach * -snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines); +/* check all codecs */ +static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) +{ + return NULL; +} +#endif /** * snd_soc_acpi_mach_params: interface for machine driver configuration @@ -105,7 +122,4 @@ struct snd_soc_acpi_codecs { u8 codecs[SND_SOC_ACPI_MAX_CODECS][ACPI_ID_LEN]; }; -/* check all codecs */ -struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg); - #endif From 4af5faf93d19d816621df96ac4b4d93af9d9802b Mon Sep 17 00:00:00 2001 From: Yizhuo Date: Fri, 25 Jan 2019 10:45:37 -0800 Subject: [PATCH 0784/1995] ASoC: rt5651: Variable "ret" in function rt5651_i2c_probe() could be uninitialized In function rt5651_i2c_probe(), local variable "ret" could be uninitialized if function regmap_read() returns -EINVAL. However, this value is used in if statement. This is potentially unsafe. Signed-off-by: Yizhuo Signed-off-by: Mark Brown (cherry picked from commit e20bfeb0b7d808bc05e7c4cb1f492cd31d837da0) --- sound/soc/codecs/rt5651.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 75994297c8964a..29b2d60076b022 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -2181,6 +2181,7 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, { struct rt5651_priv *rt5651; int ret; + int err; rt5651 = devm_kzalloc(&i2c->dev, sizeof(*rt5651), GFP_KERNEL); @@ -2197,7 +2198,10 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, return ret; } - regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret); + err = regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret); + if (err) + return err; + if (ret != RT5651_DEVICE_ID_VALUE) { dev_err(&i2c->dev, "Device with ID register %#x is not rt5651\n", ret); From 21942328e67d50036f5334ba44b0dbd04f153ce7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:55 -0600 Subject: [PATCH 0785/1995] ASoC: add helper to change platform name for all dailinks To reuse the same machine drivers with Atom/SST, Skylake and SOF, we need to change the default platform_name (or platforms->name in the "modern" representation). So far, this override was done with an automatic override, which was broken by a set of changes for DT platforms related to deferred probe handling. This automatic override is actually not really needed, the machine driver can already receive the platform name as a platform_data parameter. This is used e.g. for HDaudio support where we have different PCI aliases used for different platforms. We can reuse the same mechanism and modify the machine drivers to override the dailinks prior to registrating the card. This will require additional work for SOF, but with this helper it'll be just two lines of additional code per machine driver which is reused, not the end of the world. This helper can be simplified when all drivers have transitioned to the "modern" representation of dailinks. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit cb50358b83846e4dcb37137c431327c4dd68561b) --- include/sound/soc.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 3089257ead9544..95689680336bd1 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1580,6 +1580,37 @@ struct snd_soc_dai *snd_soc_card_get_codec_dai(struct snd_soc_card *card, return NULL; } +static inline +int snd_soc_fixup_dai_links_platform_name(struct snd_soc_card *card, + const char *platform_name) +{ + struct snd_soc_dai_link *dai_link; + const char *name; + int i; + + if (!platform_name) /* nothing to do */ + return 0; + + /* set platform name for each dailink */ + for_each_card_prelinks(card, i, dai_link) { + name = devm_kstrdup(card->dev, platform_name, GFP_KERNEL); + if (!name) + return -ENOMEM; + + if (dai_link->platforms) + /* only single platform is supported for now */ + dai_link->platforms->name = name; + else + /* + * legacy mode, this case will be removed when all + * derivers are switched to modern style dai_link. + */ + dai_link->platform_name = name; + } + + return 0; +} + #ifdef CONFIG_DEBUG_FS extern struct dentry *snd_soc_debugfs_root; #endif From 7bed3be31d1b5a7c4890b65573f8a2717a29c74b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:56 -0600 Subject: [PATCH 0786/1995] ASoC: Intel: haswell: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit e87055d732e34d8f5fa95da686958b30a03da5b4) --- sound/soc/intel/boards/haswell.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index a4022983a7ce00..971226d420420b 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "../common/sst-dsp.h" @@ -189,8 +190,22 @@ static struct snd_soc_card haswell_rt5640 = { static int haswell_audio_probe(struct platform_device *pdev) { + struct snd_soc_acpi_mach *mach; + const char *platform_name = NULL; + int ret; + haswell_rt5640.dev = &pdev->dev; + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + if (mach) /* extra check since legacy does not pass parameters */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&haswell_rt5640, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, &haswell_rt5640); } From db39b4a27a06aedea1026dc52b3a043bfcd491a5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:57 -0600 Subject: [PATCH 0787/1995] ASoC: Intel: broadwell: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 2d067b2807f9d3381a37acef1b2f43682a868c7a) --- sound/soc/intel/boards/broadwell.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 99f2a0156ae88c..b86c746d9b7a86 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "../common/sst-dsp.h" #include "../haswell/sst-haswell-ipc.h" @@ -267,7 +268,22 @@ static struct snd_soc_card broadwell_rt286 = { static int broadwell_audio_probe(struct platform_device *pdev) { + struct snd_soc_acpi_mach *mach; + const char *platform_name = NULL; + int ret; + broadwell_rt286.dev = &pdev->dev; + + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + if (mach) /* extra check since legacy does not pass parameters */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&broadwell_rt286, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286); } From 156612354417b18881b05e72afac94aa2532b589 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:58 -0600 Subject: [PATCH 0788/1995] ASoC: Intel: bdw-rt5677: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7e40ddcf974a970e750420f88365174cfd207b24) --- sound/soc/intel/boards/bdw-rt5677.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index efcfd906c8562b..1844c88ea4e2a0 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "../common/sst-dsp.h" #include "../haswell/sst-haswell-ipc.h" @@ -339,6 +340,9 @@ static struct snd_soc_card bdw_rt5677_card = { static int bdw_rt5677_probe(struct platform_device *pdev) { struct bdw_rt5677_priv *bdw_rt5677; + struct snd_soc_acpi_mach *mach; + const char *platform_name = NULL; + int ret; bdw_rt5677_card.dev = &pdev->dev; @@ -350,6 +354,16 @@ static int bdw_rt5677_probe(struct platform_device *pdev) return -ENOMEM; } + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + if (mach) /* extra check since legacy does not pass parameters */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&bdw_rt5677_card, + platform_name); + if (ret) + return ret; + snd_soc_card_set_drvdata(&bdw_rt5677_card, bdw_rt5677); return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5677_card); From 18e3aa960e1d56ca16f00d29e6f5107e4ed341e1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:59 -0600 Subject: [PATCH 0789/1995] ASoC: Intel: bytcr_rt5640: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit bd7661b761bc7f585aad4fc6e5b62d684bdad75b) --- sound/soc/intel/boards/bytcr_rt5640.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index a79466c8fb2961..940eb27158da7e 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1153,6 +1153,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; + const char *platform_name; const char *i2c_name = NULL; int ret_val = 0; int dai_index = 0; @@ -1317,6 +1318,14 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); byt_rt5640_card.long_name = byt_rt5640_long_name; + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&byt_rt5640_card, + platform_name); + if (ret_val) + return ret_val; + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); if (ret_val) { From 0473cbe0aa0836b43d82bc97c07a51e514f2aaf8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:00 -0600 Subject: [PATCH 0790/1995] ASoC: Intel: bytcr_rt5651: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 0b2c2093fc3a1f89f2ef15d945c0439ce7b9dd9d) --- sound/soc/intel/boards/bytcr_rt5651.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index e6945d11c8abde..c3b7732929cc76 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -922,6 +922,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) static const char * const mic_name[] = { "dmic", "in1", "in2", "in12" }; struct byt_rt5651_private *priv; struct snd_soc_acpi_mach *mach; + const char *platform_name; struct device *codec_dev; const char *i2c_name = NULL; const char *hp_swapped; @@ -1137,6 +1138,14 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) mic_name[BYT_RT5651_MAP(byt_rt5651_quirk)], hp_swapped); byt_rt5651_card.long_name = byt_rt5651_long_name; + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&byt_rt5651_card, + platform_name); + if (ret_val) + return ret_val; + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card); if (ret_val) { From ff68b45289de92c767b6c18945d656a07815aba6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:01 -0600 Subject: [PATCH 0791/1995] ASoC: Intel: bytcht_da7213: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 686338c12a2bd2d27f8444901fb9ce1a4c0c0b58) --- sound/soc/intel/boards/bytcht_da7213.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index 2179dedb28ad6d..b8e884803777b3 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -225,6 +225,7 @@ static int bytcht_da7213_probe(struct platform_device *pdev) { struct snd_soc_card *card; struct snd_soc_acpi_mach *mach; + const char *platform_name; const char *i2c_name = NULL; int dai_index = 0; int ret_val = 0; @@ -250,6 +251,13 @@ static int bytcht_da7213_probe(struct platform_device *pdev) dailink[dai_index].codec_name = codec_name; } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(card, platform_name); + if (ret_val) + return ret_val; + ret_val = devm_snd_soc_register_card(&pdev->dev, card); if (ret_val) { dev_err(&pdev->dev, From adc50d0a5212c21948633a2c6cbf564ff2edc850 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:02 -0600 Subject: [PATCH 0792/1995] ASoC: Intel: bytcht_es8316: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit e4bc6b1195f64d345646709c4a65edf1fc4d3228) --- sound/soc/intel/boards/bytcht_es8316.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 1364e4e601d837..d2a7e6ba11aec1 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -441,6 +441,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; + const char *platform_name; const char *i2c_name = NULL; struct device *codec_dev; int dai_index = 0; @@ -469,6 +470,14 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_dais[dai_index].codec_name = codec_name; } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&byt_cht_es8316_card, + platform_name); + if (ret) + return ret; + /* Check for BYTCR or other platform and setup quirks */ if (x86_match_cpu(baytrail_cpu_ids) && mach->mach_params.acpi_ipc_irq_index == 0) { From 2584b9480d70961804691132442abdeac6a1151a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:03 -0600 Subject: [PATCH 0793/1995] ASoC: Intel: cht_bsw_max98090_ti: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7e7e24d7c7ff0e85956288915aaa7e682e2ccd55) --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 08a5152e635ac8..3263b0495853c2 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "../../codecs/max98090.h" #include "../atom/sst-atom-controls.h" @@ -420,6 +421,8 @@ static int snd_cht_mc_probe(struct platform_device *pdev) int ret_val = 0; struct cht_mc_private *drv; const char *mclk_name; + struct snd_soc_acpi_mach *mach; + const char *platform_name; int quirks = 0; dmi_id = dmi_first_match(cht_max98090_quirk_table); @@ -442,6 +445,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev) dev_dbg(dev, "Unable to add GPIO mapping table\n"); } + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, + platform_name); + if (ret_val) + return ret_val; + /* register the soc card */ snd_soc_card_cht.dev = &pdev->dev; snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); From 459241f798bcd5a04e27002dcc52c7dc2630998d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:04 -0600 Subject: [PATCH 0794/1995] ASoC: Intel: cht_bsw_nau8824: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 4506db8043341f2351e03d45c0e96c8e1a141dfa) --- sound/soc/intel/boards/cht_bsw_nau8824.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c index 30c46977d53c28..02c2fa23933107 100644 --- a/sound/soc/intel/boards/cht_bsw_nau8824.c +++ b/sound/soc/intel/boards/cht_bsw_nau8824.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include "../atom/sst-atom-controls.h" @@ -246,6 +247,8 @@ static struct snd_soc_card snd_soc_card_cht = { static int snd_cht_mc_probe(struct platform_device *pdev) { struct cht_mc_private *drv; + struct snd_soc_acpi_mach *mach; + const char *platform_name; int ret_val; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); @@ -253,6 +256,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev) return -ENOMEM; snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, + platform_name); + if (ret_val) + return ret_val; + /* register the soc card */ snd_soc_card_cht.dev = &pdev->dev; ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); From f2aeac8c4d9d4e37d285a679b7109cdeddf4a692 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:05 -0600 Subject: [PATCH 0795/1995] ASoC: Intel: cht_bsw_rt5645: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 3a934e7c75b446a104bdea3dd676d7199db9a7bd) --- sound/soc/intel/boards/cht_bsw_rt5645.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 250a356a0cbf08..cbc2d458483f3d 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -530,6 +530,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) { struct snd_soc_card *card = snd_soc_cards[0].soc_card; struct snd_soc_acpi_mach *mach; + const char *platform_name; struct cht_mc_private *drv; const char *i2c_name = NULL; bool found = false; @@ -663,6 +664,14 @@ static int snd_cht_mc_probe(struct platform_device *pdev) cht_rt5645_cpu_dai_name; } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(card, + platform_name); + if (ret_val) + return ret_val; + drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); if (IS_ERR(drv->mclk)) { dev_err(&pdev->dev, From 9a3f7c2d52a15916b07a7da3e7ab8a0846c67fda Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:06 -0600 Subject: [PATCH 0796/1995] ASoC: Intel: cht_bsw_rt5672: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit f403906da05cdea38c222ef472fdc4df29ece47f) --- sound/soc/intel/boards/cht_bsw_rt5672.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 9de64f447e7bed..f1c1f9dd5353db 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -400,6 +400,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) int ret_val = 0; struct cht_mc_private *drv; struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; + const char *platform_name; const char *i2c_name; int i; @@ -426,6 +427,14 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, + platform_name); + if (ret_val) + return ret_val; + drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); if (IS_ERR(drv->mclk)) { dev_err(&pdev->dev, From 60cddaa279e1c4b4e8e0b037505308f9665fd6c9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:07 -0600 Subject: [PATCH 0797/1995] ASoC: Intel: bxt_da7219_max98357a: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7ebf2528eacae2a9c1edff575c3c58b75095ce08) --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 6f052fc8d1e25a..c00925f9da7340 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "../../codecs/hdac_hdmi.h" #include "../../codecs/da7219.h" #include "../../codecs/da7219-aad.h" @@ -584,6 +585,9 @@ static struct snd_soc_card broxton_audio_card = { static int broxton_audio_probe(struct platform_device *pdev) { struct bxt_card_private *ctx; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -594,6 +598,15 @@ static int broxton_audio_probe(struct platform_device *pdev) broxton_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&broxton_audio_card, ctx); + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&broxton_audio_card, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card); } From 71ee5de40933e02d913e5678940802f91f1d646b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:08 -0600 Subject: [PATCH 0798/1995] ASoC: Intel: bxt_rt298: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit fbe2c2736e295bf866110c9278504c42498318c5) --- sound/soc/intel/boards/bxt_rt298.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 27308337ab127a..e91057f83d2058 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include "../../codecs/hdac_hdmi.h" @@ -576,6 +577,9 @@ static int broxton_audio_probe(struct platform_device *pdev) struct bxt_rt286_private *ctx; struct snd_soc_card *card = (struct snd_soc_card *)pdev->id_entry->driver_data; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + int ret; int i; for (i = 0; i < ARRAY_SIZE(broxton_rt298_dais); i++) { @@ -602,6 +606,15 @@ static int broxton_audio_probe(struct platform_device *pdev) card->dev = &pdev->dev; snd_soc_card_set_drvdata(card, ctx); + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(card, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, card); } From 30c284c7cddc017334dec2b74d7b26251d2974a4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:09 -0600 Subject: [PATCH 0799/1995] ASoC: Intel: glk_rt5682_max98357a: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 5b14aa718f5993b0ecee3bbd61557468ac2420bf) --- sound/soc/intel/boards/glk_rt5682_max98357a.c | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index f6597c216fa8d3..d17126f7757cc6 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "../skylake/skl.h" #include "../../codecs/rt5682.h" #include "../../codecs/hdac_hdmi.h" @@ -571,6 +572,10 @@ static struct snd_soc_card glk_audio_card_rt5682_m98357a = { static int geminilake_audio_probe(struct platform_device *pdev) { struct glk_card_private *ctx; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + struct snd_soc_card *card; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -578,11 +583,19 @@ static int geminilake_audio_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - glk_audio_card_rt5682_m98357a.dev = &pdev->dev; - snd_soc_card_set_drvdata(&glk_audio_card_rt5682_m98357a, ctx); + card = &glk_audio_card_rt5682_m98357a; + card->dev = &pdev->dev; + snd_soc_card_set_drvdata(card, ctx); + + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(card, platform_name); + if (ret) + return ret; - return devm_snd_soc_register_card(&pdev->dev, - &glk_audio_card_rt5682_m98357a); + return devm_snd_soc_register_card(&pdev->dev, card); } static const struct platform_device_id glk_board_ids[] = { From e5003598b960578d643e562f152132409b30b1fc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 29 Jan 2019 09:42:20 -0600 Subject: [PATCH 0800/1995] ASoC: Intel: cht_bsw_rt5672: remove useless test For some reason we test if the machine is passed as a parameter before fixing up the codec name. This is unnecessary, generates false positives in static analysis tools and done only in this machine driver, remove and adjust indentation. Reported-by: Colin Ian King Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 53b6d0adffb0505db5332589e78da1c66f7e626a) --- sound/soc/intel/boards/cht_bsw_rt5672.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index f1c1f9dd5353db..3d5a2b3a06f081 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -411,18 +411,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev) strcpy(drv->codec_name, RT5672_I2C_DEFAULT); /* fixup codec name based on HID */ - if (mach) { - i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); - if (i2c_name) { - snprintf(drv->codec_name, sizeof(drv->codec_name), - "i2c-%s", i2c_name); - for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { - if (!strcmp(cht_dailink[i].codec_name, - RT5672_I2C_DEFAULT)) { - cht_dailink[i].codec_name = - drv->codec_name; - break; - } + i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); + if (i2c_name) { + snprintf(drv->codec_name, sizeof(drv->codec_name), + "i2c-%s", i2c_name); + for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { + if (!strcmp(cht_dailink[i].codec_name, + RT5672_I2C_DEFAULT)) { + cht_dailink[i].codec_name = drv->codec_name; + break; } } } From 3cd00fc1c9c80b52df6b15c68a49cd81112c576a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Fri, 25 Jan 2019 14:06:42 -0600 Subject: [PATCH 0801/1995] ASoC: topology: Reduce number of dereferences when accessing dobj MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have passed dobj, there is no reason to access it through containing structs. Signed-off-by: Amadeusz Sławiński Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 33ae6ae2111c3118d8d15eba331b6ba5932825c9) --- sound/soc/soc-topology.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 045ef136903d63..b02c41614f96e3 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -382,10 +382,10 @@ static void remove_mixer(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->control_unload) dobj->ops->control_unload(comp, dobj); - if (sm->dobj.control.kcontrol->tlv.p) - p = sm->dobj.control.kcontrol->tlv.p; - snd_ctl_remove(card, sm->dobj.control.kcontrol); - list_del(&sm->dobj.list); + if (dobj->control.kcontrol->tlv.p) + p = dobj->control.kcontrol->tlv.p; + snd_ctl_remove(card, dobj->control.kcontrol); + list_del(&dobj->list); kfree(sm); kfree(p); } @@ -404,12 +404,12 @@ static void remove_enum(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->control_unload) dobj->ops->control_unload(comp, dobj); - snd_ctl_remove(card, se->dobj.control.kcontrol); - list_del(&se->dobj.list); + snd_ctl_remove(card, dobj->control.kcontrol); + list_del(&dobj->list); - kfree(se->dobj.control.dvalues); + kfree(dobj->control.dvalues); for (i = 0; i < se->items; i++) - kfree(se->dobj.control.dtexts[i]); + kfree(dobj->control.dtexts[i]); kfree(se); } @@ -427,8 +427,8 @@ static void remove_bytes(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->control_unload) dobj->ops->control_unload(comp, dobj); - snd_ctl_remove(card, sb->dobj.control.kcontrol); - list_del(&sb->dobj.list); + snd_ctl_remove(card, dobj->control.kcontrol); + list_del(&dobj->list); kfree(sb); } @@ -464,9 +464,9 @@ static void remove_widget(struct snd_soc_component *comp, snd_ctl_remove(card, kcontrol); - kfree(se->dobj.control.dvalues); + kfree(dobj->control.dvalues); for (j = 0; j < se->items; j++) - kfree(se->dobj.control.dtexts[j]); + kfree(dobj->control.dtexts[j]); kfree(se); kfree(w->kcontrol_news[i].name); From c1da002eb8daaab733ac4e4b98e05875ff02d046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Fri, 25 Jan 2019 14:06:43 -0600 Subject: [PATCH 0802/1995] ASoC: topology: Remove widgets from dobj list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently when we unload and reload machine driver few times we end with corrupted list and try to cleanup no longer existing objects. Fix this by removing dobj from the list. Signed-off-by: Amadeusz Sławiński Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit a46e8393d128d4e5f722b47f708a0d5de91e0176) --- sound/soc/soc-topology.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index b02c41614f96e3..abc2d804d5bf4b 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -493,6 +493,8 @@ static void remove_widget(struct snd_soc_component *comp, free_news: kfree(w->kcontrol_news); + list_del(&dobj->list); + /* widget w is freed by soc-dapm.c */ } From f504955e8e770ce2ded75be551dec443e3fef54f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Fri, 25 Jan 2019 14:06:44 -0600 Subject: [PATCH 0803/1995] ASoC: topology: Fix memory leak from soc_tplg_denum_create_texts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dtexts is two dimensional array, so we also need to free it after freeing its fields. Signed-off-by: Amadeusz Sławiński Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 34db6a3e91d8f6f6fefbbd9ad7e1efc6f8d440e0) --- sound/soc/soc-topology.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index abc2d804d5bf4b..71bc5b8a9bd3c8 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -410,6 +410,7 @@ static void remove_enum(struct snd_soc_component *comp, kfree(dobj->control.dvalues); for (i = 0; i < se->items; i++) kfree(dobj->control.dtexts[i]); + kfree(dobj->control.dtexts); kfree(se); } @@ -467,6 +468,7 @@ static void remove_widget(struct snd_soc_component *comp, kfree(dobj->control.dvalues); for (j = 0; j < se->items; j++) kfree(dobj->control.dtexts[j]); + kfree(dobj->control.dtexts); kfree(se); kfree(w->kcontrol_news[i].name); @@ -1361,6 +1363,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( kfree(se->dobj.control.dvalues); for (j = 0; j < ec->items; j++) kfree(se->dobj.control.dtexts[j]); + kfree(se->dobj.control.dtexts); kfree(se); kfree(kc[i].name); From 9b0e5b972dbc124dbe4e557fcbc41b491a2d17aa Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 25 Jan 2019 14:06:45 -0600 Subject: [PATCH 0804/1995] ASoC: topology: fix memory leak in soc_tplg_dapm_widget_create template.sname and template.name are only freed when an error occur. They should be freed in the success return case, too. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7620fe9161cec2722db880affe03f5e9e2bb93d5) --- sound/soc/soc-topology.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 71bc5b8a9bd3c8..2cb0a05e2368d3 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1583,6 +1583,9 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, if (ret < 0) goto ready_err; + kfree(template.sname); + kfree(template.name); + return 0; ready_err: From 879d88bb447ca4dc700383a2d1763a4d7f7f3867 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 25 Jan 2019 14:06:46 -0600 Subject: [PATCH 0805/1995] ASoC: topology: add SND_SOC_DOBJ_GRAPH type for dapm routes Add a new dobj type SND_SOC_DOBJ_GRAPH for dapm routes and add snd_soc_dobj member to struct snd_soc_dapm_route. This enables device drivers to save driver specific data pertaining to dapm routes and also be able to clean up the data when the driver module is unloaded. Also, reorder the snd_soc_dobj_type types to align with matching topology header types. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 5c30f43f0625a792c30e465f21dbeb1bb4dfc40b) --- include/sound/soc-dapm.h | 2 ++ include/sound/soc-topology.h | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index bd8163f151cb85..46f2ba3ffcb7c1 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -540,6 +540,8 @@ struct snd_soc_dapm_route { /* Note: currently only supported for links where source is a supply */ int (*connected)(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink); + + struct snd_soc_dobj dobj; }; /* dapm audio path between two widgets */ diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index fa4b8413d2e222..8c43cfc240fa33 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -38,12 +38,13 @@ struct snd_soc_dapm_route; enum snd_soc_dobj_type { SND_SOC_DOBJ_NONE = 0, /* object is not dynamic */ SND_SOC_DOBJ_MIXER, - SND_SOC_DOBJ_ENUM, SND_SOC_DOBJ_BYTES, - SND_SOC_DOBJ_PCM, + SND_SOC_DOBJ_ENUM, + SND_SOC_DOBJ_GRAPH, + SND_SOC_DOBJ_WIDGET, SND_SOC_DOBJ_DAI_LINK, + SND_SOC_DOBJ_PCM, SND_SOC_DOBJ_CODEC_LINK, - SND_SOC_DOBJ_WIDGET, }; /* dynamic control object */ From 18006e113a1d6313459f62e6f5d5e2fefe38ec9b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 25 Jan 2019 14:06:47 -0600 Subject: [PATCH 0806/1995] ASoC: topology: modify dapm route loading routine and add dapm route unloading struct snd_soc_dapm_route has been modified to be a dynamic object so that it can be used to save driver specific data while parsing topology and clean up driver-specific data during driver unloading. This patch makes the following changes to accomplish the above: 1. Set the dobj member of snd_soc_dapm_route during the SOC_TPLG_PASS_GRAPH pass of topology parsing. 2. Add the remove_route() routine that will be called while removing all dynamic objects from the component driver. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7df04ea7a31eaa75bdad2905f07cc097b15558ee) --- sound/soc/soc-topology.c | 102 +++++++++++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 16 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 2cb0a05e2368d3..23d421370e6cb3 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -433,6 +433,23 @@ static void remove_bytes(struct snd_soc_component *comp, kfree(sb); } +/* remove a route */ +static void remove_route(struct snd_soc_component *comp, + struct snd_soc_dobj *dobj, int pass) +{ + struct snd_soc_dapm_route *route = + container_of(dobj, struct snd_soc_dapm_route, dobj); + + if (pass != SOC_TPLG_PASS_GRAPH) + return; + + if (dobj->ops && dobj->ops->dapm_route_unload) + dobj->ops->dapm_route_unload(comp, dobj); + + list_del(&dobj->list); + kfree(route); +} + /* remove a widget and it's kcontrols - routes must be removed first */ static void remove_widget(struct snd_soc_component *comp, struct snd_soc_dobj *dobj, int pass) @@ -1119,9 +1136,10 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, struct snd_soc_tplg_hdr *hdr) { struct snd_soc_dapm_context *dapm = &tplg->comp->dapm; - struct snd_soc_dapm_route route; struct snd_soc_tplg_dapm_graph_elem *elem; - int count = hdr->count, i; + struct snd_soc_dapm_route **routes; + int count = hdr->count, i, j; + int ret = 0; if (tplg->pass != SOC_TPLG_PASS_GRAPH) { tplg->pos += hdr->size + hdr->payload_size; @@ -1140,36 +1158,85 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes for index %d\n", count, hdr->index); + /* allocate memory for pointer to array of dapm routes */ + routes = kcalloc(count, sizeof(struct snd_soc_dapm_route *), + GFP_KERNEL); + if (!routes) + return -ENOMEM; + + /* + * allocate memory for each dapm route in the array. + * This needs to be done individually so that + * each route can be freed when it is removed in remove_route(). + */ + for (i = 0; i < count; i++) { + routes[i] = kzalloc(sizeof(*routes[i]), GFP_KERNEL); + if (!routes[i]) { + /* free previously allocated memory */ + for (j = 0; j < i; j++) + kfree(routes[j]); + + kfree(routes); + return -ENOMEM; + } + } + for (i = 0; i < count; i++) { elem = (struct snd_soc_tplg_dapm_graph_elem *)tplg->pos; tplg->pos += sizeof(struct snd_soc_tplg_dapm_graph_elem); /* validate routes */ if (strnlen(elem->source, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { + ret = -EINVAL; + break; + } if (strnlen(elem->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { + ret = -EINVAL; + break; + } if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { + ret = -EINVAL; + break; + } + + routes[i]->source = elem->source; + routes[i]->sink = elem->sink; - route.source = elem->source; - route.sink = elem->sink; - route.connected = NULL; /* set to NULL atm for tplg users */ + /* set to NULL atm for tplg users */ + routes[i]->connected = NULL; if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0) - route.control = NULL; + routes[i]->control = NULL; else - route.control = elem->control; + routes[i]->control = elem->control; + + /* add route dobj to dobj_list */ + routes[i]->dobj.type = SND_SOC_DOBJ_GRAPH; + routes[i]->dobj.ops = tplg->ops; + routes[i]->dobj.index = tplg->index; + list_add(&routes[i]->dobj.list, &tplg->comp->dobj_list); - soc_tplg_add_route(tplg, &route); + soc_tplg_add_route(tplg, routes[i]); /* add route, but keep going if some fail */ - snd_soc_dapm_add_routes(dapm, &route, 1); + snd_soc_dapm_add_routes(dapm, routes[i], 1); } - return 0; + /* free memory allocated for all dapm routes in case of error */ + if (ret < 0) + for (i = 0; i < count ; i++) + kfree(routes[i]); + + /* + * free pointer to array of dapm routes as this is no longer needed. + * The memory allocated for each dapm route will be freed + * when it is removed in remove_route(). + */ + kfree(routes); + + return ret; } static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( @@ -2570,6 +2637,9 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) case SND_SOC_DOBJ_BYTES: remove_bytes(comp, dobj, pass); break; + case SND_SOC_DOBJ_GRAPH: + remove_route(comp, dobj, pass); + break; case SND_SOC_DOBJ_WIDGET: remove_widget(comp, dobj, pass); break; From b8fa7905ed840cd2af8da220f7a674bfdd371197 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Feb 2019 11:05:12 -0600 Subject: [PATCH 0807/1995] ASoC: dapm: fix use-after-free issue with dailink sname Commit 7620fe9161ce ("ASoC: topology: fix memory leak in soc_tplg_dapm_widget_create") fixed a memory leak issue, but additional tests and KASAN reports show a use-after-free in soc-dapm. The widgets are created with a kmemdup operating on a template. The "name" string is also duplicated, but the "sname" string is not. As a result, when the template is freed after widget creation, its sname string is still used. Fix by explicitly duplicating the "sname" string, and freeing it when required. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 199ed3e81c49a621ce6fcb630ab9f30d92db6718) --- sound/soc/soc-dapm.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 2c4c1341953929..e71cd5b660ad09 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -295,7 +295,22 @@ EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty); static inline struct snd_soc_dapm_widget *dapm_cnew_widget( const struct snd_soc_dapm_widget *_widget) { - return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); + struct snd_soc_dapm_widget *w; + + w = kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); + if (!w) + return NULL; + + /* + * w->name is duplicated in caller, but w->sname isn't. + * Duplicate it here if defined + */ + if (_widget->sname) { + w->sname = kstrdup_const(_widget->sname, GFP_KERNEL); + if (!w->sname) + return NULL; + } + return w; } struct dapm_kcontrol_data { @@ -2412,6 +2427,7 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) kfree(w->kcontrols); kfree_const(w->name); + kfree_const(w->sname); kfree(w); } @@ -3469,6 +3485,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, else w->name = kstrdup_const(widget->name, GFP_KERNEL); if (w->name == NULL) { + kfree_const(w->sname); kfree(w); return ERR_PTR(-ENOMEM); } From 7af00f7c479758145969e4bb6fb7b9e1ea207a01 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 1 Feb 2019 11:05:13 -0600 Subject: [PATCH 0808/1995] ASoC: topology: fix oops/use-after-free case with dai driver rmmod/modprobe tests expose a kernel oops when accessing the dai driver pointer. This comes from the topology design which operates in multiple passes. Each object removal happens at a specific iteration, and the code checks for the iteration (order) number after the memory containing the order was freed. Fix this be clearing a reference to the dai driver and check its validity to avoid dereferences. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 52abe6cc1866ac3d54612f5d80563e6608c0ddfc) --- sound/soc/soc-core.c | 2 +- sound/soc/soc-topology.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d6b5edba8d2d6f..9dad2b1498c1db 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -965,7 +965,7 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order) { int err; - if (!dai || !dai->probed || + if (!dai || !dai->probed || !dai->driver || dai->driver->remove_order != order) return; diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 23d421370e6cb3..bb7e5422a419f8 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -523,6 +523,7 @@ static void remove_dai(struct snd_soc_component *comp, { struct snd_soc_dai_driver *dai_drv = container_of(dobj, struct snd_soc_dai_driver, dobj); + struct snd_soc_dai *dai; if (pass != SOC_TPLG_PASS_PCM_DAI) return; @@ -530,6 +531,10 @@ static void remove_dai(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->dai_unload) dobj->ops->dai_unload(comp, dobj); + list_for_each_entry(dai, &comp->dai_list, list) + if (dai->driver == dai_drv) + dai->driver = NULL; + kfree(dai_drv->name); list_del(&dobj->list); kfree(dai_drv); From eddcdf1799e423da4ec322d47c7049a5ebbc1ea1 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 31 Jan 2019 13:30:18 +0000 Subject: [PATCH 0809/1995] ASoC: dapm: Only power up active channels from a DAI Currently all widgets attached to a DAI link will be powered up when the DAI is active, however this may include routes that are not actually in use if there are unused channels available on the DAI. The macros for creating AIF widgets already include an entry for slot, it is proposed to change that to channel. The effective difference here being respresenting the logical channel index rather than the physical slot index. The CODECs currently using the slot entry on the DAPM_AIF macros are using it in a manner consistent with this, the CODECs not using it just have the field set to zero. A variable is added to snd_soc_dapm_widget to represent this channel index and then for each AIF widget attached to a DAI this is compared against the number of channels on the stream. Enabling the links for those which will be in use. This has the nice property that the CODECs which haven't used the slot/channel entry in the macro will function exactly as before due to all the AIF widgets having a channel of zero and a stream by definition having at least one channel. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit 078a85f2806f0ffd11289009462a6a390f9adb5c) --- include/sound/soc-dapm.h | 22 +++++++----- sound/soc/soc-dapm.c | 76 ++++++++++++++++++++++++++++++++++++++++ sound/soc/soc-pcm.c | 4 +++ 3 files changed, 94 insertions(+), 8 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 46f2ba3ffcb7c1..79b4ddfb8e9e22 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -214,21 +214,21 @@ struct device; .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD} /* stream domain */ -#define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \ +#define SND_SOC_DAPM_AIF_IN(wname, stname, wchan, wreg, wshift, winvert) \ { .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ - SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } -#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \ + .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } +#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wchan, wreg, wshift, winvert, \ wevent, wflags) \ { .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ - SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ + .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags } -#define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \ +#define SND_SOC_DAPM_AIF_OUT(wname, stname, wchan, wreg, wshift, winvert) \ { .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ - SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } -#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \ + .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } +#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wchan, wreg, wshift, winvert, \ wevent, wflags) \ { .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ - SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ + .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags } #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \ { .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \ @@ -407,6 +407,10 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card); void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card); +int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); + /* dapm path setup */ int snd_soc_dapm_new_widgets(struct snd_soc_card *card); void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm); @@ -627,6 +631,8 @@ struct snd_soc_dapm_widget { int endpoints[2]; struct clk *clk; + + int channel; }; struct snd_soc_dapm_update { diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index e71cd5b660ad09..36d964a52874e2 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2541,6 +2541,78 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) } EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); +static int dapm_update_dai_chan(struct snd_soc_dapm_path *p, + struct snd_soc_dapm_widget *w, + int channels) +{ + switch (w->id) { + case snd_soc_dapm_aif_out: + case snd_soc_dapm_aif_in: + break; + default: + return 0; + } + + dev_dbg(w->dapm->dev, "%s DAI route %s -> %s\n", + w->channel < channels ? "Connecting" : "Disconnecting", + p->source->name, p->sink->name); + + if (w->channel < channels) + soc_dapm_connect_path(p, true, "dai update"); + else + soc_dapm_connect_path(p, false, "dai update"); + + return 0; +} + +static int dapm_update_dai_unlocked(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int dir = substream->stream; + int channels = params_channels(params); + struct snd_soc_dapm_path *p; + struct snd_soc_dapm_widget *w; + int ret; + + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + w = dai->playback_widget; + else + w = dai->capture_widget; + + dev_dbg(dai->dev, "Update DAI routes for %s %s\n", dai->name, + dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture"); + + snd_soc_dapm_widget_for_each_sink_path(w, p) { + ret = dapm_update_dai_chan(p, p->sink, channels); + if (ret < 0) + return ret; + } + + snd_soc_dapm_widget_for_each_source_path(w, p) { + ret = dapm_update_dai_chan(p, p->source, channels); + if (ret < 0) + return ret; + } + + return 0; +} + +int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int ret; + + mutex_lock_nested(&rtd->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + ret = dapm_update_dai_unlocked(substream, params, dai); + mutex_unlock(&rtd->card->dapm_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_update_dai); + /* * dapm_update_widget_flags() - Re-compute widget sink and source flags * @w: The widget for which to update the flags @@ -3706,6 +3778,8 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, ret = soc_dai_hw_params(&substream, params, source); if (ret < 0) goto out; + + dapm_update_dai_unlocked(&substream, params, source); } substream.stream = SNDRV_PCM_STREAM_PLAYBACK; @@ -3726,6 +3800,8 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, ret = soc_dai_hw_params(&substream, params, sink); if (ret < 0) goto out; + + dapm_update_dai_unlocked(&substream, params, sink); } break; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 03f36e534050f4..a5b40e82dea4ac 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -969,6 +969,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, codec_dai->channels = params_channels(&codec_params); codec_dai->sample_bits = snd_pcm_format_physical_width( params_format(&codec_params)); + + snd_soc_dapm_update_dai(substream, &codec_params, codec_dai); } ret = soc_dai_hw_params(substream, params, cpu_dai); @@ -998,6 +1000,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, cpu_dai->sample_bits = snd_pcm_format_physical_width(params_format(params)); + snd_soc_dapm_update_dai(substream, params, cpu_dai); + ret = soc_pcm_params_symmetry(substream, params); if (ret) goto component_err; From 1756d140f6e03f5051c4db3adef9032fc089e2f1 Mon Sep 17 00:00:00 2001 From: Zhiwei Jiang Date: Thu, 31 Jan 2019 19:30:05 +0800 Subject: [PATCH 0810/1995] ASoC: dapm: Add warnings for widget overwrite when adding route Currently, in some complex cases, more than one widgets have same name and registed from differnt dapm context, and route add from another context too. When snd_soc_dapm_add_route, the previous registered widget will overwritten by the latest same name widget, will cause unexpect error. For Asoc framework we cant avoid this situation and we cant decide which widget that wanted with route. At least we can give users a notice. Signed-off-by: Zhiwei Jiang Signed-off-by: Mark Brown (cherry picked from commit 411db2ab7df35804422e4b26c5849b3868e6a038) --- sound/soc/soc-dapm.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 36d964a52874e2..5b74dffc9c11d6 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2829,6 +2829,8 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, char prefixed_sink[80]; char prefixed_source[80]; const char *prefix; + unsigned int sink_ref = 0; + unsigned int source_ref = 0; int ret; prefix = soc_dapm_prefix(dapm); @@ -2862,6 +2864,11 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, if (wsource) break; } + sink_ref++; + if (sink_ref > 1) + dev_warn(dapm->dev, + "ASoC: sink widget %s overwritten\n", + w->name); continue; } if (!wsource && !(strcmp(w->name, source))) { @@ -2871,6 +2878,11 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, if (wsink) break; } + source_ref++; + if (source_ref > 1) + dev_warn(dapm->dev, + "ASoC: source widget %s overwritten\n", + w->name); } } /* use widget from another DAPM context if not found from this */ From b7afcac68d91e136adbca3c99e026050cb0b8c29 Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Tue, 29 Jan 2019 13:47:09 -0800 Subject: [PATCH 0811/1995] ASoC: soc-core: clear platform pointers on error Originally snd_soc_init_platform was not cleaning up its pointers, this was fixed to always reallocate dynamic memory but created a memory leak when snd_soc_init_platform was called multiple times during the same probe attempt and also threw away any changes made to the struct between calls. In order to avoid reallocating memory that is still valid, the behaviour will be changed to clear the dynamically set pointers on a probe error and a unregister event and snd_soc_init_platform will go back to its original behaviour of only allocating null pointers so it will stop throwing away valid changes. Signed-off-by: Curtis Malainey Signed-off-by: Mark Brown (cherry picked from commit 78a24e10cd94420f1b4e2dc5923ae7109e2aaba1) --- sound/soc/soc-core.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9dad2b1498c1db..994d21d7ba0f69 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1053,7 +1053,7 @@ static int snd_soc_init_platform(struct snd_soc_card *card, * soc.h :: struct snd_soc_dai_link */ /* convert Legacy platform link */ - if (!platform || dai_link->legacy_platform) { + if (!platform) { platform = devm_kzalloc(card->dev, sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); @@ -1076,6 +1076,24 @@ static int snd_soc_init_platform(struct snd_soc_card *card, return 0; } +static void soc_cleanup_platform(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *link; + int i; + /* + * FIXME + * + * this function should be removed with snd_soc_init_platform + */ + + for_each_card_prelinks(card, i, link) { + if (link->legacy_platform) { + link->legacy_platform = 0; + link->platforms = NULL; + } + } +} + static int snd_soc_init_multicodec(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { @@ -2020,6 +2038,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) /* remove and free each DAI */ soc_remove_dai_links(card); soc_remove_pcm_runtimes(card); + soc_cleanup_platform(card); /* remove auxiliary devices */ soc_remove_aux_devices(card); From e8649bd1708d2e144a100c2d3a1e2f00e0c59b74 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 1 Feb 2019 11:07:40 -0600 Subject: [PATCH 0812/1995] ASoC: topology: unload physical dai link in remove soc_tplg_link_config() will find the physical dai link and call soc_tplg_dai_link_load() to load the BE dai link. Currently remove_link() is only used to remove the FE dai link which is created by the topology. The BE dai link cannot however be unloaded in snd_soc_tplg_component _remove(), which is problematic if anything needs to be released or reinitialized. This patch aligns the definitions of dynamic types with the existing UAPI and adds a new remove_backend_link() routine to unload the the BE dai link when snd_soc_tplg_component_remove() is invoked. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit adfebb51e1750c5df9e5d42f505b73c5542a879d) --- include/sound/soc-topology.h | 1 + sound/soc/soc-topology.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index 8c43cfc240fa33..5223896de26f51 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -45,6 +45,7 @@ enum snd_soc_dobj_type { SND_SOC_DOBJ_DAI_LINK, SND_SOC_DOBJ_PCM, SND_SOC_DOBJ_CODEC_LINK, + SND_SOC_DOBJ_BACKEND_LINK, }; /* dynamic control object */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index bb7e5422a419f8..c5638e15a2ddfb 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -562,6 +562,25 @@ static void remove_link(struct snd_soc_component *comp, kfree(link); } +/* unload dai link */ +static void remove_backend_link(struct snd_soc_component *comp, + struct snd_soc_dobj *dobj, int pass) +{ + if (pass != SOC_TPLG_PASS_LINK) + return; + + if (dobj->ops && dobj->ops->link_unload) + dobj->ops->link_unload(comp, dobj); + + /* + * We don't free the link here as what remove_link() do since BE + * links are not allocated by topology. + * We however need to reset the dobj type to its initial values + */ + dobj->type = SND_SOC_DOBJ_NONE; + list_del(&dobj->list); +} + /* bind a kcontrol to it's IO handlers */ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, struct snd_kcontrol_new *k, @@ -2168,6 +2187,12 @@ static int soc_tplg_link_config(struct soc_tplg *tplg, return ret; } + /* for unloading it in snd_soc_tplg_component_remove */ + link->dobj.index = tplg->index; + link->dobj.ops = tplg->ops; + link->dobj.type = SND_SOC_DOBJ_BACKEND_LINK; + list_add(&link->dobj.list, &tplg->comp->dobj_list); + return 0; } @@ -2654,6 +2679,13 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) case SND_SOC_DOBJ_DAI_LINK: remove_link(comp, dobj, pass); break; + case SND_SOC_DOBJ_BACKEND_LINK: + /* + * call link_unload ops if extra + * deinitialization is needed. + */ + remove_backend_link(comp, dobj, pass); + break; default: dev_err(comp->dev, "ASoC: invalid component type %d for removal\n", dobj->type); From e3c3392f50b5958e4272b8b88aebb3d36fe3abc9 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 6 Feb 2019 11:13:59 +0000 Subject: [PATCH 0813/1995] ASoC: dapm: Check for NULL widget in dapm_update_dai_unlocked DAIs linked to the dummy will not have an associated playback/capture widget, so we need to skip the update in that case. Fixes: 078a85f2806f ("ASoC: dapm: Only power up active channels from a DAI") Reported-by: Krzysztof Kozlowski Signed-off-by: Charles Keepax Tested-by: Sylwester Nawrocki Tested-by: Krzysztof Kozlowski Signed-off-by: Mark Brown (cherry picked from commit cf17a5ffd27234371d10748bf1c716ef172877f3) --- sound/soc/soc-dapm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 5b74dffc9c11d6..111a23a9708a27 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2580,6 +2580,9 @@ static int dapm_update_dai_unlocked(struct snd_pcm_substream *substream, else w = dai->capture_widget; + if (!w) + return 0; + dev_dbg(dai->dev, "Update DAI routes for %s %s\n", dai->name, dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture"); From 5292503143a0c2a0c6e81605be49efcdf681b051 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 5 Feb 2019 11:18:12 +0000 Subject: [PATCH 0814/1995] ASoC: compress: Clarify the intent of current compressed ops handling For callbacks configuring the state of the components (trigger, set_params, ack and set_metadata) simplify the code a little and make intention clearer by aborting as soon as an error is encountered. The operation has already failed and there is nothing to be gained from processing the callbacks on additional components. The operations currently abort after the callbacks, so this simply shortens the error path. For callbacks returning information from the driver (copy, get_metadata, pointer, get_codec_caps, get_caps and get_params) only look for the first callback provided, currently the code will call every callback only returning the information provided by the last. Since we can only return one set of data, it makes no sense to request the data from every component. Again this just makes the currently supported feature set a little more clear. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit 52cadf1fdbe87a3a3eee11d9cc4873796903c934) --- sound/soc/soc-compress.c | 106 ++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 58 deletions(-) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 699397a091670d..fc8742383b2302 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -353,7 +353,7 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -364,12 +364,10 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) !component->driver->compr_ops->trigger) continue; - __ret = component->driver->compr_ops->trigger(cstream, cmd); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->trigger(cstream, cmd); + if (ret < 0) + goto out; } - if (ret < 0) - goto out; if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai); @@ -394,7 +392,7 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = fe->cpu_dai; - int ret = 0, __ret, stream; + int ret, stream; if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || cmd == SND_COMPR_TRIGGER_DRAIN) { @@ -406,9 +404,10 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) !component->driver->compr_ops->trigger) continue; - __ret = component->driver->compr_ops->trigger(cstream, cmd); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->trigger(cstream, + cmd); + if (ret < 0) + return ret; } return ret; } @@ -433,12 +432,10 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) !component->driver->compr_ops->trigger) continue; - __ret = component->driver->compr_ops->trigger(cstream, cmd); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->trigger(cstream, cmd); + if (ret < 0) + goto out; } - if (ret < 0) - goto out; fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; @@ -472,7 +469,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -496,12 +493,10 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, !component->driver->compr_ops->set_params) continue; - __ret = component->driver->compr_ops->set_params(cstream, params); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->set_params(cstream, params); + if (ret < 0) + goto err; } - if (ret < 0) - goto err; if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { ret = rtd->dai_link->compr_ops->set_params(cstream); @@ -522,7 +517,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, cancel_delayed_work_sync(&rtd->delayed_work); - return ret; + return 0; err: mutex_unlock(&rtd->pcm_mutex); @@ -538,7 +533,7 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = fe->cpu_dai; - int ret = 0, __ret, stream; + int ret, stream; if (cstream->direction == SND_COMPRESS_PLAYBACK) stream = SNDRV_PCM_STREAM_PLAYBACK; @@ -578,12 +573,10 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, !component->driver->compr_ops->set_params) continue; - __ret = component->driver->compr_ops->set_params(cstream, params); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->set_params(cstream, params); + if (ret < 0) + goto out; } - if (ret < 0) - goto out; if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) { ret = fe->dai_link->compr_ops->set_params(cstream); @@ -607,7 +600,7 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -624,9 +617,8 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, !component->driver->compr_ops->get_params) continue; - __ret = component->driver->compr_ops->get_params(cstream, params); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->get_params(cstream, params); + break; } err: @@ -640,7 +632,7 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -651,9 +643,8 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream, !component->driver->compr_ops->get_caps) continue; - __ret = component->driver->compr_ops->get_caps(cstream, caps); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->get_caps(cstream, caps); + break; } mutex_unlock(&rtd->pcm_mutex); @@ -666,7 +657,7 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -677,9 +668,9 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, !component->driver->compr_ops->get_codec_caps) continue; - __ret = component->driver->compr_ops->get_codec_caps(cstream, codec); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->get_codec_caps(cstream, + codec); + break; } mutex_unlock(&rtd->pcm_mutex); @@ -692,7 +683,7 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -709,9 +700,9 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) !component->driver->compr_ops->ack) continue; - __ret = component->driver->compr_ops->ack(cstream, bytes); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->ack(cstream, bytes); + if (ret < 0) + goto err; } err: @@ -725,7 +716,7 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - int ret = 0, __ret; + int ret = 0; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -740,9 +731,8 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, !component->driver->compr_ops->pointer) continue; - __ret = component->driver->compr_ops->pointer(cstream, tstamp); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->pointer(cstream, tstamp); + break; } mutex_unlock(&rtd->pcm_mutex); @@ -781,7 +771,7 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret; if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_metadata) { ret = cpu_dai->driver->cops->set_metadata(cstream, metadata, cpu_dai); @@ -796,12 +786,13 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream, !component->driver->compr_ops->set_metadata) continue; - __ret = component->driver->compr_ops->set_metadata(cstream, metadata); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->set_metadata(cstream, + metadata); + if (ret < 0) + return ret; } - return ret; + return 0; } static int soc_compr_get_metadata(struct snd_compr_stream *cstream, @@ -811,7 +802,7 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret; if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_metadata) { ret = cpu_dai->driver->cops->get_metadata(cstream, metadata, cpu_dai); @@ -826,12 +817,11 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream, !component->driver->compr_ops->get_metadata) continue; - __ret = component->driver->compr_ops->get_metadata(cstream, metadata); - if (__ret < 0) - ret = __ret; + return component->driver->compr_ops->get_metadata(cstream, + metadata); } - return ret; + return 0; } /* ASoC Compress operations */ From 4da42818008f02c348440f7c618966ea725fd525 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 5 Feb 2019 11:18:13 +0000 Subject: [PATCH 0815/1995] ASoC: compress: Add helper functions for component trigger/set_params The trigger and set_params callbacks are called from 3 and 2 separate loops respectively, tidy up the code a little by factoring these out into helper functions. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit 4ef0ecb80e348f1888b0c7ebfa8f7c1ec3ed9006) --- sound/soc/soc-compress.c | 117 ++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 63 deletions(-) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index fc8742383b2302..03d5b9ccd3fc96 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -345,17 +345,13 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) return 0; } -static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) +static int soc_compr_components_trigger(struct snd_compr_stream *cstream, + int cmd) { - struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0; - - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + int ret; for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -366,9 +362,25 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) ret = component->driver->compr_ops->trigger(cstream, cmd); if (ret < 0) - goto out; + return ret; } + return 0; +} + +static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret; + + mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + + ret = soc_compr_components_trigger(cstream, cmd); + if (ret < 0) + goto out; + if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai); @@ -389,28 +401,12 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) { struct snd_soc_pcm_runtime *fe = cstream->private_data; - struct snd_soc_component *component; - struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = fe->cpu_dai; int ret, stream; if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || - cmd == SND_COMPR_TRIGGER_DRAIN) { - - for_each_rtdcom(fe, rtdcom) { - component = rtdcom->component; - - if (!component->driver->compr_ops || - !component->driver->compr_ops->trigger) - continue; - - ret = component->driver->compr_ops->trigger(cstream, - cmd); - if (ret < 0) - return ret; - } - return ret; - } + cmd == SND_COMPR_TRIGGER_DRAIN) + return soc_compr_components_trigger(cstream, cmd); if (cstream->direction == SND_COMPRESS_PLAYBACK) stream = SNDRV_PCM_STREAM_PLAYBACK; @@ -425,17 +421,9 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) goto out; } - for_each_rtdcom(fe, rtdcom) { - component = rtdcom->component; - - if (!component->driver->compr_ops || - !component->driver->compr_ops->trigger) - continue; - - ret = component->driver->compr_ops->trigger(cstream, cmd); - if (ret < 0) - goto out; - } + ret = soc_compr_components_trigger(cstream, cmd); + if (ret < 0) + goto out; fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; @@ -462,12 +450,33 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) return ret; } -static int soc_compr_set_params(struct snd_compr_stream *cstream, - struct snd_compr_params *params) +static int soc_compr_components_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; + int ret; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (!component->driver->compr_ops || + !component->driver->compr_ops->set_params) + continue; + + ret = component->driver->compr_ops->set_params(cstream, params); + if (ret < 0) + return ret; + } + + return 0; +} + +static int soc_compr_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; @@ -486,17 +495,9 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, goto err; } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->compr_ops || - !component->driver->compr_ops->set_params) - continue; - - ret = component->driver->compr_ops->set_params(cstream, params); - if (ret < 0) - goto err; - } + ret = soc_compr_components_set_params(cstream, params); + if (ret < 0) + goto err; if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { ret = rtd->dai_link->compr_ops->set_params(cstream); @@ -530,8 +531,6 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_pcm_substream *fe_substream = fe->pcm->streams[cstream->direction].substream; - struct snd_soc_component *component; - struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = fe->cpu_dai; int ret, stream; @@ -566,17 +565,9 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, goto out; } - for_each_rtdcom(fe, rtdcom) { - component = rtdcom->component; - - if (!component->driver->compr_ops || - !component->driver->compr_ops->set_params) - continue; - - ret = component->driver->compr_ops->set_params(cstream, params); - if (ret < 0) - goto out; - } + ret = soc_compr_components_set_params(cstream, params); + if (ret < 0) + goto out; if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) { ret = fe->dai_link->compr_ops->set_params(cstream); From 0d6df96c6bd9a236963ae14255d0013ae7e72932 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 10:22:27 -0600 Subject: [PATCH 0816/1995] ASoC: dapm: fix out-of-bounds accesses to DAPM lookup tables KASAN reports and additional traces point to out-of-bounds accesses to the dapm_up_seq and dapm_down_seq lookup tables. The indices used are larger than the array definition. Fix by adding missing entries for the new widget types in these two lookup tables, and align them with PGA values. Also the sequences for the following widgets were not defined. Since their values defaulted to zero, assign them explicitly snd_soc_dapm_input snd_soc_dapm_output snd_soc_dapm_vmid snd_soc_dapm_siggen snd_soc_dapm_sink Fixes: 8a70b4544ef4 ('ASoC: dapm: Add new widget type for constructing DAPM graphs on DSPs.'). Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit c16e12010060c6c7a31f08b4a99513064cb53b7d) --- sound/soc/soc-dapm.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 111a23a9708a27..40e7190f533a99 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -70,12 +70,16 @@ static int dapm_up_seq[] = { [snd_soc_dapm_clock_supply] = 1, [snd_soc_dapm_supply] = 2, [snd_soc_dapm_micbias] = 3, + [snd_soc_dapm_vmid] = 3, [snd_soc_dapm_dai_link] = 2, [snd_soc_dapm_dai_in] = 4, [snd_soc_dapm_dai_out] = 4, [snd_soc_dapm_aif_in] = 4, [snd_soc_dapm_aif_out] = 4, [snd_soc_dapm_mic] = 5, + [snd_soc_dapm_siggen] = 5, + [snd_soc_dapm_input] = 5, + [snd_soc_dapm_output] = 5, [snd_soc_dapm_mux] = 6, [snd_soc_dapm_demux] = 6, [snd_soc_dapm_dac] = 7, @@ -83,11 +87,19 @@ static int dapm_up_seq[] = { [snd_soc_dapm_mixer] = 8, [snd_soc_dapm_mixer_named_ctl] = 8, [snd_soc_dapm_pga] = 9, + [snd_soc_dapm_buffer] = 9, + [snd_soc_dapm_scheduler] = 9, + [snd_soc_dapm_effect] = 9, + [snd_soc_dapm_src] = 9, + [snd_soc_dapm_asrc] = 9, + [snd_soc_dapm_encoder] = 9, + [snd_soc_dapm_decoder] = 9, [snd_soc_dapm_adc] = 10, [snd_soc_dapm_out_drv] = 11, [snd_soc_dapm_hp] = 11, [snd_soc_dapm_spk] = 11, [snd_soc_dapm_line] = 11, + [snd_soc_dapm_sink] = 11, [snd_soc_dapm_kcontrol] = 12, [snd_soc_dapm_post] = 13, }; @@ -100,13 +112,25 @@ static int dapm_down_seq[] = { [snd_soc_dapm_spk] = 3, [snd_soc_dapm_line] = 3, [snd_soc_dapm_out_drv] = 3, + [snd_soc_dapm_sink] = 3, [snd_soc_dapm_pga] = 4, + [snd_soc_dapm_buffer] = 4, + [snd_soc_dapm_scheduler] = 4, + [snd_soc_dapm_effect] = 4, + [snd_soc_dapm_src] = 4, + [snd_soc_dapm_asrc] = 4, + [snd_soc_dapm_encoder] = 4, + [snd_soc_dapm_decoder] = 4, [snd_soc_dapm_switch] = 5, [snd_soc_dapm_mixer_named_ctl] = 5, [snd_soc_dapm_mixer] = 5, [snd_soc_dapm_dac] = 6, [snd_soc_dapm_mic] = 7, + [snd_soc_dapm_siggen] = 7, + [snd_soc_dapm_input] = 7, + [snd_soc_dapm_output] = 7, [snd_soc_dapm_micbias] = 8, + [snd_soc_dapm_vmid] = 8, [snd_soc_dapm_mux] = 9, [snd_soc_dapm_demux] = 9, [snd_soc_dapm_aif_in] = 10, From a81b0d4782360f75856b180e1f3b79dd19eacc55 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 10:22:28 -0600 Subject: [PATCH 0817/1995] ASoC: dapm: harden use of lookup tables To detect potential errors, let's add: a) build-time warnings when the table size isn't aligned with the enum list b) run-time warnings when the values are not initialized. This requires an increase by one of all values to avoid the default 0. Suggested-by: Takashi Iwai Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit f13d4b5f85e1c436c9bf21205509266b5a81a320) --- include/sound/soc-dapm.h | 3 + sound/soc/soc-dapm.c | 158 ++++++++++++++++++++------------------- 2 files changed, 85 insertions(+), 76 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 79b4ddfb8e9e22..c00a0b8ade0861 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -523,6 +523,9 @@ enum snd_soc_dapm_type { snd_soc_dapm_asrc, /* DSP/CODEC ASRC component */ snd_soc_dapm_encoder, /* FW/SW audio encoder component */ snd_soc_dapm_decoder, /* FW/SW audio decoder component */ + + /* Don't edit below this line */ + SND_SOC_DAPM_TYPE_COUNT }; enum snd_soc_dapm_subclass { diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 40e7190f533a99..d31d295b540fcc 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -64,85 +64,85 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, /* dapm power sequences - make this per codec in the future */ static int dapm_up_seq[] = { - [snd_soc_dapm_pre] = 0, - [snd_soc_dapm_regulator_supply] = 1, - [snd_soc_dapm_pinctrl] = 1, - [snd_soc_dapm_clock_supply] = 1, - [snd_soc_dapm_supply] = 2, - [snd_soc_dapm_micbias] = 3, - [snd_soc_dapm_vmid] = 3, - [snd_soc_dapm_dai_link] = 2, - [snd_soc_dapm_dai_in] = 4, - [snd_soc_dapm_dai_out] = 4, - [snd_soc_dapm_aif_in] = 4, - [snd_soc_dapm_aif_out] = 4, - [snd_soc_dapm_mic] = 5, - [snd_soc_dapm_siggen] = 5, - [snd_soc_dapm_input] = 5, - [snd_soc_dapm_output] = 5, - [snd_soc_dapm_mux] = 6, - [snd_soc_dapm_demux] = 6, - [snd_soc_dapm_dac] = 7, - [snd_soc_dapm_switch] = 8, - [snd_soc_dapm_mixer] = 8, - [snd_soc_dapm_mixer_named_ctl] = 8, - [snd_soc_dapm_pga] = 9, - [snd_soc_dapm_buffer] = 9, - [snd_soc_dapm_scheduler] = 9, - [snd_soc_dapm_effect] = 9, - [snd_soc_dapm_src] = 9, - [snd_soc_dapm_asrc] = 9, - [snd_soc_dapm_encoder] = 9, - [snd_soc_dapm_decoder] = 9, - [snd_soc_dapm_adc] = 10, - [snd_soc_dapm_out_drv] = 11, - [snd_soc_dapm_hp] = 11, - [snd_soc_dapm_spk] = 11, - [snd_soc_dapm_line] = 11, - [snd_soc_dapm_sink] = 11, - [snd_soc_dapm_kcontrol] = 12, - [snd_soc_dapm_post] = 13, + [snd_soc_dapm_pre] = 1, + [snd_soc_dapm_regulator_supply] = 2, + [snd_soc_dapm_pinctrl] = 2, + [snd_soc_dapm_clock_supply] = 2, + [snd_soc_dapm_supply] = 3, + [snd_soc_dapm_micbias] = 4, + [snd_soc_dapm_vmid] = 4, + [snd_soc_dapm_dai_link] = 3, + [snd_soc_dapm_dai_in] = 5, + [snd_soc_dapm_dai_out] = 5, + [snd_soc_dapm_aif_in] = 5, + [snd_soc_dapm_aif_out] = 5, + [snd_soc_dapm_mic] = 6, + [snd_soc_dapm_siggen] = 6, + [snd_soc_dapm_input] = 6, + [snd_soc_dapm_output] = 6, + [snd_soc_dapm_mux] = 7, + [snd_soc_dapm_demux] = 7, + [snd_soc_dapm_dac] = 8, + [snd_soc_dapm_switch] = 9, + [snd_soc_dapm_mixer] = 9, + [snd_soc_dapm_mixer_named_ctl] = 9, + [snd_soc_dapm_pga] = 10, + [snd_soc_dapm_buffer] = 10, + [snd_soc_dapm_scheduler] = 10, + [snd_soc_dapm_effect] = 10, + [snd_soc_dapm_src] = 10, + [snd_soc_dapm_asrc] = 10, + [snd_soc_dapm_encoder] = 10, + [snd_soc_dapm_decoder] = 10, + [snd_soc_dapm_adc] = 11, + [snd_soc_dapm_out_drv] = 12, + [snd_soc_dapm_hp] = 12, + [snd_soc_dapm_spk] = 12, + [snd_soc_dapm_line] = 12, + [snd_soc_dapm_sink] = 12, + [snd_soc_dapm_kcontrol] = 13, + [snd_soc_dapm_post] = 14, }; static int dapm_down_seq[] = { - [snd_soc_dapm_pre] = 0, - [snd_soc_dapm_kcontrol] = 1, - [snd_soc_dapm_adc] = 2, - [snd_soc_dapm_hp] = 3, - [snd_soc_dapm_spk] = 3, - [snd_soc_dapm_line] = 3, - [snd_soc_dapm_out_drv] = 3, - [snd_soc_dapm_sink] = 3, - [snd_soc_dapm_pga] = 4, - [snd_soc_dapm_buffer] = 4, - [snd_soc_dapm_scheduler] = 4, - [snd_soc_dapm_effect] = 4, - [snd_soc_dapm_src] = 4, - [snd_soc_dapm_asrc] = 4, - [snd_soc_dapm_encoder] = 4, - [snd_soc_dapm_decoder] = 4, - [snd_soc_dapm_switch] = 5, - [snd_soc_dapm_mixer_named_ctl] = 5, - [snd_soc_dapm_mixer] = 5, - [snd_soc_dapm_dac] = 6, - [snd_soc_dapm_mic] = 7, - [snd_soc_dapm_siggen] = 7, - [snd_soc_dapm_input] = 7, - [snd_soc_dapm_output] = 7, - [snd_soc_dapm_micbias] = 8, - [snd_soc_dapm_vmid] = 8, - [snd_soc_dapm_mux] = 9, - [snd_soc_dapm_demux] = 9, - [snd_soc_dapm_aif_in] = 10, - [snd_soc_dapm_aif_out] = 10, - [snd_soc_dapm_dai_in] = 10, - [snd_soc_dapm_dai_out] = 10, - [snd_soc_dapm_dai_link] = 11, - [snd_soc_dapm_supply] = 12, - [snd_soc_dapm_clock_supply] = 13, - [snd_soc_dapm_pinctrl] = 13, - [snd_soc_dapm_regulator_supply] = 13, - [snd_soc_dapm_post] = 14, + [snd_soc_dapm_pre] = 1, + [snd_soc_dapm_kcontrol] = 2, + [snd_soc_dapm_adc] = 3, + [snd_soc_dapm_hp] = 4, + [snd_soc_dapm_spk] = 4, + [snd_soc_dapm_line] = 4, + [snd_soc_dapm_out_drv] = 4, + [snd_soc_dapm_sink] = 4, + [snd_soc_dapm_pga] = 5, + [snd_soc_dapm_buffer] = 5, + [snd_soc_dapm_scheduler] = 5, + [snd_soc_dapm_effect] = 5, + [snd_soc_dapm_src] = 5, + [snd_soc_dapm_asrc] = 5, + [snd_soc_dapm_encoder] = 5, + [snd_soc_dapm_decoder] = 5, + [snd_soc_dapm_switch] = 6, + [snd_soc_dapm_mixer_named_ctl] = 6, + [snd_soc_dapm_mixer] = 6, + [snd_soc_dapm_dac] = 7, + [snd_soc_dapm_mic] = 8, + [snd_soc_dapm_siggen] = 8, + [snd_soc_dapm_input] = 8, + [snd_soc_dapm_output] = 8, + [snd_soc_dapm_micbias] = 9, + [snd_soc_dapm_vmid] = 9, + [snd_soc_dapm_mux] = 10, + [snd_soc_dapm_demux] = 10, + [snd_soc_dapm_aif_in] = 11, + [snd_soc_dapm_aif_out] = 11, + [snd_soc_dapm_dai_in] = 11, + [snd_soc_dapm_dai_out] = 11, + [snd_soc_dapm_dai_link] = 12, + [snd_soc_dapm_supply] = 13, + [snd_soc_dapm_clock_supply] = 14, + [snd_soc_dapm_pinctrl] = 14, + [snd_soc_dapm_regulator_supply] = 14, + [snd_soc_dapm_post] = 15, }; static void dapm_assert_locked(struct snd_soc_dapm_context *dapm) @@ -1425,11 +1425,17 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a, { int *sort; + BUILD_BUG_ON(ARRAY_SIZE(dapm_up_seq) != SND_SOC_DAPM_TYPE_COUNT); + BUILD_BUG_ON(ARRAY_SIZE(dapm_down_seq) != SND_SOC_DAPM_TYPE_COUNT); + if (power_up) sort = dapm_up_seq; else sort = dapm_down_seq; + WARN_ONCE(sort[a->id] == 0, "offset a->id %d not initialized\n", a->id); + WARN_ONCE(sort[b->id] == 0, "offset b->id %d not initialized\n", b->id); + if (sort[a->id] != sort[b->id]) return sort[a->id] - sort[b->id]; if (a->subseq != b->subseq) { From c9c4929a21ecfde340cd5f9c88181d123b88ae6a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 18:40:27 -0600 Subject: [PATCH 0818/1995] ASoC: SOF: cleanup sof.h Remove unused prototypes, cleanup comments and remove id field (not sure what it was used for, if ever) Signed-off-by: Pierre-Louis Bossart --- include/sound/sof.h | 11 ++--------- sound/soc/sof/sof-pci-dev.c | 1 - sound/soc/sof/sof-spi-dev.c | 1 - 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index 251103f46fe51a..824cce4b512f90 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -21,22 +21,19 @@ struct snd_sof_dsp_ops; * SOF Platform data. */ struct snd_sof_pdata { - u32 id; /* PCI/ACPI ID */ const struct firmware *fw; const char *drv_name; const char *name; const char *platform; - /* parent device */ struct device *dev; /* * notification callback used if the hardware initialization * can take time or is handled in a workqueue. This callback - * can be used by the parent device to e.g. enable runtime_pm + * can be used by the caller to e.g. enable runtime_pm * or limit functionality until all low-level inits are - * complete. The device argument refers to the parent, not the - * "sof-audio" device. + * complete. */ void (*sof_probe_complete)(struct device *dev); @@ -90,8 +87,4 @@ int sof_nocodec_setup(struct device *dev, struct snd_soc_acpi_mach *mach, const struct sof_dev_desc *desc, const struct snd_sof_dsp_ops *ops); - -int sof_bes_setup(struct device *dev, const struct snd_sof_dsp_ops *ops, - struct snd_soc_dai_link *links, int link_num, - struct snd_soc_card *card); #endif diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 9fcb8087898e90..88ba86cec593dd 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -220,7 +220,6 @@ static int sof_pci_probe(struct pci_dev *pci, mach->mach_params.platform = dev_name(dev); #endif /* CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE */ - sof_pdata->id = pci_id->device; sof_pdata->name = pci_name(pci); sof_pdata->machine = mach; sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data; diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index ae06fa18acb1ce..210e3c66fa3222 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -117,7 +117,6 @@ static int sof_spi_probe(struct spi_device *spi) mach->asoc_plat_name = "sof-platform"; mach->mach_params.platform = dev_name(dev); - sof_pdata->id = -1; sof_pdata->name = dev_name(&spi->dev); sof_pdata->machine = mach; sof_pdata->desc = desc; From 407a22e2cd0aa772d25812bd3226708eac33c6f4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 18:57:03 -0600 Subject: [PATCH 0819/1995] ASoC: SOF: remove use of pci field use to_pci_dev() as needed, no need to have a dedicated field in the core Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 2 -- sound/soc/sof/intel/byt.c | 2 +- sound/soc/sof/intel/hda-loader-skl.c | 2 +- sound/soc/sof/intel/hda-loader.c | 2 +- sound/soc/sof/intel/hda-stream.c | 2 +- sound/soc/sof/intel/hda.c | 31 ++++++++++++++-------------- sound/soc/sof/ops.c | 5 +++-- sound/soc/sof/sof-priv.h | 1 - 8 files changed, 22 insertions(+), 25 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index af5dadee9c399d..c25e086e42e96c 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -402,8 +402,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) /* initialize sof device */ sdev->dev = dev; - if dev_is_pci(plat_data->dev) - sdev->pci = to_pci_dev(plat_data->dev); sdev->pdata = plat_data; sdev->first_boot = true; diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 2f59d6672e10aa..94b4d96f4fc4b8 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -516,7 +516,7 @@ static int byt_pci_probe(struct snd_sof_dev *sdev) { struct snd_sof_pdata *pdata = sdev->pdata; const struct sof_dev_desc *desc = pdata->desc; - struct pci_dev *pci = sdev->pci; + struct pci_dev *pci = to_pci_dev(sdev->dev); u32 base, size; int ret = 0; diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index da250ad8fdc755..690c90efff1313 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -270,7 +270,7 @@ static void cl_skl_cldma_setup_controller(struct snd_sof_dev *sdev, static int cl_stream_prepare_skl(struct snd_sof_dev *sdev) { - struct pci_dev *pci = sdev->pci; + struct pci_dev *pci = to_pci_dev(sdev->dev); int frags = 0; int ret = 0; __le32 *bdl; diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 68a27810520a50..bd862b989fb965 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -29,7 +29,7 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, { struct hdac_ext_stream *dsp_stream = NULL; struct hdac_stream *hstream; - struct pci_dev *pci = sdev->pci; + struct pci_dev *pci = to_pci_dev(sdev->dev); int ret; if (direction == SNDRV_PCM_STREAM_PLAYBACK) { diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index f62f6a51caadb2..7d409973b5518d 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -481,7 +481,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_ext_stream *stream; struct hdac_stream *hstream; - struct pci_dev *pci = sdev->pci; + struct pci_dev *pci = to_pci_dev(sdev->dev); int sd_offset; int i, num_playback, num_capture, num_total, ret; u32 gcap; diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index e7c14cb002e8ef..b4380ff785426b 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -184,7 +184,7 @@ static int hda_init(struct snd_sof_dev *sdev) struct hda_bus *hbus; struct hdac_bus *bus; struct hdac_ext_bus_ops *ext_ops = NULL; - struct pci_dev *pci = sdev->pci; + struct pci_dev *pci = to_pci_dev(sdev->dev); int ret; hbus = sof_to_hbus(sdev); @@ -217,7 +217,7 @@ static int hda_init(struct snd_sof_dev *sdev) /* get controller capabilities */ ret = hda_dsp_ctrl_get_caps(sdev); if (ret < 0) - dev_err(&pci->dev, "error: get caps error\n"); + dev_err(sdev->dev, "error: get caps error\n"); return ret; } @@ -227,7 +227,6 @@ static int hda_init(struct snd_sof_dev *sdev) static int hda_init_caps(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); - struct pci_dev *pci = sdev->pci; struct hdac_ext_link *hlink = NULL; struct snd_soc_acpi_mach_params *mach_params; struct snd_soc_acpi_mach *hda_mach = NULL; @@ -241,7 +240,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) /* check if dsp is there */ if (bus->ppcap) - dev_dbg(&pci->dev, "PP capability, will probe DSP later.\n"); + dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n"); if (bus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(bus); @@ -249,7 +248,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) /* init i915 and HDMI codecs */ ret = hda_codec_i915_init(sdev); if (ret < 0) { - dev_err(&pci->dev, "error: no HDMI audio devices found\n"); + dev_err(sdev->dev, "error: no HDMI audio devices found\n"); return ret; } @@ -355,7 +354,7 @@ static const struct sof_intel_dsp_desc int hda_dsp_probe(struct snd_sof_dev *sdev) { - struct pci_dev *pci = sdev->pci; + struct pci_dev *pci = to_pci_dev(sdev->dev); struct sof_intel_hda_dev *hdev; struct hdac_bus *bus; struct hdac_stream *stream; @@ -386,17 +385,17 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) goto err; } - hdev = devm_kzalloc(&pci->dev, sizeof(*hdev), GFP_KERNEL); + hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL); if (!hdev) return -ENOMEM; sdev->pdata->hw_pdata = hdev; hdev->desc = chip; - hdev->dmic_dev = platform_device_register_data(&pci->dev, "dmic-codec", + hdev->dmic_dev = platform_device_register_data(sdev->dev, "dmic-codec", PLATFORM_DEVID_NONE, NULL, 0); if (IS_ERR(hdev->dmic_dev)) { - dev_err(&pci->dev, "error: failed to create DMIC device\n"); + dev_err(sdev->dev, "error: failed to create DMIC device\n"); return PTR_ERR(hdev->dmic_dev); } @@ -419,7 +418,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) /* DSP base */ sdev->bar[HDA_DSP_BAR] = pci_ioremap_bar(pci, HDA_DSP_BAR); if (!sdev->bar[HDA_DSP_BAR]) { - dev_err(&pci->dev, "error: ioremap error\n"); + dev_err(sdev->dev, "error: ioremap error\n"); ret = -ENXIO; goto hdac_bus_unmap; } @@ -429,10 +428,10 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) /* allow 64bit DMA address if supported by H/W */ if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(64))) { - dev_dbg(&pci->dev, "DMA mask is 64 bit\n"); + dev_dbg(sdev->dev, "DMA mask is 64 bit\n"); dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(64)); } else { - dev_dbg(&pci->dev, "DMA mask is 32 bit\n"); + dev_dbg(sdev->dev, "DMA mask is 32 bit\n"); dma_set_mask(&pci->dev, DMA_BIT_MASK(32)); dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32)); } @@ -440,7 +439,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) /* init streams */ ret = hda_dsp_stream_init(sdev); if (ret < 0) { - dev_err(&pci->dev, "error: failed to init streams\n"); + dev_err(sdev->dev, "error: failed to init streams\n"); /* * not all errors are due to memory issues, but trying * to free everything does not harm @@ -510,14 +509,14 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) /* reset HDA controller */ ret = hda_dsp_ctrl_link_reset(sdev, true); if (ret < 0) { - dev_err(&pci->dev, "error: failed to reset HDA controller\n"); + dev_err(sdev->dev, "error: failed to reset HDA controller\n"); goto free_ipc_irq; } /* exit HDA controller reset */ ret = hda_dsp_ctrl_link_reset(sdev, false); if (ret < 0) { - dev_err(&pci->dev, "error: failed to exit HDA controller reset\n"); + dev_err(sdev->dev, "error: failed to exit HDA controller reset\n"); goto free_ipc_irq; } @@ -588,7 +587,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) struct sof_intel_hda_dev *hda = (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; struct hdac_bus *bus = sof_to_bus(sdev); - struct pci_dev *pci = sdev->pci; + struct pci_dev *pci = to_pci_dev(sdev->dev); const struct sof_intel_dsp_desc *chip = hda->desc; #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index f7e05c6696a189..3dcdeb75fdd161 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -14,10 +14,11 @@ int snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset, u32 mask, u32 value) { + struct pci_dev *pci = to_pci_dev(sdev->dev); unsigned int old, new; u32 ret = ~0; /* explicit init to remove uninitialized use warnings */ - pci_read_config_dword(sdev->pci, offset, &ret); + pci_read_config_dword(pci, offset, &ret); old = ret; dev_dbg(sdev->dev, "Debug PCIR: %8.8x at %8.8x\n", old & mask, offset); @@ -26,7 +27,7 @@ int snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset, if (old == new) return false; - pci_write_config_dword(sdev->pci, offset, new); + pci_write_config_dword(pci, offset, new); dev_dbg(sdev->dev, "Debug PCIW: %8.8x at %8.8x\n", value, offset); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index f0cd75213d5a3b..0f343e4c319b6e 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -318,7 +318,6 @@ struct snd_sof_dev { struct device *dev; spinlock_t ipc_lock; /* lock for IPC users */ spinlock_t hw_lock; /* lock for HW IO access */ - struct pci_dev *pci; /* ASoC components */ struct snd_soc_component_driver plat_drv; From d58f0aefc943c393aff34b585dfd4fdaa7537365 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 20:06:46 -0600 Subject: [PATCH 0820/1995] ASoC: SOF: pci: make struct const copy/pastes likely, fix missing const Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-pci-dev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 88ba86cec593dd..e5c276e5b56860 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -22,7 +22,7 @@ #include "intel/hda.h" #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) -static struct sof_dev_desc bxt_desc = { +static const struct sof_dev_desc bxt_desc = { .machines = snd_soc_acpi_intel_bxt_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, @@ -38,7 +38,7 @@ static struct sof_dev_desc bxt_desc = { #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) -static struct sof_dev_desc glk_desc = { +static const struct sof_dev_desc glk_desc = { .machines = snd_soc_acpi_intel_glk_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, @@ -113,7 +113,7 @@ static const struct sof_dev_desc icl_desc = { #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) -static struct sof_dev_desc skl_desc = { +static const struct sof_dev_desc skl_desc = { .machines = snd_soc_acpi_intel_skl_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, @@ -129,7 +129,7 @@ static struct sof_dev_desc skl_desc = { #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) -static struct sof_dev_desc kbl_desc = { +static const struct sof_dev_desc kbl_desc = { .machines = snd_soc_acpi_intel_kbl_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, From c2ffcdca83831e64683b0fa8a30425e133a98c5a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 20:07:53 -0600 Subject: [PATCH 0821/1995] ASoC: SOF: acpi: make struct consts again missing const, add Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-acpi-dev.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 150053ef9330c1..b6bce070d8e82e 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -25,7 +25,7 @@ #include "intel/shim.h" #if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL) -static struct sof_dev_desc sof_acpi_haswell_desc = { +static const struct sof_dev_desc sof_acpi_haswell_desc = { .machines = snd_soc_acpi_intel_haswell_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = 1, @@ -40,7 +40,7 @@ static struct sof_dev_desc sof_acpi_haswell_desc = { #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) -static struct sof_dev_desc sof_acpi_broadwell_desc = { +static const struct sof_dev_desc sof_acpi_broadwell_desc = { .machines = snd_soc_acpi_intel_broadwell_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = 1, @@ -57,7 +57,7 @@ static struct sof_dev_desc sof_acpi_broadwell_desc = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) /* BYTCR uses different IRQ index */ -static struct sof_dev_desc sof_acpi_baytrailcr_desc = { +static const struct sof_dev_desc sof_acpi_baytrailcr_desc = { .machines = snd_soc_acpi_intel_baytrail_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = 1, @@ -70,7 +70,7 @@ static struct sof_dev_desc sof_acpi_baytrailcr_desc = { .arch_ops = &sof_xtensa_arch_ops }; -static struct sof_dev_desc sof_acpi_baytrail_desc = { +static const struct sof_dev_desc sof_acpi_baytrail_desc = { .machines = snd_soc_acpi_intel_baytrail_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = 1, @@ -133,7 +133,7 @@ static int is_byt_cr(struct platform_device *pdev) } #endif -static struct sof_dev_desc sof_acpi_cherrytrail_desc = { +static const struct sof_dev_desc sof_acpi_cherrytrail_desc = { .machines = snd_soc_acpi_intel_cherrytrail_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = 1, From 14d15ff438adbfa8656638cc5a50cb958b5fce95 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 6 Feb 2019 07:49:55 -0600 Subject: [PATCH 0822/1995] ASoC: SOF: sof-priv.h: add note on plat_drv we set the .ignore_machine field dynamically to the machine driver name, so add note to say we cannot use const (reported by checkpatch) Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-priv.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 0f343e4c319b6e..f3e518d434dbac 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -319,7 +319,10 @@ struct snd_sof_dev { spinlock_t ipc_lock; /* lock for IPC users */ spinlock_t hw_lock; /* lock for HW IO access */ - /* ASoC components */ + /* + * ASoC components. plat_drv fields are set dynamically so + * can't use const + */ struct snd_soc_component_driver plat_drv; /* DSP firmware boot */ From eb411296aebb1ab43a59b456fd72d81ae7b47e83 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 6 Feb 2019 11:57:12 -0600 Subject: [PATCH 0823/1995] ASoC: SOF: hda: fixup topology name for HDMI-only platforms rather than require the user to change topology files, play with the topology file name. This assumes the HDMI-only topology uses the -idisp.tlpl suffix Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 42 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index b4380ff785426b..cf56ee987aafb3 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -224,6 +224,29 @@ static int hda_init(struct snd_sof_dev *sdev) #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +static const char *fixup_tplg_name(struct snd_sof_dev *sdev, + const char *sof_tplg_filename) +{ + char *filename; + const char *tplg_filename = NULL; + int length; + + filename = devm_kstrdup(sdev->dev, sof_tplg_filename, GFP_KERNEL); + if (!filename) + return NULL; + + /* this assumes a .tplg extension */ + length = strlen(filename); + if (length >= 6) { + filename[length - 5] = '\0'; + tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, + "%s-idisp.tplg", filename); + if (!tplg_filename) + return NULL; + } + return tplg_filename; +} + static int hda_init_caps(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); @@ -232,6 +255,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) struct snd_soc_acpi_mach *hda_mach = NULL; struct snd_sof_pdata *pdata = sdev->pdata; struct snd_soc_acpi_mach *mach; + char *tplg_filename; int codec_num = 0; int ret = 0; int i; @@ -255,8 +279,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) ret = hda_dsp_ctrl_init_chip(sdev, true); if (ret < 0) { dev_err(bus->dev, "error: init chip failed with ret: %d\n", ret); - hda_codec_i915_exit(sdev); - return ret; + goto out; } /* codec detection */ @@ -295,6 +318,17 @@ static int hda_init_caps(struct snd_sof_dev *sdev) dev_info(bus->dev, "using HDA machine driver %s now\n", hda_mach->drv_name); } + + /* fixup topology file for HDMI only platforms */ + if (codec_num == 1 && + !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) { + /* use local variable for readability */ + tplg_filename = hda_mach->sof_tplg_filename; + tplg_filename = fixup_tplg_name(sdev, tplg_filename); + if (!tplg_filename) + goto out; + hda_mach->sof_tplg_filename = tplg_filename; + } } } @@ -318,6 +352,10 @@ static int hda_init_caps(struct snd_sof_dev *sdev) snd_hdac_ext_bus_link_put(bus, hlink); return 0; + +out: + hda_codec_i915_exit(sdev); + return ret; } #else From 391fd86d904b349eef2f6d5f60f24410b83fa7cf Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 14:25:59 -0600 Subject: [PATCH 0824/1995] ASoC: SOF: define default paths for firmware/topology Add default path and means to override it. Paths may be different for firmware and topology (and released separately) Signed-off-by: Pierre-Louis Bossart --- include/sound/sof.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/sound/sof.h b/include/sound/sof.h index 824cce4b512f90..4640566b54fe90 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -40,6 +40,12 @@ struct snd_sof_pdata { /* descriptor */ const struct sof_dev_desc *desc; + /* firmware and topology filenames */ + const char *fw_filename_prefix; + const char *fw_filename; + const char *tplg_filename_prefix; + const char *tplg_filename; + /* machine */ struct platform_device *pdev_mach; const struct snd_soc_acpi_mach *machine; @@ -78,6 +84,10 @@ struct sof_dev_desc { const char *nocodec_fw_filename; const char *nocodec_tplg_filename; + /* defaults paths for firmware and topology files */ + const char *default_fw_path; + const char *default_tplg_path; + const struct snd_sof_dsp_ops *ops; const struct sof_arch_ops *arch_ops; }; From 4fb563b39a82d56ae8b6b1aafd99b02897d687a4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 14:51:07 -0600 Subject: [PATCH 0825/1995] ASoC: SOF: implement support for fw/topology prefix information set and use the prefix, with priority for the alternate path if specified as a module parameter. This changes the defaults to intel/sof and intel/sof-tplg Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-loader.c | 8 +++- sound/soc/sof/intel/hda.c | 28 +++++++------ sound/soc/sof/loader.c | 8 +++- sound/soc/sof/nocodec.c | 4 +- sound/soc/sof/pcm.c | 8 +++- sound/soc/sof/sof-acpi-dev.c | 55 +++++++++++++++++++----- sound/soc/sof/sof-pci-dev.c | 72 +++++++++++++++++++++++++------- sound/soc/sof/sof-spi-dev.c | 34 +++++++++++++-- 8 files changed, 169 insertions(+), 48 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index bd862b989fb965..0ad61422ad54fa 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -252,7 +252,13 @@ int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev) /* set code loading condition to true */ sdev->code_loading = 1; - fw_filename = plat_data->machine->sof_fw_filename; + + fw_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, + "%s/%s", + plat_data->fw_filename_prefix, + plat_data->fw_filename); + if (!fw_filename) + return -ENOMEM; return request_firmware(&plat_data->fw, fw_filename, sdev->dev); } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index cf56ee987aafb3..19d2c18070fa19 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -227,20 +227,19 @@ static int hda_init(struct snd_sof_dev *sdev) static const char *fixup_tplg_name(struct snd_sof_dev *sdev, const char *sof_tplg_filename) { - char *filename; const char *tplg_filename = NULL; - int length; + char *filename; + char *split_ext; filename = devm_kstrdup(sdev->dev, sof_tplg_filename, GFP_KERNEL); if (!filename) return NULL; /* this assumes a .tplg extension */ - length = strlen(filename); - if (length >= 6) { - filename[length - 5] = '\0'; + split_ext = strsep(&filename, "."); + if (split_ext) { tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, - "%s-idisp.tplg", filename); + "%s-idisp.tplg", split_ext); if (!tplg_filename) return NULL; } @@ -255,7 +254,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) struct snd_soc_acpi_mach *hda_mach = NULL; struct snd_sof_pdata *pdata = sdev->pdata; struct snd_soc_acpi_mach *mach; - char *tplg_filename; + const char *tplg_filename; int codec_num = 0; int ret = 0; int i; @@ -310,11 +309,16 @@ static int hda_init_caps(struct snd_sof_dev *sdev) if (codec_num == 2 || !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) { hda_mach = snd_soc_acpi_intel_hda_machines; - mach = pdata->desc->machines; - hda_mach->sof_fw_filename = - mach->sof_fw_filename; pdata->machine = hda_mach; + /* topology: use the info from hda_machines */ + pdata->tplg_filename = + hda_mach->sof_tplg_filename; + + /* firmware: pick the first in machine list */ + mach = pdata->desc->machines; + pdata->fw_filename = mach->sof_fw_filename; + dev_info(bus->dev, "using HDA machine driver %s now\n", hda_mach->drv_name); } @@ -323,11 +327,11 @@ static int hda_init_caps(struct snd_sof_dev *sdev) if (codec_num == 1 && !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) { /* use local variable for readability */ - tplg_filename = hda_mach->sof_tplg_filename; + tplg_filename = pdata->tplg_filename; tplg_filename = fixup_tplg_name(sdev, tplg_filename); if (!tplg_filename) goto out; - hda_mach->sof_tplg_filename = tplg_filename; + pdata->tplg_filename = tplg_filename; } } } diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 443764e59dd939..5256c5ecce8355 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -231,7 +231,13 @@ int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev) /* set code loading condition to true */ sdev->code_loading = 1; - fw_filename = plat_data->machine->sof_fw_filename; + + fw_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, + "%s/%s", + plat_data->fw_filename_prefix, + plat_data->fw_filename); + if (!fw_filename) + return -ENOMEM; ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev); diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index fa5b2d5904e126..4a66abe065c991 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -64,8 +64,8 @@ int sof_nocodec_setup(struct device *dev, sof_pdata->drv_name = "sof-nocodec"; mach->drv_name = "sof-nocodec"; - mach->sof_fw_filename = desc->nocodec_fw_filename; - mach->sof_tplg_filename = desc->nocodec_tplg_filename; + sof_pdata->fw_filename = desc->nocodec_fw_filename; + sof_pdata->tplg_filename = desc->nocodec_tplg_filename; /* create dummy BE dai_links */ links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 82c3d8a20aca10..b60362d08626b1 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -647,7 +647,13 @@ static int sof_pcm_probe(struct snd_soc_component *component) /* load the default topology */ sdev->component = component; - tplg_filename = plat_data->machine->sof_tplg_filename; + + tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, + "%s/%s", + plat_data->tplg_filename_prefix, + plat_data->tplg_filename); + if (!tplg_filename) + return -ENOMEM; ret = snd_sof_load_topology(sdev, tplg_filename); if (ret < 0) { diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index b6bce070d8e82e..51d7887633eb6d 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -24,6 +24,14 @@ /* platform specific devices */ #include "intel/shim.h" +static char *fw_path; +module_param(fw_path, charp, 0444); +MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); + +static char *tplg_path; +module_param(tplg_path, charp, 0444); +MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); + #if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL) static const struct sof_dev_desc sof_acpi_haswell_desc = { .machines = snd_soc_acpi_intel_haswell_machines, @@ -32,8 +40,10 @@ static const struct sof_dev_desc sof_acpi_haswell_desc = { .resindex_imr_base = -1, .irqindex_host_ipc = 0, .chip_info = &hsw_chip_info, - .nocodec_fw_filename = "intel/sof-hsw.ri", - .nocodec_tplg_filename = "intel/sof-hsw-nocodec.tplg", + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-hsw.ri", + .nocodec_tplg_filename = "sof-hsw-nocodec.tplg", .ops = &sof_hsw_ops, .arch_ops = &sof_xtensa_arch_ops }; @@ -47,8 +57,10 @@ static const struct sof_dev_desc sof_acpi_broadwell_desc = { .resindex_imr_base = -1, .irqindex_host_ipc = 0, .chip_info = &bdw_chip_info, - .nocodec_fw_filename = "intel/sof-bdw.ri", - .nocodec_tplg_filename = "intel/sof-bdw-nocodec.tplg", + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-bdw.ri", + .nocodec_tplg_filename = "sof-bdw-nocodec.tplg", .ops = &sof_bdw_ops, .arch_ops = &sof_xtensa_arch_ops }; @@ -64,8 +76,10 @@ static const struct sof_dev_desc sof_acpi_baytrailcr_desc = { .resindex_imr_base = 2, .irqindex_host_ipc = 0, .chip_info = &byt_chip_info, - .nocodec_fw_filename = "intel/sof-byt.ri", - .nocodec_tplg_filename = "intel/sof-byt-nocodec.tplg", + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-byt.ri", + .nocodec_tplg_filename = "sof-byt-nocodec.tplg", .ops = &sof_byt_ops, .arch_ops = &sof_xtensa_arch_ops }; @@ -77,8 +91,10 @@ static const struct sof_dev_desc sof_acpi_baytrail_desc = { .resindex_imr_base = 2, .irqindex_host_ipc = 5, .chip_info = &byt_chip_info, - .nocodec_fw_filename = "intel/sof-byt.ri", - .nocodec_tplg_filename = "intel/sof-byt-nocodec.tplg", + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-byt.ri", + .nocodec_tplg_filename = "sof-byt-nocodec.tplg", .ops = &sof_byt_ops, .arch_ops = &sof_xtensa_arch_ops }; @@ -140,8 +156,10 @@ static const struct sof_dev_desc sof_acpi_cherrytrail_desc = { .resindex_imr_base = 2, .irqindex_host_ipc = 5, .chip_info = &cht_chip_info, - .nocodec_fw_filename = "intel/sof-cht.ri", - .nocodec_tplg_filename = "intel/sof-cht-nocodec.tplg", + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-cht.ri", + .nocodec_tplg_filename = "sof-cht-nocodec.tplg", .ops = &sof_cht_ops, .arch_ops = &sof_xtensa_arch_ops }; @@ -228,11 +246,26 @@ static int sof_acpi_probe(struct platform_device *pdev) sof_pdata->dev = &pdev->dev; sof_pdata->platform = dev_name(dev); + /* alternate fw and tplg filenames ? */ + if (fw_path) + sof_pdata->fw_filename_prefix = fw_path; + else + sof_pdata->fw_filename_prefix = + sof_pdata->desc->default_fw_path; + + if (tplg_path) + sof_pdata->tplg_filename_prefix = tplg_path; + else + sof_pdata->tplg_filename_prefix = + sof_pdata->desc->default_tplg_path; + + sof_pdata->fw_filename = mach->sof_fw_filename; + sof_pdata->tplg_filename = mach->sof_tplg_filename; + #if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) /* set callback to enable runtime_pm */ sof_pdata->sof_probe_complete = sof_acpi_probe_complete; #endif - /* call sof helper for DSP hardware probe */ ret = snd_sof_device_probe(dev, sof_pdata); if (ret) { diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index e5c276e5b56860..36150512397ec6 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -21,6 +21,14 @@ #include "intel/shim.h" #include "intel/hda.h" +static char *fw_path; +module_param(fw_path, charp, 0444); +MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); + +static char *tplg_path; +module_param(tplg_path, charp, 0444); +MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); + #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) static const struct sof_dev_desc bxt_desc = { .machines = snd_soc_acpi_intel_bxt_machines, @@ -30,8 +38,10 @@ static const struct sof_dev_desc bxt_desc = { .irqindex_host_ipc = -1, .resindex_dma_base = -1, .chip_info = &apl_chip_info, - .nocodec_fw_filename = "intel/sof-apl.ri", - .nocodec_tplg_filename = "intel/sof-apl-nocodec.tplg", + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-apl.ri", + .nocodec_tplg_filename = "sof-apl-nocodec.tplg", .ops = &sof_apl_ops, .arch_ops = &sof_xtensa_arch_ops }; @@ -46,8 +56,10 @@ static const struct sof_dev_desc glk_desc = { .irqindex_host_ipc = -1, .resindex_dma_base = -1, .chip_info = &apl_chip_info, - .nocodec_fw_filename = "intel/sof-glk.ri", - .nocodec_tplg_filename = "intel/sof-glk-nocodec.tplg", + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-glk.ri", + .nocodec_tplg_filename = "sof-glk-nocodec.tplg", .ops = &sof_apl_ops, .arch_ops = &sof_xtensa_arch_ops }; @@ -58,8 +70,8 @@ static struct snd_soc_acpi_mach sof_tng_machines[] = { { .id = "INT343A", .drv_name = "edison", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt.tplg", .asoc_plat_name = "baytrail-pcm-audio", }, {} @@ -73,8 +85,10 @@ static const struct sof_dev_desc tng_desc = { .irqindex_host_ipc = -1, .resindex_dma_base = -1, .chip_info = &tng_chip_info, - .nocodec_fw_filename = "intel/sof-byt.ri", - .nocodec_tplg_filename = "intel/sof-byt.tplg", + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-byt.ri", + .nocodec_tplg_filename = "sof-byt.tplg", .ops = &sof_tng_ops, .arch_ops = &sof_xtensa_arch_ops }; @@ -89,8 +103,10 @@ static const struct sof_dev_desc cnl_desc = { .irqindex_host_ipc = -1, .resindex_dma_base = -1, .chip_info = &cnl_chip_info, - .nocodec_fw_filename = "intel/sof-cnl.ri", - .nocodec_tplg_filename = "intel/sof-cnl-nocodec.tplg", + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-cnl.ri", + .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops }; @@ -105,8 +121,10 @@ static const struct sof_dev_desc icl_desc = { .irqindex_host_ipc = -1, .resindex_dma_base = -1, .chip_info = &cnl_chip_info, - .nocodec_fw_filename = "intel/sof-icl.ri", - .nocodec_tplg_filename = "intel/sof-icl-nocodec.tplg", + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-icl.ri", + .nocodec_tplg_filename = "sof-icl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops }; @@ -121,8 +139,10 @@ static const struct sof_dev_desc skl_desc = { .irqindex_host_ipc = -1, .resindex_dma_base = -1, .chip_info = &skl_chip_info, - .nocodec_fw_filename = "intel/sof-skl.ri", - .nocodec_tplg_filename = "intel/sof-skl-nocodec.tplg", + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-skl.ri", + .nocodec_tplg_filename = "sof-skl-nocodec.tplg", .ops = &sof_skl_ops, .arch_ops = &sof_xtensa_arch_ops }; @@ -137,8 +157,10 @@ static const struct sof_dev_desc kbl_desc = { .irqindex_host_ipc = -1, .resindex_dma_base = -1, .chip_info = &skl_chip_info, - .nocodec_fw_filename = "intel/sof-kbl.ri", - .nocodec_tplg_filename = "intel/sof-kbl-nocodec.tplg", + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-kbl.ri", + .nocodec_tplg_filename = "sof-kbl-nocodec.tplg", .ops = &sof_skl_ops, .arch_ops = &sof_xtensa_arch_ops }; @@ -226,6 +248,24 @@ static int sof_pci_probe(struct pci_dev *pci, sof_pdata->dev = dev; sof_pdata->platform = dev_name(dev); + /* alternate fw and tplg filenames ? */ + if (fw_path) + sof_pdata->fw_filename_prefix = fw_path; + else + sof_pdata->fw_filename_prefix = + sof_pdata->desc->default_fw_path; + + if (tplg_path) + sof_pdata->tplg_filename_prefix = tplg_path; + else + sof_pdata->tplg_filename_prefix = + sof_pdata->desc->default_tplg_path; + + if (mach) { + sof_pdata->fw_filename = mach->sof_fw_filename; + sof_pdata->tplg_filename = mach->sof_tplg_filename; + } + #if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) /* set callback to enable runtime_pm */ sof_pdata->sof_probe_complete = sof_pci_probe_complete; diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index 210e3c66fa3222..f4e43a7b97d636 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -23,21 +23,31 @@ #include "hw-spi.h" #include "ops.h" +static char *fw_path; +module_param(fw_path, charp, 0444); +MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); + +static char *tplg_path; +module_param(tplg_path, charp, 0444); +MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); + /* FIXME: replace with some meaningful values */ static struct snd_soc_acpi_mach spi_machines[] = { { .id = "INT343A", .drv_name = "bxt_alc298s_i2s", - .sof_fw_filename = "intel/sof-spi.ri", - .sof_tplg_filename = "intel/sof-spi.tplg", + .sof_fw_filename = "sof-spi.ri", + .sof_tplg_filename = "sof-spi.tplg", .asoc_plat_name = "0000:00:0e.0", }, }; static const struct sof_dev_desc spi_desc = { .machines = spi_machines, - .nocodec_fw_filename = "intel/sof-spi.ri", - .nocodec_tplg_filename = "intel/sof-spi.tplg", + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-spi.ri", + .nocodec_tplg_filename = "sof-spi.tplg", .resindex_lpe_base = -1, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, @@ -122,6 +132,22 @@ static int sof_spi_probe(struct spi_device *spi) sof_pdata->desc = desc; sof_pdata->dev = dev; + /* alternate fw and tplg filenames ? */ + if (fw_path) + sof_pdata->fw_filename_prefix = fw_path; + else + sof_pdata->fw_filename_prefix = + sof_pdata->desc->default_fw_path; + + if (tplg_path) + sof_pdata->tplg_filename_prefix = tplg_path; + else + sof_pdata->tplg_filename_prefix = + sof_pdata->desc->default_tplg_path; + + sof_pdata->fw_filename = mach->sof_fw_filename; + sof_pdata->tplg_filename = mach->sof_tplg_filename; + /* call sof helper for DSP hardware probe */ ret = snd_sof_device_probe(dev, sof_pdata); if (ret) { From 7338abf14d7bbde4f264b846e24266344b5a1f7a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 15:06:31 -0600 Subject: [PATCH 0826/1995] ASoC: Intel: bxt-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart --- .../intel/common/soc-acpi-intel-bxt-match.c | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c index 61dedc103b1966..c0e5780e2ad165 100644 --- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c @@ -51,8 +51,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .id = "INT343A", .drv_name = "bxt_alc298s_i2s", .fw_filename = "intel/dsp_fw_bxtn.bin", - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-rt298.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-rt298.tplg", .asoc_plat_name = "0000:00:0e.0", }, { @@ -61,30 +61,30 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .fw_filename = "intel/dsp_fw_bxtn.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &bxt_codecs, - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-da7219.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-da7219.tplg", .asoc_plat_name = "0000:00:0e.0", }, { .id = "104C5122", .drv_name = "bxt-pcm512x", - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-pcm512x.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-pcm512x.tplg", .asoc_plat_name = "0000:00:0e.0", }, { .id = "1AEC8804", .drv_name = "bxt-wm8804", - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-wm8804.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-wm8804.tplg", .asoc_plat_name = "0000:00:0e.0", }, { .id = "INT34C3", .drv_name = "bxt_tdf8532", .machine_quirk = apl_quirk, - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-tdf8532.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-tdf8532.tplg", .asoc_plat_name = "0000:00:0e.0", }, {}, From 98cadcb82fdbb7708dafd9f0c9ff109b2db2937f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 15:06:31 -0600 Subject: [PATCH 0827/1995] ASoC: Intel: byt-match.c: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart --- .../intel/common/soc-acpi-intel-byt-match.c | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index a4ffad0c91aa8e..306168d3430f48 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -83,8 +83,8 @@ static struct snd_soc_acpi_mach byt_thinkpad_10 = { .drv_name = "cht-bsw-rt5672", .fw_filename = "intel/fw_sst_0f28.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5670.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5670.tplg", .asoc_plat_name = "sst-mfld-platform", }; @@ -93,8 +93,8 @@ static struct snd_soc_acpi_mach byt_pov_p1006w = { .drv_name = "bytcr_rt5651", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5651", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5651.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5651.tplg", .asoc_plat_name = "sst-mfld-platform", }; @@ -136,8 +136,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5640", .machine_quirk = byt_quirk, - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5640.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -145,8 +145,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcr_rt5640", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5640", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5640.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -154,8 +154,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcr_rt5640", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5640", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5640.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -163,8 +163,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcr_rt5651", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5651", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5651.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5651.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -172,8 +172,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcht_da7213", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcht_da7213", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-da7213.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -181,8 +181,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcht_da7213", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcht_da7213", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-da7213.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -190,8 +190,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcht_es8316", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcht_es8316", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-es8316.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-es8316.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -207,8 +207,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_0f28.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5645.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -216,8 +216,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_0f28.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5645.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, /* use CHT driver to Baytrail Chromebooks */ @@ -226,8 +226,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "cht-bsw-max98090", .fw_filename = "intel/fw_sst_0f28.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-max98090.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-max98090.tplg", .asoc_plat_name = "sst-mfld-platform", }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) From ebc39f914665f847b2d6bcaac5f06455b02a3e81 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 15:06:32 -0600 Subject: [PATCH 0828/1995] ASoC: Intel: cht-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart --- .../intel/common/soc-acpi-intel-cht-match.c | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c index 2038dba88144c3..00ef347ad42563 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -44,8 +44,8 @@ static struct snd_soc_acpi_mach cht_surface_mach = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5645.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }; @@ -68,8 +68,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5672", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5670.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5670.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -77,8 +77,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5672", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5670.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5670.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -86,8 +86,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5645.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -95,8 +95,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5645.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -104,8 +104,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5645.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -113,8 +113,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-max98090", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-max98090.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-max98090.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -122,8 +122,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-nau8824", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-nau8824.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-nau8824.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -131,8 +131,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcht_da7213", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcht_da7213", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-da7213.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -140,8 +140,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcht_da7213", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcht_da7213", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-da7213.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -149,8 +149,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcht_es8316", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcht_es8316", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-es8316.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-es8316.tplg", .asoc_plat_name = "sst-mfld-platform", }, /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ @@ -160,8 +160,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcr_rt5640", .machine_quirk = cht_quirk, - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5640.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -169,8 +169,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcr_rt5640", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcr_rt5640", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5640.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -186,8 +186,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcr_rt5651", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcr_rt5651", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5651.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5651.tplg", .asoc_plat_name = "sst-mfld-platform", }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) From d538104d22f2b0fd7d20feb0ff503ffd2fa3845e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 15:06:32 -0600 Subject: [PATCH 0829/1995] ASoC: Intel: cnl-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index ea8872dc4d8ee4..b2e8e37768ca71 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -20,8 +20,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .drv_name = "cnl_rt274", .fw_filename = "intel/dsp_fw_cnl.bin", .pdata = &cnl_pdata, - .sof_fw_filename = "intel/sof-cnl.ri", - .sof_tplg_filename = "intel/sof-cnl-rt274.tplg", + .sof_fw_filename = "sof-cnl.ri", + .sof_tplg_filename = "sof-cnl-rt274.tplg", .asoc_plat_name = "0000:00:1f.3", }, { From 5b05f20608cfb9c490f4626f5d2d642f872baf05 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 15:06:33 -0600 Subject: [PATCH 0830/1995] ASoC: Intel: glk-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-glk-match.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c index 305875af71caee..75bc0109166a0a 100644 --- a/sound/soc/intel/common/soc-acpi-intel-glk-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c @@ -19,8 +19,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { .id = "INT343A", .drv_name = "glk_alc298s_i2s", .fw_filename = "intel/dsp_fw_glk.bin", - .sof_fw_filename = "intel/sof-glk.ri", - .sof_tplg_filename = "intel/sof-glk-alc298.tplg", + .sof_fw_filename = "sof-glk.ri", + .sof_tplg_filename = "sof-glk-alc298.tplg", .asoc_plat_name = "0000:00:0e.0", }, { @@ -29,8 +29,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { .fw_filename = "intel/dsp_fw_glk.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &glk_codecs, - .sof_fw_filename = "intel/sof-glk.ri", - .sof_tplg_filename = "intel/sof-glk-da7219.tplg", + .sof_fw_filename = "sof-glk.ri", + .sof_tplg_filename = "sof-glk-da7219.tplg", .asoc_plat_name = "0000:00:0e.0", }, {}, From 872197966b28e1a99ba04bf0e51a64d6d2380f98 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 15:06:33 -0600 Subject: [PATCH 0831/1995] ASoC: Intel: hda-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-hda-match.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-hda-match.c b/sound/soc/intel/common/soc-acpi-intel-hda-match.c index 533c1064f84b33..68ae43f7b4b288 100644 --- a/sound/soc/intel/common/soc-acpi-intel-hda-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-hda-match.c @@ -23,7 +23,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[] = { /* .sof_fw_filename is dynamically set in sof/intel driver */ - .sof_tplg_filename = "intel/sof-hda-generic.tplg", + .sof_tplg_filename = "sof-hda-generic.tplg", /* * .machine_quirk and .quirk_data are not used here but From ab0f87eed6a3eb8ec2ec748e887aab3502c20843 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 15:06:34 -0600 Subject: [PATCH 0832/1995] ASoC: Intel: hsw-bdw-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart --- .../intel/common/soc-acpi-intel-hsw-bdw-match.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c index 494a0ea9b02903..ddfe4250c2bcb9 100644 --- a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c @@ -23,8 +23,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_haswell_machines[] = { .id = "INT33CA", .drv_name = "haswell-audio", .fw_filename = "intel/IntcSST1.bin", - .sof_fw_filename = "intel/sof-hsw.ri", - .sof_tplg_filename = "intel/sof-hsw.tplg", + .sof_fw_filename = "sof-hsw.ri", + .sof_tplg_filename = "sof-hsw.tplg", .asoc_plat_name = "haswell-pcm-audio", }, {} @@ -36,24 +36,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { .id = "INT343A", .drv_name = "broadwell-audio", .fw_filename = "intel/IntcSST2.bin", - .sof_fw_filename = "intel/sof-bdw.ri", - .sof_tplg_filename = "intel/sof-bdw-rt286.tplg", + .sof_fw_filename = "sof-bdw.ri", + .sof_tplg_filename = "sof-bdw-rt286.tplg", .asoc_plat_name = "haswell-pcm-audio", }, { .id = "RT5677CE", .drv_name = "bdw-rt5677", .fw_filename = "intel/IntcSST2.bin", - .sof_fw_filename = "intel/sof-bdw.ri", - .sof_tplg_filename = "intel/sof-bdw-rt5677.tplg", + .sof_fw_filename = "sof-bdw.ri", + .sof_tplg_filename = "sof-bdw-rt5677.tplg", .asoc_plat_name = "haswell-pcm-audio", }, { .id = "INT33CA", .drv_name = "haswell-audio", .fw_filename = "intel/IntcSST2.bin", - .sof_fw_filename = "intel/sof-bdw.ri", - .sof_tplg_filename = "intel/sof-bdw-rt5640.tplg", + .sof_fw_filename = "sof-bdw.ri", + .sof_tplg_filename = "sof-bdw-rt5640.tplg", .asoc_plat_name = "haswell-pcm-audio", }, {} From 3cd4f9869a295e615e2745470f4c37e6b2abf5b7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 15:06:34 -0600 Subject: [PATCH 0833/1995] ASoC: Intel: icl-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-icl-match.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c index c58e86d9692b41..e13978f51b744b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -20,8 +20,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { .drv_name = "icl_rt274", .fw_filename = "intel/dsp_fw_icl.bin", .pdata = &icl_pdata, - .sof_fw_filename = "intel/sof-icl.ri", - .sof_tplg_filename = "intel/sof-icl-rt274.tplg", + .sof_fw_filename = "sof-icl.ri", + .sof_tplg_filename = "sof-icl-rt274.tplg", .asoc_plat_name = "0000:00:1f.3", }, { From 4d155572a455af50b2f2577061677e0758cceec0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 15:23:27 -0600 Subject: [PATCH 0834/1995] ASoC: Intel: byt-match.c: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-byt-match.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 306168d3430f48..d84dbe9ac8e344 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -197,8 +197,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { { .id = "10EC5682", .drv_name = "sof_rt5682", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5682.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5682.tplg", .asoc_plat_name = "sst-mfld-platform", }, /* some Baytrail platforms rely on RT5645, use CHT machine driver */ From 3f07525f3f499fc7f86a11b82bbf36bc9f40f727 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 15:23:28 -0600 Subject: [PATCH 0835/1995] ASoC: Intel: cht-match.c.c: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-cht-match.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c index 00ef347ad42563..dbab81a870ecbd 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -176,8 +176,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { { .id = "10EC5682", .drv_name = "sof_rt5682", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5682.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5682.tplg", .asoc_plat_name = "sst-mfld-platform", }, /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */ From 8eebbe2375c0cce6160ba384902852e60952a49b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 15:23:28 -0600 Subject: [PATCH 0836/1995] ASoC: Intel: cnl-match.c.c: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index b2e8e37768ca71..6ed354d0eafb11 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -29,15 +29,15 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .drv_name = "cnl_max98373", .fw_filename = "intel/dsp_fw_cnl.bin", .pdata = &cnl_pdata, - .sof_fw_filename = "intel/sof-cnl.ri", - .sof_tplg_filename = "intel/sof-cnl.tplg", + .sof_fw_filename = "sof-cnl.ri", + .sof_tplg_filename = "sof-cnl.tplg", .asoc_plat_name = "0000:00:0e.0", }, { .id = "10EC5682", .drv_name = "sof_rt5682", - .sof_fw_filename = "intel/sof-cnl.ri", - .sof_tplg_filename = "intel/sof-cml-rt5682.tplg", + .sof_fw_filename = "sof-cnl.ri", + .sof_tplg_filename = "sof-cml-rt5682.tplg", .asoc_plat_name = "0000:00:0e.0", }, {}, From ffd2e26e35a549e5ee082e8979002f5bf53fac3b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 15:23:29 -0600 Subject: [PATCH 0837/1995] ASoC: Intel: icl-match.c.c: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-icl-match.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c index e13978f51b744b..d6f6834a341fa9 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -27,8 +27,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { { .id = "10EC5682", .drv_name = "sof_rt5682", - .sof_fw_filename = "intel/sof-icl.ri", - .sof_tplg_filename = "intel/sof-icl-rt5682.tplg", + .sof_fw_filename = "sof-icl.ri", + .sof_tplg_filename = "sof-icl-rt5682.tplg", .asoc_plat_name = "0000:00:1f.3", }, {}, From 1f6e6197f9b5515acf211d9993e4a88017ccf4a3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 15:26:21 -0600 Subject: [PATCH 0838/1995] ASoC: Intel: bcm283x-rpi-sof.dtsi.c: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart --- arch/arm/boot/dts/bcm283x-rpi-sof.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/bcm283x-rpi-sof.dtsi b/arch/arm/boot/dts/bcm283x-rpi-sof.dtsi index 1b69ac517f95bb..2243ef50c3477c 100644 --- a/arch/arm/boot/dts/bcm283x-rpi-sof.dtsi +++ b/arch/arm/boot/dts/bcm283x-rpi-sof.dtsi @@ -7,8 +7,8 @@ compatible = "sof,spi-sue-creek"; // FIXME: frequency value spi-max-frequency = <54000000>; - fw_filename = "intel/sof-spi.ri"; - tplg_filename = "intel/sof-spi.tplg"; + fw_filename = "sof-spi.ri"; + tplg_filename = "sof-spi.tplg"; // FIXME: GPIO controller and IRQ number and sense interrupt-parent = <&gpio1>; interrupts = <9 IRQ_TYPE_EDGE_FALLING>; From d96f3eebcf50b0def8141b992d854c2f8a0428f9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 11:25:23 -0600 Subject: [PATCH 0839/1995] ASoC: SOF: add load_firmware_raw helper De-duplicate code between regular and HDaudio loader. Introduce a new helper to just request the firmware. Tested on Up2 with HDMI output Suggested-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/apl.c | 2 +- sound/soc/sof/intel/cnl.c | 2 +- sound/soc/sof/intel/hda-loader.c | 18 ------------------ sound/soc/sof/intel/hda.h | 1 - sound/soc/sof/intel/skl.c | 2 +- sound/soc/sof/loader.c | 15 +++++++++++++-- sound/soc/sof/sof-priv.h | 1 + 7 files changed, 17 insertions(+), 24 deletions(-) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index bcad8edb079d98..d9177a56d2e5b6 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -68,7 +68,7 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .pcm_pointer = hda_dsp_pcm_pointer, /* firmware loading */ - .load_firmware = hda_dsp_cl_load_fw, + .load_firmware = snd_sof_load_firmware_raw, /* firmware run */ .run = hda_dsp_cl_boot_firmware, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 6b3bda8c5e17f2..d132edef051765 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -217,7 +217,7 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .pcm_trigger = hda_dsp_pcm_trigger, /* firmware loading */ - .load_firmware = hda_dsp_cl_load_fw, + .load_firmware = snd_sof_load_firmware_raw, /* pre/post fw run */ .pre_fw_run = hda_dsp_pre_fw_run, diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 0ad61422ad54fa..6a5e07df411655 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -245,24 +245,6 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) return status; } -int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev) -{ - struct snd_sof_pdata *plat_data = sdev->pdata; - const char *fw_filename; - - /* set code loading condition to true */ - sdev->code_loading = 1; - - fw_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, - "%s/%s", - plat_data->fw_filename_prefix, - plat_data->fw_filename); - if (!fw_filename) - return -ENOMEM; - - return request_firmware(&plat_data->fw, fw_filename, sdev->dev); -} - int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) { struct snd_sof_pdata *plat_data = sdev->pdata; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 79953d05d020c5..ca6e8fc947f4ab 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -479,7 +479,6 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); /* * DSP Code loader. */ -int hda_dsp_cl_load_fw(struct snd_sof_dev *sdev); int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev); int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev); diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 014720aefdb166..e987b5607cbfc1 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -67,7 +67,7 @@ const struct snd_sof_dsp_ops sof_skl_ops = { .pcm_trigger = hda_dsp_pcm_trigger, /* firmware loading */ - .load_firmware = hda_dsp_cl_load_fw, + .load_firmware = snd_sof_load_firmware_raw, /* pre/post fw run */ .pre_fw_run = hda_dsp_pre_fw_run, diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 5256c5ecce8355..8a1a45df73889e 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -223,7 +223,7 @@ static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw) return 0; } -int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev) +int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev) { struct snd_sof_pdata *plat_data = sdev->pdata; const char *fw_filename; @@ -244,8 +244,19 @@ int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "error: request firmware %s failed err: %d\n", fw_filename, ret); - return ret; } + return ret; +} +EXPORT_SYMBOL(snd_sof_load_firmware_raw); + +int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + int ret; + + ret = snd_sof_load_firmware_raw(sdev); + if (ret < 0) + return ret; /* make sure the FW header and file is valid */ ret = check_header(sdev, plat_data->fw); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index f3e518d434dbac..aa64fa75e355d5 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -417,6 +417,7 @@ int snd_sof_create_page_table(struct snd_sof_dev *sdev, * Firmware loading. */ int snd_sof_load_firmware(struct snd_sof_dev *sdev); +int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev); int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev); int snd_sof_run_firmware(struct snd_sof_dev *sdev); int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, From 94db22be08648363cec62032ec0ab6b3de39f302 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 11:41:53 -0600 Subject: [PATCH 0840/1995] ASoC: SOF: control: align declaration and definitions for ext_bytes Reported by cppcheck - use binary_data [sof-priv.h:520] -> [control.c:206]: (style, inconclusive) Function 'snd_sof_bytes_ext_put' argument 2 names different: declaration 'bytes' definition 'binary_data'. [sof-priv.h:523] -> [control.c:290]: (style, inconclusive) Function 'snd_sof_bytes_ext_get' argument 2 names different: declaration 'bytes' definition 'binary_data'. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-priv.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index aa64fa75e355d5..32e6c29279eec8 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -531,10 +531,10 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, - const unsigned int __user *bytes, + const unsigned int __user *binary_data, unsigned int size); int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, - unsigned int __user *bytes, + unsigned int __user *binary_data, unsigned int size); /* From 88a3cb655c7442e6896aa02a4bc04ff750cf7597 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 11:45:47 -0600 Subject: [PATCH 0841/1995] ASoC: SOF: debug: remove unneeded init Reported by cppcheck [debug.c:145]: (style) Variable 'err' is assigned a value that is never used. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/debug.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index f59980831b2ea9..16f11b325d1390 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -142,7 +142,8 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) { const struct snd_sof_dsp_ops *ops = sof_ops(sdev); const struct snd_sof_debugfs_map *map; - int err = 0, i; + int i; + int err; /* use "sof" as top level debugFS dir */ sdev->debugfs_root = debugfs_create_dir("sof", NULL); From 72d0aee9f801c1b9ebcd9a412fb8ea3f70d9b1e2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 11:48:37 -0600 Subject: [PATCH 0842/1995] ASoC: SOF: Intel: cnl: remove unneeded inits Reported by cppcheck [cnl.c:32]: (style) Variable 'msg' is assigned a value that is never used. [cnl.c:32]: (style) Variable 'msg_ext' is assigned a value that is never used. Also remove all declarations on one line. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/cnl.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index d132edef051765..a294f80940c738 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -29,7 +29,13 @@ static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; - u32 hipci, hipcctl, hipcida, hipctdr, hipctdd, msg = 0, msg_ext = 0; + u32 hipci; + u32 hipcctl; + u32 hipcida; + u32 hipctdr; + u32 hipctdd; + u32 msg; + u32 msg_ext; irqreturn_t ret = IRQ_NONE; /* here we handle IPC interrupts only */ From 8ee4b273c2d8f5e518c690540347d74d07eebc7e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 11:51:17 -0600 Subject: [PATCH 0843/1995] ASoC: SOF: Intel: hda: remove unneeded initialization reported by cppcheck [hda-ipc.c:121]: (style) Variable 'msg' is assigned a value that is never used. [hda-ipc.c:121]: (style) Variable 'msg_ext' is assigned a value that is never used. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-ipc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 03e8e3e1dca84e..b25f9d9fb781a6 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -118,7 +118,13 @@ int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev, irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; - u32 hipci, hipcie, hipct, hipcte, hipcctl, msg = 0, msg_ext = 0; + u32 hipci; + u32 hipcie; + u32 hipct; + u32 hipcte; + u32 hipcctl; + u32 msg; + u32 msg_ext; irqreturn_t ret = IRQ_NONE; int reply = -EINVAL; From d7879a927801774098d5df7feeb13400f2490dae Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 12:18:58 -0600 Subject: [PATCH 0844/1995] ASoC: SOF: Intel: hda-stream: fix tag declaration reported by cppcheck [hda.h:461] -> [hda-stream.c:185]: (style, inconclusive) Function 'hda_dsp_stream_put' argument 3 names different: declaration 'stream_tag' definition 'tag'. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-stream.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 7d409973b5518d..4899d5b4ba699a 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -182,7 +182,7 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction) } /* free a stream */ -int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int tag) +int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag) { struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_stream *s; @@ -192,7 +192,7 @@ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int tag) /* find used stream */ list_for_each_entry(s, &bus->stream_list, list) { if (s->direction == direction && - s->opened && s->stream_tag == tag) { + s->opened && s->stream_tag == stream_tag) { s->opened = false; spin_unlock_irq(&bus->reg_lock); return 0; @@ -201,7 +201,7 @@ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int tag) spin_unlock_irq(&bus->reg_lock); - dev_dbg(sdev->dev, "tag %d not opened!\n", tag); + dev_dbg(sdev->dev, "stream_tag %d not opened!\n", stream_tag); return -ENODEV; } From aa5eca777d6ff0cef97f3114096efc78c36884c1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 12:21:40 -0600 Subject: [PATCH 0845/1995] ASoC: SOF: Intel: hda-trace: fix trace definition reported by cppcheck [hda.h:532] -> [hda-trace.c:41]: (style, inconclusive) Function 'hda_dsp_trace_init' argument 2 names different: declaration 'stream_tag' definition 'tag'. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-trace.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c index dc0d1a091854cb..6fd77d511118c7 100644 --- a/sound/soc/sof/intel/hda-trace.c +++ b/sound/soc/sof/intel/hda-trace.c @@ -38,7 +38,7 @@ static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev) return ret; } -int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *tag) +int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag) { struct sof_intel_hda_dev *hda = (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; @@ -53,7 +53,7 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *tag) return -ENODEV; } - *tag = hda->dtrace_stream->hstream.stream_tag; + *stream_tag = hda->dtrace_stream->hstream.stream_tag; /* * initialize capture stream, set BDL address and return corresponding @@ -62,9 +62,9 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *tag) ret = hda_dsp_trace_prepare(sdev); if (ret < 0) { dev_err(sdev->dev, "error: hdac trace init failed: %x\n", ret); - hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_CAPTURE, *tag); + hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_CAPTURE, *stream_tag); hda->dtrace_stream = NULL; - *tag = 0; + *stream_tag = 0; } return ret; From 394ce7a785ea7f3b1ccce0e3f98d74de544acde2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 12:25:30 -0600 Subject: [PATCH 0846/1995] ASoC: SOF: ipc: fix header mismatch reported by cppcheck [sof-priv.h:428] -> [ipc.c:246]: (style, inconclusive) Function 'sof_ipc_tx_message' argument 3 names different: declaration 'tx_data' definition 'msg_data'. [sof-priv.h:429] -> [ipc.c:246]: (style, inconclusive) Function 'sof_ipc_tx_message' argument 4 names different: declaration 'tx_bytes' definition 'msg_bytes'. [sof-priv.h:429] -> [ipc.c:246]: (style, inconclusive) Function 'sof_ipc_tx_message' argument 5 names different: declaration 'rx_data' definition 'reply_data'. [sof-priv.h:429] -> [ipc.c:247]: (style, inconclusive) Function 'sof_ipc_tx_message' argument 6 names different: declaration 'rx_bytes' definition 'reply_bytes'. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-priv.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 32e6c29279eec8..8a94c9ae711916 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -439,8 +439,9 @@ int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox, size_t dspbox_size, u32 hostbox, size_t hostbox_size); int snd_sof_ipc_valid(struct snd_sof_dev *sdev); -int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, void *tx_data, - size_t tx_bytes, void *rx_data, size_t rx_bytes); +int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, + void *msg_data, size_t msg_bytes, void *reply_data, + size_t reply_bytes); struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev, char *name); struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev, From eb9858827c5a5b2de3f3cfa2254fd98f231f40fc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 12:28:06 -0600 Subject: [PATCH 0847/1995] ASoC: SOF: utils: remove unneeded initialization reported by cppcheck [utils.c:97]: (style) Variable 'tmp' is assigned a value that is never used. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index 73c5900319d338..9ade9aa30ab5f7 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -74,7 +74,7 @@ void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, void __iomem *dest = sdev->bar[bar] + offset; const u8 *src_byte = src; u32 affected_mask; - u32 tmp = 0; + u32 tmp; int m, n; m = size / 4; From d3c50de03c17338406956cae0ff472ef7e6beacb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 12:55:39 -0600 Subject: [PATCH 0848/1995] ASoC: SOF: core: fix declaration reported by cppcheck [sof-priv.h:514] -> [core.c:145]: (style, inconclusive) Function 'snd_sof_get_status' argument 7 names different: declaration 'stack_size' definition 'stack_words'. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-priv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 8a94c9ae711916..fbdd31829eeb85 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -511,7 +511,7 @@ void snd_sof_trace_notify_for_error(struct snd_sof_dev *sdev); int snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, u32 tracep_code, void *oops, struct sof_ipc_panic_info *panic_info, - void *stack, size_t stack_size); + void *stack, size_t stack_words); int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev); /* From c6fcfc4383ebc3fb8c5ed737f8aee37171e4f893 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 14:10:34 -0600 Subject: [PATCH 0849/1995] ASoC: SOF: dai-intel: add LBM quirk to align with firmware Definition only, the actual quirk will need to be propagated with the existing quirk token Signed-off-by: Pierre-Louis Bossart --- include/sound/sof/dai-intel.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h index 11e6fec8ec21a8..4bd83f7adddf65 100644 --- a/include/sound/sof/dai-intel.h +++ b/include/sound/sof/dai-intel.h @@ -23,6 +23,9 @@ #define SOF_DAI_INTEL_SSP_QUIRK_PSPSTWFDFD (1 << 4) /* ssc2: PSPSRWFDFD */ #define SOF_DAI_INTEL_SSP_QUIRK_PSPSRWFDFD (1 << 5) +/* ssc1: LBM */ +#define SOF_DAI_INTEL_SSP_QUIRK_LBM (1 << 6) + /* here is the possibility to define others aux macros */ #define SOF_DAI_INTEL_SSP_FRAME_PULSE_WIDTH_MAX 38 From 12b8b009c75cabfa2f0ac7e934393b2d7340979f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 16:26:40 -0600 Subject: [PATCH 0850/1995] ASoC: SOF: remove use of asoc_plat_name This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-pci-dev.c | 1 - sound/soc/sof/sof-spi-dev.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 36150512397ec6..f7503d1c502ab2 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -72,7 +72,6 @@ static struct snd_soc_acpi_mach sof_tng_machines[] = { .drv_name = "edison", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt.tplg", - .asoc_plat_name = "baytrail-pcm-audio", }, {} }; diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c index f4e43a7b97d636..7cc051d17f0162 100644 --- a/sound/soc/sof/sof-spi-dev.c +++ b/sound/soc/sof/sof-spi-dev.c @@ -38,7 +38,6 @@ static struct snd_soc_acpi_mach spi_machines[] = { .drv_name = "bxt_alc298s_i2s", .sof_fw_filename = "sof-spi.ri", .sof_tplg_filename = "sof-spi.tplg", - .asoc_plat_name = "0000:00:0e.0", }, }; @@ -124,7 +123,6 @@ static int sof_spi_probe(struct spi_device *spi) */ mach->sof_fw_filename = desc->nocodec_fw_filename; mach->sof_tplg_filename = desc->nocodec_tplg_filename; - mach->asoc_plat_name = "sof-platform"; mach->mach_params.platform = dev_name(dev); sof_pdata->name = dev_name(&spi->dev); From d464b73cb92987d20a3ffe426705caca4066bbfa Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 16:29:29 -0600 Subject: [PATCH 0851/1995] ASoC: Intel: soc-acpi: remove asoc_plat_name This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-byt-match.c | 1 - sound/soc/intel/common/soc-acpi-intel-cht-match.c | 1 - sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 2 -- sound/soc/intel/common/soc-acpi-intel-icl-match.c | 1 - 4 files changed, 5 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index d84dbe9ac8e344..118258aa11a0d8 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -199,7 +199,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "sof_rt5682", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5682.tplg", - .asoc_plat_name = "sst-mfld-platform", }, /* some Baytrail platforms rely on RT5645, use CHT machine driver */ { diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c index dbab81a870ecbd..e6fa7f3f055257 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -178,7 +178,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "sof_rt5682", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5682.tplg", - .asoc_plat_name = "sst-mfld-platform", }, /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */ { diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index 6ed354d0eafb11..e8eabf031d768f 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -31,14 +31,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .pdata = &cnl_pdata, .sof_fw_filename = "sof-cnl.ri", .sof_tplg_filename = "sof-cnl.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "10EC5682", .drv_name = "sof_rt5682", .sof_fw_filename = "sof-cnl.ri", .sof_tplg_filename = "sof-cml-rt5682.tplg", - .asoc_plat_name = "0000:00:0e.0", }, {}, }; diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c index d6f6834a341fa9..777f27286f6e82 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -29,7 +29,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { .drv_name = "sof_rt5682", .sof_fw_filename = "sof-icl.ri", .sof_tplg_filename = "sof-icl-rt5682.tplg", - .asoc_plat_name = "0000:00:1f.3", }, {}, }; From 08c7c091206074b39a8387b8ff5ca097fc5edbfa Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 16:11:28 -0600 Subject: [PATCH 0852/1995] ASoC: Intel: soc-acpi: bxt-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-bxt-match.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c index c0e5780e2ad165..229e395868684e 100644 --- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c @@ -53,7 +53,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .fw_filename = "intel/dsp_fw_bxtn.bin", .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-rt298.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "DLGS7219", @@ -63,21 +62,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .quirk_data = &bxt_codecs, .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-da7219.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "104C5122", .drv_name = "bxt-pcm512x", .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-pcm512x.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "1AEC8804", .drv_name = "bxt-wm8804", .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-wm8804.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "INT34C3", @@ -85,7 +81,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .machine_quirk = apl_quirk, .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-tdf8532.tplg", - .asoc_plat_name = "0000:00:0e.0", }, {}, }; From bc08eef38d3ff232bb1382d406a3d951b5fc0d09 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 16:11:42 -0600 Subject: [PATCH 0853/1995] ASoC: Intel: soc-acpi: byt-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-byt-match.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 118258aa11a0d8..0cfab247876ab2 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -85,7 +85,6 @@ static struct snd_soc_acpi_mach byt_thinkpad_10 = { .board = "cht-bsw", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5670.tplg", - .asoc_plat_name = "sst-mfld-platform", }; static struct snd_soc_acpi_mach byt_pov_p1006w = { @@ -95,7 +94,6 @@ static struct snd_soc_acpi_mach byt_pov_p1006w = { .board = "bytcr_rt5651", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5651.tplg", - .asoc_plat_name = "sst-mfld-platform", }; static struct snd_soc_acpi_mach *byt_quirk(void *arg) @@ -138,7 +136,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .machine_quirk = byt_quirk, .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5642", @@ -147,7 +144,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcr_rt5640", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "INTCCFFD", @@ -156,7 +152,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcr_rt5640", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5651", @@ -165,7 +160,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcr_rt5651", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5651.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "DLGS7212", @@ -174,7 +168,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcht_da7213", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-da7213.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "DLGS7213", @@ -183,7 +176,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcht_da7213", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-da7213.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "ESSX8316", @@ -192,7 +184,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcht_es8316", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-es8316.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5682", @@ -208,7 +199,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5648", @@ -217,7 +207,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, /* use CHT driver to Baytrail Chromebooks */ { @@ -227,7 +216,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-max98090.tplg", - .asoc_plat_name = "sst-mfld-platform", }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) /* From 9b9ea2bade5d84de154b9f657aa6e470e692b7ae Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 16:11:42 -0600 Subject: [PATCH 0854/1995] ASoC: Intel: soc-acpi: cht-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-cht-match.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c index e6fa7f3f055257..ff9c31a39ad400 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -46,7 +46,6 @@ static struct snd_soc_acpi_mach cht_surface_mach = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }; static struct snd_soc_acpi_mach *cht_quirk(void *arg) @@ -70,7 +69,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5670.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5672", @@ -79,7 +77,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5670.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5645", @@ -88,7 +85,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5650", @@ -97,7 +93,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC3270", @@ -106,7 +101,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "193C9890", @@ -115,7 +109,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-max98090.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10508824", @@ -124,7 +117,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-nau8824.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "DLGS7212", @@ -133,7 +125,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcht_da7213", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-da7213.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "DLGS7213", @@ -142,7 +133,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcht_da7213", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-da7213.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "ESSX8316", @@ -151,7 +141,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcht_es8316", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-es8316.tplg", - .asoc_plat_name = "sst-mfld-platform", }, /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ { @@ -162,7 +151,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .machine_quirk = cht_quirk, .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC3276", @@ -171,7 +159,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcr_rt5640", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5682", @@ -187,7 +174,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcr_rt5651", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5651.tplg", - .asoc_plat_name = "sst-mfld-platform", }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) /* From ab4eee25a96495f4df29d830f83347baa974296f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 16:11:42 -0600 Subject: [PATCH 0855/1995] ASoC: Intel: soc-acpi: glk-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-glk-match.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c index 75bc0109166a0a..3f2061475ae426 100644 --- a/sound/soc/intel/common/soc-acpi-intel-glk-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c @@ -21,7 +21,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { .fw_filename = "intel/dsp_fw_glk.bin", .sof_fw_filename = "sof-glk.ri", .sof_tplg_filename = "sof-glk-alc298.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "DLGS7219", @@ -31,7 +30,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { .quirk_data = &glk_codecs, .sof_fw_filename = "sof-glk.ri", .sof_tplg_filename = "sof-glk-da7219.tplg", - .asoc_plat_name = "0000:00:0e.0", }, {}, }; From cce368e22c2da1631af6f146534e9acbd8fed10b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 16:11:43 -0600 Subject: [PATCH 0856/1995] ASoC: Intel: soc-acpi: hsw-bdw-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c index ddfe4250c2bcb9..690b305a255b4b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c @@ -25,7 +25,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_haswell_machines[] = { .fw_filename = "intel/IntcSST1.bin", .sof_fw_filename = "sof-hsw.ri", .sof_tplg_filename = "sof-hsw.tplg", - .asoc_plat_name = "haswell-pcm-audio", }, {} }; @@ -38,7 +37,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { .fw_filename = "intel/IntcSST2.bin", .sof_fw_filename = "sof-bdw.ri", .sof_tplg_filename = "sof-bdw-rt286.tplg", - .asoc_plat_name = "haswell-pcm-audio", }, { .id = "RT5677CE", @@ -46,7 +44,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { .fw_filename = "intel/IntcSST2.bin", .sof_fw_filename = "sof-bdw.ri", .sof_tplg_filename = "sof-bdw-rt5677.tplg", - .asoc_plat_name = "haswell-pcm-audio", }, { .id = "INT33CA", @@ -54,7 +51,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { .fw_filename = "intel/IntcSST2.bin", .sof_fw_filename = "sof-bdw.ri", .sof_tplg_filename = "sof-bdw-rt5640.tplg", - .asoc_plat_name = "haswell-pcm-audio", }, {} }; From 6d849d062d6a2123ba0725226df79b680b114b59 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 16:11:43 -0600 Subject: [PATCH 0857/1995] ASoC: Intel: soc-acpi: icl-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-icl-match.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c index 777f27286f6e82..0b430b9b367368 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -22,7 +22,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { .pdata = &icl_pdata, .sof_fw_filename = "sof-icl.ri", .sof_tplg_filename = "sof-icl-rt274.tplg", - .asoc_plat_name = "0000:00:1f.3", }, { .id = "10EC5682", From 54c2f32769ea4fd889c17bfd476d48bb74bd63eb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 16:16:45 -0600 Subject: [PATCH 0858/1995] ASoC: Intel: soc-acpi: cnl-match.c: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index e8eabf031d768f..39343ff9bf3456 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -22,7 +22,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .pdata = &cnl_pdata, .sof_fw_filename = "sof-cnl.ri", .sof_tplg_filename = "sof-cnl-rt274.tplg", - .asoc_plat_name = "0000:00:1f.3", }, { .id = "MX98373", From 74dc3d2318011aa57981918d9bf0f7833d084fae Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 16:21:39 -0600 Subject: [PATCH 0859/1995] ASoC: soc-acpi: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart --- include/sound/soc-acpi.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 6cbbeed9cdd0c8..655e4e010cc821 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -86,8 +86,6 @@ struct snd_soc_acpi_mach_params { * is not constant since this field may be updated at run-time * @sof_fw_filename: Sound Open Firmware file name, if enabled * @sof_tplg_filename: Sound Open Firmware topology file name, if enabled - * @asoc_plat_name: ASoC platform name, used for binding machine drivers - * if non NULL * @new_mach_data: machine driver private data fixup */ /* Descriptor for SST ASoC machine driver */ @@ -102,7 +100,6 @@ struct snd_soc_acpi_mach { struct snd_soc_acpi_mach_params mach_params; const char *sof_fw_filename; const char *sof_tplg_filename; - const char *asoc_plat_name; struct platform_device * (*new_mach_data)(void *pdata); }; From 43dfb36631b77e80894538a0631a9ce85a927333 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:15:46 -0600 Subject: [PATCH 0860/1995] ASoC: soc-acpi: remove new_mach_data field We never used this field (or in older SOF implementations), let's remove it Signed-off-by: Pierre-Louis Bossart --- include/sound/soc-acpi.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 655e4e010cc821..35b38e41e5b296 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -86,7 +86,6 @@ struct snd_soc_acpi_mach_params { * is not constant since this field may be updated at run-time * @sof_fw_filename: Sound Open Firmware file name, if enabled * @sof_tplg_filename: Sound Open Firmware topology file name, if enabled - * @new_mach_data: machine driver private data fixup */ /* Descriptor for SST ASoC machine driver */ struct snd_soc_acpi_mach { @@ -100,7 +99,6 @@ struct snd_soc_acpi_mach { struct snd_soc_acpi_mach_params mach_params; const char *sof_fw_filename; const char *sof_tplg_filename; - struct platform_device * (*new_mach_data)(void *pdata); }; #define SND_SOC_ACPI_MAX_CODECS 3 From 4f4afbeac332eb33bc4465455127b192a3988a49 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 16:40:30 -0600 Subject: [PATCH 0861/1995] ASoC: Intel: bxt_wm8804: add pm_ops Needed for PM support w/ SOF Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bxt_wm8804.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/boards/bxt_wm8804.c b/sound/soc/intel/boards/bxt_wm8804.c index de6a4669731bd2..2cf51115482ef8 100644 --- a/sound/soc/intel/boards/bxt_wm8804.c +++ b/sound/soc/intel/boards/bxt_wm8804.c @@ -252,6 +252,7 @@ static int bxt_wm8804_probe(struct platform_device *pdev) static struct platform_driver bxt_wm8804_driver = { .driver = { .name = "bxt-wm8804", + .pm = &snd_soc_pm_ops, }, .probe = bxt_wm8804_probe, }; From bd10b56a61b8f54a95b215b1b5613403376f7899 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 19:21:55 -0600 Subject: [PATCH 0862/1995] ASoC: SOF: Kconfig: remove trailing space Fix warnings with git am. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 06b237f726e17d..4c8396dccb301f 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -156,4 +156,3 @@ source "sound/soc/sof/intel/Kconfig" source "sound/soc/sof/xtensa/Kconfig" endif - From 54ad0e15e8d80d073112b9467e37b268b5578b76 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 19:21:55 -0600 Subject: [PATCH 0863/1995] ASoC: SOF: intel/hda-ctrl: remove trailing space Fix warnings with git am. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-ctrl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index e8f27012ec119b..cda8c6c6e85920 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -163,4 +163,3 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) return ret; } #endif - From 0b452ad8359ef667d79d13f1187963418116b33d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 19:21:56 -0600 Subject: [PATCH 0864/1995] ASoC: SOF: intel/hda-pcm: remove trailing space Fix warnings with git am. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-pcm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 1e91d42e700da7..1c6adecf4a4fbe 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -233,4 +233,3 @@ int hda_dsp_pcm_close(struct snd_sof_dev *sdev, substream->runtime->private_data = NULL; return 0; } - From 9a6afd1d2528acad299443ab87c5c29aecf0e170 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 19:21:56 -0600 Subject: [PATCH 0865/1995] ASoC: SOF: intel/hda-stream: remove trailing space Fix warnings with git am. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-stream.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 4899d5b4ba699a..c70046f20eece1 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -661,4 +661,3 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev) devm_kfree(sdev->dev, stream); } } - From f89d568694261e2ac2b60e3c3ee569a1e1bf6695 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 19:21:57 -0600 Subject: [PATCH 0866/1995] ASoC: SOF: pcm: remove trailing space Fix warnings with git am. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pcm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index b60362d08626b1..3376633b0d461d 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -708,4 +708,3 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) /* do not increase the refcount in core */ pd->ignore_module_refcount = 1; } - From 66ca36b921dbd27778804a440ceea8668614b56c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 19:21:57 -0600 Subject: [PATCH 0867/1995] ASoC: SOF: xtensa/Kconfig: remove trailing space Fix warnings with git am. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/xtensa/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/xtensa/Kconfig b/sound/soc/sof/xtensa/Kconfig index f66f17bb03357f..8a9343b8514673 100644 --- a/sound/soc/sof/xtensa/Kconfig +++ b/sound/soc/sof/xtensa/Kconfig @@ -1,3 +1,2 @@ config SND_SOC_SOF_XTENSA tristate - From bf067df761b08be1465c5dd36c25f3cfb3226ad9 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 8 Feb 2019 12:17:42 -0800 Subject: [PATCH 0868/1995] ASoC: SOF: don't overwrite nocodec fw filenames move fw filename and tplg filename fix up right after a machine driver match is found. This will avoid overwriting the nocodec file names. Also, no need to set up nocodec machine driver in sof-acpi-dev as this will be done during sof_probe if no matching ASoC machine driver has been found. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/sof-acpi-dev.c | 18 ++++-------------- sound/soc/sof/sof-pci-dev.c | 13 ++++++------- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 51d7887633eb6d..53d2ade525b57f 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -224,17 +224,10 @@ static int sof_acpi_probe(struct platform_device *pdev) /* find machine */ mach = snd_soc_acpi_find_machine(desc->machines); if (!mach) { -#if IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) - /* fallback to nocodec mode */ - dev_warn(dev, "No matching ASoC machine driver found - using nocodec\n"); - mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); - ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); - if (ret < 0) - return ret; -#else - dev_err(dev, "error: no matching ASoC machine driver found - aborting probe\n"); - return -ENODEV; -#endif + dev_warn(dev, "warning: No matching ASoC machine driver found\n"); + } else { + sof_pdata->fw_filename = mach->sof_fw_filename; + sof_pdata->tplg_filename = mach->sof_tplg_filename; } #endif @@ -259,9 +252,6 @@ static int sof_acpi_probe(struct platform_device *pdev) sof_pdata->tplg_filename_prefix = sof_pdata->desc->default_tplg_path; - sof_pdata->fw_filename = mach->sof_fw_filename; - sof_pdata->tplg_filename = mach->sof_tplg_filename; - #if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) /* set callback to enable runtime_pm */ sof_pdata->sof_probe_complete = sof_acpi_probe_complete; diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index f7503d1c502ab2..27d43bcca8de4e 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -232,13 +232,17 @@ static int sof_pci_probe(struct pci_dev *pci, ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); if (ret < 0) goto release_regions; + #else /* find machine */ mach = snd_soc_acpi_find_machine(desc->machines); - if (!mach) + if (!mach) { dev_warn(dev, "warning: No matching ASoC machine driver found\n"); - else + } else { mach->mach_params.platform = dev_name(dev); + sof_pdata->fw_filename = mach->sof_fw_filename; + sof_pdata->tplg_filename = mach->sof_tplg_filename; + } #endif /* CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE */ sof_pdata->name = pci_name(pci); @@ -260,11 +264,6 @@ static int sof_pci_probe(struct pci_dev *pci, sof_pdata->tplg_filename_prefix = sof_pdata->desc->default_tplg_path; - if (mach) { - sof_pdata->fw_filename = mach->sof_fw_filename; - sof_pdata->tplg_filename = mach->sof_tplg_filename; - } - #if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) /* set callback to enable runtime_pm */ sof_pdata->sof_probe_complete = sof_pci_probe_complete; From 93e64a10c90037599fb88f1f57e62839ccffa9f4 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Fri, 8 Feb 2019 20:07:19 +0200 Subject: [PATCH 0869/1995] ASoC: SOF: Fix DMIC IPC ABI break by setting fifo_bits_b value The previous firmware version 3:0:0 contains check for this parameter for a supported word length despite that is not used. Setting it to fixed value 16 with old firmware avoids the parameters check code to return error. Signed-off-by: Seppo Ingalsuo --- sound/soc/sof/topology.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index b6a65c149f6618..e163138088e68f 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2103,6 +2103,8 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_private *private = &cfg->priv; struct sof_ipc_dai_config *ipc_config; struct sof_ipc_reply reply; + struct sof_ipc_fw_ready *ready = &sdev->fw_ready; + struct sof_ipc_fw_version *v = &ready->version; u32 size; int ret, j; @@ -2188,6 +2190,11 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, ipc_config->dmic.pdm[j].skew); } + if (SOF_ABI_VER(v->major, v->minor, v->micro) < SOF_ABI_VER(3, 0, 1)) { + /* this takes care of backwards compatible handling of fifo_bits_b */ + ipc_config->dmic.reserved_2 = ipc_config->dmic.fifo_bits; + } + /* send message to DSP */ ret = sof_ipc_tx_message(sdev->ipc, ipc_config->hdr.cmd, ipc_config, size, &reply, From 12f2d57ccdcc081dd84265e13daff4738d257059 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Sun, 10 Feb 2019 23:06:44 +0800 Subject: [PATCH 0870/1995] ASoC: intel: sof_rt5682: add quirk for Google Hatch Add quirk for Google Hatch. Signed-off-by: Bard liao --- sound/soc/intel/boards/sof_rt5682.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 92581a192bc2cc..a8905aaa5ccd8c 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -66,6 +66,16 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { SOF_RT5682_MCLK_24MHZ | SOF_RT5682_SSP(1)), }, + { + .callback = sof_rt5682_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_PRODUCT_NAME, "Hatch"), + }, + .driver_data = (void *)(SOF_RT5682_MCLK_EN | + SOF_RT5682_MCLK_24MHZ | + SOF_RT5682_SSP(0)), + }, { .callback = sof_rt5682_quirk_cb, .matches = { From 9a4d3f472145e89d7f0150f99cb8546523372547 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 7 Feb 2019 11:38:54 -0800 Subject: [PATCH 0871/1995] ASoC: SOF: debug: unify dfsentry struct Unify the dfsentry structure for the IO and buffer types with a common structure and a type member. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/debug.c | 15 ++++++++++----- sound/soc/sof/sof-priv.h | 18 ++++++++++-------- sound/soc/sof/trace.c | 5 +++-- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 16f11b325d1390..abe306b8f01438 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -20,7 +20,7 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { - struct snd_sof_dfsentry_io *dfse = file->private_data; + struct snd_sof_dfsentry *dfse = file->private_data; struct snd_sof_dev *sdev = dfse->sdev; int size; u32 *buf; @@ -48,7 +48,10 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, /* copy from DSP MMIO */ pm_runtime_get_noresume(sdev->dev); - memcpy_fromio(buf, dfse->buf + pos, size); + if (dfse->type == SOF_DFSENTRY_TYPE_IOMEM) + memcpy_fromio(buf, dfse->io_mem + pos, size); + else + memcpy(buf, dfse->buf + pos, size); /* * TODO: revisit to check if we need mark_last_busy, or if we @@ -83,7 +86,7 @@ int snd_sof_debugfs_io_create_item(struct snd_sof_dev *sdev, void __iomem *base, size_t size, const char *name) { - struct snd_sof_dfsentry_io *dfse; + struct snd_sof_dfsentry *dfse; if (!sdev) return -EINVAL; @@ -92,7 +95,8 @@ int snd_sof_debugfs_io_create_item(struct snd_sof_dev *sdev, if (!dfse) return -ENOMEM; - dfse->buf = base; + dfse->type = SOF_DFSENTRY_TYPE_IOMEM; + dfse->io_mem = base; dfse->size = size; dfse->sdev = sdev; @@ -113,7 +117,7 @@ int snd_sof_debugfs_buf_create_item(struct snd_sof_dev *sdev, void *base, size_t size, const char *name) { - struct snd_sof_dfsentry_buf *dfse; + struct snd_sof_dfsentry *dfse; if (!sdev) return -EINVAL; @@ -122,6 +126,7 @@ int snd_sof_debugfs_buf_create_item(struct snd_sof_dev *sdev, if (!dfse) return -ENOMEM; + dfse->type = SOF_DFSENTRY_TYPE_BUF; dfse->buf = base; dfse->size = size; dfse->sdev = sdev; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index fbdd31829eeb85..57eb32d9d3560a 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -197,19 +197,21 @@ struct sof_ops_table { const struct snd_sof_dsp_ops *ops; }; -/* FS entry for debug files that can expose DSP memories, registers */ -struct snd_sof_dfsentry_io { - struct dentry *dfsentry; - size_t size; - void __iomem *buf; - struct snd_sof_dev *sdev; +enum sof_dfsentry_type { + SOF_DFSENTRY_TYPE_IOMEM = 0, + SOF_DFSENTRY_TYPE_BUF, }; -struct snd_sof_dfsentry_buf { +/* FS entry for debug files that can expose DSP memories, registers */ +struct snd_sof_dfsentry { struct dentry *dfsentry; size_t size; - void *buf; + enum sof_dfsentry_type type; struct snd_sof_dev *sdev; + union { + void __iomem *io_mem; + void *buf; + }; }; /* Debug mapping for any DSP memory or registers that can used for debug */ diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 157b01dc237894..d74074096dcb86 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -53,7 +53,7 @@ static size_t sof_wait_trace_avail(struct snd_sof_dev *sdev, static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { - struct snd_sof_dfsentry_buf *dfse = file->private_data; + struct snd_sof_dfsentry *dfse = file->private_data; struct snd_sof_dev *sdev = dfse->sdev; unsigned long rem; loff_t lpos = *ppos; @@ -105,7 +105,7 @@ static const struct file_operations sof_dfs_trace_fops = { static int trace_debugfs_create(struct snd_sof_dev *sdev) { - struct snd_sof_dfsentry_buf *dfse; + struct snd_sof_dfsentry *dfse; if (!sdev) return -EINVAL; @@ -114,6 +114,7 @@ static int trace_debugfs_create(struct snd_sof_dev *sdev) if (!dfse) return -ENOMEM; + dfse->type = SOF_DFSENTRY_TYPE_BUF; dfse->buf = sdev->dmatb.area; dfse->size = sdev->dmatb.bytes; dfse->sdev = sdev; From ee3814af5e921885a3d7d5c468f406ced265aafb Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 7 Feb 2019 13:10:06 -0800 Subject: [PATCH 0872/1995] ASoC: SOF: debug: specify debugfs memory access type This patch does the following: 1. Add an access_type member to the debugfs map and the dfsentry structure if the debugfs memory is always accessible or only if the DSP is in D0. 2. Update the access_type in the debug_fs map for all platforms. The assumption is: For SKL- platforms, iram/dram and memory windows will be accessible only in D0. For SKL+ platforms all memory windows will be accessible only on D0. 2. If the memory is accessible only in D0, then create a cache buffer in the debugfs entry that will be used to copy the contents prior to the DSP entering d3. 3. replace snd_sof_debugfs_io_create_item() with snd_sof_debugfs_io_item() and snd_sof_debugfs_buf_create_item with snd_sof_debugfs_buf_item. This will help with avoiding checkpatch errors with the lines shooting over 80 chars. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/debug.c | 57 ++++++++++----- sound/soc/sof/intel/apl.c | 6 +- sound/soc/sof/intel/bdw.c | 92 ++++++++++++++---------- sound/soc/sof/intel/byt.c | 131 ++++++++++++++++++++-------------- sound/soc/sof/intel/cnl.c | 6 +- sound/soc/sof/intel/hda-ipc.c | 83 +++++++++++---------- sound/soc/sof/intel/hsw.c | 92 ++++++++++++++---------- sound/soc/sof/intel/skl.c | 6 +- sound/soc/sof/loader.c | 8 +-- sound/soc/sof/sof-priv.h | 30 ++++++-- 10 files changed, 307 insertions(+), 204 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index abe306b8f01438..415258f2e2393d 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -45,12 +45,23 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, if (!buf) return -ENOMEM; - /* copy from DSP MMIO */ - pm_runtime_get_noresume(sdev->dev); - - if (dfse->type == SOF_DFSENTRY_TYPE_IOMEM) - memcpy_fromio(buf, dfse->io_mem + pos, size); - else + if (dfse->type == SOF_DFSENTRY_TYPE_IOMEM) { + + /* + * If the DSP is active: copy from IO. + * If the DSP is suspended: + * - Copy from IO if the memory is always accessible. + * - Otherwise, copy from cached buffer. + */ + if (pm_runtime_active(sdev->dev) || + dfse->access_type == SOF_DEBUGFS_ACCESS_ALWAYS) { + memcpy_fromio(buf, dfse->io_mem + pos, size); + } else { + dev_info(sdev->dev, + "Copying cached debugfs data\n"); + memcpy(buf, dfse->cache_buf + pos, size); + } + } else { memcpy(buf, dfse->buf + pos, size); /* @@ -82,9 +93,10 @@ static const struct file_operations sof_dfs_fops = { }; /* create FS entry for debug files that can expose DSP memories, registers */ -int snd_sof_debugfs_io_create_item(struct snd_sof_dev *sdev, - void __iomem *base, size_t size, - const char *name) +int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev, + void __iomem *base, size_t size, + const char *name, + enum sof_debugfs_access_type access_type) { struct snd_sof_dfsentry *dfse; @@ -99,6 +111,17 @@ int snd_sof_debugfs_io_create_item(struct snd_sof_dev *sdev, dfse->io_mem = base; dfse->size = size; dfse->sdev = sdev; + dfse->access_type = access_type; + + /* + * allocate cache buffer that will be used to save the mem window + * contents prior to suspend + */ + if (access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) { + dfse->cache_buf = devm_kzalloc(sdev->dev, size, GFP_KERNEL); + if (!dfse->cache_buf) + return -ENOMEM; + } dfse->dfsentry = debugfs_create_file(name, 0444, sdev->debugfs_root, dfse, &sof_dfs_fops); @@ -110,12 +133,12 @@ int snd_sof_debugfs_io_create_item(struct snd_sof_dev *sdev, return 0; } -EXPORT_SYMBOL_GPL(snd_sof_debugfs_io_create_item); +EXPORT_SYMBOL_GPL(snd_sof_debugfs_io_item); /* create FS entry for debug files to expose kernel memory */ -int snd_sof_debugfs_buf_create_item(struct snd_sof_dev *sdev, - void *base, size_t size, - const char *name) +int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, + void *base, size_t size, + const char *name) { struct snd_sof_dfsentry *dfse; @@ -141,7 +164,7 @@ int snd_sof_debugfs_buf_create_item(struct snd_sof_dev *sdev, return 0; } -EXPORT_SYMBOL_GPL(snd_sof_debugfs_buf_create_item); +EXPORT_SYMBOL_GPL(snd_sof_debugfs_buf_item); int snd_sof_dbg_init(struct snd_sof_dev *sdev) { @@ -161,9 +184,9 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) for (i = 0; i < ops->debug_map_count; i++) { map = &ops->debug_map[i]; - err = snd_sof_debugfs_io_create_item(sdev, sdev->bar[map->bar] + - map->offset, map->size, - map->name); + err = snd_sof_debugfs_io_item(sdev, sdev->bar[map->bar] + + map->offset, map->size, + map->name, map->access_type); /* errors are only due to memory allocation, not debugfs */ if (err < 0) return err; diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index d9177a56d2e5b6..1c040b600891d3 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -19,9 +19,9 @@ #include "hda.h" static const struct snd_sof_debugfs_map apl_dsp_debugfs[] = { - {"hda", HDA_DSP_HDA_BAR, 0, 0x4000}, - {"pp", HDA_DSP_PP_BAR, 0, 0x1000}, - {"dsp", HDA_DSP_BAR, 0, 0x10000}, + {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, }; /* apollolake ops */ diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index ec4aa750b09a7d..7d5fa9387b39c9 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -51,13 +51,20 @@ #define BDW_PANIC_OFFSET(x) ((x) & 0xFFFF) static const struct snd_sof_debugfs_map bdw_debugfs[] = { - {"dmac0", BDW_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE}, - {"dmac1", BDW_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE}, - {"ssp0", BDW_DSP_BAR, SSP0_OFFSET, SSP_SIZE}, - {"ssp1", BDW_DSP_BAR, SSP1_OFFSET, SSP_SIZE}, - {"iram", BDW_DSP_BAR, IRAM_OFFSET, BDW_IRAM_SIZE}, - {"dram", BDW_DSP_BAR, DRAM_OFFSET, BDW_DRAM_SIZE}, - {"shim", BDW_DSP_BAR, SHIM_OFFSET, SHIM_SIZE}, + {"dmac0", BDW_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dmac1", BDW_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp0", BDW_DSP_BAR, SSP0_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp1", BDW_DSP_BAR, SSP1_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"iram", BDW_DSP_BAR, IRAM_OFFSET, BDW_IRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"dram", BDW_DSP_BAR, DRAM_OFFSET, BDW_DRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"shim", BDW_DSP_BAR, SHIM_OFFSET, SHIM_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, }; static int bdw_cmd_done(struct snd_sof_dev *sdev, int dir); @@ -332,55 +339,62 @@ static void bdw_get_windows(struct snd_sof_dev *sdev) case SOF_IPC_REGION_UPBOX: inbox_offset = elem->offset + MBOX_OFFSET; inbox_size = elem->size; - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[BDW_DSP_BAR] + - inbox_offset, - elem->size, "inbox"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[BDW_DSP_BAR] + + inbox_offset, + elem->size, "inbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_DOWNBOX: outbox_offset = elem->offset + MBOX_OFFSET; outbox_size = elem->size; - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[BDW_DSP_BAR] + - outbox_offset, - elem->size, "outbox"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[BDW_DSP_BAR] + + outbox_offset, + elem->size, "outbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "etrace"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[BDW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "etrace", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "debug"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[BDW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "debug", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_STREAM: stream_offset = elem->offset + MBOX_OFFSET; stream_size = elem->size; - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[BDW_DSP_BAR] + - stream_offset, - elem->size, "stream"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[BDW_DSP_BAR] + + stream_offset, + elem->size, "stream", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_REGS: - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "regs"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[BDW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "regs", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_EXCEPTION: sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "exception"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[BDW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "exception", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; default: dev_err(sdev->dev, "error: get illegal window info\n"); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 94b4d96f4fc4b8..34ad7536bdc806 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -60,29 +60,49 @@ #define BYT_IMR_BAR 2 static const struct snd_sof_debugfs_map byt_debugfs[] = { - {"dmac0", BYT_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE}, - {"dmac1", BYT_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE}, - {"ssp0", BYT_DSP_BAR, SSP0_OFFSET, SSP_SIZE}, - {"ssp1", BYT_DSP_BAR, SSP1_OFFSET, SSP_SIZE}, - {"ssp2", BYT_DSP_BAR, SSP2_OFFSET, SSP_SIZE}, - {"iram", BYT_DSP_BAR, IRAM_OFFSET, IRAM_SIZE}, - {"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE}, - {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE}, + {"dmac0", BYT_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dmac1", BYT_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp0", BYT_DSP_BAR, SSP0_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp1", BYT_DSP_BAR, SSP1_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp2", BYT_DSP_BAR, SSP2_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"iram", BYT_DSP_BAR, IRAM_OFFSET, IRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, }; static const struct snd_sof_debugfs_map cht_debugfs[] = { - {"dmac0", BYT_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE}, - {"dmac1", BYT_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE}, - {"dmac2", BYT_DSP_BAR, DMAC2_OFFSET, DMAC_SIZE}, - {"ssp0", BYT_DSP_BAR, SSP0_OFFSET, SSP_SIZE}, - {"ssp1", BYT_DSP_BAR, SSP1_OFFSET, SSP_SIZE}, - {"ssp2", BYT_DSP_BAR, SSP2_OFFSET, SSP_SIZE}, - {"ssp3", BYT_DSP_BAR, SSP3_OFFSET, SSP_SIZE}, - {"ssp4", BYT_DSP_BAR, SSP4_OFFSET, SSP_SIZE}, - {"ssp5", BYT_DSP_BAR, SSP5_OFFSET, SSP_SIZE}, - {"iram", BYT_DSP_BAR, IRAM_OFFSET, IRAM_SIZE}, - {"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE}, - {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE}, + {"dmac0", BYT_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dmac1", BYT_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dmac2", BYT_DSP_BAR, DMAC2_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp0", BYT_DSP_BAR, SSP0_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp1", BYT_DSP_BAR, SSP1_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp2", BYT_DSP_BAR, SSP2_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp3", BYT_DSP_BAR, SSP3_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp4", BYT_DSP_BAR, SSP4_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp5", BYT_DSP_BAR, SSP5_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"iram", BYT_DSP_BAR, IRAM_OFFSET, IRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, }; static int byt_cmd_done(struct snd_sof_dev *sdev, int dir); @@ -113,55 +133,62 @@ static void byt_get_windows(struct snd_sof_dev *sdev) case SOF_IPC_REGION_UPBOX: inbox_offset = elem->offset + MBOX_OFFSET; inbox_size = elem->size; - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[BYT_DSP_BAR] + - inbox_offset, - elem->size, "inbox"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[BYT_DSP_BAR] + + inbox_offset, + elem->size, "inbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_DOWNBOX: outbox_offset = elem->offset + MBOX_OFFSET; outbox_size = elem->size; - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[BYT_DSP_BAR] + - outbox_offset, - elem->size, "outbox"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[BYT_DSP_BAR] + + outbox_offset, + elem->size, "outbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "etrace"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[BYT_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "etrace", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "debug"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[BYT_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "debug", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_STREAM: stream_offset = elem->offset + MBOX_OFFSET; stream_size = elem->size; - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[BYT_DSP_BAR] + - stream_offset, - elem->size, "stream"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[BYT_DSP_BAR] + + stream_offset, + elem->size, "stream", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_REGS: - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "regs"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[BYT_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "regs", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_EXCEPTION: sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "exception"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[BYT_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "exception", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; default: dev_err(sdev->dev, "error: get illegal window info\n"); diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index a294f80940c738..ae080b865bccc8 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -19,9 +19,9 @@ #include "hda.h" static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = { - {"hda", HDA_DSP_HDA_BAR, 0, 0x4000}, - {"pp", HDA_DSP_PP_BAR, 0, 0x1000}, - {"dsp", HDA_DSP_BAR, 0, 0x10000}, + {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, }; static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index b25f9d9fb781a6..d792cc97923233 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -276,64 +276,71 @@ static void ipc_get_windows(struct snd_sof_dev *sdev) inbox_offset = elem->offset + SRAM_WINDOW_OFFSET(elem->id); inbox_size = elem->size; - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[HDA_DSP_BAR] + - inbox_offset, - elem->size, "inbox"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[HDA_DSP_BAR] + + inbox_offset, + elem->size, "inbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_DOWNBOX: outbox_offset = elem->offset + SRAM_WINDOW_OFFSET(elem->id); outbox_size = elem->size; - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[HDA_DSP_BAR] + - outbox_offset, - elem->size, "outbox"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[HDA_DSP_BAR] + + outbox_offset, + elem->size, "outbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "etrace"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "etrace", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "debug"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "debug", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_STREAM: stream_offset = elem->offset + SRAM_WINDOW_OFFSET(elem->id); stream_size = elem->size; - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "stream"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "stream", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_REGS: - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "regs"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "regs", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_EXCEPTION: sdev->dsp_oops_offset = elem->offset + SRAM_WINDOW_OFFSET(elem->id); - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "exception"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "exception", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; default: dev_err(sdev->dev, "error: get illegal window info\n"); diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 174f8dabca93fa..95807406eeb866 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -51,13 +51,20 @@ #define HSW_PANIC_OFFSET(x) ((x) & 0xFFFF) static const struct snd_sof_debugfs_map hsw_debugfs[] = { - {"dmac0", HSW_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE}, - {"dmac1", HSW_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE}, - {"ssp0", HSW_DSP_BAR, SSP0_OFFSET, SSP_SIZE}, - {"ssp1", HSW_DSP_BAR, SSP1_OFFSET, SSP_SIZE}, - {"iram", HSW_DSP_BAR, IRAM_OFFSET, HSW_IRAM_SIZE}, - {"dram", HSW_DSP_BAR, DRAM_OFFSET, HSW_DRAM_SIZE}, - {"shim", HSW_DSP_BAR, SHIM_OFFSET, SHIM_SIZE}, + {"dmac0", HSW_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dmac1", HSW_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp0", HSW_DSP_BAR, SSP0_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp1", HSW_DSP_BAR, SSP1_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"iram", HSW_DSP_BAR, IRAM_OFFSET, HSW_IRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"dram", HSW_DSP_BAR, DRAM_OFFSET, HSW_DRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"shim", HSW_DSP_BAR, SHIM_OFFSET, SHIM_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, }; static int hsw_cmd_done(struct snd_sof_dev *sdev, int dir); @@ -333,55 +340,62 @@ static void hsw_get_windows(struct snd_sof_dev *sdev) case SOF_IPC_REGION_UPBOX: inbox_offset = elem->offset + MBOX_OFFSET; inbox_size = elem->size; - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[HSW_DSP_BAR] + - inbox_offset, - elem->size, "inbox"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[HSW_DSP_BAR] + + inbox_offset, + elem->size, "inbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_DOWNBOX: outbox_offset = elem->offset + MBOX_OFFSET; outbox_size = elem->size; - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[HSW_DSP_BAR] + - outbox_offset, - elem->size, "outbox"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[HSW_DSP_BAR] + + outbox_offset, + elem->size, "outbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[HSW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "etrace"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[HSW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "etrace", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[HSW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "debug"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[HSW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "debug", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_STREAM: stream_offset = elem->offset + MBOX_OFFSET; stream_size = elem->size; - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[HSW_DSP_BAR] + - stream_offset, - elem->size, "stream"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[HSW_DSP_BAR] + + stream_offset, + elem->size, "stream", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_REGS: - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[HSW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "regs"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[HSW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "regs", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; case SOF_IPC_REGION_EXCEPTION: sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; - snd_sof_debugfs_io_create_item(sdev, - sdev->bar[HSW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "exception"); + snd_sof_debugfs_io_item(sdev, + sdev->bar[HSW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "exception", + SOF_DEBUGFS_ACCESS_D0_ONLY); break; default: dev_err(sdev->dev, "error: get illegal window info\n"); diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index e987b5607cbfc1..f8409c26b748c5 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -19,9 +19,9 @@ #include "hda.h" static const struct snd_sof_debugfs_map skl_dsp_debugfs[] = { - {"hda", HDA_DSP_HDA_BAR, 0, 0x4000}, - {"pp", HDA_DSP_PP_BAR, 0, 0x1000}, - {"dsp", HDA_DSP_BAR, 0, 0x10000}, + {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, }; /* skylake ops */ diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 8a1a45df73889e..f996082fa656aa 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -307,12 +307,12 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) /* create fw_version debugfs to store boot version info */ if (sdev->first_boot) { - ret = snd_sof_debugfs_buf_create_item(sdev, &sdev->fw_version, - sizeof(sdev->fw_version), - "fw_version"); + ret = snd_sof_debugfs_buf_item(sdev, &sdev->fw_version, + sizeof(sdev->fw_version), + "fw_version"); /* errors are only due to memory allocation, not debugfs */ if (ret < 0) { - dev_err(sdev->dev, "error: snd_sof_debugfs_buf_create_item failed\n"); + dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n"); return ret; } } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 57eb32d9d3560a..f771721ab3521a 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -202,11 +202,23 @@ enum sof_dfsentry_type { SOF_DFSENTRY_TYPE_BUF, }; +enum sof_debugfs_access_type { + SOF_DEBUGFS_ACCESS_ALWAYS = 0, + SOF_DEBUGFS_ACCESS_D0_ONLY, +}; + /* FS entry for debug files that can expose DSP memories, registers */ struct snd_sof_dfsentry { struct dentry *dfsentry; size_t size; enum sof_dfsentry_type type; + /* + * access_type specifies if the + * memory -> DSP resource (memory, register etc) is always accessible + * or if it is accessible only when the DSP is in D0. + */ + enum sof_debugfs_access_type access_type; + char *cache_buf; /* buffer to cache the contents of memory windows */ struct snd_sof_dev *sdev; union { void __iomem *io_mem; @@ -220,6 +232,11 @@ struct snd_sof_debugfs_map { u32 bar; u32 offset; u32 size; + /* + * access_type specifies if the memory is always accessible + * or if it is accessible only when the DSP is in D0. + */ + enum sof_debugfs_access_type access_type; }; /* mailbox descriptor, used for host <-> DSP IPC */ @@ -501,12 +518,13 @@ void snd_sof_release_trace(struct snd_sof_dev *sdev); void snd_sof_free_trace(struct snd_sof_dev *sdev); int snd_sof_dbg_init(struct snd_sof_dev *sdev); void snd_sof_free_debug(struct snd_sof_dev *sdev); -int snd_sof_debugfs_io_create_item(struct snd_sof_dev *sdev, - void __iomem *base, size_t size, - const char *name); -int snd_sof_debugfs_buf_create_item(struct snd_sof_dev *sdev, - void *base, size_t size, - const char *name); +int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev, + void __iomem *base, size_t size, + const char *name, + enum sof_debugfs_access_type access_type); +int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, + void *base, size_t size, + const char *name); int snd_sof_trace_update_pos(struct snd_sof_dev *sdev, struct sof_ipc_dma_trace_posn *posn); void snd_sof_trace_notify_for_error(struct snd_sof_dev *sdev); From 3fa94279d0717ab9c0e949ab33500e764e4a98cc Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 7 Feb 2019 13:20:40 -0800 Subject: [PATCH 0873/1995] ASoC: SOF: add list of debugfs entries Add a list of debugfs entries to the sof device. This will be used for caching the contents of those memory windows whose contents will not be valid upon runtime suspend. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/debug.c | 10 ++++++++++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 415258f2e2393d..3a60f91c88781f 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -129,6 +129,10 @@ int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev, /* can't rely on debugfs, only log error and keep going */ dev_err(sdev->dev, "error: cannot create debugfs entry %s\n", name); + } else { + /* add to dfsentry list */ + list_add(&dfse->list, &sdev->dfsentry_list); + } return 0; @@ -160,6 +164,9 @@ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, /* can't rely on debugfs, only log error and keep going */ dev_err(sdev->dev, "error: cannot create debugfs entry %s\n", name); + } else { + /* add to dfsentry list */ + list_add(&dfse->list, &sdev->dfsentry_list); } return 0; @@ -180,6 +187,9 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) return 0; } + /* init dfsentry list */ + INIT_LIST_HEAD(&sdev->dfsentry_list); + /* create debugFS files for platform specific MMIO/DSP memories */ for (i = 0; i < ops->debug_map_count; i++) { map = &ops->debug_map[i]; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index f771721ab3521a..a7065d5ef87ab7 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -220,6 +220,7 @@ struct snd_sof_dfsentry { enum sof_debugfs_access_type access_type; char *cache_buf; /* buffer to cache the contents of memory windows */ struct snd_sof_dev *sdev; + struct list_head list; /* list in sdev dfsentry list */ union { void __iomem *io_mem; void *buf; @@ -373,6 +374,7 @@ struct snd_sof_dev { /* debug */ struct dentry *debugfs_root; + struct list_head dfsentry_list; /* firmware loader */ struct snd_dma_buffer dmab; From 502315359c6984cb28be61671741100ce387cb60 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 7 Feb 2019 14:27:23 -0800 Subject: [PATCH 0874/1995] ASoC: SOF: debug: cache debugfs prior to suspending This patch allows to cache debugfs memory windows that have their cache_upon_suspend flag set. Copying all the memory from IO will increase the suspend latency. Therefore, it is only allowed as a debug option. Also modify the debugfs_read() to copy from IO if the config option to cache debugfs memory is not set. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/Kconfig | 10 ++++++++++ sound/soc/sof/debug.c | 28 +++++++++++++++++----------- sound/soc/sof/pm.c | 24 ++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 4 +++- 4 files changed, 54 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 4c8396dccb301f..e08053cb8d322c 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -129,6 +129,16 @@ config SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION DPIB/posbuf is not ready, select "Y". If unsure select "N". +config SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE + bool "SOF enable debugfs caching" + help + This option enables caching of debugfs + memory -> DSP resource (memory, register, etc) + before the audio DSP is suspended. This will increase the suspend + latency and therefore should be used for debug purposes only. + Say Y if you want to enable caching the memory windows. + If unsure, select "N". + endif ## SND_SOC_SOF_DEBUG endif ## SND_SOC_SOF_OPTIONS diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 3a60f91c88781f..83871f3ac2a167 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -22,11 +22,11 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, { struct snd_sof_dfsentry *dfse = file->private_data; struct snd_sof_dev *sdev = dfse->sdev; + struct dentry *dfsentry = dfse->dfsentry; int size; u32 *buf; loff_t pos = *ppos; size_t size_ret; - int ret; size = dfse->size; @@ -46,7 +46,7 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, return -ENOMEM; if (dfse->type == SOF_DFSENTRY_TYPE_IOMEM) { - +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) /* * If the DSP is active: copy from IO. * If the DSP is suspended: @@ -61,17 +61,21 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, "Copying cached debugfs data\n"); memcpy(buf, dfse->cache_buf + pos, size); } +#else + /* if the DSP is in D3 */ + if (!pm_runtime_active(sdev->dev) && + dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) { + dev_err(sdev->dev, + "error: debugfs entry %s cannot be read in DSP D3\n", + dfsentry->d_name.name); + return -EINVAL; + } + + memcpy_fromio(buf, dfse->io_mem + pos, size); +#endif } else { memcpy(buf, dfse->buf + pos, size); - - /* - * TODO: revisit to check if we need mark_last_busy, or if we - * should change to use xxx_put_sync[_suspend](). - */ - ret = pm_runtime_put_sync_autosuspend(sdev->dev); - if (ret < 0) - dev_warn(sdev->dev, "warn: debugFS failed to autosuspend %d\n", - ret); + } /* copy to userspace */ size_ret = copy_to_user(buffer, buf, count); @@ -113,6 +117,7 @@ int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev, dfse->sdev = sdev; dfse->access_type = access_type; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) /* * allocate cache buffer that will be used to save the mem window * contents prior to suspend @@ -122,6 +127,7 @@ int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev, if (!dfse->cache_buf) return -ENOMEM; } +#endif dfse->dfsentry = debugfs_create_file(name, 0444, sdev->debugfs_root, dfse, &sof_dfs_fops); diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index bb199eb014df10..f306095bfb5d5f 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -215,6 +215,25 @@ static void sof_set_restore_stream(struct snd_sof_dev *sdev) } } +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) +static void sof_cache_debugfs(struct snd_sof_dev *sdev) +{ + struct snd_sof_dfsentry *dfse; + + list_for_each_entry(dfse, &sdev->dfsentry_list, list) { + + /* nothing to do if debugfs buffer is not IO mem */ + if (dfse->type == SOF_DFSENTRY_TYPE_BUF) + continue; + + /* cache memory that is only accessible in D0 */ + if (dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) + memcpy_fromio(dfse->cache_buf, dfse->io_mem, + dfse->size); + } +} +#endif + static int sof_resume(struct device *dev, bool runtime_resume) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); @@ -300,6 +319,11 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) if (!runtime_suspend) sof_set_restore_stream(sdev); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) + /* cache debugfs contents during runtime suspend */ + if (runtime_suspend) + sof_cache_debugfs(sdev); +#endif /* notify DSP of upcoming power down */ ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_SAVE); if (ret < 0) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index a7065d5ef87ab7..1bd9db4005fcf9 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -218,7 +218,9 @@ struct snd_sof_dfsentry { * or if it is accessible only when the DSP is in D0. */ enum sof_debugfs_access_type access_type; - char *cache_buf; /* buffer to cache the contents of memory windows */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) + char *cache_buf; /* buffer to cache the contents of debugfs memory */ +#endif struct snd_sof_dev *sdev; struct list_head list; /* list in sdev dfsentry list */ union { From 85c24a4c29da4567eac47551ec10ac4aa0b4b4c6 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 5 Feb 2019 16:29:40 +0000 Subject: [PATCH 0875/1995] ALSA: compress: Fix stop handling on compressed capture streams It is normal user behaviour to start, stop, then start a stream again without closing it. Currently this works for compressed playback streams but not capture ones. The states on a compressed capture stream go directly from OPEN to PREPARED, unlike a playback stream which moves to SETUP and waits for a write of data before moving to PREPARED. Currently however, when a stop is sent the state is set to SETUP for both types of streams. This leaves a capture stream in the situation where a new start can't be sent as that requires the state to be PREPARED and a new set_params can't be sent as that requires the state to be OPEN. The only option being to close the stream, and then reopen. Correct this issues by allowing snd_compr_drain_notify to set the state depending on the stream direction, as we already do in set_params. Fixes: 49bb6402f1aa ("ALSA: compress_core: Add support for capture streams") Signed-off-by: Charles Keepax Cc: Signed-off-by: Takashi Iwai (cherry picked from commit 4f2ab5e1d13d6aa77c55f4914659784efd776eb4) --- include/sound/compress_driver.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index 0cdc3999ecfa84..c5188ff724d122 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -173,7 +173,11 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream) if (snd_BUG_ON(!stream)) return; - stream->runtime->state = SNDRV_PCM_STATE_SETUP; + if (stream->direction == SND_COMPRESS_PLAYBACK) + stream->runtime->state = SNDRV_PCM_STATE_SETUP; + else + stream->runtime->state = SNDRV_PCM_STATE_PREPARED; + wake_up(&stream->runtime->sleep); } From b1c1777a6bde5bba8f949f6a01390213bf458741 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 8 Feb 2019 14:45:20 +0100 Subject: [PATCH 0876/1995] ASoC: regulator notifier registration should be managed Regulator notifiers, that were registered during codec driver probing, must be unregistered during driver release, or device managed versions have to be used. This patch fixes codec drivers, that weren't explicitly unregistering notifiers and simplifies those, that did that manually. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mark Brown (cherry picked from commit 0bb423f2eaafedf89715c482a543dcd629ba3946) --- sound/soc/codecs/max9860.c | 3 ++- sound/soc/codecs/pcm512x.c | 5 +++-- sound/soc/codecs/tlv320aic31xx.c | 16 +++------------- sound/soc/codecs/tlv320aic3x.c | 25 ++++--------------------- sound/soc/codecs/wm8770.c | 18 +++--------------- sound/soc/codecs/wm8962.c | 9 +++------ sound/soc/codecs/wm8995.c | 29 +++++++---------------------- sound/soc/codecs/wm8996.c | 9 +++------ 8 files changed, 28 insertions(+), 86 deletions(-) diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c index de3d44e9199b03..8be636fe655206 100644 --- a/sound/soc/codecs/max9860.c +++ b/sound/soc/codecs/max9860.c @@ -615,7 +615,8 @@ static int max9860_probe(struct i2c_client *i2c) max9860->dvddio_nb.notifier_call = max9860_dvddio_event; - ret = regulator_register_notifier(max9860->dvddio, &max9860->dvddio_nb); + ret = devm_regulator_register_notifier(max9860->dvddio, + &max9860->dvddio_nb); if (ret) dev_err(dev, "Failed to register DVDDIO notifier: %d\n", ret); diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index ae3bd533eadb5a..62d05b01711f12 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1540,8 +1540,9 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap) pcm512x->supply_nb[2].notifier_call = pcm512x_regulator_event_2; for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) { - ret = regulator_register_notifier(pcm512x->supplies[i].consumer, - &pcm512x->supply_nb[i]); + ret = devm_regulator_register_notifier( + pcm512x->supplies[i].consumer, + &pcm512x->supply_nb[i]); if (ret != 0) { dev_err(dev, "Failed to register regulator notifier: %d\n", diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 608ad49ad97876..7a4a607cca3c82 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1274,8 +1274,9 @@ static int aic31xx_codec_probe(struct snd_soc_component *component) aic31xx->disable_nb[i].nb.notifier_call = aic31xx_regulator_event; aic31xx->disable_nb[i].aic31xx = aic31xx; - ret = regulator_register_notifier(aic31xx->supplies[i].consumer, - &aic31xx->disable_nb[i].nb); + ret = devm_regulator_register_notifier( + aic31xx->supplies[i].consumer, + &aic31xx->disable_nb[i].nb); if (ret) { dev_err(component->dev, "Failed to request regulator notifier: %d\n", @@ -1298,19 +1299,8 @@ static int aic31xx_codec_probe(struct snd_soc_component *component) return 0; } -static void aic31xx_codec_remove(struct snd_soc_component *component) -{ - struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component); - int i; - - for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) - regulator_unregister_notifier(aic31xx->supplies[i].consumer, - &aic31xx->disable_nb[i].nb); -} - static const struct snd_soc_component_driver soc_codec_driver_aic31xx = { .probe = aic31xx_codec_probe, - .remove = aic31xx_codec_remove, .set_bias_level = aic31xx_set_bias_level, .controls = common31xx_snd_controls, .num_controls = ARRAY_SIZE(common31xx_snd_controls), diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 6a271e6e6b8fc0..6dcc3ace9d70eb 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1605,13 +1605,14 @@ static int aic3x_probe(struct snd_soc_component *component) for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) { aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event; aic3x->disable_nb[i].aic3x = aic3x; - ret = regulator_register_notifier(aic3x->supplies[i].consumer, - &aic3x->disable_nb[i].nb); + ret = devm_regulator_register_notifier( + aic3x->supplies[i].consumer, + &aic3x->disable_nb[i].nb); if (ret) { dev_err(component->dev, "Failed to request regulator notifier: %d\n", ret); - goto err_notif; + return ret; } } @@ -1669,29 +1670,11 @@ static int aic3x_probe(struct snd_soc_component *component) aic3x_add_widgets(component); return 0; - -err_notif: - while (i--) - regulator_unregister_notifier(aic3x->supplies[i].consumer, - &aic3x->disable_nb[i].nb); - return ret; -} - -static void aic3x_remove(struct snd_soc_component *component) -{ - struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component); - int i; - - list_del(&aic3x->list); - for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) - regulator_unregister_notifier(aic3x->supplies[i].consumer, - &aic3x->disable_nb[i].nb); } static const struct snd_soc_component_driver soc_component_dev_aic3x = { .set_bias_level = aic3x_set_bias_level, .probe = aic3x_probe, - .remove = aic3x_remove, .controls = aic3x_snd_controls, .num_controls = ARRAY_SIZE(aic3x_snd_controls), .dapm_widgets = aic3x_dapm_widgets, diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index 806245c70f8beb..37467c51259774 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -666,8 +666,9 @@ static int wm8770_spi_probe(struct spi_device *spi) /* This should really be moved into the regulator core */ for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) { - ret = regulator_register_notifier(wm8770->supplies[i].consumer, - &wm8770->disable_nb[i]); + ret = devm_regulator_register_notifier( + wm8770->supplies[i].consumer, + &wm8770->disable_nb[i]); if (ret) { dev_err(&spi->dev, "Failed to register regulator notifier: %d\n", @@ -687,25 +688,12 @@ static int wm8770_spi_probe(struct spi_device *spi) return ret; } -static int wm8770_spi_remove(struct spi_device *spi) -{ - struct wm8770_priv *wm8770 = spi_get_drvdata(spi); - int i; - - for (i = 0; i < ARRAY_SIZE(wm8770->supplies); ++i) - regulator_unregister_notifier(wm8770->supplies[i].consumer, - &wm8770->disable_nb[i]); - - return 0; -} - static struct spi_driver wm8770_spi_driver = { .driver = { .name = "wm8770", .of_match_table = wm8770_of_match, }, .probe = wm8770_spi_probe, - .remove = wm8770_spi_remove }; module_spi_driver(wm8770_spi_driver); diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index efd8910b1ff77a..467ed78dd2df4e 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3424,8 +3424,9 @@ static int wm8962_probe(struct snd_soc_component *component) /* This should really be moved into the regulator core */ for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) { - ret = regulator_register_notifier(wm8962->supplies[i].consumer, - &wm8962->disable_nb[i]); + ret = devm_regulator_register_notifier( + wm8962->supplies[i].consumer, + &wm8962->disable_nb[i]); if (ret != 0) { dev_err(component->dev, "Failed to register regulator notifier: %d\n", @@ -3467,15 +3468,11 @@ static int wm8962_probe(struct snd_soc_component *component) static void wm8962_remove(struct snd_soc_component *component) { struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); - int i; cancel_delayed_work_sync(&wm8962->mic_work); wm8962_free_gpio(component); wm8962_free_beep(component); - for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) - regulator_unregister_notifier(wm8962->supplies[i].consumer, - &wm8962->disable_nb[i]); } static const struct snd_soc_component_driver soc_component_dev_wm8962 = { diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 68c99fe3709741..79ee91906bb937 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -1995,20 +1995,6 @@ static int wm8995_set_bias_level(struct snd_soc_component *component, return 0; } -static void wm8995_remove(struct snd_soc_component *component) -{ - struct wm8995_priv *wm8995; - int i; - - wm8995 = snd_soc_component_get_drvdata(component); - - for (i = 0; i < ARRAY_SIZE(wm8995->supplies); ++i) - regulator_unregister_notifier(wm8995->supplies[i].consumer, - &wm8995->disable_nb[i]); - - regulator_bulk_free(ARRAY_SIZE(wm8995->supplies), wm8995->supplies); -} - static int wm8995_probe(struct snd_soc_component *component) { struct wm8995_priv *wm8995; @@ -2021,8 +2007,9 @@ static int wm8995_probe(struct snd_soc_component *component) for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++) wm8995->supplies[i].supply = wm8995_supply_names[i]; - ret = regulator_bulk_get(component->dev, ARRAY_SIZE(wm8995->supplies), - wm8995->supplies); + ret = devm_regulator_bulk_get(component->dev, + ARRAY_SIZE(wm8995->supplies), + wm8995->supplies); if (ret) { dev_err(component->dev, "Failed to request supplies: %d\n", ret); return ret; @@ -2039,8 +2026,9 @@ static int wm8995_probe(struct snd_soc_component *component) /* This should really be moved into the regulator core */ for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++) { - ret = regulator_register_notifier(wm8995->supplies[i].consumer, - &wm8995->disable_nb[i]); + ret = devm_regulator_register_notifier( + wm8995->supplies[i].consumer, + &wm8995->disable_nb[i]); if (ret) { dev_err(component->dev, "Failed to register regulator notifier: %d\n", @@ -2052,7 +2040,7 @@ static int wm8995_probe(struct snd_soc_component *component) wm8995->supplies); if (ret) { dev_err(component->dev, "Failed to enable supplies: %d\n", ret); - goto err_reg_get; + return ret; } ret = snd_soc_component_read32(component, WM8995_SOFTWARE_RESET); @@ -2099,8 +2087,6 @@ static int wm8995_probe(struct snd_soc_component *component) err_reg_enable: regulator_bulk_disable(ARRAY_SIZE(wm8995->supplies), wm8995->supplies); -err_reg_get: - regulator_bulk_free(ARRAY_SIZE(wm8995->supplies), wm8995->supplies); return ret; } @@ -2188,7 +2174,6 @@ static struct snd_soc_dai_driver wm8995_dai[] = { static const struct snd_soc_component_driver soc_component_dev_wm8995 = { .probe = wm8995_probe, - .remove = wm8995_remove, .set_bias_level = wm8995_set_bias_level, .controls = wm8995_snd_controls, .num_controls = ARRAY_SIZE(wm8995_snd_controls), diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 91711f8958c562..ab04ea18c31276 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2801,8 +2801,9 @@ static int wm8996_i2c_probe(struct i2c_client *i2c, /* This should really be moved into the regulator core */ for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) { - ret = regulator_register_notifier(wm8996->supplies[i].consumer, - &wm8996->disable_nb[i]); + ret = devm_regulator_register_notifier( + wm8996->supplies[i].consumer, + &wm8996->disable_nb[i]); if (ret != 0) { dev_err(&i2c->dev, "Failed to register regulator notifier: %d\n", @@ -3071,16 +3072,12 @@ static int wm8996_i2c_probe(struct i2c_client *i2c, static int wm8996_i2c_remove(struct i2c_client *client) { struct wm8996_priv *wm8996 = i2c_get_clientdata(client); - int i; wm8996_free_gpio(wm8996); if (wm8996->pdata.ldo_ena > 0) { gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); gpio_free(wm8996->pdata.ldo_ena); } - for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) - regulator_unregister_notifier(wm8996->supplies[i].consumer, - &wm8996->disable_nb[i]); return 0; } From 0d09c24998325dd9e024f98c04a4e6b56ff61aef Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 6 Feb 2019 22:49:46 +0200 Subject: [PATCH 0877/1995] gpiolib: acpi: Introduce ACPI_GPIO_QUIRK_ONLY_GPIOIO New quirk enforces search for GPIO based on its type, i.e. iterate over GpioIo resources only. Signed-off-by: Andy Shevchenko Acked-by: Mika Westerberg Acked-by: Linus Walleij Tested-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit 4d1f7a6eabd45639d9de22a8a004f3c208d13c1a) --- drivers/gpio/gpiolib-acpi.c | 15 ++++-- include/linux/acpi.h | 7 +++ sound/soc/intel/boards/bytcr_rt5651.c | 74 ++++----------------------- 3 files changed, 27 insertions(+), 69 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 7f93954c58ea47..9518158c366e97 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -535,17 +535,24 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data) if (ares->type != ACPI_RESOURCE_TYPE_GPIO) return 1; - if (lookup->n++ == lookup->index && !lookup->desc) { + if (!lookup->desc) { const struct acpi_resource_gpio *agpio = &ares->data.gpio; - int pin_index = lookup->pin_index; + bool gpioint = agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; + int pin_index; + if (lookup->info.quirks & ACPI_GPIO_QUIRK_ONLY_GPIOIO && gpioint) + lookup->index++; + + if (lookup->n++ != lookup->index) + return 1; + + pin_index = lookup->pin_index; if (pin_index >= agpio->pin_table_length) return 1; lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr, agpio->pin_table[pin_index]); - lookup->info.gpioint = - agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; + lookup->info.gpioint = gpioint; /* * Polarity and triggering are only specified for GpioInt diff --git a/include/linux/acpi.h b/include/linux/acpi.h index ed80f147bd5089..a9e08d2e30dfc4 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -1007,6 +1007,13 @@ struct acpi_gpio_mapping { /* Ignore IoRestriction field */ #define ACPI_GPIO_QUIRK_NO_IO_RESTRICTION BIT(0) +/* + * When ACPI GPIO mapping table is in use the index parameter inside it + * refers to the GPIO resource in _CRS method. That index has no + * distinction of actual type of the resource. When consumer wants to + * get GpioIo type explicitly, this quirk may be used. + */ +#define ACPI_GPIO_QUIRK_ONLY_GPIOIO BIT(1) unsigned int quirks; }; diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index c3b7732929cc76..b0a4d297176e02 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -844,74 +844,18 @@ static const struct x86_cpu_id cherrytrail_cpu_ids[] = { {} }; -static const struct acpi_gpio_params first_gpio = { 0, 0, false }; -static const struct acpi_gpio_params second_gpio = { 1, 0, false }; +static const struct acpi_gpio_params ext_amp_enable_gpios = { 0, 0, false }; -static const struct acpi_gpio_mapping byt_rt5651_amp_en_first[] = { - { "ext-amp-enable-gpios", &first_gpio, 1 }, - { }, -}; - -static const struct acpi_gpio_mapping byt_rt5651_amp_en_second[] = { - { "ext-amp-enable-gpios", &second_gpio, 1 }, +static const struct acpi_gpio_mapping cht_rt5651_gpios[] = { + /* + * Some boards have I2cSerialBusV2, GpioIo, GpioInt as ACPI resources, + * other boards may have I2cSerialBusV2, GpioInt, GpioIo instead. + * We want the GpioIo one for the ext-amp-enable-gpio. + */ + { "ext-amp-enable-gpios", &ext_amp_enable_gpios, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, { }, }; -/* - * Some boards have I2cSerialBusV2, GpioIo, GpioInt as ACPI resources, other - * boards may have I2cSerialBusV2, GpioInt, GpioIo instead. We want the - * GpioIo one for the ext-amp-enable-gpio and both count for the index in - * acpi_gpio_params index. So we have 2 different mappings and the code - * below figures out which one to use. - */ -struct byt_rt5651_acpi_resource_data { - int gpio_count; - int gpio_int_idx; -}; - -static int snd_byt_rt5651_acpi_resource(struct acpi_resource *ares, void *arg) -{ - struct byt_rt5651_acpi_resource_data *data = arg; - - if (ares->type != ACPI_RESOURCE_TYPE_GPIO) - return 0; - - if (ares->data.gpio.connection_type == ACPI_RESOURCE_GPIO_TYPE_INT) - data->gpio_int_idx = data->gpio_count; - - data->gpio_count++; - return 0; -} - -static void snd_byt_rt5651_mc_pick_amp_en_gpio_mapping(struct device *codec) -{ - struct byt_rt5651_acpi_resource_data data = { 0, -1 }; - LIST_HEAD(resources); - int ret; - - ret = acpi_dev_get_resources(ACPI_COMPANION(codec), &resources, - snd_byt_rt5651_acpi_resource, &data); - if (ret < 0) { - dev_warn(codec, "Failed to get ACPI resources, not adding external amplifier GPIO mapping\n"); - return; - } - - /* All info we need is gathered during the walk */ - acpi_dev_free_resource_list(&resources); - - switch (data.gpio_int_idx) { - case 0: - byt_rt5651_gpios = byt_rt5651_amp_en_second; - break; - case 1: - byt_rt5651_gpios = byt_rt5651_amp_en_first; - break; - default: - dev_warn(codec, "Unknown GpioInt index %d, not adding external amplifier GPIO mapping\n", - data.gpio_int_idx); - } -} - struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ u64 aif_value; /* 1: AIF1, 2: AIF2 */ u64 mclock_value; /* usually 25MHz (0x17d7940), ignored */ @@ -1038,7 +982,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) /* Cherry Trail devices use an external amplifier enable gpio */ if (x86_match_cpu(cherrytrail_cpu_ids) && !byt_rt5651_gpios) - snd_byt_rt5651_mc_pick_amp_en_gpio_mapping(codec_dev); + byt_rt5651_gpios = cht_rt5651_gpios; if (byt_rt5651_gpios) { devm_acpi_dev_add_driver_gpios(codec_dev, byt_rt5651_gpios); From bc6df860bbeaac1d5fd9573af5ea063ebe74697c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Feb 2019 11:22:23 -0600 Subject: [PATCH 0878/1995] ASoC: core: don't increase component module refcount unconditionally The ASoC core has for the longest time increased the module reference counts, even before the transition to the component model. This is probably fine on most platforms, but it introduces a deadlock case on Intel devices with the Skylake and SOF drivers which cannot be removed due to their reference counts being modified by the core. In these 2 cases, the PCI or ACPI driver .probe creates a platform device to let the machine driver .probe register the audio card. Conversely the PCI or ACPI driver .remove will unregister the platform device which results in the card being removed by the machine driver .remove. With ascii art, this can be represented as modprobe snd_soc_skl/ soc-pci-dev/sof-acpci-dev ----------> pci/acpi probe ^ | | ---------------| | | | | V V increase register register machine refcount component platform_device ^ | | | | V component <---- register card <---- probe probe The issue is that by playing with the component's module reference counts during the card registration, it's no longer possible to remove the module which controls the component. This can be shown, e.g. with the following error: root@plb-XPS-13-9350:~# lsmod | grep snd_soc_skl snd_soc_skl 110592 1 root@plb-XPS-13-9350:~# rmmod snd_soc_skl rmmod: ERROR: Module snd_soc_skl is in use Increasing the reference count during the component probe is not useful. If the PCI/ACPI module is removed, the card will be removed anyway. To avoid breaking existing platforms and allowing Intel platforms to safely deal with module load/unload cases, this patch introduces a flag which needs to be set during the component initialization. This is a strictly opt-in capability that should only be used when the handling of the component module does not require a reference count increase to prevent removal during use. Note that this solution is not directly applicable to the legacy Atom/SST driver, which uses a different device hierarchy. There are however additional refcount issues which prevent the ACPI driver from being removed. This is a different issue which would need a different patch. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit b450b87847b157d69dbf9af7aefb4cec29e89cc9) --- include/sound/soc.h | 3 +++ sound/soc/soc-core.c | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 95689680336bd1..eb7db605955b85 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -802,6 +802,9 @@ struct snd_soc_component_driver { int probe_order; int remove_order; + /* signal if the module handling the component cannot be removed */ + unsigned int ignore_module_refcount:1; + /* bits */ unsigned int idle_bias_on:1; unsigned int suspend_bias_off:1; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 994d21d7ba0f69..93d316d5bf8e3c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -947,7 +947,8 @@ static void soc_cleanup_component(struct snd_soc_component *component) snd_soc_dapm_free(snd_soc_component_get_dapm(component)); soc_cleanup_component_debugfs(component); component->card = NULL; - module_put(component->dev->driver->owner); + if (!component->driver->ignore_module_refcount) + module_put(component->dev->driver->owner); } static void soc_remove_component(struct snd_soc_component *component) @@ -1380,7 +1381,8 @@ static int soc_probe_component(struct snd_soc_card *card, return 0; } - if (!try_module_get(component->dev->driver->owner)) + if (!component->driver->ignore_module_refcount && + !try_module_get(component->dev->driver->owner)) return -ENODEV; component->card = card; From 6d81a18c1e3ba793b4bb968185b65bca9b707a2b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Feb 2019 11:22:24 -0600 Subject: [PATCH 0879/1995] ASoC: Intel: Skylake: set .ignore_module_refcount field in component There is no risk of the module being removed while the platform components are in use. This solves the problem of the snd_soc_skl module not being removable with rmmod Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit e0771fc98909096b65c9781c438ac9d9c98ac41a) --- sound/soc/intel/skylake/skl-pcm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 8e589d698c588e..a4284778f117d6 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1464,6 +1464,7 @@ static const struct snd_soc_component_driver skl_component = { .ops = &skl_platform_ops, .pcm_new = skl_pcm_new, .pcm_free = skl_pcm_free, + .ignore_module_refcount = 1, /* do not increase the refcount in core */ }; int skl_platform_register(struct device *dev) From b65d7e1be7a37ed6d81220329cc83928fc97762a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:26:53 -0600 Subject: [PATCH 0880/1995] ASoC: hdac_hdmi: use devm_kzalloc for all structures Loading/unloading modules exposes issues with memory allocation, which is a mix of devm_kzalloc and manual kzalloc. Move to devm_k routines everywhere to simplify all this. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit c7ba4e5396fbe998502390e4fc7935163b189c50) --- sound/soc/codecs/hdac_hdmi.c | 87 ++++++++---------------------------- 1 file changed, 18 insertions(+), 69 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index b19d7a3e7a2cc0..5eeb0fe836a9a9 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1176,13 +1176,15 @@ static int hdac_hdmi_add_cvt(struct hdac_device *hdev, hda_nid_t nid) struct hdac_hdmi_cvt *cvt; char name[NAME_SIZE]; - cvt = kzalloc(sizeof(*cvt), GFP_KERNEL); + cvt = devm_kzalloc(&hdev->dev, sizeof(*cvt), GFP_KERNEL); if (!cvt) return -ENOMEM; cvt->nid = nid; sprintf(name, "cvt %d", cvt->nid); - cvt->name = kstrdup(name, GFP_KERNEL); + cvt->name = devm_kstrdup(&hdev->dev, name, GFP_KERNEL); + if (!cvt->name) + return -ENOMEM; list_add_tail(&cvt->head, &hdmi->cvt_list); hdmi->num_cvt++; @@ -1287,8 +1289,8 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, mutex_unlock(&hdmi->pin_mutex); } -static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi, - struct hdac_hdmi_pin *pin) +static int hdac_hdmi_add_ports(struct hdac_device *hdev, + struct hdac_hdmi_pin *pin) { struct hdac_hdmi_port *ports; int max_ports = HDA_MAX_PORTS; @@ -1300,7 +1302,7 @@ static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi, * implemented. */ - ports = kcalloc(max_ports, sizeof(*ports), GFP_KERNEL); + ports = devm_kcalloc(&hdev->dev, max_ports, sizeof(*ports), GFP_KERNEL); if (!ports) return -ENOMEM; @@ -1319,14 +1321,14 @@ static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid) struct hdac_hdmi_pin *pin; int ret; - pin = kzalloc(sizeof(*pin), GFP_KERNEL); + pin = devm_kzalloc(&hdev->dev, sizeof(*pin), GFP_KERNEL); if (!pin) return -ENOMEM; pin->nid = nid; pin->mst_capable = false; pin->hdev = hdev; - ret = hdac_hdmi_add_ports(hdmi, pin); + ret = hdac_hdmi_add_ports(hdev, pin); if (ret < 0) return ret; @@ -1468,8 +1470,6 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev, { hda_nid_t nid; int i, num_nodes; - struct hdac_hdmi_cvt *temp_cvt, *cvt_next; - struct hdac_hdmi_pin *temp_pin, *pin_next; struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); int ret; @@ -1497,51 +1497,35 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev, case AC_WID_AUD_OUT: ret = hdac_hdmi_add_cvt(hdev, nid); if (ret < 0) - goto free_widgets; + return ret; break; case AC_WID_PIN: ret = hdac_hdmi_add_pin(hdev, nid); if (ret < 0) - goto free_widgets; + return ret; break; } } if (!hdmi->num_pin || !hdmi->num_cvt) { ret = -EIO; - goto free_widgets; + dev_err(&hdev->dev, "Bad pin/cvt setup in %s\n", __func__); + return ret; } ret = hdac_hdmi_create_dais(hdev, dais, hdmi, hdmi->num_cvt); if (ret) { dev_err(&hdev->dev, "Failed to create dais with err: %d\n", - ret); - goto free_widgets; + ret); + return ret; } *num_dais = hdmi->num_cvt; ret = hdac_hdmi_init_dai_map(hdev); if (ret < 0) - goto free_widgets; - - return ret; - -free_widgets: - list_for_each_entry_safe(temp_cvt, cvt_next, &hdmi->cvt_list, head) { - list_del(&temp_cvt->head); - kfree(temp_cvt->name); - kfree(temp_cvt); - } - - list_for_each_entry_safe(temp_pin, pin_next, &hdmi->pin_list, head) { - for (i = 0; i < temp_pin->num_ports; i++) - temp_pin->ports[i].pin = NULL; - kfree(temp_pin->ports); - list_del(&temp_pin->head); - kfree(temp_pin); - } - + dev_err(&hdev->dev, "Failed to init DAI map with err: %d\n", + ret); return ret; } @@ -1782,7 +1766,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, * this is a new PCM device, create new pcm and * add to the pcm list */ - pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); + pcm = devm_kzalloc(&hdev->dev, sizeof(*pcm), GFP_KERNEL); if (!pcm) return -ENOMEM; pcm->pcm_id = device; @@ -1798,7 +1782,6 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, dev_err(&hdev->dev, "chmap control add failed with err: %d for pcm: %d\n", err, device); - kfree(pcm); return err; } } @@ -2075,42 +2058,8 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) static int hdac_hdmi_dev_remove(struct hdac_device *hdev) { - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); - struct hdac_hdmi_pin *pin, *pin_next; - struct hdac_hdmi_cvt *cvt, *cvt_next; - struct hdac_hdmi_pcm *pcm, *pcm_next; - struct hdac_hdmi_port *port, *port_next; - int i; - snd_hdac_display_power(hdev->bus, hdev->addr, false); - list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { - pcm->cvt = NULL; - if (list_empty(&pcm->port_list)) - continue; - - list_for_each_entry_safe(port, port_next, - &pcm->port_list, head) - list_del(&port->head); - - list_del(&pcm->head); - kfree(pcm); - } - - list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) { - list_del(&cvt->head); - kfree(cvt->name); - kfree(cvt); - } - - list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) { - for (i = 0; i < pin->num_ports; i++) - pin->ports[i].pin = NULL; - kfree(pin->ports); - list_del(&pin->head); - kfree(pin); - } - return 0; } From b57cbe383ce101407a2feb1b6e4d7d688c5eff72 Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Wed, 23 Jan 2019 20:41:30 +0100 Subject: [PATCH 0881/1995] ASoC: Use __printf markup to silence compiler Silence warnings (triggered at W=1) by adding relevant __printf attributes. sound/soc/soc-dapm.c:149:2: warning: function 'pop_dbg' might be a candidate for 'gnu_printf' format attribute [-Wsuggest-attribute=format] Signed-off-by: Mathieu Malaterre Signed-off-by: Mark Brown (cherry picked from commit 595d2f74cd3caedb704a118bd09c1b4dfbfc0ec0) --- sound/soc/soc-dapm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d31d295b540fcc..dea6fc2353e47b 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -157,6 +157,7 @@ static void pop_wait(u32 pop_time) schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time)); } +__printf(3, 4) static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...) { va_list args; From 5472430c1256aff1a620aea39f07bf8cb431b519 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Feb 2019 18:00:09 +0100 Subject: [PATCH 0882/1995] ASoC: dmaengine: Improve of_node test in dmaengine_pcm_request_chan_of() Currently when of_node of the "PCM" device is null dmaengine_pcm_request_chan_of() function will bail out, including cases when custom DMA device is intended to be used. To have the channels properly requested when custom DMA device is provided extend the of_node test to also consider dma_dev->of_node. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown (cherry picked from commit 51256d348c9af1bf544a4432abc1d5f2fd3ef34b) --- sound/soc/soc-generic-dmaengine-pcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 30e791a5335280..6d7638c1233d62 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -415,7 +415,8 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT | SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) || - !dev->of_node) + (!dev->of_node && !(config && config->dma_dev && + config->dma_dev->of_node))) return 0; if (config && config->dma_dev) { From 30d0f8042b9fc832c01233aa698c1f9a0f7bdde2 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Feb 2019 18:00:10 +0100 Subject: [PATCH 0883/1995] ASoC: dmaengine: Extend use of chan_names provided in custom DMA config There are currently two ways to specify custom DMA channel names: - through the SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME flag and snd_dmaengine_dai_dma_data data structure, - through chan_names field of struct snd_dmaengine_pcm_config. In order to replace the DAI DMA data method with the custom DMA config one on non-DT platforms the dmaengine_pcm_new() function is extended to also consider channel names specified in the custom DMA config. If both config->chan_names and dma_data->chan_name are provided the former will be used. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown (cherry picked from commit 10cbf3507bcb9baa82bf3445502e8ccafaa09fc8) --- sound/soc/soc-generic-dmaengine-pcm.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 6d7638c1233d62..1b44e363c50c7e 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -288,9 +288,16 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if (!pcm->chan[i] && - (pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) + ((pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME) || + (config && config->chan_names[i]))) { + const char *chan_name = dma_data->chan_name; + + if (config && config->chan_names[i]) + chan_name = config->chan_names[i]; + pcm->chan[i] = dma_request_slave_channel(dev, - dma_data->chan_name); + chan_name); + } if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) { pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd, From 7891e7f7c1471e77d827be150681aa7813506a84 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:41 -0600 Subject: [PATCH 0884/1995] ASoC: Intel: bxt-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit e529a9d44a9778b851a1683e6689c2f52d6750ac) --- .../intel/common/soc-acpi-intel-bxt-match.c | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c index 61dedc103b1966..c0e5780e2ad165 100644 --- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c @@ -51,8 +51,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .id = "INT343A", .drv_name = "bxt_alc298s_i2s", .fw_filename = "intel/dsp_fw_bxtn.bin", - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-rt298.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-rt298.tplg", .asoc_plat_name = "0000:00:0e.0", }, { @@ -61,30 +61,30 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .fw_filename = "intel/dsp_fw_bxtn.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &bxt_codecs, - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-da7219.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-da7219.tplg", .asoc_plat_name = "0000:00:0e.0", }, { .id = "104C5122", .drv_name = "bxt-pcm512x", - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-pcm512x.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-pcm512x.tplg", .asoc_plat_name = "0000:00:0e.0", }, { .id = "1AEC8804", .drv_name = "bxt-wm8804", - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-wm8804.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-wm8804.tplg", .asoc_plat_name = "0000:00:0e.0", }, { .id = "INT34C3", .drv_name = "bxt_tdf8532", .machine_quirk = apl_quirk, - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-tdf8532.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-tdf8532.tplg", .asoc_plat_name = "0000:00:0e.0", }, {}, From 35b1ae4e12301f18cb359f2a8cdcf825b395b798 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:42 -0600 Subject: [PATCH 0885/1995] ASoC: Intel: byt-match.c: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 528f07152a7840b5affe1c8844ddd1ee9d3aabd7) --- .../intel/common/soc-acpi-intel-byt-match.c | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 96f9c553fe6c9f..a46a3514a0f00b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -83,8 +83,8 @@ static struct snd_soc_acpi_mach byt_thinkpad_10 = { .drv_name = "cht-bsw-rt5672", .fw_filename = "intel/fw_sst_0f28.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5670.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5670.tplg", .asoc_plat_name = "sst-mfld-platform", }; @@ -93,8 +93,8 @@ static struct snd_soc_acpi_mach byt_pov_p1006w = { .drv_name = "bytcr_rt5651", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5651", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5651.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5651.tplg", .asoc_plat_name = "sst-mfld-platform", }; @@ -136,8 +136,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5640", .machine_quirk = byt_quirk, - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5640.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -145,8 +145,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcr_rt5640", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5640", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5640.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -154,8 +154,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcr_rt5640", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5640", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5640.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -163,8 +163,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcr_rt5651", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5651", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5651.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5651.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -172,8 +172,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcht_da7213", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcht_da7213", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-da7213.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -181,8 +181,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcht_da7213", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcht_da7213", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-da7213.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -190,8 +190,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcht_es8316", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcht_es8316", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-es8316.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-es8316.tplg", .asoc_plat_name = "sst-mfld-platform", }, /* some Baytrail platforms rely on RT5645, use CHT machine driver */ @@ -200,8 +200,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_0f28.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5645.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -209,8 +209,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_0f28.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5645.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, /* use CHT driver to Baytrail Chromebooks */ @@ -219,8 +219,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "cht-bsw-max98090", .fw_filename = "intel/fw_sst_0f28.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-max98090.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-max98090.tplg", .asoc_plat_name = "sst-mfld-platform", }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) From 6e35143c195d00f2817afd56e98b4a437717fb9d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:43 -0600 Subject: [PATCH 0886/1995] ASoC: Intel: cht-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 2e441dea9fee379e85dca15988671c23d6013d1c) --- .../intel/common/soc-acpi-intel-cht-match.c | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c index 91bb99b69601dd..21ce4bcbf25b7e 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -44,8 +44,8 @@ static struct snd_soc_acpi_mach cht_surface_mach = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5645.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }; @@ -68,8 +68,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5672", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5670.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5670.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -77,8 +77,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5672", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5670.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5670.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -86,8 +86,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5645.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -95,8 +95,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5645.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -104,8 +104,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5645.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -113,8 +113,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-max98090", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-max98090.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-max98090.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -122,8 +122,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-nau8824", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-nau8824.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-nau8824.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -131,8 +131,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcht_da7213", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcht_da7213", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-da7213.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -140,8 +140,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcht_da7213", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcht_da7213", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-da7213.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -149,8 +149,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcht_es8316", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcht_es8316", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-es8316.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-es8316.tplg", .asoc_plat_name = "sst-mfld-platform", }, /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ @@ -160,8 +160,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcr_rt5640", .machine_quirk = cht_quirk, - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5640.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -169,8 +169,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcr_rt5640", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcr_rt5640", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5640.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */ @@ -179,8 +179,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcr_rt5651", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcr_rt5651", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5651.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5651.tplg", .asoc_plat_name = "sst-mfld-platform", }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) From 880ad268947a47b66f965b32e55ba3b17ee2575b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:44 -0600 Subject: [PATCH 0887/1995] ASoC: Intel: cnl-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7466e749a3b4e838882cc8728bc66a39df0e9dfa) --- sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index ec8e28e7b937aa..b80b50ddb22b12 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -20,8 +20,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .drv_name = "cnl_rt274", .fw_filename = "intel/dsp_fw_cnl.bin", .pdata = &cnl_pdata, - .sof_fw_filename = "intel/sof-cnl.ri", - .sof_tplg_filename = "intel/sof-cnl-rt274.tplg", + .sof_fw_filename = "sof-cnl.ri", + .sof_tplg_filename = "sof-cnl-rt274.tplg", .asoc_plat_name = "0000:00:1f.3", }, {}, From b217a77388c2d21dd1c9efbce07d527be8665072 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:45 -0600 Subject: [PATCH 0888/1995] ASoC: Intel: glk-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 6d356d52297ded6b1bae86c54b364d7784c0a528) --- sound/soc/intel/common/soc-acpi-intel-glk-match.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c index 305875af71caee..75bc0109166a0a 100644 --- a/sound/soc/intel/common/soc-acpi-intel-glk-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c @@ -19,8 +19,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { .id = "INT343A", .drv_name = "glk_alc298s_i2s", .fw_filename = "intel/dsp_fw_glk.bin", - .sof_fw_filename = "intel/sof-glk.ri", - .sof_tplg_filename = "intel/sof-glk-alc298.tplg", + .sof_fw_filename = "sof-glk.ri", + .sof_tplg_filename = "sof-glk-alc298.tplg", .asoc_plat_name = "0000:00:0e.0", }, { @@ -29,8 +29,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { .fw_filename = "intel/dsp_fw_glk.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &glk_codecs, - .sof_fw_filename = "intel/sof-glk.ri", - .sof_tplg_filename = "intel/sof-glk-da7219.tplg", + .sof_fw_filename = "sof-glk.ri", + .sof_tplg_filename = "sof-glk-da7219.tplg", .asoc_plat_name = "0000:00:0e.0", }, {}, From 3797ee2c10f290a7a94d90b58e80af9791afa97d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:46 -0600 Subject: [PATCH 0889/1995] ASoC: Intel: hda-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit e576b097918f8ee563fbfde7d4186f09df856fe9) --- sound/soc/intel/common/soc-acpi-intel-hda-match.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-hda-match.c b/sound/soc/intel/common/soc-acpi-intel-hda-match.c index 533c1064f84b33..68ae43f7b4b288 100644 --- a/sound/soc/intel/common/soc-acpi-intel-hda-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-hda-match.c @@ -23,7 +23,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[] = { /* .sof_fw_filename is dynamically set in sof/intel driver */ - .sof_tplg_filename = "intel/sof-hda-generic.tplg", + .sof_tplg_filename = "sof-hda-generic.tplg", /* * .machine_quirk and .quirk_data are not used here but From 16c642474faaf7749cd2d077fe1df55d4e6aaaf8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:47 -0600 Subject: [PATCH 0890/1995] ASoC: Intel: hsw-bdw-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit bb2538e28a54f97455597eca01e1b9452c67a5d4) --- .../intel/common/soc-acpi-intel-hsw-bdw-match.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c index 494a0ea9b02903..ddfe4250c2bcb9 100644 --- a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c @@ -23,8 +23,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_haswell_machines[] = { .id = "INT33CA", .drv_name = "haswell-audio", .fw_filename = "intel/IntcSST1.bin", - .sof_fw_filename = "intel/sof-hsw.ri", - .sof_tplg_filename = "intel/sof-hsw.tplg", + .sof_fw_filename = "sof-hsw.ri", + .sof_tplg_filename = "sof-hsw.tplg", .asoc_plat_name = "haswell-pcm-audio", }, {} @@ -36,24 +36,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { .id = "INT343A", .drv_name = "broadwell-audio", .fw_filename = "intel/IntcSST2.bin", - .sof_fw_filename = "intel/sof-bdw.ri", - .sof_tplg_filename = "intel/sof-bdw-rt286.tplg", + .sof_fw_filename = "sof-bdw.ri", + .sof_tplg_filename = "sof-bdw-rt286.tplg", .asoc_plat_name = "haswell-pcm-audio", }, { .id = "RT5677CE", .drv_name = "bdw-rt5677", .fw_filename = "intel/IntcSST2.bin", - .sof_fw_filename = "intel/sof-bdw.ri", - .sof_tplg_filename = "intel/sof-bdw-rt5677.tplg", + .sof_fw_filename = "sof-bdw.ri", + .sof_tplg_filename = "sof-bdw-rt5677.tplg", .asoc_plat_name = "haswell-pcm-audio", }, { .id = "INT33CA", .drv_name = "haswell-audio", .fw_filename = "intel/IntcSST2.bin", - .sof_fw_filename = "intel/sof-bdw.ri", - .sof_tplg_filename = "intel/sof-bdw-rt5640.tplg", + .sof_fw_filename = "sof-bdw.ri", + .sof_tplg_filename = "sof-bdw-rt5640.tplg", .asoc_plat_name = "haswell-pcm-audio", }, {} From d86508e96ee7c955ed99bca28841622431d0b2f6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:48 -0600 Subject: [PATCH 0891/1995] ASoC: Intel: icl-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit a5b1e2284567c487b1023b580656de4a19cc1a83) --- sound/soc/intel/common/soc-acpi-intel-icl-match.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c index 33b441dca4d308..bf6e25257a398a 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -20,8 +20,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { .drv_name = "icl_rt274", .fw_filename = "intel/dsp_fw_icl.bin", .pdata = &icl_pdata, - .sof_fw_filename = "intel/sof-icl.ri", - .sof_tplg_filename = "intel/sof-icl-rt274.tplg", + .sof_fw_filename = "sof-icl.ri", + .sof_tplg_filename = "sof-icl-rt274.tplg", .asoc_plat_name = "0000:00:1f.3", }, {}, From d9922ab5a96b69564a8e06656a203f764e871e49 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:49 -0600 Subject: [PATCH 0892/1995] ASoC: Intel: soc-acpi: bxt-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit dcc9de2ebe86791a041a92cdf9806bde004706c6) --- sound/soc/intel/common/soc-acpi-intel-bxt-match.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c index c0e5780e2ad165..229e395868684e 100644 --- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c @@ -53,7 +53,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .fw_filename = "intel/dsp_fw_bxtn.bin", .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-rt298.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "DLGS7219", @@ -63,21 +62,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .quirk_data = &bxt_codecs, .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-da7219.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "104C5122", .drv_name = "bxt-pcm512x", .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-pcm512x.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "1AEC8804", .drv_name = "bxt-wm8804", .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-wm8804.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "INT34C3", @@ -85,7 +81,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .machine_quirk = apl_quirk, .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-tdf8532.tplg", - .asoc_plat_name = "0000:00:0e.0", }, {}, }; From f55597f08a0f1650d9acb631598fb6333ba7a75f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:50 -0600 Subject: [PATCH 0893/1995] ASoC: Intel: soc-acpi: byt-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit f01d00c30095f420ad8b447ba21c9492da93cebf) --- sound/soc/intel/common/soc-acpi-intel-byt-match.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index a46a3514a0f00b..fe812a909db4a9 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -85,7 +85,6 @@ static struct snd_soc_acpi_mach byt_thinkpad_10 = { .board = "cht-bsw", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5670.tplg", - .asoc_plat_name = "sst-mfld-platform", }; static struct snd_soc_acpi_mach byt_pov_p1006w = { @@ -95,7 +94,6 @@ static struct snd_soc_acpi_mach byt_pov_p1006w = { .board = "bytcr_rt5651", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5651.tplg", - .asoc_plat_name = "sst-mfld-platform", }; static struct snd_soc_acpi_mach *byt_quirk(void *arg) @@ -138,7 +136,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .machine_quirk = byt_quirk, .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5642", @@ -147,7 +144,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcr_rt5640", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "INTCCFFD", @@ -156,7 +152,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcr_rt5640", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5651", @@ -165,7 +160,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcr_rt5651", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5651.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "DLGS7212", @@ -174,7 +168,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcht_da7213", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-da7213.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "DLGS7213", @@ -183,7 +176,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcht_da7213", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-da7213.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "ESSX8316", @@ -192,7 +184,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcht_es8316", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-es8316.tplg", - .asoc_plat_name = "sst-mfld-platform", }, /* some Baytrail platforms rely on RT5645, use CHT machine driver */ { @@ -202,7 +193,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5648", @@ -211,7 +201,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, /* use CHT driver to Baytrail Chromebooks */ { @@ -221,7 +210,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-max98090.tplg", - .asoc_plat_name = "sst-mfld-platform", }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) /* From d731173011b475b56ae6f943e934f8b0e2abc9b4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:51 -0600 Subject: [PATCH 0894/1995] ASoC: Intel: soc-acpi: cht-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 9eebe4372f4a608e51b7a2c0b064069e78a6ce5b) --- sound/soc/intel/common/soc-acpi-intel-cht-match.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c index 21ce4bcbf25b7e..deafd87cc76466 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -46,7 +46,6 @@ static struct snd_soc_acpi_mach cht_surface_mach = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }; static struct snd_soc_acpi_mach *cht_quirk(void *arg) @@ -70,7 +69,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5670.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5672", @@ -79,7 +77,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5670.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5645", @@ -88,7 +85,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5650", @@ -97,7 +93,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC3270", @@ -106,7 +101,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "193C9890", @@ -115,7 +109,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-max98090.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10508824", @@ -124,7 +117,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-nau8824.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "DLGS7212", @@ -133,7 +125,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcht_da7213", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-da7213.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "DLGS7213", @@ -142,7 +133,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcht_da7213", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-da7213.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "ESSX8316", @@ -151,7 +141,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcht_es8316", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-es8316.tplg", - .asoc_plat_name = "sst-mfld-platform", }, /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ { @@ -162,7 +151,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .machine_quirk = cht_quirk, .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC3276", @@ -171,7 +159,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcr_rt5640", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */ { @@ -181,7 +168,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcr_rt5651", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5651.tplg", - .asoc_plat_name = "sst-mfld-platform", }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) /* From 18c790520360b551eb27d1bd2f392eff8d4e3bac Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:52 -0600 Subject: [PATCH 0895/1995] ASoC: Intel: soc-acpi: glk-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 3f4d9d67c3399bde7e08aeeb9758868852413343) --- sound/soc/intel/common/soc-acpi-intel-glk-match.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c index 75bc0109166a0a..3f2061475ae426 100644 --- a/sound/soc/intel/common/soc-acpi-intel-glk-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c @@ -21,7 +21,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { .fw_filename = "intel/dsp_fw_glk.bin", .sof_fw_filename = "sof-glk.ri", .sof_tplg_filename = "sof-glk-alc298.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "DLGS7219", @@ -31,7 +30,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { .quirk_data = &glk_codecs, .sof_fw_filename = "sof-glk.ri", .sof_tplg_filename = "sof-glk-da7219.tplg", - .asoc_plat_name = "0000:00:0e.0", }, {}, }; From a9d2a8ab9d91c1d7520ce5b639929a642ba824ca Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:53 -0600 Subject: [PATCH 0896/1995] ASoC: Intel: soc-acpi: hsw-bdw-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 2eddca128be282f600347ea07ef0b516dbc4e7ce) --- sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c index ddfe4250c2bcb9..690b305a255b4b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c @@ -25,7 +25,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_haswell_machines[] = { .fw_filename = "intel/IntcSST1.bin", .sof_fw_filename = "sof-hsw.ri", .sof_tplg_filename = "sof-hsw.tplg", - .asoc_plat_name = "haswell-pcm-audio", }, {} }; @@ -38,7 +37,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { .fw_filename = "intel/IntcSST2.bin", .sof_fw_filename = "sof-bdw.ri", .sof_tplg_filename = "sof-bdw-rt286.tplg", - .asoc_plat_name = "haswell-pcm-audio", }, { .id = "RT5677CE", @@ -46,7 +44,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { .fw_filename = "intel/IntcSST2.bin", .sof_fw_filename = "sof-bdw.ri", .sof_tplg_filename = "sof-bdw-rt5677.tplg", - .asoc_plat_name = "haswell-pcm-audio", }, { .id = "INT33CA", @@ -54,7 +51,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { .fw_filename = "intel/IntcSST2.bin", .sof_fw_filename = "sof-bdw.ri", .sof_tplg_filename = "sof-bdw-rt5640.tplg", - .asoc_plat_name = "haswell-pcm-audio", }, {} }; From 52cb9bfb8fc65e2577e90780a03b2e8637f74916 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:54 -0600 Subject: [PATCH 0897/1995] ASoC: Intel: soc-acpi: icl-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit fc906fda39c1705c2d89937fce13a6c11a5955bb) --- sound/soc/intel/common/soc-acpi-intel-icl-match.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c index bf6e25257a398a..e5a6be5bc0ee62 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -22,7 +22,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { .pdata = &icl_pdata, .sof_fw_filename = "sof-icl.ri", .sof_tplg_filename = "sof-icl-rt274.tplg", - .asoc_plat_name = "0000:00:1f.3", }, {}, }; From e77838c0422f16d112b8de3cd90e58fe9d7b804b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:55 -0600 Subject: [PATCH 0898/1995] ASoC: Intel: soc-acpi: cnl-match.c: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit c5898050fe801443dc66cd0302c21ceefa313916) --- sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index b80b50ddb22b12..a914dd238d0a46 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -22,7 +22,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .pdata = &cnl_pdata, .sof_fw_filename = "sof-cnl.ri", .sof_tplg_filename = "sof-cnl-rt274.tplg", - .asoc_plat_name = "0000:00:1f.3", }, {}, }; From 3ad2985b2bb37fce2909071ff05680297abf4a3f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:56 -0600 Subject: [PATCH 0899/1995] ASoC: soc-acpi: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit ecefff3e5b9b6a427a1a78c0c3f5eb147fd2d761) --- include/sound/soc-acpi.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 6cbbeed9cdd0c8..655e4e010cc821 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -86,8 +86,6 @@ struct snd_soc_acpi_mach_params { * is not constant since this field may be updated at run-time * @sof_fw_filename: Sound Open Firmware file name, if enabled * @sof_tplg_filename: Sound Open Firmware topology file name, if enabled - * @asoc_plat_name: ASoC platform name, used for binding machine drivers - * if non NULL * @new_mach_data: machine driver private data fixup */ /* Descriptor for SST ASoC machine driver */ @@ -102,7 +100,6 @@ struct snd_soc_acpi_mach { struct snd_soc_acpi_mach_params mach_params; const char *sof_fw_filename; const char *sof_tplg_filename; - const char *asoc_plat_name; struct platform_device * (*new_mach_data)(void *pdata); }; From 2d9ea25e7b5ce514af517ac706d29f64b61a11e0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:57 -0600 Subject: [PATCH 0900/1995] ASoC: soc-acpi: remove new_mach_data field We never used this field (or in older SOF implementations), let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit b3d8f7cad1b41411de443018cc5323070db06ab2) --- include/sound/soc-acpi.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 655e4e010cc821..35b38e41e5b296 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -86,7 +86,6 @@ struct snd_soc_acpi_mach_params { * is not constant since this field may be updated at run-time * @sof_fw_filename: Sound Open Firmware file name, if enabled * @sof_tplg_filename: Sound Open Firmware topology file name, if enabled - * @new_mach_data: machine driver private data fixup */ /* Descriptor for SST ASoC machine driver */ struct snd_soc_acpi_mach { @@ -100,7 +99,6 @@ struct snd_soc_acpi_mach { struct snd_soc_acpi_mach_params mach_params; const char *sof_fw_filename; const char *sof_tplg_filename; - struct platform_device * (*new_mach_data)(void *pdata); }; #define SND_SOC_ACPI_MAX_CODECS 3 From add92c2f5c9bcb2800d16e716f4ce0b5816fc165 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 17 Jan 2019 09:57:29 -0800 Subject: [PATCH 0901/1995] ASoC: SOF: add field to keep track of cores enabled in SMP Add a field "enabled_cores_mask" to keep track of the cores that are enabled in SMP and update it during topology loading/unloading. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/sof-priv.h | 1 + sound/soc/sof/topology.c | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 1bd9db4005fcf9..dad43559ec589a 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -392,6 +392,7 @@ struct snd_sof_dev { struct list_head dai_list; struct list_head route_list; struct snd_soc_component *component; + u32 enabled_cores_mask; /* keep track of enabled cores */ /* FW configuration */ struct sof_ipc_dma_buffer_data *info_buffer; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index e163138088e68f..c2192e1aa99430 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1110,12 +1110,15 @@ int sof_load_pipeline_ipc(struct snd_sof_dev *sdev, return ret; } + /* update enabled cores mask */ + sdev->enabled_cores_mask |= 1 << pipeline->core; + /* * Now notify DSP that the core that this pipeline is scheduled on * has been powered up */ memset(&pm_core_config, 0, sizeof(pm_core_config)); - pm_core_config.enable_mask = 1 << pipeline->core; + pm_core_config.enable_mask = sdev->enabled_cores_mask; /* configure CORE_ENABLE ipc message */ pm_core_config.hdr.size = sizeof(pm_core_config); @@ -1842,6 +1845,10 @@ static int sof_widget_unload(struct snd_soc_component *scomp, if (ret < 0) dev_err(sdev->dev, "error: powering down pipeline schedule core %d\n", pipeline->core); + + /* update enabled cores mask */ + sdev->enabled_cores_mask &= ~(1 << pipeline->core); + break; case snd_soc_dapm_pga: From 153573a0b2576bbd442734677e0e11a41784631b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 8 Feb 2019 18:11:09 -0800 Subject: [PATCH 0902/1995] ASoC: SOF: add init_core_mask to struct sof_intel_dsp_desc Add a init_core_mask member to sof_intel_dsp_desc and set the value for SKL+ platforms. This will be used to specify which cores are enabled after fw boot is complete. Also make snd_sof_dsp_run() op return the init_core_mask. SKL- platforms with single core DSP's just return 1. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/apl.c | 1 + sound/soc/sof/intel/bdw.c | 3 ++- sound/soc/sof/intel/byt.c | 3 ++- sound/soc/sof/intel/cnl.c | 1 + sound/soc/sof/intel/hda-loader.c | 11 +++++++++-- sound/soc/sof/intel/hsw.c | 3 ++- sound/soc/sof/intel/shim.h | 1 + sound/soc/sof/intel/skl.c | 1 + sound/soc/sof/loader.c | 6 ++++++ sound/soc/sof/ops.h | 5 +++++ 10 files changed, 30 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 1c040b600891d3..692f0e06652f2f 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -101,6 +101,7 @@ EXPORT_SYMBOL(sof_apl_ops); const struct sof_intel_dsp_desc apl_chip_info = { /* Apollolake */ .cores_num = 2, + .init_core_mask = 1, .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1), .ipc_req = HDA_DSP_REG_HIPCI, .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY, diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 7d5fa9387b39c9..fbaa170fc5e14a 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -84,7 +84,8 @@ static int bdw_run(struct snd_sof_dev *sdev) snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CSR, SHIM_CSR_STALL, 0x0); - return 0; + /* return init core mask */ + return 1; } static int bdw_reset(struct snd_sof_dev *sdev) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 34ad7536bdc806..8baf98764488b2 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -463,7 +463,8 @@ static int byt_run(struct snd_sof_dev *sdev) return -ENODEV; } - return 0; + /* return init core mask */ + return 1; } static int byt_reset(struct snd_sof_dev *sdev) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index ae080b865bccc8..626f3d49bf8c36 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -256,6 +256,7 @@ EXPORT_SYMBOL(sof_cnl_ops); const struct sof_intel_dsp_desc cnl_chip_info = { /* Cannonlake */ .cores_num = 4, + .init_core_mask = 1, .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1) | HDA_DSP_CORE_MASK(2) | diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 6a5e07df411655..9362771ee0d0a9 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -248,10 +248,14 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) { struct snd_sof_pdata *plat_data = sdev->pdata; + const struct sof_dev_desc *desc = plat_data->desc; + const struct sof_intel_dsp_desc *chip_info; struct hdac_ext_stream *stream; struct firmware stripped_firmware; int ret, ret1, tag, i; + chip_info = (struct sof_intel_dsp_desc *)desc->chip_info; + stripped_firmware.data = plat_data->fw->data; stripped_firmware.size = plat_data->fw->size; @@ -329,9 +333,12 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) ret = ret1; } - /* return if both copying fw and stream clean up are successful */ + /* + * return master core id if both fw copy + * and stream clean up are successful + */ if (!ret) - return ret; + return chip_info->init_core_mask; /* dump dsp registers and disable DSP upon error */ err: diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 95807406eeb866..8295b4b02dd41c 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -84,7 +84,8 @@ static int hsw_run(struct snd_sof_dev *sdev) snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_CSR, SHIM_CSR_STALL, 0x0); - return 0; //TODO: Fix return value + /* return init core mask */ + return 1; } static int hsw_reset(struct snd_sof_dev *sdev) diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 1a92b155af24c7..63fc9b7499a09b 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -155,6 +155,7 @@ struct sof_intel_dsp_desc { int cores_num; int cores_mask; + int init_core_mask; /* cores available after fw boot */ int ipc_req; int ipc_req_mask; int ipc_ack; diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index f8409c26b748c5..fd3d187f9face5 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -94,6 +94,7 @@ EXPORT_SYMBOL(sof_skl_ops); const struct sof_intel_dsp_desc skl_chip_info = { /* Apollolake */ .cores_num = 2, + .init_core_mask = 1, .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1), .ipc_req = HDA_DSP_REG_HIPCI, .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY, diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index f996082fa656aa..230fb696e8fb1f 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -301,6 +301,7 @@ EXPORT_SYMBOL(snd_sof_load_firmware); int snd_sof_run_firmware(struct snd_sof_dev *sdev) { int ret; + int init_core_mask; init_waitqueue_head(&sdev->boot_wait); sdev->boot_complete = false; @@ -333,6 +334,8 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) return ret; } + init_core_mask = ret; + /* now wait for the DSP to boot */ ret = wait_event_timeout(sdev->boot_wait, sdev->boot_complete, msecs_to_jiffies(sdev->boot_timeout)); @@ -352,6 +355,9 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) return ret; } + /* fw boot is complete. Update the active cores mask */ + sdev->enabled_cores_mask = init_core_mask; + return 0; } EXPORT_SYMBOL(snd_sof_run_firmware); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index c6374f0210e987..b070ad34e17c62 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -40,6 +40,11 @@ static inline int snd_sof_remove(struct snd_sof_dev *sdev) } /* control */ + +/* + * snd_sof_dsp_run returns the core mask of the cores that are available + * after successful fw boot + */ static inline int snd_sof_dsp_run(struct snd_sof_dev *sdev) { if (sof_ops(sdev)->run) From 81fd9edf054dd2d077b0624939c1aea721578199 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 7 Feb 2019 16:32:54 +0000 Subject: [PATCH 0903/1995] ASoC: topology: Align tplg pointer increment across all kcontrols This aligns all kcontrol tplg pointer increments to be consistent in the respective create methods and ensures that the position is pointing to the next widget rather the current invalid widget. Signed-off-by: Liam Girdwood Signed-off-by: Ranjani Sridharan --- sound/soc/soc-topology.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index c5638e15a2ddfb..6de9c3ae859878 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -993,8 +993,6 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, for (i = 0; i < count; i++) { ec = (struct snd_soc_tplg_enum_control *)tplg->pos; - tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + - ec->priv.size); /* validate kcontrol */ if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == @@ -1005,6 +1003,9 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, if (se == NULL) return -ENOMEM; + tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + + ec->priv.size); + dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n", ec->hdr.name, ec->items); @@ -1281,14 +1282,14 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( if (sm == NULL) goto err; - tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) + - mc->priv.size); - /* validate kcontrol */ if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) goto err_str; + tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) + + mc->priv.size); + dev_dbg(tplg->dev, " adding DAPM widget mixer control %s at %d\n", mc->hdr.name, i); @@ -1373,6 +1374,9 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( if (se == NULL) goto err; + tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + + ec->priv.size); + dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n", ec->hdr.name); @@ -1437,9 +1441,6 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( ec->hdr.name); goto err_se; } - - tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + - ec->priv.size); } return kc; From d421f6e1af134f9633f392c7958990e7c13fe380 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 7 Feb 2019 20:13:33 +0000 Subject: [PATCH 0904/1995] ASoC: SOF: controls: Add support for enum and switch kcontrols This patch defines and implements the get/put IO handlers for enum and switch type kcontrols. Switch type kcontrol is a variety of mixer type control with a max value of 1. Signed-off-by: Liam Girdwood Signed-off-by: Ranjani Sridharan --- include/uapi/sound/sof/tokens.h | 1 + sound/soc/sof/control.c | 144 ++++++++++++++++++++++++++++++++ sound/soc/sof/pm.c | 4 + sound/soc/sof/sof-priv.h | 8 ++ sound/soc/sof/topology.c | 50 ++++++++++- 5 files changed, 203 insertions(+), 4 deletions(-) diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index c894b51b34b690..ebf7ab5a00a773 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -23,6 +23,7 @@ #define SOF_TPLG_KCTL_VOL_ID 256 #define SOF_TPLG_KCTL_ENUM_ID 257 #define SOF_TPLG_KCTL_BYTES_ID 258 +#define SOF_TPLG_KCTL_SWITCH_ID 259 /* * Tokens - must match values in topology configurations diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 71950d39aa5bf3..945b01a2612967 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -109,6 +109,150 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, return 0; } +int snd_sof_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *sm = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_sof_control *scontrol = sm->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + unsigned int i, channels = scontrol->num_channels; + int err, ret; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err_ratelimited(sdev->dev, "error: switch get failed to resume %d\n", + ret); + return ret; + } + + /* get all the mixer data from DSP */ + snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_SWITCH); + + /* read back each channel */ + for (i = 0; i < channels; i++) + ucontrol->value.integer.value[i] = cdata->chanv[i].value; + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, "error: switch get failed to idle %d\n", + err); + return 0; +} + +int snd_sof_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *sm = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_sof_control *scontrol = sm->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + unsigned int i, channels = scontrol->num_channels; + int ret, err; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err_ratelimited(sdev->dev, "error: switch put failed to resume %d\n", + ret); + return ret; + } + + /* update each channel */ + for (i = 0; i < channels; i++) { + cdata->chanv[i].value = ucontrol->value.integer.value[i]; + cdata->chanv[i].channel = i; + } + + /* notify DSP of mixer updates */ + snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_SWITCH); + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, "error: switch put failed to idle %d\n", + err); + return 0; +} + +int snd_sof_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *se = + (struct soc_enum *)kcontrol->private_value; + struct snd_sof_control *scontrol = se->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + unsigned int i, channels = scontrol->num_channels; + int err, ret; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err_ratelimited(sdev->dev, "error: enum get failed to resume %d\n", + ret); + return ret; + } + + /* get all the mixer data from DSP */ + snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_ENUM); + + /* read back each channel */ + for (i = 0; i < channels; i++) + ucontrol->value.enumerated.item[i] = cdata->chanv[i].value; + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, "error: enum get failed to idle %d\n", + err); + return 0; +} + +int snd_sof_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *se = + (struct soc_enum *)kcontrol->private_value; + struct snd_sof_control *scontrol = se->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + unsigned int i, channels = scontrol->num_channels; + int ret, err; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err_ratelimited(sdev->dev, "error: enum put failed to resume %d\n", + ret); + return ret; + } + + /* update each channel */ + for (i = 0; i < channels; i++) { + cdata->chanv[i].value = ucontrol->value.enumerated.item[i]; + cdata->chanv[i].channel = i; + } + + /* notify DSP of mixer updates */ + snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_ENUM); + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, "error: enum put failed to idle %d\n", + err); + return 0; +} + int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index f306095bfb5d5f..225336b9cd5e91 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -25,6 +25,10 @@ static int sof_restore_kcontrols(struct snd_sof_dev *sdev) /* notify DSP of kcontrol values */ switch (scontrol->cmd) { case SOF_CTRL_CMD_VOLUME: + /* fallthrough */ + case SOF_CTRL_CMD_ENUM: + /* fallthrough */ + case SOF_CTRL_CMD_SWITCH: ipc_cmd = SOF_IPC_COMP_SET_VALUE; ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET; ret = snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index dad43559ec589a..644d7a4a17e68c 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -552,6 +552,14 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_sof_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int snd_sof_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index c2192e1aa99430..4298d2e0cb1390 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -285,12 +285,50 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, scontrol->comp_id = sdev->next_comp_id; scontrol->num_channels = le32_to_cpu(mc->num_channels); + /* set cmd for mixer control */ + if (mc->max > 1) + scontrol->cmd = SOF_CTRL_CMD_VOLUME; + else + scontrol->cmd = SOF_CTRL_CMD_SWITCH; + dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", scontrol->comp_id, scontrol->num_channels); return 0; } +static int sof_control_load_enum(struct snd_soc_component *scomp, + struct snd_sof_control *scontrol, + struct snd_kcontrol_new *kc, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_enum_control *ec = + (struct snd_soc_tplg_enum_control *)hdr; + + /* validate topology data */ + if (le32_to_cpu(ec->num_channels) > SND_SOC_TPLG_MAX_CHAN) + return -EINVAL; + + /* init the enum get/put data */ + scontrol->size = sizeof(struct sof_ipc_ctrl_data) + + sizeof(struct sof_ipc_ctrl_value_chan) * + le32_to_cpu(ec->num_channels); + scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); + if (!scontrol->control_data) + return -ENOMEM; + + scontrol->comp_id = sdev->next_comp_id; + scontrol->num_channels = le32_to_cpu(ec->num_channels); + + scontrol->cmd = SOF_CTRL_CMD_ENUM; + + dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d comp_id %d\n", + scontrol->comp_id, scontrol->num_channels, scontrol->comp_id); + + return 0; +} + static int sof_control_load_bytes(struct snd_soc_component *scomp, struct snd_sof_control *scontrol, struct snd_kcontrol_new *kc, @@ -798,7 +836,8 @@ static int sof_control_load(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_ctl_hdr *hdr) { struct soc_mixer_control *sm; - struct soc_bytes_ext *sbe; + struct soc_bytes_ext *sbe; + struct soc_enum *se; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_dobj *dobj = NULL; struct snd_sof_control *scontrol; @@ -829,6 +868,10 @@ static int sof_control_load(struct snd_soc_component *scomp, int index, break; case SND_SOC_TPLG_CTL_ENUM: case SND_SOC_TPLG_CTL_ENUM_VALUE: + se = (struct soc_enum *)kc->private_value; + dobj = &se->dobj; + ret = sof_control_load_enum(scomp, scontrol, kc, hdr); + break; case SND_SOC_TPLG_CTL_RANGE: case SND_SOC_TPLG_CTL_STROBE: case SND_SOC_TPLG_DAPM_CTL_VOLSW: @@ -1280,9 +1323,6 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, /* get volume control */ scontrol = sm->dobj.private; - /* set cmd for pga kcontrol */ - scontrol->cmd = SOF_CTRL_CMD_VOLUME; - /* get topology tlv data */ p = kc->tlv.p; @@ -2733,6 +2773,8 @@ static int sof_manifest(struct snd_soc_component *scomp, int index, static const struct snd_soc_tplg_kcontrol_ops sof_io_ops[] = { {SOF_TPLG_KCTL_VOL_ID, snd_sof_volume_get, snd_sof_volume_put}, {SOF_TPLG_KCTL_BYTES_ID, snd_sof_bytes_get, snd_sof_bytes_put}, + {SOF_TPLG_KCTL_ENUM_ID, snd_sof_enum_get, snd_sof_enum_put}, + {SOF_TPLG_KCTL_SWITCH_ID, snd_sof_switch_get, snd_sof_switch_put}, }; /* vendor specific bytes ext handlers available for binding */ From 0fc2f31ffb32f5e91a490c8b92c58645b69c5934 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 11 Feb 2019 21:32:10 -0800 Subject: [PATCH 0905/1995] ASoC: SOF: topology: add support for MUX comp Add support for loading Mux component in topology. Signed-off-by: Liam Girdwood Signed-off-by: Ranjani Sridharan --- sound/soc/sof/topology.c | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 4298d2e0cb1390..d23c6c346e3af1 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1284,6 +1284,53 @@ static int sof_widget_load_mixer(struct snd_soc_component *scomp, int index, return ret; } +/* + * Mux topology + */ +static int sof_widget_load_mux(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_mux *mux; + int ret; + + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return -ENOMEM; + + /* configure mux IPC message */ + mux->comp.hdr.size = sizeof(*mux); + mux->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + mux->comp.id = swidget->comp_id; + mux->comp.type = SOF_COMP_MUX; + mux->comp.pipeline_id = index; + mux->config.hdr.size = sizeof(mux->config); + + ret = sof_parse_tokens(scomp, &mux->config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse mux.cfg tokens failed %d\n", + private->size); + kfree(mux); + return ret; + } + + sof_dbg_comp_config(scomp, &mux->config); + + swidget->private = (void *)mux; + + ret = sof_ipc_tx_message(sdev->ipc, mux->comp.hdr.cmd, mux, + sizeof(*mux), r, sizeof(*r)); + if (ret < 0) + kfree(mux); + + return ret; +} + /* * PGA Topology */ @@ -1804,6 +1851,8 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, break; case snd_soc_dapm_mux: case snd_soc_dapm_demux: + ret = sof_widget_load_mux(scomp, index, swidget, tw, &reply); + break; case snd_soc_dapm_switch: case snd_soc_dapm_dai_link: case snd_soc_dapm_kcontrol: From 322f2071cbcb1d94b326904c6856a0ee4b67d846 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 15 Feb 2019 05:09:19 +0800 Subject: [PATCH 0906/1995] ASoC: topology: free created components in tplg load error Topology resources are no longer needed if any element failed to load. Signed-off-by: Bard liao --- sound/soc/soc-topology.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 6de9c3ae859878..40fa2a48fa1d5b 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -2588,6 +2588,7 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp, struct snd_soc_tplg_ops *ops, const struct firmware *fw, u32 id) { struct soc_tplg tplg; + int ret; /* setup parsing context */ memset(&tplg, 0, sizeof(tplg)); @@ -2601,7 +2602,12 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp, tplg.bytes_ext_ops = ops->bytes_ext_ops; tplg.bytes_ext_ops_count = ops->bytes_ext_ops_count; - return soc_tplg_load(&tplg); + ret = soc_tplg_load(&tplg); + /* free the created components if fail to load topology */ + if (ret) + snd_soc_tplg_component_remove(comp, SND_SOC_TPLG_INDEX_ALL); + + return ret; } EXPORT_SYMBOL_GPL(snd_soc_tplg_component_load); From 57360afbbdf5ce87cc7dac8c72cc3725172cf647 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 14 Feb 2019 14:03:01 -0600 Subject: [PATCH 0907/1995] ASoC: soc.h: remove old FIXME We renamed the field to take care of Mark's comments but didn't remove the FIXME. Reported-by: Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- include/sound/soc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index da3c1318526341..57ef2482c2b3d7 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1234,7 +1234,7 @@ struct snd_soc_pcm_runtime { unsigned int pop_wait:1; /* private data - core does not touch */ - void *private; /* FIXME: still SOF-specific, needs to less ambiguous */ + void *private; }; #define for_each_rtd_codec_dai(rtd, i, dai)\ for ((i) = 0; \ From c179c1cce0aad7af74354145e413c80fe250c886 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 14 Feb 2019 14:30:11 -0600 Subject: [PATCH 0908/1995] ASoC: SOF: pcm: test status of _open and _close functions These functions are optional but that's not an excuse. We need to test the status and return an error if relevant. Reported-by: Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pcm.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 3376633b0d461d..4510f1649f0772 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -371,6 +371,7 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) struct snd_soc_tplg_stream_caps *caps = &spcm->pcm.caps[substream->stream]; int ret; + int err; /* nothing todo for BE */ if (rtd->dai_link->no_pcm) @@ -427,10 +428,21 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) spcm->stream[substream->stream].posn.dai_posn = 0; spcm->stream[substream->stream].substream = substream; - snd_sof_pcm_platform_open(sdev, substream); + ret = snd_sof_pcm_platform_open(sdev, substream); + if (ret < 0) { + dev_err(sdev->dev, "error: pcm open failed %d\n", + ret); + + pm_runtime_mark_last_busy(sdev->dev); + + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err(sdev->dev, "error: pcm close failed to idle %d\n", + err); + } mutex_unlock(&spcm->mutex); - return 0; + return ret; } static int sof_pcm_close(struct snd_pcm_substream *substream) @@ -450,7 +462,15 @@ static int sof_pcm_close(struct snd_pcm_substream *substream) dev_dbg(sdev->dev, "pcm: close stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); - snd_sof_pcm_platform_close(sdev, substream); + err = snd_sof_pcm_platform_close(sdev, substream); + if (err < 0) { + dev_err(sdev->dev, "error: pcm close failed %d\n", + err); + /* + * keep going, no point in preventing the close + * from happening + */ + } mutex_lock(&spcm->mutex); pm_runtime_mark_last_busy(sdev->dev); From 5d97c789088639aea713d2f8fce1a2562331719a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 14 Feb 2019 14:33:27 -0600 Subject: [PATCH 0909/1995] [5.1/-next only] ASoC: SOF: pcm: remove checks on preallocate_pages this is needed only when integrating SOF after commit bb580602f3924 ("ALSA: pcm: Define snd_pcm_lib_preallocate_*() as returning void") DO NOT BACKPORT TO EARLIER VERSIONS Reported-by: Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pcm.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 4510f1649f0772..2ecb7732728437 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -532,17 +532,10 @@ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) dev_dbg(sdev->dev, "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n", caps->name, caps->buffer_size_min, caps->buffer_size_max); - ret = snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream, - SNDRV_DMA_TYPE_DEV_SG, sdev->dev, - le32_to_cpu(caps->buffer_size_min), - le32_to_cpu(caps->buffer_size_max)); - if (ret) { - dev_err(sdev->dev, "error: can't alloc DMA buffer size 0x%x/0x%x for %s %d\n", - caps->buffer_size_min, caps->buffer_size_max, - caps->name, ret); - return ret; - } - + snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream, + SNDRV_DMA_TYPE_DEV_SG, sdev->dev, + le32_to_cpu(caps->buffer_size_min), + le32_to_cpu(caps->buffer_size_max)); capture: stream = SNDRV_PCM_STREAM_CAPTURE; @@ -556,14 +549,10 @@ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) dev_dbg(sdev->dev, "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n", caps->name, caps->buffer_size_min, caps->buffer_size_max); - ret = snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream, - SNDRV_DMA_TYPE_DEV_SG, sdev->dev, - le32_to_cpu(caps->buffer_size_min), - le32_to_cpu(caps->buffer_size_max)); - if (ret) - dev_err(sdev->dev, "error: can't alloc DMA buffer size 0x%x/0x%x for %s %d\n", - caps->buffer_size_min, caps->buffer_size_max, - caps->name, ret); + snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream, + SNDRV_DMA_TYPE_DEV_SG, sdev->dev, + le32_to_cpu(caps->buffer_size_min), + le32_to_cpu(caps->buffer_size_max)); return ret; } From c12e99547bd8b5d8a4258d077ad4bf7b3a5399b2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 14 Feb 2019 14:38:40 -0600 Subject: [PATCH 0910/1995] ASoC: SOF: pcm: remove casts, use snd_mask_set_format Ironically I initiated the report on those ugly casts but never made the change to use the new helper. Fix. Reported-by: Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pcm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 2ecb7732728437..b3f22b17c1068d 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -586,7 +586,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, channels->max = 2; snd_mask_none(fmt); - snd_mask_set(fmt, (__force int)SNDRV_PCM_FORMAT_S16_LE); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); return 0; } @@ -596,13 +596,13 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, switch (dai->comp_dai.config.frame_fmt) { case SOF_IPC_FRAME_S16_LE: - snd_mask_set(fmt, (__force int)SNDRV_PCM_FORMAT_S16_LE); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); break; case SOF_IPC_FRAME_S24_4LE: - snd_mask_set(fmt, (__force int)SNDRV_PCM_FORMAT_S24_LE); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); break; case SOF_IPC_FRAME_S32_LE: - snd_mask_set(fmt, (__force int)SNDRV_PCM_FORMAT_S32_LE); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); break; default: dev_err(sdev->dev, "error: No available DAI format!\n"); From 302f9ece2a66ed63768b8e594a4e005c323718e4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 14 Feb 2019 14:47:40 -0600 Subject: [PATCH 0911/1995] ASoC: SOF: trace: remove duplicate remove_wait_queue() No need to do the same thing in the if and else cases Reported-by: Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/trace.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index d74074096dcb86..205de91a439343 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -35,13 +35,11 @@ static size_t sof_wait_trace_avail(struct snd_sof_dev *sdev, set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&sdev->trace_sleep, &wait); - if (signal_pending(current)) { - remove_wait_queue(&sdev->trace_sleep, &wait); - } else { + if (!signal_pending(current)) { /* set timeout to max value, no error code */ schedule_timeout(MAX_SCHEDULE_TIMEOUT); - remove_wait_queue(&sdev->trace_sleep, &wait); } + remove_wait_queue(&sdev->trace_sleep, &wait); /* return bytes available for copy */ if (sdev->host_offset < pos) From 2897a1e9578b2220cc4b942e5cb380a109981cad Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 14 Feb 2019 14:53:13 -0600 Subject: [PATCH 0912/1995] ASoC: SOF: utils: add note on wrappers These wrappers cannot be inlined since they are typically referenced in ops structures Reported-by: Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/utils.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index 9ade9aa30ab5f7..fbefddde34d2ea 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -16,6 +16,9 @@ /* * Register IO + * + * The sof_io_xyz() wrappers are typically referenced in snd_sof_dsp_ops + * structures and and cannot be inlined. */ void sof_io_write(struct snd_sof_dev *sdev, void __iomem *addr, u32 value) From deae80380719f1edb02293cac05fd3dc56f1feb6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 14 Feb 2019 15:53:25 -0600 Subject: [PATCH 0913/1995] ASoC: SOF: ops: fix inits, return types, remove symbols Remove initialization to remove warnings. This was not needed. Move types to bool when applicable Make some functions as static, remove symbols Re-order functions more logically Remove spurious parenthesis No functional change Reported-by: Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/ops.c | 65 +++++++++++++++++++++++---------------------- sound/soc/sof/ops.h | 29 ++++++++------------ 2 files changed, 44 insertions(+), 50 deletions(-) diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index 3dcdeb75fdd161..bd3aca388aebd4 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -11,18 +11,19 @@ #include #include "ops.h" -int snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset, - u32 mask, u32 value) +static +bool snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset, + u32 mask, u32 value) { struct pci_dev *pci = to_pci_dev(sdev->dev); unsigned int old, new; - u32 ret = ~0; /* explicit init to remove uninitialized use warnings */ + u32 ret; pci_read_config_dword(pci, offset, &ret); old = ret; dev_dbg(sdev->dev, "Debug PCIR: %8.8x at %8.8x\n", old & mask, offset); - new = (old & (~mask)) | (value & mask); + new = (old & ~mask) | (value & mask); if (old == new) return false; @@ -33,10 +34,9 @@ int snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset, return true; } -EXPORT_SYMBOL(snd_sof_pci_update_bits_unlocked); -int snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset, - u32 mask, u32 value) +bool snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset, + u32 mask, u32 value) { unsigned long flags; bool change; @@ -48,8 +48,8 @@ int snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset, } EXPORT_SYMBOL(snd_sof_pci_update_bits); -int snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, - u32 offset, u32 mask, u32 value) +bool snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u32 mask, u32 value) { unsigned int old, new; u32 ret; @@ -57,7 +57,7 @@ int snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, ret = snd_sof_dsp_read(sdev, bar, offset); old = ret; - new = (old & (~mask)) | (value & mask); + new = (old & ~mask) | (value & mask); if (old == new) return false; @@ -68,14 +68,14 @@ int snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, } EXPORT_SYMBOL(snd_sof_dsp_update_bits_unlocked); -int snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar, - u32 offset, u64 mask, u64 value) +bool snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u64 mask, u64 value) { u64 old, new; old = snd_sof_dsp_read64(sdev, bar, offset); - new = (old & (~mask)) | (value & mask); + new = (old & ~mask) | (value & mask); if (old == new) return false; @@ -86,24 +86,10 @@ int snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar, } EXPORT_SYMBOL(snd_sof_dsp_update_bits64_unlocked); -/* This is for registers bits with attribute RWC */ -void snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev *sdev, u32 bar, - u32 offset, u32 mask, u32 value) -{ - unsigned int old, new; - u32 ret; - - ret = snd_sof_dsp_read(sdev, bar, offset); - - old = ret; - new = (old & (~mask)) | (value & mask); - - snd_sof_dsp_write(sdev, bar, offset, new); -} -EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced_unlocked); -int snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset, - u32 mask, u32 value) +/* This is for registers bits with attribute RWC */ +bool snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset, + u32 mask, u32 value) { unsigned long flags; bool change; @@ -116,8 +102,8 @@ int snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset, } EXPORT_SYMBOL(snd_sof_dsp_update_bits); -int snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, u32 offset, - u64 mask, u64 value) +bool snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, u32 offset, + u64 mask, u64 value) { unsigned long flags; bool change; @@ -130,6 +116,21 @@ int snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, u32 offset, } EXPORT_SYMBOL(snd_sof_dsp_update_bits64); +static +void snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u32 mask, u32 value) +{ + unsigned int old, new; + u32 ret; + + ret = snd_sof_dsp_read(sdev, bar, offset); + + old = ret; + new = (old & ~mask) | (value & mask); + + snd_sof_dsp_write(sdev, bar, offset, new); +} + /* This is for registers bits with attribute RWC */ void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 mask, u32 value) diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index b070ad34e17c62..e5a00f573c0608 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -385,32 +385,25 @@ static inline const struct snd_sof_dsp_ops return NULL; } -int snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, - u32 offset, u32 mask, u32 value); +/* This is for registers bits with attribute RWC */ +bool snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset, + u32 mask, u32 value); -int snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar, - u32 offset, u64 mask, u64 value); +bool snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u32 mask, u32 value); -/* This is for registers bits with attribute RWC */ -void snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev *sdev, u32 bar, - u32 offset, u32 mask, u32 value); +bool snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u64 mask, u64 value); -int snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset, - u32 mask, u32 value); +bool snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset, + u32 mask, u32 value); -int snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, - u32 offset, u64 mask, u64 value); +bool snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u64 mask, u64 value); -/* This is for registers bits with attribute RWC */ void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 mask, u32 value); -int snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset, - u32 mask, u32 value); - -int snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset, - u32 mask, u32 value); - int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 mask, u32 target, u32 timeout_ms, u32 interval_us); From 3cb406f4cf804abb119590bc1c18c204b163513f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 14 Feb 2019 16:27:53 -0600 Subject: [PATCH 0914/1995] ASoC: SOF: debug: fix errors on copy_to_user() status copy_to_user() returns the number of bytes that could not be copied. Testing for the return value being equal to the requested value is not correct. Treat a non-zero return as an error Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 83871f3ac2a167..ccc125430a0be4 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -82,9 +82,9 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, kfree(buf); /* update count & position if copy succeeded */ - if (size_ret == count) + if (size_ret) return -EFAULT; - count -= size_ret; + *ppos = pos + count; return count; From 69a41dab0c937d969cc27ca8f553a2a4f6a7d8a6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 14 Feb 2019 16:29:59 -0600 Subject: [PATCH 0915/1995] ASoC: SOF: logger: fix errors on copy_to_user() status copy_to_user() returns the number of bytes that could not be copied. Testing for the return value being equal to the requested value is not correct. Treat a non-zero return as an error Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 205de91a439343..890dba4c7c2661 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -86,7 +86,7 @@ static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer, /* copy available trace data to debugfs */ rem = copy_to_user(buffer, dfse->buf + lpos, count); - if (rem == count) + if (rem) return -EFAULT; *ppos += count; From 3e31e2892e63d0e80430e281f9b0bcc758f6589c Mon Sep 17 00:00:00 2001 From: Bard liao Date: Wed, 20 Feb 2019 22:58:00 +0800 Subject: [PATCH 0916/1995] ASoC: SOF: no need to check pdata in snd_sof_device_remove pdata is assigned in snd_sof_device_probe(), and snd_sof_device_remove() will be called only if probe successfully. Remove the check will make KW check happy. Signed-off-by: Bard liao --- sound/soc/sof/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index c25e086e42e96c..c878c196169ce9 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -457,7 +457,7 @@ int snd_sof_device_remove(struct device *dev) * So it should be called after unregistering the comp driver * so that the card is valid while unregistering comp driver. */ - if (pdata && !IS_ERR_OR_NULL(pdata->pdev_mach)) + if (!IS_ERR_OR_NULL(pdata->pdev_mach)) platform_device_unregister(pdata->pdev_mach); /* release firmware */ From 33d8b46d2f4ccedbbbfb5b3a9852f8b4d59ab4a6 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 13 Feb 2019 10:42:58 +0800 Subject: [PATCH 0917/1995] ASoC:hdac_hda: use correct format to setup hda codec The current implementation of the hdac_hda codec results in zero-valued samples on capture and noise with headset playback when SOF is used on platforms with an on-board HDaudio codec. This is root-caused to SOF using be_hw_params_fixup, and the prepare() call using invalid runtime fields to determine the format. This patch moves the format handling to the hw_params() callback, as done already for hdac_hdmi, to make sure the fixed-up information is taken into account but keeps the codec initialization in prepare() as the stream_tag is only available at that time. Moving everything in the prepare() callback is possible but the code is less elegant so this two-step solution was chosen. The solution was tested with the SST driver with no regressions, and all the issues with SOF playback and capture are solved. Signed-off-by: Rander Wang --- sound/soc/codecs/hdac_hda.c | 53 +++++++++++++++++++++++++++---------- sound/soc/codecs/hdac_hda.h | 1 + 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index ffecdaaa8cf2bb..f889d94c8e3cf7 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -38,6 +38,9 @@ static void hdac_hda_dai_close(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); +static int hdac_hda_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, @@ -50,6 +53,7 @@ static const struct snd_soc_dai_ops hdac_hda_dai_ops = { .startup = hdac_hda_dai_open, .shutdown = hdac_hda_dai_close, .prepare = hdac_hda_dai_prepare, + .hw_params = hdac_hda_dai_hw_params, .hw_free = hdac_hda_dai_hw_free, .set_tdm_slot = hdac_hda_dai_set_tdm_slot, }; @@ -139,6 +143,39 @@ static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, return 0; } +static int hdac_hda_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct hdac_hda_priv *hda_pvt; + unsigned int format_val; + unsigned int maxbps; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + maxbps = dai->driver->playback.sig_bits; + else + maxbps = dai->driver->capture.sig_bits; + + hda_pvt = snd_soc_component_get_drvdata(component); + format_val = snd_hdac_calc_stream_format(params_rate(params), + params_channels(params), + params_format(params), + maxbps, + 0); + if (!format_val) { + dev_err(dai->dev, + "invalid format_val, rate=%d, ch=%d, format=%d, maxbps=%d\n", + params_rate(params), params_channels(params), + params_format(params), maxbps); + + return -EINVAL; + } + + hda_pvt->pcm[dai->id].format_val[substream->stream] = format_val; + return 0; +} + static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -162,10 +199,9 @@ static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; + struct hda_pcm_stream *hda_stream; struct hdac_hda_priv *hda_pvt; - struct snd_pcm_runtime *runtime = substream->runtime; struct hdac_device *hdev; - struct hda_pcm_stream *hda_stream; unsigned int format_val; struct hda_pcm *pcm; unsigned int stream; @@ -179,19 +215,8 @@ static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, hda_stream = &pcm->stream[substream->stream]; - format_val = snd_hdac_calc_stream_format(runtime->rate, - runtime->channels, - runtime->format, - hda_stream->maxbps, - 0); - if (!format_val) { - dev_err(&hdev->dev, - "invalid format_val, rate=%d, ch=%d, format=%d\n", - runtime->rate, runtime->channels, runtime->format); - return -EINVAL; - } - stream = hda_pvt->pcm[dai->id].stream_tag[substream->stream]; + format_val = hda_pvt->pcm[dai->id].format_val[substream->stream]; ret = snd_hda_codec_prepare(&hda_pvt->codec, hda_stream, stream, format_val, substream); diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h index e444ef5933606c..6b1bd4f428e70e 100644 --- a/sound/soc/codecs/hdac_hda.h +++ b/sound/soc/codecs/hdac_hda.h @@ -8,6 +8,7 @@ struct hdac_hda_pcm { int stream_tag[2]; + unsigned int format_val[2]; }; struct hdac_hda_priv { From 2a63a07d72e64f0528a82debf63c928eb5aeb40b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 20 Feb 2019 16:21:19 -0600 Subject: [PATCH 0918/1995] ASoC: SOF: Intel: don't use u64 for IPC registers Likely a copy/paste issue. snd_sof_dsp_read returns a u32, there is no point in using u64 variables. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/cnl.c | 2 +- sound/soc/sof/intel/hda-ipc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 626f3d49bf8c36..5ec0246b9400d4 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -155,7 +155,7 @@ static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev, int dir) static int cnl_is_ipc_ready(struct snd_sof_dev *sdev) { - u64 busy, done; + u32 busy, done; busy = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR); done = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index d792cc97923233..38dae0ddbfa43f 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -57,7 +57,7 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir) int hda_dsp_is_ipc_ready(struct snd_sof_dev *sdev) { - u64 busy, done; + u32 busy, done; /* is DSP ready for next IPC command */ busy = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI); From 124fbe17a90e1de9f0e025a46fcb655ff5e44dff Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 20 Feb 2019 16:37:10 -0600 Subject: [PATCH 0919/1995] ASoC: SOF: fix ASLA typo s/ASLA/ALSA Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-priv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 644d7a4a17e68c..2f38a7ce0aa77c 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -271,7 +271,7 @@ struct snd_sof_pcm_stream { struct snd_pcm_substream *substream; }; -/* ASLA SOF PCM device */ +/* ALSA SOF PCM device */ struct snd_sof_pcm { struct snd_sof_dev *sdev; struct snd_soc_tplg_pcm pcm; From ee19d24e26c7e8cb193bfb72cce27561ec281c92 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 21 Feb 2019 14:50:20 -0600 Subject: [PATCH 0920/1995] ASoC: SOF: debug: fix compilation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove local variable and use explicit indirection to fix GCC warning: debug.c: In function ‘sof_dfsentry_read’: debug.c:25:17: warning: unused variable ‘dfsentry’ [-Wunused-variable] struct dentry *dfsentry = dfse->dfsentry; Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/debug.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index ccc125430a0be4..76628952775cb4 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -22,7 +22,6 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, { struct snd_sof_dfsentry *dfse = file->private_data; struct snd_sof_dev *sdev = dfse->sdev; - struct dentry *dfsentry = dfse->dfsentry; int size; u32 *buf; loff_t pos = *ppos; @@ -67,7 +66,7 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) { dev_err(sdev->dev, "error: debugfs entry %s cannot be read in DSP D3\n", - dfsentry->d_name.name); + dfse->dfsentry->d_name.name); return -EINVAL; } From e3cad63f1d51223a94d27692e1831fb38f1a4340 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Thu, 14 Feb 2019 03:17:20 +0800 Subject: [PATCH 0921/1995] ASoC: SOF: intel: don't read CTX_SAVE reply The memory windows are powered off before sending IPC reply back to the host, so the host should not try to read the mailbox for CTX_SAVE reply. Signed-off-by: Bard liao --- sound/soc/sof/intel/hda-ipc.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 38dae0ddbfa43f..589264524f08c5 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -86,11 +86,24 @@ int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { struct sof_ipc_reply reply; + struct sof_ipc_cmd_hdr *hdr; int ret = 0; u32 size; - /* get IPC reply from DSP in the mailbox */ - sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); + hdr = (struct sof_ipc_cmd_hdr *)msg->msg_data; + if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) { + /* + * memory windows are powered off before sending IPC reply, + * so we can't read the mailbox for CTX_SAVE reply. + */ + reply.error = 0; + reply.hdr.cmd = SOF_IPC_GLB_REPLY; + reply.hdr.size = sizeof(reply); + } else { + /* get IPC reply from DSP in the mailbox */ + sof_mailbox_read(sdev, sdev->host_box.offset, &reply, + sizeof(reply)); + } if (reply.error < 0) { size = sizeof(reply); ret = reply.error; From f9eece48cebe905cc96d6a6c204e4ce47172e255 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 21 Feb 2019 14:30:35 -0600 Subject: [PATCH 0922/1995] ASoC: SOF: make snd_sof_find_spcm_dai() static inline This routine will be used to retrieve the spcm information, make it inline to speed things up and avoid symbol declaration issues Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 13 ------------- sound/soc/sof/sof-priv.h | 15 ++++++++++++++- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index c878c196169ce9..6f62ad714f3560 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -23,19 +23,6 @@ * Generic object lookup APIs. */ -struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_sof_dev *sdev, - struct snd_soc_pcm_runtime *rtd) -{ - struct snd_sof_pcm *spcm = NULL; - - list_for_each_entry(spcm, &sdev->pcm_list, list) { - if (le32_to_cpu(spcm->pcm.dai_id) == rtd->dai_link->id) - return spcm; - } - - return NULL; -} - struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev, char *name) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 2f38a7ce0aa77c..6253bc37f60249 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -470,8 +470,21 @@ struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev, char *name); struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev, char *name); + +static inline struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_sof_dev *sdev, - struct snd_soc_pcm_runtime *rtd); + struct snd_soc_pcm_runtime *rtd) +{ + struct snd_sof_pcm *spcm = NULL; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + if (le32_to_cpu(spcm->pcm.dai_id) == rtd->dai_link->id) + return spcm; + } + + return NULL; +} + struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev, char *name); struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev, From 58d6d1914a0d9ec0b6ba526cef305d6a4938e43d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 21 Feb 2019 14:33:03 -0600 Subject: [PATCH 0923/1995] ASoC: SOF: remove use of rtd->private Feedback from Mark Brown indicates it's a bad idea to extend the runtime information. So far this field was only used to store the spcm information, and we can find it with a simple list walk using existing snd_soc_find_spcm_dai() routine. Signed-off-by: Pierre-Louis Bossart --- include/sound/soc.h | 3 --- sound/soc/sof/intel/hda-pcm.c | 11 ++++++-- sound/soc/sof/pcm.c | 48 +++++++++++++++++++++++++++-------- 3 files changed, 47 insertions(+), 15 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 57ef2482c2b3d7..eb7db605955b85 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1232,9 +1232,6 @@ struct snd_soc_pcm_runtime { /* bit field */ unsigned int dev_registered:1; unsigned int pop_wait:1; - - /* private data - core does not touch */ - void *private; }; #define for_each_rtd_codec_dai(rtd, i, dai)\ for ((i) = 0; \ diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 1c6adecf4a4fbe..bbcef74f8a33be 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -139,13 +139,20 @@ int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { - struct hdac_stream *hstream = substream->runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct hdac_stream *hstream = substream->runtime->private_data; struct sof_intel_hda_dev *hda = (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; - struct snd_sof_pcm *spcm = rtd->private; + struct snd_sof_pcm *spcm; snd_pcm_uframes_t pos = 0; + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) { + dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n", + rtd->dai_link->id); + return 0; + } + if (hda && !hda->no_ipc_position) { /* read position from IPC position */ pos = spcm->stream[substream->stream].posn.host_posn; diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index b3f22b17c1068d..9534411450075a 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -27,10 +27,14 @@ static int create_page_table(struct snd_pcm_substream *substream, snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - struct snd_sof_pcm *spcm = rtd->private; + struct snd_sof_pcm *spcm; struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream); int stream = substream->stream; + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + return snd_sof_create_page_table(sdev, dmab, spcm->stream[stream].page_table.area, size); } @@ -45,7 +49,7 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - struct snd_sof_pcm *spcm = rtd->private; + struct snd_sof_pcm *spcm; struct sof_ipc_pcm_params pcm; struct sof_ipc_pcm_params_reply ipc_params_reply; int posn_offset; @@ -55,6 +59,10 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, if (rtd->dai_link->no_pcm) return 0; + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + dev_dbg(sdev->dev, "pcm: hw params stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); @@ -176,7 +184,7 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - struct snd_sof_pcm *spcm = rtd->private; + struct snd_sof_pcm *spcm; struct sof_ipc_stream stream; struct sof_ipc_reply reply; int ret; @@ -185,6 +193,10 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) if (rtd->dai_link->no_pcm) return 0; + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); @@ -238,7 +250,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - struct snd_sof_pcm *spcm = rtd->private; + struct snd_sof_pcm *spcm; struct sof_ipc_stream stream; struct sof_ipc_reply reply; int ret = 0; @@ -247,6 +259,10 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) if (rtd->dai_link->no_pcm) return 0; + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + dev_dbg(sdev->dev, "pcm: trigger stream %d dir %d cmd %d\n", spcm->pcm.pcm_id, substream->stream, cmd); @@ -336,7 +352,7 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - struct snd_sof_pcm *spcm = rtd->private; + struct snd_sof_pcm *spcm; snd_pcm_uframes_t host = 0, dai = 0; /* nothing todo for BE */ @@ -347,6 +363,10 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) if (sof_ops(sdev)->pcm_pointer) return sof_ops(sdev)->pcm_pointer(sdev, substream); + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + /* read position from DSP */ host = bytes_to_frames(substream->runtime, spcm->stream[substream->stream].posn.host_posn); @@ -367,9 +387,8 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - struct snd_sof_pcm *spcm = rtd->private; - struct snd_soc_tplg_stream_caps *caps = - &spcm->pcm.caps[substream->stream]; + struct snd_sof_pcm *spcm; + struct snd_soc_tplg_stream_caps *caps; int ret; int err; @@ -377,9 +396,15 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) if (rtd->dai_link->no_pcm) return 0; + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); + caps = &spcm->pcm.caps[substream->stream]; + mutex_lock(&spcm->mutex); ret = pm_runtime_get_sync(sdev->dev); @@ -452,13 +477,17 @@ static int sof_pcm_close(struct snd_pcm_substream *substream) snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - struct snd_sof_pcm *spcm = rtd->private; + struct snd_sof_pcm *spcm; int err; /* nothing todo for BE */ if (rtd->dai_link->no_pcm) return 0; + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + dev_dbg(sdev->dev, "pcm: close stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); @@ -518,7 +547,6 @@ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) rtd->dai_link->id); return 0; } - rtd->private = spcm; dev_dbg(sdev->dev, "creating new PCM %s\n", spcm->pcm.pcm_name); From b5711b3ef40adf6c4ed489b8c237728c5bf8d94d Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Mon, 25 Feb 2019 13:20:13 +0800 Subject: [PATCH 0924/1995] ASoC: SOF: bxt_pcm512x use dai_link id as the pcm device The old code uses dai->id as the pcm device value, which is wrong. dai->id of HDMI audio starts from 0. But HDMI audio PCM device is determined by the machine/topology setting. For example HDMI audio uses PCM 1, PCM 2 and PCM3 on bxt_pcm512x. So let's use dai_link as the pcm device, which is set based on FE dai_link id. Signed-off-by: Libin Yang --- sound/soc/intel/boards/bxt_pcm512x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bxt_pcm512x.c b/sound/soc/intel/boards/bxt_pcm512x.c index 47e21e26c0084b..c0d6e8a9d7943b 100644 --- a/sound/soc/intel/boards/bxt_pcm512x.c +++ b/sound/soc/intel/boards/bxt_pcm512x.c @@ -47,7 +47,8 @@ static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) if (!pcm) return -ENOMEM; - pcm->device = dai->id; + /* dai_link id is 1:1 mapped to the PCM device */ + pcm->device = rtd->dai_link->id; pcm->codec_dai = dai; list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); From fc85af7b4fc5593b41d33f803f3fc13c4e8670fa Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Thu, 28 Feb 2019 09:15:26 +0800 Subject: [PATCH 0925/1995] ASoC: SOF: sof_rt5682 use dai_link id as the pcm device The old code uses dai->id as the pcm device value, which is wrong. dai->id of HDMI audio starts from 0. But HDMI audio PCM device is determined by the machine/topology setting. So let's use dai_link as the pcm device, which is set based on FE dai_link id. Signed-off-by: Libin Yang --- sound/soc/intel/boards/sof_rt5682.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index a8905aaa5ccd8c..eab6eaaedd6c9e 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -98,7 +98,8 @@ static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd) if (!pcm) return -ENOMEM; - pcm->device = dai->id; + /* dai_link id is 1:1 mapped to the PCM device */ + pcm->device = rtd->dai_link->id; pcm->codec_dai = dai; list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); From a72f3d463b3d40f3839701b41c718d1ce6d25202 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 25 Feb 2019 15:00:17 -0800 Subject: [PATCH 0926/1995] ASoC: SOF: bind pcm to host comp when the dai is loaded Previously, PCM's were bound to the host component by using an explicit pipeline graph path from the PCM device to the host comp in topology. This graph route is unnecessary and it results in a duplicate connection shown for the host dapm widget from the PCM device. Instead, pcm's should be bound to the respective host comp when the dai is loaded. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 21 ++++++++++ sound/soc/sof/sof-priv.h | 2 + sound/soc/sof/topology.c | 84 ++++++++++++++++++---------------------- 3 files changed, 60 insertions(+), 47 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 6f62ad714f3560..fad3fd1aea0307 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -89,6 +89,27 @@ struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev, return NULL; } +/* find widget by stream name and direction */ +struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev, + char *pcm_name, int dir) +{ + struct snd_sof_widget *swidget = NULL; + enum snd_soc_dapm_type type; + + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + type = snd_soc_dapm_aif_in; + else + type = snd_soc_dapm_aif_out; + + list_for_each_entry(swidget, &sdev->widget_list, list) { + if (!strcmp(pcm_name, swidget->widget->sname) && + swidget->id == type) + return swidget; + } + + return NULL; +} + struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev, char *name) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 6253bc37f60249..926053e50e0aa8 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -468,6 +468,8 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, size_t reply_bytes); struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev, char *name); +struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev, + char *pcm_name, int dir); struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev, char *name); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index d23c6c346e3af1..aa1c6c8a794e5f 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1068,6 +1068,25 @@ static int sof_widget_load_buffer(struct snd_soc_component *scomp, int index, return ret; } +/* bind PCM ID to host component ID */ +static int spcm_bind(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, + int dir) +{ + struct snd_sof_widget *host_widget; + + host_widget = snd_sof_find_swidget_sname(sdev, + spcm->pcm.caps[dir].name, + dir); + if (!host_widget) { + dev_err(sdev->dev, "can't find host comp to bind pcm\n"); + return -EINVAL; + } + + spcm->stream[dir].comp_id = host_widget->comp_id; + + return 0; +} + /* * PCM Topology */ @@ -1989,6 +2008,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, spcm->sdev = sdev; spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id = COMP_ID_UNASSIGNED; spcm->stream[SNDRV_PCM_STREAM_CAPTURE].comp_id = COMP_ID_UNASSIGNED; + if (pcm) { spcm->pcm = *pcm; dev_dbg(sdev->dev, "tplg: load pcm %s\n", pcm->dai_name); @@ -2013,6 +2033,14 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, return ret; } + /* bind pcm to host comp */ + ret = spcm_bind(sdev, spcm, stream); + if (ret) { + dev_err(sdev->dev, + "error: can't bind pcm to host\n"); + goto free_playback_tables; + } + capture: stream = SNDRV_PCM_STREAM_CAPTURE; @@ -2031,6 +2059,15 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, goto free_playback_tables; } + /* bind pcm to host comp */ + ret = spcm_bind(sdev, spcm, stream); + if (ret) { + dev_err(sdev->dev, + "error: can't bind pcm to host\n"); + snd_dma_free_pages(&spcm->stream[stream].page_table); + goto free_playback_tables; + } + return ret; free_playback_tables: @@ -2610,38 +2647,6 @@ static int sof_link_unload(struct snd_soc_component *scomp, return ret; } -/* bind PCM ID to host component ID */ -static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm, - const char *host) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_sof_widget *host_widget; - - host_widget = snd_sof_find_swidget(sdev, (char *)host); - if (!host_widget) { - dev_err(sdev->dev, "error: can't find host component %s\n", - host); - return -ENODEV; - } - - switch (host_widget->id) { - case snd_soc_dapm_aif_in: - spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id = - host_widget->comp_id; - break; - case snd_soc_dapm_aif_out: - spcm->stream[SNDRV_PCM_STREAM_CAPTURE].comp_id = - host_widget->comp_id; - break; - default: - dev_err(sdev->dev, "error: host is wrong type %d\n", - host_widget->id); - return -EINVAL; - } - - return 0; -} - /* DAI link - used for any driver specific init */ static int sof_route_load(struct snd_soc_component *scomp, int index, struct snd_soc_dapm_route *route) @@ -2650,7 +2655,6 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, struct sof_ipc_pipe_comp_connect *connect; struct snd_sof_widget *source_swidget, *sink_swidget; struct snd_soc_dobj *dobj = &route->dobj; - struct snd_sof_pcm *spcm; struct snd_sof_route *sroute; struct sof_ipc_reply reply; int ret = 0; @@ -2678,13 +2682,6 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, /* source component */ source_swidget = snd_sof_find_swidget(sdev, (char *)route->source); if (!source_swidget) { - /* don't send any routes to DSP that include a driver PCM */ - spcm = snd_sof_find_spcm_name(sdev, (char *)route->source); - if (spcm) { - ret = spcm_bind(scomp, spcm, route->sink); - goto err; - } - dev_err(sdev->dev, "error: source %s not found\n", route->source); ret = -EINVAL; @@ -2696,13 +2693,6 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, /* sink component */ sink_swidget = snd_sof_find_swidget(sdev, (char *)route->sink); if (!sink_swidget) { - /* don't send any routes to DSP that include a driver PCM */ - spcm = snd_sof_find_spcm_name(sdev, (char *)route->sink); - if (spcm) { - ret = spcm_bind(scomp, spcm, route->source); - goto err; - } - dev_err(sdev->dev, "error: sink %s not found\n", route->sink); ret = -EINVAL; From 0a36bd486f2cc17b4c77042d8e84398b87a4f86f Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 25 Feb 2019 15:13:49 -0800 Subject: [PATCH 0927/1995] ASoC: dapm: set power_check callback for widgets that shouldnt be always on Currently, buffers, schedulers, src's, encoders, decoders and effect type dapm widgets remain always on as their power_check method is not set. Setting this callback allows these widgets in the audio path to be powered managed properly. Signed-off-by: Ranjani Sridharan --- sound/soc/soc-dapm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index dad19e903cb92d..de847cde153867 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3651,6 +3651,13 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, case snd_soc_dapm_dac: case snd_soc_dapm_aif_in: case snd_soc_dapm_pga: + case snd_soc_dapm_buffer: + case snd_soc_dapm_scheduler: + case snd_soc_dapm_effect: + case snd_soc_dapm_src: + case snd_soc_dapm_asrc: + case snd_soc_dapm_encoder: + case snd_soc_dapm_decoder: case snd_soc_dapm_out_drv: case snd_soc_dapm_micbias: case snd_soc_dapm_line: From d4557b8f5c7d14a26a8b71d867405d2cc8640734 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 25 Feb 2019 18:57:14 -0800 Subject: [PATCH 0928/1995] ASoC: SOF: remove dai capabilities from dai definitions Dai capabilities/configuration are defined in topology. The capabilities defined in the dai drv for the resp platforms don't seem to be used at all. As an additional benefit, removing these cleans up the DAPM graph. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/bdw.c | 11 -------- sound/soc/sof/intel/byt.c | 27 ------------------- sound/soc/sof/intel/hda-dai.c | 49 ----------------------------------- sound/soc/sof/intel/hsw.c | 11 -------- 4 files changed, 98 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index fbaa170fc5e14a..1340ccf6fba845 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -640,24 +640,13 @@ static int bdw_probe(struct snd_sof_dev *sdev) return ret; } -#define BDW_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE) - /* Broadwell DAIs */ static struct snd_soc_dai_driver bdw_dai[] = { { .name = "ssp0-port", - .playback = SOF_DAI_STREAM("ssp0 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BDW_FORMATS), - .capture = SOF_DAI_STREAM("ssp0 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BDW_FORMATS), }, { .name = "ssp1-port", - .playback = SOF_DAI_STREAM("ssp1 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BDW_FORMATS), - .capture = SOF_DAI_STREAM("ssp1 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BDW_FORMATS), }, }; diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 8baf98764488b2..74a618c095df56 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -485,52 +485,25 @@ static int byt_reset(struct snd_sof_dev *sdev) return 0; } -#define BYT_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE) - /* Baytrail DAIs */ static struct snd_soc_dai_driver byt_dai[] = { { .name = "ssp0-port", - .playback = SOF_DAI_STREAM("ssp0 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), - .capture = SOF_DAI_STREAM("ssp0 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), }, { .name = "ssp1-port", - .playback = SOF_DAI_STREAM("ssp1 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), - .capture = SOF_DAI_STREAM("ssp1 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), }, { .name = "ssp2-port", - .playback = SOF_DAI_STREAM("ssp2 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), - .capture = SOF_DAI_STREAM("ssp2 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), }, { .name = "ssp3-port", - .playback = SOF_DAI_STREAM("ssp3 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), - .capture = SOF_DAI_STREAM("ssp3 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), }, { .name = "ssp4-port", - .playback = SOF_DAI_STREAM("ssp4 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), - .capture = SOF_DAI_STREAM("ssp4 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), }, { .name = "ssp5-port", - .playback = SOF_DAI_STREAM("ssp5 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), - .capture = SOF_DAI_STREAM("ssp5 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, BYT_FORMATS), }, }; diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index f7b9771ec3cd93..5e04aba0c0518b 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -13,9 +13,6 @@ #include "../sof-priv.h" #include "hda.h" -#define SKL_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE) - #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hda_pipe_params { @@ -265,98 +262,52 @@ static const struct snd_soc_dai_ops hda_link_dai_ops = { struct snd_soc_dai_driver skl_dai[] = { { .name = "SSP0 Pin", - .playback = SOF_DAI_STREAM("ssp0 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), - .capture = SOF_DAI_STREAM("ssp0 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, { .name = "SSP1 Pin", - .playback = SOF_DAI_STREAM("ssp1 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), - .capture = SOF_DAI_STREAM("ssp1 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, { .name = "SSP2 Pin", - .playback = SOF_DAI_STREAM("ssp2 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), - .capture = SOF_DAI_STREAM("ssp2 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, { .name = "SSP3 Pin", - .playback = SOF_DAI_STREAM("ssp3 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), - .capture = SOF_DAI_STREAM("ssp3 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, { .name = "SSP4 Pin", - .playback = SOF_DAI_STREAM("ssp4 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), - .capture = SOF_DAI_STREAM("ssp4 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, { .name = "SSP5 Pin", - .playback = SOF_DAI_STREAM("ssp5 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), - .capture = SOF_DAI_STREAM("ssp5 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, { .name = "DMIC01 Pin", - .capture = SOF_DAI_STREAM("DMIC01 Rx", 1, 4, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, { .name = "DMIC16k Pin", - .capture = SOF_DAI_STREAM("DMIC16k Rx", 1, 4, - SNDRV_PCM_RATE_16000, SKL_FORMATS), }, #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) { .name = "iDisp1 Pin", .ops = &hda_link_dai_ops, - .playback = SOF_DAI_STREAM("iDisp1 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, { .name = "iDisp2 Pin", .ops = &hda_link_dai_ops, - .playback = SOF_DAI_STREAM("iDisp2 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, { .name = "iDisp3 Pin", .ops = &hda_link_dai_ops, - .playback = SOF_DAI_STREAM("iDisp3 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, { .name = "Analog CPU DAI", .ops = &hda_link_dai_ops, - .playback = SOF_DAI_STREAM("Analog CPU Playback", 1, 16, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), - .capture = SOF_DAI_STREAM("Analog CPU Capture", 1, 16, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, { .name = "Digital CPU DAI", .ops = &hda_link_dai_ops, - .playback = SOF_DAI_STREAM("Digital CPU Playback", 1, 16, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), - .capture = SOF_DAI_STREAM("Digital CPU Capture", 1, 16, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, { .name = "Alt Analog CPU DAI", .ops = &hda_link_dai_ops, - .playback = SOF_DAI_STREAM("Alt Analog CPU Playback", 1, 16, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), - .capture = SOF_DAI_STREAM("Alt Analog CPU Capture", 1, 16, - SNDRV_PCM_RATE_8000_192000, SKL_FORMATS), }, #endif }; diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 8295b4b02dd41c..09c9ab8e0f67bd 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -640,24 +640,13 @@ static int hsw_probe(struct snd_sof_dev *sdev) return ret; } -#define HSW_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE) - /* Haswell DAIs */ static struct snd_soc_dai_driver hsw_dai[] = { { .name = "ssp0-port", - .playback = SOF_DAI_STREAM("ssp0 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, HSW_FORMATS), - .capture = SOF_DAI_STREAM("ssp0 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, HSW_FORMATS), }, { .name = "ssp1-port", - .playback = SOF_DAI_STREAM("ssp1 Tx", 1, 8, - SNDRV_PCM_RATE_8000_192000, HSW_FORMATS), - .capture = SOF_DAI_STREAM("ssp1 Rx", 1, 8, - SNDRV_PCM_RATE_8000_192000, HSW_FORMATS), }, }; From 65df8efe4b966c9a4717f6f207454512ce3b617c Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 26 Feb 2019 17:31:26 -0800 Subject: [PATCH 0929/1995] ASoC: SOF: validate SSP fsync rate and channel count in topology Validate the fsync rate and channel count for SSP before configuring the DAI. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/topology.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index aa1c6c8a794e5f..cc4a08f2d4f968 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2206,6 +2206,19 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, config->ssp.tdm_slot_width, config->ssp.tdm_slots, config->ssp.mclk_id); + /* validate SSP fsync rate and channel count */ + if (config->ssp.fsync_rate < 8000 || config->ssp.fsync_rate > 192000) { + dev_err(sdev->dev, "error: invalid fsync rate for SSP%d\n", + config->dai_index); + return -EINVAL; + } + + if (config->ssp.tdm_slots < 1 || config->ssp.tdm_slots > 8) { + dev_err(sdev->dev, "error: invalid channel count for SSP%d\n", + config->dai_index); + return -EINVAL; + } + /* send message to DSP */ ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, size, &reply, From e1a24850951acbb3817be9ebce11b5f274d60b9f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 6 Feb 2019 07:30:44 +0100 Subject: [PATCH 0930/1995] ALSA: pcm: Revert capture stream behavior change in blocking mode In the commit 62ba568f7aef ("ALSA: pcm: Return 0 when size < start_threshold in capture"), we changed the behavior of __snd_pcm_lib_xfer() to return immediately with 0 when a capture stream has a high start_threshold. This was intended to be a correction of the behavior consistency and looked harmless, but this was the culprit of the recent breakage reported by syzkaller, which was fixed by the commit e190161f96b8 ("ALSA: pcm: Fix tight loop of OSS capture stream"). At the time for the OSS fix, I didn't touch the behavior for ALSA native API, as assuming that this behavior actually is good. But this turned out to be also broken actually for a similar deployment, e.g. one thread goes to a write loop in blocking mode while another thread controls the start/stop of the stream manually. Overall, the original commit is harmful, and it brings less merit to keep that behavior. Let's revert it. Fixes: 62ba568f7aef ("ALSA: pcm: Return 0 when size < start_threshold in capture") Fixes: e190161f96b8 ("ALSA: pcm: Fix tight loop of OSS capture stream") Cc: Signed-off-by: Takashi Iwai (cherry picked from commit 00a399cad1a063e7665f06b6497a807db20441fd) --- sound/core/pcm_lib.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 6c99fa8ac5fa18..6c0b30391ba99c 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2112,13 +2112,6 @@ int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream, return 0; } -/* allow waiting for a capture stream that hasn't been started */ -#if IS_ENABLED(CONFIG_SND_PCM_OSS) -#define wait_capture_start(substream) ((substream)->oss.oss) -#else -#define wait_capture_start(substream) false -#endif - /* the common loop for read/write data */ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, void *data, bool interleaved, @@ -2184,16 +2177,11 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, snd_pcm_update_hw_ptr(substream); if (!is_playback && - runtime->status->state == SNDRV_PCM_STATE_PREPARED) { - if (size >= runtime->start_threshold) { - err = snd_pcm_start(substream); - if (err < 0) - goto _end_unlock; - } else if (!wait_capture_start(substream)) { - /* nothing to do */ - err = 0; + runtime->status->state == SNDRV_PCM_STATE_PREPARED && + size >= runtime->start_threshold) { + err = snd_pcm_start(substream); + if (err < 0) goto _end_unlock; - } } avail = snd_pcm_avail(substream); From 4acd02457aa779cc46cb46c942c971ade52b33e6 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Thu, 14 Feb 2019 10:13:29 +0000 Subject: [PATCH 0931/1995] ASoC: da7219: Add support for master mode BCLK rate adjustment Previously the driver would default the BCLK periods per WCLK to 64, to cover all possible non-TDM scenarios when the codec was DAI clock master. However some devices require a lower BCLK rate to operate correctly so with this in mind, this commit updates the code to be more dynamic, with BCLK rate now based on SR and word length provided to hw_params(). Signed-off-by: Adam Thomson Signed-off-by: Mark Brown (cherry picked from commit 9fd729542cf4aff3c70b8e5be6f510e6722bc369) --- sound/soc/codecs/da7219.c | 36 ++++++++++++++++++++++++++---------- sound/soc/codecs/da7219.h | 1 + 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index b1df4bb361050e..c599aa9f609b6e 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1376,11 +1376,7 @@ static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } - /* By default 64 BCLKs per WCLK is supported */ - dai_clk_mode |= DA7219_DAI_BCLKS_PER_WCLK_64; - snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, - DA7219_DAI_BCLKS_PER_WCLK_MASK | DA7219_DAI_CLK_POL_MASK | DA7219_DAI_WCLK_POL_MASK, dai_clk_mode); snd_soc_component_update_bits(component, DA7219_DAI_CTRL, DA7219_DAI_FORMAT_MASK, @@ -1399,14 +1395,12 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, __le16 offset; u32 frame_size; - /* No channels enabled so disable TDM, revert to 64-bit frames */ + /* No channels enabled so disable TDM */ if (!tx_mask) { snd_soc_component_update_bits(component, DA7219_DAI_TDM_CTRL, DA7219_DAI_TDM_CH_EN_MASK | DA7219_DAI_TDM_MODE_EN_MASK, 0); - snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, - DA7219_DAI_BCLKS_PER_WCLK_MASK, - DA7219_DAI_BCLKS_PER_WCLK_64); + da7219->tdm_en = false; return 0; } @@ -1458,6 +1452,8 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, (tx_mask << DA7219_DAI_TDM_CH_EN_SHIFT) | DA7219_DAI_TDM_MODE_EN_MASK); + da7219->tdm_en = true; + return 0; } @@ -1466,10 +1462,13 @@ static int da7219_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; - u8 dai_ctrl = 0, fs; + struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); + u8 dai_ctrl = 0, dai_bclks_per_wclk = 0, fs; unsigned int channels; + int word_len = params_width(params); + int frame_size; - switch (params_width(params)) { + switch (word_len) { case 16: dai_ctrl |= DA7219_DAI_WORD_LENGTH_S16_LE; break; @@ -1533,6 +1532,23 @@ static int da7219_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + /* + * If we're master, then we have a limited set of BCLK rates we + * support. For slave mode this isn't the case and the codec can detect + * the BCLK rate automatically. + */ + if (da7219->master && !da7219->tdm_en) { + frame_size = word_len * 2; + if (frame_size <= 32) + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32; + else + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64; + + snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, + DA7219_DAI_BCLKS_PER_WCLK_MASK, + dai_bclks_per_wclk); + } + snd_soc_component_update_bits(component, DA7219_DAI_CTRL, DA7219_DAI_WORD_LENGTH_MASK | DA7219_DAI_CH_NUM_MASK, diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index 366cf46118a005..018819c631fbe4 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -830,6 +830,7 @@ struct da7219_priv { int clk_src; bool master; + bool tdm_en; bool alc_en; bool micbias_on_event; unsigned int mic_pga_delay; From 890809fc9912c358f2083e0c83a09b51101f9819 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Thu, 14 Feb 2019 10:13:30 +0000 Subject: [PATCH 0932/1995] ASoC: da7219: Update TDM usage to be more flexible The previous implementatation was restrictive with regards to BCLK rates for slave mode where the driver would not allow rates the codec couldn't provide itself as clock master. The codec is able to automatically determine and handle whatever rate is provided so this restriction isn't necessary for slave mode. The code was also flawed with regards to setting of the frame offset as using rx_mask to explicitly set the offset has the knock on effect of impacting the min and max channels for the codec, in soc_pcm_hw_params() through the call to soc_pcm_codec_params_fixup(). With this update, the driver now only limits frame size if codec is clock master, and dynamically determines the BCLK offset relating to WCLK using the tx_mask for slot offset along with the slot width provided. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown (cherry picked from commit 541ccdc113f000d51858ee7e135889e4096a3316) --- sound/soc/codecs/da7219.c | 80 +++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index c599aa9f609b6e..121a8190f93edc 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1391,8 +1391,10 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, { struct snd_soc_component *component = dai->component; struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - u8 dai_bclks_per_wclk; - __le16 offset; + unsigned int ch_mask; + u8 dai_bclks_per_wclk, slot_offset; + u16 offset; + __le16 dai_offset; u32 frame_size; /* No channels enabled so disable TDM */ @@ -1405,51 +1407,63 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, } /* Check we have valid slots */ - if (fls(tx_mask) > DA7219_DAI_TDM_MAX_SLOTS) { - dev_err(component->dev, "Invalid number of slots, max = %d\n", + slot_offset = ffs(tx_mask) - 1; + ch_mask = (tx_mask >> slot_offset); + if (fls(ch_mask) > DA7219_DAI_TDM_MAX_SLOTS) { + dev_err(component->dev, + "Invalid number of slots, max = %d\n", DA7219_DAI_TDM_MAX_SLOTS); return -EINVAL; } - /* Check we have a valid offset given */ - if (rx_mask > DA7219_DAI_OFFSET_MAX) { - dev_err(component->dev, "Invalid slot offset, max = %d\n", - DA7219_DAI_OFFSET_MAX); + /* + * Ensure we have a valid offset into the frame, based on slot width + * and slot offset of first slot we're interested in. + */ + offset = slot_offset * slot_width; + if (offset > DA7219_DAI_OFFSET_MAX) { + dev_err(component->dev, "Invalid frame offset %d\n", offset); return -EINVAL; } - /* Calculate & validate frame size based on slot info provided. */ - frame_size = slots * slot_width; - switch (frame_size) { - case 32: - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32; - break; - case 64: - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64; - break; - case 128: - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128; - break; - case 256: - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256; - break; - default: - dev_err(component->dev, "Invalid frame size %d\n", frame_size); - return -EINVAL; - } + /* + * If we're master, calculate & validate frame size based on slot info + * provided as we have a limited set of rates available. + */ + if (da7219->master) { + frame_size = slots * slot_width; + switch (frame_size) { + case 32: + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32; + break; + case 64: + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64; + break; + case 128: + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128; + break; + case 256: + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256; + break; + default: + dev_err(component->dev, "Invalid frame size %d\n", + frame_size); + return -EINVAL; + } - snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, - DA7219_DAI_BCLKS_PER_WCLK_MASK, - dai_bclks_per_wclk); + snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, + DA7219_DAI_BCLKS_PER_WCLK_MASK, + dai_bclks_per_wclk); + } - offset = cpu_to_le16(rx_mask); + dai_offset = cpu_to_le16(offset); regmap_bulk_write(da7219->regmap, DA7219_DAI_OFFSET_LOWER, - &offset, sizeof(offset)); + &dai_offset, sizeof(dai_offset)); snd_soc_component_update_bits(component, DA7219_DAI_TDM_CTRL, DA7219_DAI_TDM_CH_EN_MASK | DA7219_DAI_TDM_MODE_EN_MASK, - (tx_mask << DA7219_DAI_TDM_CH_EN_SHIFT) | + (ch_mask << DA7219_DAI_TDM_CH_EN_SHIFT) | DA7219_DAI_TDM_MODE_EN_MASK); da7219->tdm_en = true; From ac17c1ff60560d4843211150d67c3b77d81c4d14 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 16:45:55 +0100 Subject: [PATCH 0933/1995] ASoC: dmaengine: Remove unused SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME flag There is now no users of this flag so remove it together with related code. The chan_name field of snd_dmaengine_dai_dma_data data structure is not removed as it is still in use by the PXA platform. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown (cherry picked from commit 76d9c68b360f852e784170f10cb431e4713c7d0b) --- include/sound/dmaengine_pcm.h | 4 ---- sound/soc/soc-generic-dmaengine-pcm.c | 21 ++++----------------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 2c4cfaa135a62e..c679f611658022 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -99,10 +99,6 @@ void snd_dmaengine_pcm_set_config_from_dai_data( * playback. */ #define SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX BIT(3) -/* - * The PCM streams have custom channel names specified. - */ -#define SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME BIT(4) /** * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 1b44e363c50c7e..f1ab6285a08510 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -265,7 +265,6 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) struct dmaengine_pcm *pcm = soc_component_to_pcm(component); const struct snd_dmaengine_pcm_config *config = pcm->config; struct device *dev = component->dev; - struct snd_dmaengine_dai_dma_data *dma_data; struct snd_pcm_substream *substream; size_t prealloc_buffer_size; size_t max_buffer_size; @@ -285,19 +284,9 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) if (!substream) continue; - dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - - if (!pcm->chan[i] && - ((pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME) || - (config && config->chan_names[i]))) { - const char *chan_name = dma_data->chan_name; - - if (config && config->chan_names[i]) - chan_name = config->chan_names[i]; - + if (!pcm->chan[i] && config && config->chan_names[i]) pcm->chan[i] = dma_request_slave_channel(dev, - chan_name); - } + config->chan_names[i]); if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) { pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd, @@ -420,10 +409,8 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, const char *name; struct dma_chan *chan; - if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT | - SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) || - (!dev->of_node && !(config && config->dma_dev && - config->dma_dev->of_node))) + if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_DT) || (!dev->of_node && + !(config && config->dma_dev && config->dma_dev->of_node))) return 0; if (config && config->dma_dev) { From 8b87f9dd47b011d4e027e7a9a04e858cc6156056 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Sun, 17 Feb 2019 21:23:47 +0800 Subject: [PATCH 0934/1995] ASoC: topology: free created components in tplg load error Topology resources are no longer needed if any element failed to load. Signed-off-by: Bard liao Signed-off-by: Mark Brown (cherry picked from commit 304017d31df36fb61eb2ed3ebf65fb6870b3c731) --- sound/soc/soc-topology.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index c5638e15a2ddfb..25fca7055464a8 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -2587,6 +2587,7 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp, struct snd_soc_tplg_ops *ops, const struct firmware *fw, u32 id) { struct soc_tplg tplg; + int ret; /* setup parsing context */ memset(&tplg, 0, sizeof(tplg)); @@ -2600,7 +2601,12 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp, tplg.bytes_ext_ops = ops->bytes_ext_ops; tplg.bytes_ext_ops_count = ops->bytes_ext_ops_count; - return soc_tplg_load(&tplg); + ret = soc_tplg_load(&tplg); + /* free the created components if fail to load topology */ + if (ret) + snd_soc_tplg_component_remove(comp, SND_SOC_TPLG_INDEX_ALL); + + return ret; } EXPORT_SYMBOL_GPL(snd_soc_tplg_component_load); From 54df23bd5adfddf156934cbc46f2453c110e2c5d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 19 Feb 2019 15:04:27 +0300 Subject: [PATCH 0935/1995] ASoC: dapm: Potential small memory leak in dapm_cnew_widget() We should free "w" on the error path. Fixes: 199ed3e81c49 ("ASoC: dapm: fix use-after-free issue with dailink sname") Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown (cherry picked from commit a6d9cef30eb11b2de8cbfed9065e3dc5b1f829a8) --- sound/soc/soc-dapm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index dea6fc2353e47b..1ec06ef6d16160 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -332,8 +332,10 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( */ if (_widget->sname) { w->sname = kstrdup_const(_widget->sname, GFP_KERNEL); - if (!w->sname) + if (!w->sname) { + kfree(w); return NULL; + } } return w; } From 801748a46e4221e7c3ff3f103d3bf4de21662fdf Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Wed, 13 Feb 2019 17:08:51 -0600 Subject: [PATCH 0936/1995] ASoC: Intel: Headset button support in broxton machine driver Map the 4 headset buttons to KEY_PAUSE, KEY_VOLUMEUP, KEY_VOLUMEDOWN and KEY_VOICECOMMAND. Acked-by: Pierre-Louis Bossart Signed-off-by: Naveen Manohar Signed-off-by: Yong Zhi Signed-off-by: Mark Brown (cherry picked from commit 9dd9b210f8c6104690ba48a630bbe9af2f32c292) --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index c00925f9da7340..30311b81a5436d 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -193,6 +194,12 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) return ret; } + snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_3, + KEY_VOICECOMMAND); + da7219_aad_jack_det(component, &broxton_headset); snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); From 5bbab076829d0818ec51d3d03b692cc88d257016 Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Wed, 13 Feb 2019 17:08:52 -0600 Subject: [PATCH 0937/1995] ASoC: Intel: Add Geminilake Dialog Maxim machine driver This patch enables support for GeminiLake with the DA7219 codec and MAX98357A amplifier. To avoid duplicating code, the existing machine driver for ApolloLake is reused with only changes in hardware connectivity (SSP2 for DA7219 and SSP1 for MAX98357A). The dailinks are directly modified in this patch. Using a helper would be nicer, but it'll be done in a follow-up step with validation done across multiple machine drivers. Acked-by: Pierre-Louis Bossart Signed-off-by: Yong Zhi Signed-off-by: Naveen Manohar Signed-off-by: Harsha Priya Signed-off-by: Mark Brown (cherry picked from commit c011245a197017f8e9e9d140b658bdb2b702a0c5) --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 79 ++++++++++++++++--- 1 file changed, 67 insertions(+), 12 deletions(-) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 30311b81a5436d..407b0cfc516711 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -104,7 +105,7 @@ static const struct snd_soc_dapm_widget broxton_widgets[] = { 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 audio_map[] = { /* HP jack connectors - unknown if we have jack detection */ {"Headphone Jack", NULL, "HPL"}, {"Headphone Jack", NULL, "HPR"}, @@ -119,15 +120,6 @@ static const struct snd_soc_dapm_route broxton_map[] = { {"DMic", NULL, "SoC DMIC"}, /* CODEC BE connections */ - {"HiFi Playback", NULL, "ssp5 Tx"}, - {"ssp5 Tx", NULL, "codec0_out"}, - - {"Playback", NULL, "ssp1 Tx"}, - {"ssp1 Tx", NULL, "codec1_out"}, - - {"codec0_in", NULL, "ssp1 Rx"}, - {"ssp1 Rx", NULL, "Capture"}, - {"HDMI1", NULL, "hif5-0 Output"}, {"HDMI2", NULL, "hif6-0 Output"}, {"HDMI2", NULL, "hif7-0 Output"}, @@ -147,6 +139,28 @@ static const struct snd_soc_dapm_route broxton_map[] = { { "Headset Mic", NULL, "Platform Clock" }, }; +static const struct snd_soc_dapm_route broxton_map[] = { + {"HiFi Playback", NULL, "ssp5 Tx"}, + {"ssp5 Tx", NULL, "codec0_out"}, + + {"Playback", NULL, "ssp1 Tx"}, + {"ssp1 Tx", NULL, "codec1_out"}, + + {"codec0_in", NULL, "ssp1 Rx"}, + {"ssp1 Rx", NULL, "Capture"}, +}; + +static const struct snd_soc_dapm_route gemini_map[] = { + {"HiFi Playback", NULL, "ssp1 Tx"}, + {"ssp1 Tx", NULL, "codec0_out"}, + + {"Playback", NULL, "ssp2 Tx"}, + {"ssp2 Tx", NULL, "codec1_out"}, + + {"codec0_in", NULL, "ssp2 Rx"}, + {"ssp2 Rx", NULL, "Capture"}, +}; + static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -539,6 +553,11 @@ static struct snd_soc_dai_link broxton_dais[] = { }, }; +static const struct x86_cpu_id glk_ids[] = { + { X86_VENDOR_INTEL, 6, 0x7A }, /* Geminilake CPU_ID */ + {} +}; + #define NAME_SIZE 32 static int bxt_card_late_probe(struct snd_soc_card *card) { @@ -548,6 +567,13 @@ static int bxt_card_late_probe(struct snd_soc_card *card) int err, i = 0; char jack_name[NAME_SIZE]; + if (x86_match_cpu(glk_ids)) + snd_soc_dapm_add_routes(&card->dapm, gemini_map, + ARRAY_SIZE(gemini_map)); + else + snd_soc_dapm_add_routes(&card->dapm, broxton_map, + ARRAY_SIZE(broxton_map)); + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { component = pcm->codec_dai->component; snprintf(jack_name, sizeof(jack_name), @@ -583,8 +609,8 @@ static struct snd_soc_card broxton_audio_card = { .num_controls = ARRAY_SIZE(broxton_controls), .dapm_widgets = broxton_widgets, .num_dapm_widgets = ARRAY_SIZE(broxton_widgets), - .dapm_routes = broxton_map, - .num_dapm_routes = ARRAY_SIZE(broxton_map), + .dapm_routes = audio_map, + .num_dapm_routes = ARRAY_SIZE(audio_map), .fully_routed = true, .late_probe = bxt_card_late_probe, }; @@ -604,6 +630,26 @@ static int broxton_audio_probe(struct platform_device *pdev) broxton_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&broxton_audio_card, ctx); + if (x86_match_cpu(glk_ids)) { + unsigned int i; + + broxton_audio_card.name = "glkda7219max"; + /* Fixup the SSP entries for geminilake */ + for (i = 0; i < ARRAY_SIZE(broxton_dais); i++) { + /* MAXIM_CODEC is connected to SSP1. */ + if (!strcmp(broxton_dais[i].codec_dai_name, + BXT_MAXIM_CODEC_DAI)) { + broxton_dais[i].name = "SSP1-Codec"; + broxton_dais[i].cpu_dai_name = "SSP1 Pin"; + } + /* DIALOG_CODE is connected to SSP2 */ + else if (!strcmp(broxton_dais[i].codec_dai_name, + BXT_DIALOG_CODEC_DAI)) { + broxton_dais[i].name = "SSP2-Codec"; + broxton_dais[i].cpu_dai_name = "SSP2 Pin"; + } + } + } /* override plaform name, if required */ mach = (&pdev->dev)->platform_data; @@ -617,12 +663,19 @@ static int broxton_audio_probe(struct platform_device *pdev) return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card); } +static const struct platform_device_id bxt_board_ids[] = { + { .name = "bxt_da7219_max98357a" }, + { .name = "glk_da7219_max98357a" }, + { } +}; + static struct platform_driver broxton_audio = { .probe = broxton_audio_probe, .driver = { .name = "bxt_da7219_max98357a", .pm = &snd_soc_pm_ops, }, + .id_table = bxt_board_ids, }; module_platform_driver(broxton_audio) @@ -632,5 +685,7 @@ MODULE_AUTHOR("Sathyanarayana Nujella "); MODULE_AUTHOR("Rohit Ainapure "); MODULE_AUTHOR("Harsha Priya "); MODULE_AUTHOR("Conrad Cooke "); +MODULE_AUTHOR("Naveen Manohar "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:bxt_da7219_max98357a"); +MODULE_ALIAS("platform:glk_da7219_max98357a"); From 8387b12c798baa26b8634fdb00fb3581e45e6e9f Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Wed, 13 Feb 2019 17:08:53 -0600 Subject: [PATCH 0938/1995] ASoC: Intel: glk: Add DAI links for Multi-Playback Add FE DAI link to support parallel playback on 2 ports simultaneously. Acked-by: Pierre-Louis Bossart Signed-off-by: Naveen Manohar Signed-off-by: Yong Zhi Signed-off-by: Mark Brown (cherry picked from commit bc3523a3acb3ba311d5d9939901ff2b7f8833e44) --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 407b0cfc516711..5cadb7f654f3a0 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -51,6 +51,7 @@ struct bxt_card_private { enum { BXT_DPCM_AUDIO_PB = 0, BXT_DPCM_AUDIO_CP, + BXT_DPCM_AUDIO_HS_PB, BXT_DPCM_AUDIO_REF_CP, BXT_DPCM_AUDIO_DMIC_CP, BXT_DPCM_AUDIO_HDMI1_PB, @@ -405,6 +406,20 @@ static struct snd_soc_dai_link broxton_dais[] = { .dpcm_capture = 1, .ops = &broxton_da7219_fe_ops, }, + [BXT_DPCM_AUDIO_HS_PB] = { + .name = "Bxt Audio Headset Playback", + .stream_name = "Headset Playback", + .cpu_dai_name = "System Pin2", + .platform_name = "0000:00:0e.0", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &broxton_da7219_fe_ops, + }, [BXT_DPCM_AUDIO_REF_CP] = { .name = "Bxt Audio Reference cap", From 2440818ea32e2bc17c51a92abf97e9ac3ee54415 Mon Sep 17 00:00:00 2001 From: Jenny TC Date: Mon, 25 Feb 2019 22:17:31 +0530 Subject: [PATCH 0939/1995] ASoC: Intel: Boards: Add Maxim98373 support This patch enables the reuse of kbl_da7219_max98927 machine driver to support max98373. The same machine driver is modified for cases where one amplifier is swapped out with another. Most of the changes are about renaming the codec and codec_dai names, with minor differences due to support for 24 bits in one case and 16 in the other. Signed-off-by: Jenny TC Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 716d53cc7837aec7f439ce2a20fc2597a89dae53) --- sound/soc/intel/boards/Kconfig | 1 + sound/soc/intel/boards/kbl_da7219_max98927.c | 203 ++++++++++++++++-- .../intel/common/soc-acpi-intel-kbl-match.c | 19 ++ 3 files changed, 200 insertions(+), 23 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 0a7e40d0639572..12d6b73e9531d7 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -293,6 +293,7 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_DA7219 select SND_SOC_MAX98927 + select SND_SOC_MAX98373 select SND_SOC_DMIC select SND_SOC_HDAC_HDMI help diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 6dd5c69671b3f6..2768a572d0651b 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -2,7 +2,7 @@ // Copyright(c) 2018 Intel Corporation. /* - * Intel Kabylake I2S Machine Driver with MAX98927 & DA7219 Codecs + * Intel Kabylake I2S Machine Driver with MAX98927, MAX98373 & DA7219 Codecs * * Modified from: * Intel Kabylake I2S Machine driver supporting MAX98927 and @@ -24,8 +24,14 @@ #define KBL_DIALOG_CODEC_DAI "da7219-hifi" #define MAX98927_CODEC_DAI "max98927-aif1" -#define MAXIM_DEV0_NAME "i2c-MX98927:00" -#define MAXIM_DEV1_NAME "i2c-MX98927:01" +#define MAX98927_DEV0_NAME "i2c-MX98927:00" +#define MAX98927_DEV1_NAME "i2c-MX98927:01" + +#define MAX98373_CODEC_DAI "max98373-aif1" +#define MAX98373_DEV0_NAME "i2c-MX98373:00" +#define MAX98373_DEV1_NAME "i2c-MX98373:01" + + #define DUAL_CHANNEL 2 #define QUAD_CHANNEL 4 #define NAME_SIZE 32 @@ -176,20 +182,38 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, for (j = 0; j < runtime->num_codecs; j++) { struct snd_soc_dai *codec_dai = runtime->codec_dais[j]; - if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { + if (!strcmp(codec_dai->component->name, MAX98927_DEV0_NAME)) { ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); if (ret < 0) { dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret); return ret; } } - if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { + if (!strcmp(codec_dai->component->name, MAX98927_DEV1_NAME)) { ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); if (ret < 0) { dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret); return ret; } } + if (!strcmp(codec_dai->component->name, MAX98373_DEV0_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + 0x03, 3, 8, 24); + if (ret < 0) { + dev_err(runtime->dev, + "DEV0 TDM slot err:%d\n", ret); + return ret; + } + } + if (!strcmp(codec_dai->component->name, MAX98373_DEV1_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + 0x0C, 3, 8, 24); + if (ret < 0) { + dev_err(runtime->dev, + "DEV0 TDM slot err:%d\n", ret); + return ret; + } + } } return 0; @@ -212,6 +236,25 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai_link *fe_dai_link = dpcm->fe->dai_link; struct snd_soc_dai_link *be_dai_link = dpcm->be->dai_link; + /* + * Topology for kblda7219m98373 & kblmax98373 supports only S24_LE, + * where as kblda7219m98927 & kblmax98927 supports S16_LE by default. + * Skipping the port wise FE and BE configuration for kblda7219m98373 & + * kblmax98373 as the topology (FE & BE) supports S24_LE only. + */ + + if (!strcmp(rtd->card->name, "kblda7219m98373") || + !strcmp(rtd->card->name, "kblmax98373")) { + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = DUAL_CHANNEL; + + /* set SSP to 24 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + return 0; + } + /* * The ADSP will convert the FE rate to 48k, stereo, 24 bit */ @@ -352,20 +395,31 @@ static struct snd_pcm_hw_constraint_list constraints_channels_quad = { static int kbl_fe_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *soc_rt = substream->private_data; /* * On this platform for PCM device we support, * 48Khz * stereo - * 16 bit audio */ runtime->hw.channels_max = DUAL_CHANNEL; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + /* + * Setup S24_LE (32 bit container and 24 bit valid data) for + * kblda7219m98373 & kblmax98373. For kblda7219m98927 & + * kblmax98927 keeping it as 16/16 due to topology FW dependency. + */ + if (!strcmp(soc_rt->card->name, "kblda7219m98373") || + !strcmp(soc_rt->card->name, "kblmax98373")) { + runtime->hw.formats = SNDRV_PCM_FMTBIT_S24_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); + + } else { + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + } snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); @@ -398,11 +452,23 @@ static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, static int kabylake_dmic_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *soc_rt = substream->private_data; runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &constraints_channels_quad); + /* + * Topology for kblda7219m98373 & kblmax98373 supports only S24_LE. + * The DMIC also configured for S24_LE. Forcing the DMIC format to + * S24_LE due to the topology FW dependency. + */ + if (!strcmp(soc_rt->card->name, "kblda7219m98373") || + !strcmp(soc_rt->card->name, "kblmax98373")) { + runtime->hw.formats = SNDRV_PCM_FMTBIT_S24_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); + } + return snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } @@ -448,29 +514,55 @@ static struct snd_soc_ops skylake_refcap_ops = { static struct snd_soc_codec_conf max98927_codec_conf[] = { { - .dev_name = MAXIM_DEV0_NAME, + .dev_name = MAX98927_DEV0_NAME, + .name_prefix = "Right", + }, + + { + .dev_name = MAX98927_DEV1_NAME, + .name_prefix = "Left", + }, +}; + +static struct snd_soc_codec_conf max98373_codec_conf[] = { + + { + .dev_name = MAX98373_DEV0_NAME, .name_prefix = "Right", }, { - .dev_name = MAXIM_DEV1_NAME, + .dev_name = MAX98373_DEV1_NAME, .name_prefix = "Left", }, }; -static struct snd_soc_dai_link_component ssp0_codec_components[] = { +static struct snd_soc_dai_link_component max98927_ssp0_codec_components[] = { { /* Left */ - .name = MAXIM_DEV0_NAME, + .name = MAX98927_DEV0_NAME, .dai_name = MAX98927_CODEC_DAI, }, { /* For Right */ - .name = MAXIM_DEV1_NAME, + .name = MAX98927_DEV1_NAME, .dai_name = MAX98927_CODEC_DAI, }, }; +static struct snd_soc_dai_link_component max98373_ssp0_codec_components[] = { + { /* Left */ + .name = MAX98373_DEV0_NAME, + .dai_name = MAX98373_CODEC_DAI, + }, + + { /* For Right */ + .name = MAX98373_DEV1_NAME, + .dai_name = MAX98373_CODEC_DAI, + }, + +}; + /* kabylake digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link kabylake_dais[] = { /* Front End DAI links */ @@ -607,8 +699,8 @@ static struct snd_soc_dai_link kabylake_dais[] = { .cpu_dai_name = "SSP0 Pin", .platform_name = "0000:00:1f.3", .no_pcm = 1, - .codecs = ssp0_codec_components, - .num_codecs = ARRAY_SIZE(ssp0_codec_components), + .codecs = max98927_ssp0_codec_components, + .num_codecs = ARRAY_SIZE(max98927_ssp0_codec_components), .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, @@ -683,7 +775,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { }; /* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_max98927_dais[] = { +static struct snd_soc_dai_link kabylake_max98_927_373_dais[] = { /* Front End DAI links */ [KBL_DPCM_AUDIO_PB] = { .name = "Kbl Audio Port", @@ -802,8 +894,8 @@ static struct snd_soc_dai_link kabylake_max98927_dais[] = { .cpu_dai_name = "SSP0 Pin", .platform_name = "0000:00:1f.3", .no_pcm = 1, - .codecs = ssp0_codec_components, - .num_codecs = ARRAY_SIZE(ssp0_codec_components), + .codecs = max98927_ssp0_codec_components, + .num_codecs = ARRAY_SIZE(max98927_ssp0_codec_components), .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, @@ -917,8 +1009,8 @@ static struct snd_soc_card kbl_audio_card_da7219_m98927 = { static struct snd_soc_card kbl_audio_card_max98927 = { .name = "kblmax98927", .owner = THIS_MODULE, - .dai_link = kabylake_max98927_dais, - .num_links = ARRAY_SIZE(kabylake_max98927_dais), + .dai_link = kabylake_max98_927_373_dais, + .num_links = ARRAY_SIZE(kabylake_max98_927_373_dais), .controls = kabylake_controls, .num_controls = ARRAY_SIZE(kabylake_controls), .dapm_widgets = kabylake_widgets, @@ -931,9 +1023,46 @@ static struct snd_soc_card kbl_audio_card_max98927 = { .late_probe = kabylake_card_late_probe, }; +static struct snd_soc_card kbl_audio_card_da7219_m98373 = { + .name = "kblda7219m98373", + .owner = THIS_MODULE, + .dai_link = kabylake_dais, + .num_links = ARRAY_SIZE(kabylake_dais), + .controls = kabylake_controls, + .num_controls = ARRAY_SIZE(kabylake_controls), + .dapm_widgets = kabylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), + .dapm_routes = kabylake_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_map), + .codec_conf = max98373_codec_conf, + .num_configs = ARRAY_SIZE(max98373_codec_conf), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + +static struct snd_soc_card kbl_audio_card_max98373 = { + .name = "kblmax98373", + .owner = THIS_MODULE, + .dai_link = kabylake_max98_927_373_dais, + .num_links = ARRAY_SIZE(kabylake_max98_927_373_dais), + .controls = kabylake_controls, + .num_controls = ARRAY_SIZE(kabylake_controls), + .dapm_widgets = kabylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), + .dapm_routes = kabylake_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_map), + .codec_conf = max98373_codec_conf, + .num_configs = ARRAY_SIZE(max98373_codec_conf), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + static int kabylake_audio_probe(struct platform_device *pdev) { struct kbl_codec_private *ctx; + struct snd_soc_dai_link *kbl_dai_link; + struct snd_soc_dai_link_component **codecs; + int i = 0; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -944,6 +1073,22 @@ static int kabylake_audio_probe(struct platform_device *pdev) kabylake_audio_card = (struct snd_soc_card *)pdev->id_entry->driver_data; + kbl_dai_link = kabylake_audio_card->dai_link; + + /* Update codecs for SSP0 with max98373 codec info */ + if (!strcmp(pdev->name, "kbl_da7219_max98373") || + (!strcmp(pdev->name, "kbl_max98373"))) { + for (i = 0; i < kabylake_audio_card->num_links; ++i) { + if (strcmp(kbl_dai_link[i].name, "SSP0-Codec")) + continue; + + codecs = &(kbl_dai_link[i].codecs); + *codecs = max98373_ssp0_codec_components; + kbl_dai_link[i].num_codecs = + ARRAY_SIZE(max98373_ssp0_codec_components); + break; + } + } kabylake_audio_card->dev = &pdev->dev; snd_soc_card_set_drvdata(kabylake_audio_card, ctx); @@ -961,13 +1106,23 @@ static const struct platform_device_id kbl_board_ids[] = { .driver_data = (kernel_ulong_t)&kbl_audio_card_max98927, }, + { + .name = "kbl_da7219_max98373", + .driver_data = + (kernel_ulong_t)&kbl_audio_card_da7219_m98373, + }, + { + .name = "kbl_max98373", + .driver_data = + (kernel_ulong_t)&kbl_audio_card_max98373, + }, { } }; static struct platform_driver kabylake_audio = { .probe = kabylake_audio_probe, .driver = { - .name = "kbl_da7219_max98927", + .name = "kbl_da7219_max98_927_373", .pm = &snd_soc_pm_ops, }, .id_table = kbl_board_ids, @@ -976,8 +1131,10 @@ static struct platform_driver kabylake_audio = { module_platform_driver(kabylake_audio) /* Module information */ -MODULE_DESCRIPTION("Audio KabyLake Machine driver for MAX98927 & DA7219"); +MODULE_DESCRIPTION("Audio KabyLake Machine driver for MAX98927/MAX98373 & DA7219"); MODULE_AUTHOR("Mac Chiang "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:kbl_da7219_max98927"); MODULE_ALIAS("platform:kbl_max98927"); +MODULE_ALIAS("platform:kbl_da7219_max98373"); +MODULE_ALIAS("platform:kbl_max98373"); diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c index e6fa6f470526dc..4b331058e8070a 100644 --- a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c @@ -37,6 +37,11 @@ static struct snd_soc_acpi_codecs kbl_7219_98927_codecs = { .codecs = {"MX98927"} }; +static struct snd_soc_acpi_codecs kbl_7219_98373_codecs = { + .num_codecs = 1, + .codecs = {"MX98373"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { { .id = "INT343A", @@ -106,6 +111,20 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .drv_name = "kbl_rt5660", .fw_filename = "intel/dsp_fw_kbl.bin", }, + { + .id = "DLGS7219", + .drv_name = "kbl_da7219_max98373", + .fw_filename = "intel/dsp_fw_kbl.bin", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &kbl_7219_98373_codecs, + .pdata = &skl_dmic_data + }, + { + .id = "MX98373", + .drv_name = "kbl_max98373", + .fw_filename = "intel/dsp_fw_kbl.bin", + .pdata = &skl_dmic_data + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines); From d0a758be34e00798f82589e5106509b76f88baa1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 8 Feb 2019 08:41:53 +0100 Subject: [PATCH 0940/1995] regulator: fix device unlinking Device links are refcounted, device_link_remove() has to be called as many times as device_link_add(). Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mark Brown (cherry picked from commit 82874ba4c6455ca8a90a8fe59834baa4cd4a1e50) --- drivers/regulator/core.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 2c66b528aedec0..342102e8bc213f 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1837,15 +1837,7 @@ static void _regulator_put(struct regulator *regulator) debugfs_remove_recursive(regulator->debugfs); if (regulator->dev) { - int count = 0; - struct regulator *r; - - list_for_each_entry(r, &rdev->consumer_list, list) - if (r->dev == regulator->dev) - count++; - - if (count == 1) - device_link_remove(regulator->dev, &rdev->dev); + device_link_remove(regulator->dev, &rdev->dev); /* remove any sysfs entries */ sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); From 8b3669a1bbc71d477a8eb170eddbee1a8aa5a10a Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Thu, 28 Feb 2019 13:48:55 +0800 Subject: [PATCH 0941/1995] ASoc:SOF:intel:skl:fix cldma bdl buffer size remove the size check since we only use one CLDMA buffer, and this also fix the cppcheck warning. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-loader-skl.c | 51 +++++++++++++--------------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 690c90efff1313..6f893c987ff0ff 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -106,30 +106,25 @@ (((x) << HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & \ HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK) -static int cl_skl_cldma_setup_bdle(struct snd_sof_dev *sdev, - struct snd_dma_buffer *dmab_data, - __le32 **bdlp, int size, int with_ioc) +static void cl_skl_cldma_setup_bdle(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab_data, + __le32 **bdlp) { + const unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; + phys_addr_t addr = virt_to_phys(dmab_data->area); __le32 *bdl = *bdlp; - int frags = 0; - while (size > 0) { - phys_addr_t addr = virt_to_phys(dmab_data->area + - (frags * size)); - - bdl[0] = cpu_to_le32(lower_32_bits(addr)); - bdl[1] = cpu_to_le32(upper_32_bits(addr)); - - bdl[2] = cpu_to_le32(size); - - size -= size; - bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01); + /* + * The CLDMA using a single physically-contiguous memory + * to transfer the data to DSP, so need an interrupt at the + * end of every transfer. + */ + bdl[0] = cpu_to_le32(lower_32_bits(addr)); + bdl[1] = cpu_to_le32(upper_32_bits(addr)); - bdl += 4; - frags++; - } + bdl[2] = cpu_to_le32(bufsize); - return frags; + bdl[3] = cpu_to_le32(0x01); } static void cl_skl_cldma_stream_run(struct snd_sof_dev *sdev, bool enable) @@ -233,10 +228,11 @@ static void cl_skl_cldma_cleanup_spb(struct snd_sof_dev *sdev) } static void cl_skl_cldma_setup_controller(struct snd_sof_dev *sdev, - struct snd_dma_buffer *dmab_bdl, - unsigned int max_size, u32 count) + struct snd_dma_buffer *dmab_bdl) { + const unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; int sd_offset = SOF_HDA_ADSP_LOADER_BASE; + /* Clear the stream first and then set it. */ cl_skl_cldma_stream_clear(sdev); @@ -250,10 +246,10 @@ static void cl_skl_cldma_setup_controller(struct snd_sof_dev *sdev, /* Set the Cyclic Buffer Length. */ snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, max_size); + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, bufsize); /* Set the Last Valid Index. */ snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, count - 1); + sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, 0); /* * Set the Interrupt On Completion, FIFO Error Interrupt, @@ -271,10 +267,9 @@ static void cl_skl_cldma_setup_controller(struct snd_sof_dev *sdev, static int cl_stream_prepare_skl(struct snd_sof_dev *sdev) { struct pci_dev *pci = to_pci_dev(sdev->dev); - int frags = 0; - int ret = 0; + int ret; __le32 *bdl; - unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; + const unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, bufsize, &sdev->dmab); @@ -293,8 +288,8 @@ static int cl_stream_prepare_skl(struct snd_sof_dev *sdev) } bdl = (__le32 *)sdev->dmab_bdl.area; - frags = cl_skl_cldma_setup_bdle(sdev, &sdev->dmab, &bdl, bufsize, 1); - cl_skl_cldma_setup_controller(sdev, &sdev->dmab_bdl, bufsize, frags); + cl_skl_cldma_setup_bdle(sdev, &sdev->dmab, &bdl); + cl_skl_cldma_setup_controller(sdev, &sdev->dmab_bdl); return ret; } From 96a2434fb38b7fa16c0fb954e430c76eb6765226 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Wed, 13 Feb 2019 19:36:43 +0800 Subject: [PATCH 0942/1995] ASoC:SOF:intel:skl:remove wait interrupt error check remove the wait interrupt fail check since using pollmode, this also fix the code cppcheck warning Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-loader-skl.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 6f893c987ff0ff..6524b74e5e709b 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -397,7 +397,6 @@ static int cl_skl_cldma_copy_to_buf(struct snd_sof_dev *sdev, const void *bin, u32 total_size, u32 bufsize) { - int ret = 0; unsigned int bytes_left = total_size; const void *curr_pos = bin; @@ -414,13 +413,6 @@ cl_skl_cldma_copy_to_buf(struct snd_sof_dev *sdev, const void *bin, cl_skl_cldma_fill_buffer(sdev, bufsize, bufsize, curr_pos, true, true); - if (ret < 0) { - dev_err(sdev->dev, "error: fw failed to load. 0x%x bytes remaining\n", - bytes_left); - cl_skl_cldma_stream_run(sdev, false); - return ret; - } - bytes_left -= bufsize; curr_pos += bufsize; } else { From cf5978aec2476d89bdd8b50574ba93bf3b86b426 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Wed, 13 Feb 2019 19:42:54 +0800 Subject: [PATCH 0943/1995] ASoC:SOF:intel:skl:fix cppcheck warning replace void* with u8* to fix the cppcheck warning, simplify cl_skl_cldma_fill_buffer parameters by remove bufsize, since it was tested in cl_skl_cldma_copy_to_buf. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-loader-skl.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 6524b74e5e709b..6deeafac9c64cc 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -371,14 +371,11 @@ static int cl_dsp_init_skl(struct snd_sof_dev *sdev) } static void cl_skl_cldma_fill_buffer(struct snd_sof_dev *sdev, - unsigned int bufsize, - unsigned int copysize, + unsigned int size, const void *curr_pos, bool intr_enable, bool trigger) { - /* 1. copy the image into the buffer with the maximum buffer size. */ - unsigned int size = (bufsize == copysize) ? bufsize : copysize; - + /* 1. copy the image into the buffer. */ memcpy(sdev->dmab.area, curr_pos, size); /* 2. Set the interrupt. */ @@ -398,7 +395,7 @@ cl_skl_cldma_copy_to_buf(struct snd_sof_dev *sdev, const void *bin, u32 total_size, u32 bufsize) { unsigned int bytes_left = total_size; - const void *curr_pos = bin; + const u8 *curr_pos = (u8 *)bin; if (total_size <= 0) return -EINVAL; @@ -410,7 +407,7 @@ cl_skl_cldma_copy_to_buf(struct snd_sof_dev *sdev, const void *bin, dev_dbg(sdev->dev, "cldma copy 0x%x bytes\n", bufsize); - cl_skl_cldma_fill_buffer(sdev, bufsize, bufsize, + cl_skl_cldma_fill_buffer(sdev, bufsize, curr_pos, true, true); bytes_left -= bufsize; @@ -421,7 +418,7 @@ cl_skl_cldma_copy_to_buf(struct snd_sof_dev *sdev, const void *bin, bytes_left); cl_skl_cldma_set_intr(sdev, false); - cl_skl_cldma_fill_buffer(sdev, bufsize, bytes_left, + cl_skl_cldma_fill_buffer(sdev, bytes_left, curr_pos, false, false); return 0; } From 7b12f06406c9a0f89417b157b829f8eb4ba04ca0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Mar 2019 12:33:45 -0600 Subject: [PATCH 0944/1995] ASoC: SOF: Intel: make HDA link and NOCODEC mutually incompatible If the HDAudio link is configured but not used, there are multiple issues with syspend/resume. Just make the two options incompatible and move on. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 50cb06b160a87d..267b5606c6baa1 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -215,6 +215,7 @@ if SND_SOC_SOF_HDA_COMMON config SND_SOC_SOF_HDA_LINK bool "SOF support for HDA Links(HDA/HDMI)" + depends on SND_SOC_SOF_NOCODEC=n select SND_SOC_SOF_PROBE_WORK_QUEUE help This adds support for HDA links(HDA/HDMI) with Sound Open Firmware From 9a5e2e4ff4d12e7988db52473ca86ccbafb352cb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Mar 2019 12:35:29 -0600 Subject: [PATCH 0945/1995] ASoC: SOF: Intel: remove support for NOCODEC when HDA link is enabled since we've made the two options mutually incompatible in Kconfig, there is no point in maintaining the code that falls back to nocodec if there is no external HDAudio codec detected. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 19d2c18070fa19..a57374be06e6ff 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -297,35 +297,27 @@ static int hda_init_caps(struct snd_sof_dev *sdev) * If no machine driver is found, then: * * hda machine driver is used if : - * 1. there are HDMI codec and one external HDAudio codec - * 2. only HDMI codec and NOCODEC is not enabled - * - * nocodec machine driver would be used if: - * 1. only HDMI codec and but NOCODEC is enabled - * 2. there is no codec found + * 1. there is one HDMI codec and one external HDAudio codec + * 2. only HDMI codec */ if (!pdata->machine && codec_num <= 2 && HDA_IDISP_CODEC(bus->codec_mask)) { - if (codec_num == 2 || - !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) { - hda_mach = snd_soc_acpi_intel_hda_machines; - pdata->machine = hda_mach; + hda_mach = snd_soc_acpi_intel_hda_machines; + pdata->machine = hda_mach; - /* topology: use the info from hda_machines */ - pdata->tplg_filename = - hda_mach->sof_tplg_filename; + /* topology: use the info from hda_machines */ + pdata->tplg_filename = + hda_mach->sof_tplg_filename; - /* firmware: pick the first in machine list */ - mach = pdata->desc->machines; - pdata->fw_filename = mach->sof_fw_filename; + /* firmware: pick the first in machine list */ + mach = pdata->desc->machines; + pdata->fw_filename = mach->sof_fw_filename; - dev_info(bus->dev, "using HDA machine driver %s now\n", - hda_mach->drv_name); - } + dev_info(bus->dev, "using HDA machine driver %s now\n", + hda_mach->drv_name); /* fixup topology file for HDMI only platforms */ - if (codec_num == 1 && - !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) { + if (codec_num == 1) { /* use local variable for readability */ tplg_filename = pdata->tplg_filename; tplg_filename = fixup_tplg_name(sdev, tplg_filename); From 9f27bde6fe93be17999e07414f7af238d8a6039e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:02 -0600 Subject: [PATCH 0946/1995] ASoC: Intel: Skylake: remove useless cast Detected with Coccinelle sound/soc/intel/skylake/skl-topology.c:3106:16-20: WARNING: casting value returned by memory allocation function to (char *) is useless. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 431b67c27c57bc6a752482727c87f6dda988aae5) --- sound/soc/intel/skylake/skl-topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index cf8848b779dcc2..389f1862bc4391 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -3103,7 +3103,7 @@ static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, ac->size = dfw_ac->max; if (ac->max) { - ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL); + ac->params = devm_kzalloc(dev, ac->max, GFP_KERNEL); if (!ac->params) return -ENOMEM; From 56098a182c2ee5bc04e3ccdc0fde540f7160e517 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:03 -0600 Subject: [PATCH 0947/1995] ASoC: Intel: Skylake: simplify boolean tests Detected with Coccinelle skl-messages.c:419:5-32: WARNING: Comparison to bool skl-pcm.c:1426:6-33: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit d8747d30aa7f9e7dc6123709d7ca1d8429d648b0) --- sound/soc/intel/skylake/skl-messages.c | 2 +- sound/soc/intel/skylake/skl-pcm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index b0e6fb93eaf83c..28c4806b196a2f 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -416,7 +416,7 @@ int skl_resume_dsp(struct skl *skl) snd_hdac_ext_bus_ppcap_int_enable(bus, true); /* check if DSP 1st boot is done */ - if (skl->skl_sst->is_first_boot == true) + if (skl->skl_sst->is_first_boot) return 0; /* diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 557f80c0bfe530..8e589d698c588e 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1423,7 +1423,7 @@ static int skl_platform_soc_probe(struct snd_soc_component *component) if (!ops) return -EIO; - if (skl->skl_sst->is_first_boot == false) { + if (!skl->skl_sst->is_first_boot) { dev_err(component->dev, "DSP reports first boot done!!!\n"); return -EIO; } From 213854203458b5141b476b5b872f0e845a9412b3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:04 -0600 Subject: [PATCH 0948/1995] ASoC: Intel: Haswell: remove unneeded semicolon Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 6c5414589721d696fe300dc0b8720e0368e3907a) --- sound/soc/intel/haswell/sst-haswell-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index fe2c826e710c73..fb9b8608eb3b2b 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c @@ -544,7 +544,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, dev_err(rtd->dev, "error: invalid DAI ID %d\n", rtd->cpu_dai->id); return -EINVAL; - }; + } ret = sst_hsw_stream_format(hsw, pcm_data->stream, path_id, stream_type, SST_HSW_STREAM_FORMAT_PCM_FORMAT); From b4dd0a933a9c0c71b5b59f96b4ffc36f168a87a7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:05 -0600 Subject: [PATCH 0949/1995] ASoC: Intel: Haswell: assign booleans to true/false Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit bf88b3c3c277c8138d688a0fc3199b57fecfaf56) --- sound/soc/intel/haswell/sst-haswell-ipc.c | 2 +- sound/soc/intel/haswell/sst-haswell-pcm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index d33bdaf92c57c8..31fcdf12c67def 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -1216,7 +1216,7 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream) return ret; } - stream->commited = 1; + stream->commited = true; trace_hsw_stream_alloc_reply(stream); return 0; diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index fb9b8608eb3b2b..2debcc2ed99a1f 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c @@ -861,7 +861,7 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream) dev_dbg(rtd->dev, "error: free stream failed %d\n", ret); goto out; } - pcm_data->allocated = 0; + pcm_data->allocated = false; pcm_data->stream = NULL; out: From 38287780ec7a6720b64557d216975d40983a32ce Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:06 -0600 Subject: [PATCH 0950/1995] ASoC: Intel: Baytrail: remove unneeded variable Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 060d35be2dfa9202d37f967fd20f133c530505d2) --- sound/soc/intel/baytrail/sst-baytrail-ipc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c index 260447da32b870..2cd8f9668b5046 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-ipc.c +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c @@ -278,7 +278,6 @@ static int sst_byt_process_notification(struct sst_byt *byt, struct sst_byt_stream *stream; u64 header; u8 msg_id, stream_id; - int handled = 1; header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD); msg_id = sst_byt_header_msg_id(header); @@ -298,7 +297,7 @@ static int sst_byt_process_notification(struct sst_byt *byt, break; } - return handled; + return 1; } static irqreturn_t sst_byt_irq_thread(int irq, void *context) From 96d0dfeaae69f4efc5b75c0b6a8e82150a20c80e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:07 -0600 Subject: [PATCH 0951/1995] ASoC: Intel: Baytrail: simplify boolean test Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit e295450dd86d974861e1e9e302d67b0a23457ea8) --- sound/soc/intel/baytrail/sst-baytrail-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c index aabb35bf6b963d..498fb5346f1a81 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-pcm.c +++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c @@ -188,7 +188,7 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd) sst_byt_stream_start(byt, pcm_data->stream, 0); break; case SNDRV_PCM_TRIGGER_RESUME: - if (pdata->restore_stream == true) + if (pdata->restore_stream) schedule_work(&pcm_data->work); else sst_byt_stream_resume(byt, pcm_data->stream); From 794a7609694d9af15434d72a670b928a47f76a1d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:08 -0600 Subject: [PATCH 0952/1995] ASoC: Intel: Atom: simplify boolean tests Detected with Coccinelle Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 10583cdac237b32c0d3f6027b06c5eec8bf91211) --- sound/soc/intel/atom/sst-atom-controls.c | 2 +- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 2 +- sound/soc/intel/atom/sst/sst_acpi.c | 2 +- sound/soc/intel/atom/sst/sst_drv_interface.c | 2 +- sound/soc/intel/atom/sst/sst_loader.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 3672d36b4b66f4..d1207ea53523d4 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -647,7 +647,7 @@ static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w, set_mixer = false; } - if (set_mixer == false) + if (!set_mixer) return 0; if (SND_SOC_DAPM_EVENT_ON(event) || diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 91a2436ce9525a..b0873fea23ab4e 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -190,7 +190,7 @@ int sst_fill_stream_params(void *substream, map = ctx->pdata->pdev_strm_map; map_size = ctx->pdata->strm_map_size; - if (is_compress == true) + if (is_compress) cstream = (struct snd_compr_stream *)substream; else pstream = (struct snd_pcm_substream *)substream; diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index ac542535b9d53f..3a95ebbfc45d30 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -334,7 +334,7 @@ static int sst_acpi_probe(struct platform_device *pdev) return ret; ret = is_byt_cr(dev, &bytcr); - if (!((ret < 0) || (bytcr == false))) { + if (!(ret < 0 || !bytcr)) { dev_info(dev, "Detected Baytrail-CR platform\n"); /* override resource info */ diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c index 5455d6e0ab53cc..a592df06aa58eb 100644 --- a/sound/soc/intel/atom/sst/sst_drv_interface.c +++ b/sound/soc/intel/atom/sst/sst_drv_interface.c @@ -146,7 +146,7 @@ static int sst_power_control(struct device *dev, bool state) int ret = 0; int usage_count = 0; - if (state == true) { + if (state) { ret = pm_runtime_get_sync(dev); usage_count = GET_USAGE_COUNT(dev); dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count); diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c index b8c456753f015f..321c783cf833ca 100644 --- a/sound/soc/intel/atom/sst/sst_loader.c +++ b/sound/soc/intel/atom/sst/sst_loader.c @@ -269,7 +269,7 @@ static void sst_do_memcpy(struct list_head *memcpy_list) struct sst_memcpy_list *listnode; list_for_each_entry(listnode, memcpy_list, memcpylist) { - if (listnode->is_io == true) + if (listnode->is_io) memcpy32_toio((void __iomem *)listnode->dstn, listnode->src, listnode->size); else From d3dfb05a1ec372d12fe9b6e9163b0e5cd1c30448 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 16 Dec 2018 16:49:10 -0600 Subject: [PATCH 0953/1995] ASoC: Intel: boards: use snd_mask_set_format in all machine drivers Fix Sparse warnings with two machine drivers which weren't updated Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 4e88068ed0888549acd1cbb2f6e271b007051203) --- sound/soc/intel/boards/glk_rt5682_max98357a.c | 2 +- sound/soc/intel/boards/kbl_da7219_max98927.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index 8f83b182c4f95d..f6597c216fa8d3 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -126,7 +126,7 @@ static int geminilake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, /* set SSP to 24 bit */ snd_mask_none(fmt); - snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); return 0; } diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 723a4935ed76ed..6dd5c69671b3f6 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -221,7 +221,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, rate->min = rate->max = 48000; channels->min = channels->max = 2; snd_mask_none(fmt); - snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); } /* @@ -229,7 +229,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, * thus changing the mask here */ if (!strcmp(be_dai_link->name, "SSP0-Codec")) - snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); return 0; } From 614d730c64af31ea5caec0cb65ac0e7007fe59df Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:45:42 +0900 Subject: [PATCH 0954/1995] ASoC: simple-card-utils: check "reg" property on asoc_simple_card_get_dai_id() We will get DAI ID from "reg" property if it has on DT, otherwise get it by counting port/endpoint. But in below case, we need to get DAI ID = 0 via port reg = <0>, but current implementation returns ID = 1, because it can't judge ID = 0 was from "non reg" or "reg = <0>". Thus, it will count port/endpoint number as "non reg" case. of_graph_parse_endpoint() implementation itself is not a problem, but because asoc_simple_card_get_dai_id() need to count port/endpoint number when "non reg" case, it need to know ID = 0 was from "non reg" or "reg = <0>". This patch fix this issue. port { reg = <0>; xxxx: endpoint@0 { }; => xxxx: endpoint@1 { }; }; Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit a0c426fe143328760c9fd565cd203a37a7b4fde8) --- sound/soc/generic/simple-card-utils.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index b807a47515ebc8..336895f7fd1e9e 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -283,12 +283,20 @@ static int asoc_simple_card_get_dai_id(struct device_node *ep) /* use endpoint/port reg if exist */ ret = of_graph_parse_endpoint(ep, &info); if (ret == 0) { - if (info.id) + /* + * Because it will count port/endpoint if it doesn't have "reg". + * But, we can't judge whether it has "no reg", or "reg = <0>" + * only of_graph_parse_endpoint(). + * We need to check "reg" property + */ + if (of_get_property(ep, "reg", NULL)) return info.id; - if (info.port) + + node = of_get_parent(ep); + of_node_put(node); + if (of_get_property(node, "reg", NULL)) return info.port; } - node = of_graph_get_port_parent(ep); /* From d3ed505263ab33135ff31b135de0d4f4cc0ad1d8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:45:48 +0900 Subject: [PATCH 0955/1995] ASoC: audio-graph-card: add asoc_graph_card_get_conversion() audio-graph-card is now supporting normal sound and DPCM sound. For DPCM sound, original sound card (= audio-graph-scu) had been supported 1 CPU : 1 Codec connection which uses hw_params_fixup() for convert-rate/channel. But, merged audio-graph-card is completely forgeting about it. To re-support 1 CPU : 1 Codec DPCM for hw_params_fixup(), it need to judge whether it is DPCM by checking convert-rate/channel. For this purpose, this patch adds asoc_graph_card_get_conversion() as preparation Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 40dfae169ad047535d566a4791daae3b08f71c0c) --- sound/soc/generic/audio-graph-card.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 0d6144560a1e5d..c3e80bc27e803c 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -169,6 +169,22 @@ static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } +static void asoc_graph_card_get_conversion(struct device *dev, + struct device_node *ep, + struct asoc_simple_card_data *adata) +{ + struct device_node *top = dev->of_node; + struct device_node *port = of_get_parent(ep); + struct device_node *ports = of_get_parent(port); + struct device_node *node = of_graph_get_port_parent(ep); + + asoc_simple_card_parse_convert(dev, top, NULL, adata); + asoc_simple_card_parse_convert(dev, node, PREFIX, adata); + asoc_simple_card_parse_convert(dev, ports, NULL, adata); + asoc_simple_card_parse_convert(dev, port, NULL, adata); + asoc_simple_card_parse_convert(dev, ep, NULL, adata); +} + static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, struct device_node *cpu_ep, struct device_node *codec_ep, @@ -194,11 +210,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, of_property_read_u32(port, "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(ep, "mclk-fs", &dai_props->mclk_fs); - asoc_simple_card_parse_convert(dev, top, NULL, &dai_props->adata); - asoc_simple_card_parse_convert(dev, node, PREFIX, &dai_props->adata); - asoc_simple_card_parse_convert(dev, ports, NULL, &dai_props->adata); - asoc_simple_card_parse_convert(dev, port, NULL, &dai_props->adata); - asoc_simple_card_parse_convert(dev, ep, NULL, &dai_props->adata); + asoc_graph_card_get_conversion(dev, ep, &dai_props->adata); of_node_put(ports); of_node_put(port); From 81c5f761c8c42832ae7229d5c8691e0c814c712b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Dec 2018 11:50:32 +0900 Subject: [PATCH 0956/1995] ASoC: audio-graph-scu-card: remove audio-graph-scu-card It is already merged into audio-graph-card. audio-graph-scu-card is no longer needed. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 61c263ac27a307cdf7f46aaee4810619103effad) --- sound/soc/generic/Kconfig | 9 - sound/soc/generic/Makefile | 2 - sound/soc/generic/audio-graph-scu-card.c | 501 ----------------------- 3 files changed, 512 deletions(-) delete mode 100644 sound/soc/generic/audio-graph-scu-card.c diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig index 92c2cf06f40ac8..59190f42fc084c 100644 --- a/sound/soc/generic/Kconfig +++ b/sound/soc/generic/Kconfig @@ -24,12 +24,3 @@ config SND_AUDIO_GRAPH_CARD This option enables generic simple sound card support with OF-graph DT bindings. It also support DPCM of multi CPU single Codec ststem. - -config SND_AUDIO_GRAPH_SCU_CARD - tristate "ASoC Audio Graph SCU sound card support" - depends on OF - select SND_SIMPLE_CARD_UTILS - help - This option enables generic simple SCU sound card support - with OF-graph DT bindings. - It supports DPCM of multi CPU single Codec ststem. diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile index 9dec293a4c4de9..9fbfdd524b2456 100644 --- a/sound/soc/generic/Makefile +++ b/sound/soc/generic/Makefile @@ -3,10 +3,8 @@ snd-soc-simple-card-utils-objs := simple-card-utils.o snd-soc-simple-card-objs := simple-card.o snd-soc-simple-scu-card-objs := simple-scu-card.o snd-soc-audio-graph-card-objs := audio-graph-card.o -snd-soc-audio-graph-scu-card-objs := audio-graph-scu-card.o obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o obj-$(CONFIG_SND_AUDIO_GRAPH_CARD) += snd-soc-audio-graph-card.o -obj-$(CONFIG_SND_AUDIO_GRAPH_SCU_CARD) += snd-soc-audio-graph-scu-card.o diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c deleted file mode 100644 index e1b192ea147b53..00000000000000 --- a/sound/soc/generic/audio-graph-scu-card.c +++ /dev/null @@ -1,501 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// ASoC audio graph SCU sound card support -// -// Copyright (C) 2017 Renesas Solutions Corp. -// Kuninori Morimoto -// -// based on -// ${LINUX}/sound/soc/generic/simple-scu-card.c -// ${LINUX}/sound/soc/generic/audio-graph-card.c - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct graph_card_data { - struct snd_soc_card snd_card; - struct graph_dai_props { - struct asoc_simple_dai *cpu_dai; - struct asoc_simple_dai *codec_dai; - struct snd_soc_dai_link_component codecs; - struct snd_soc_dai_link_component platform; - struct asoc_simple_card_data adata; - struct snd_soc_codec_conf *codec_conf; - } *dai_props; - struct snd_soc_dai_link *dai_link; - struct asoc_simple_dai *dais; - struct asoc_simple_card_data adata; - struct snd_soc_codec_conf *codec_conf; -}; - -#define graph_priv_to_card(priv) (&(priv)->snd_card) -#define graph_priv_to_props(priv, i) ((priv)->dai_props + (i)) -#define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev) -#define graph_priv_to_link(priv, i) (graph_priv_to_card(priv)->dai_link + (i)) - -#define PREFIX "audio-graph-card," - -static int asoc_graph_card_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - int ret = 0; - - ret = asoc_simple_card_clk_enable(dai_props->cpu_dai); - if (ret) - return ret; - - ret = asoc_simple_card_clk_enable(dai_props->codec_dai); - if (ret) - asoc_simple_card_clk_disable(dai_props->cpu_dai); - - return ret; -} - -static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - - asoc_simple_card_clk_disable(dai_props->cpu_dai); - - asoc_simple_card_clk_disable(dai_props->codec_dai); -} - -static const struct snd_soc_ops asoc_graph_card_ops = { - .startup = asoc_graph_card_startup, - .shutdown = asoc_graph_card_shutdown, -}; - -static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) -{ - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - int ret = 0; - - ret = asoc_simple_card_init_dai(rtd->codec_dai, - dai_props->codec_dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_init_dai(rtd->cpu_dai, - dai_props->cpu_dai); - if (ret < 0) - return ret; - - return 0; -} - -static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); - - asoc_simple_card_convert_fixup(&dai_props->adata, params); - - /* overwrite by top level adata if exist */ - asoc_simple_card_convert_fixup(&priv->adata, params); - - return 0; -} - -static int asoc_graph_card_dai_link_of(struct device_node *cpu_ep, - struct device_node *codec_ep, - struct graph_card_data *priv, - int *dai_idx, int link_idx, - int *conf_idx, int is_fe) -{ - struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx); - struct snd_soc_card *card = graph_priv_to_card(priv); - struct device_node *ep = is_fe ? cpu_ep : codec_ep; - struct device_node *node = of_graph_get_port_parent(ep); - struct asoc_simple_dai *dai; - int ret; - - if (is_fe) { - struct snd_soc_dai_link_component *codecs; - - /* BE is dummy */ - codecs = dai_link->codecs; - codecs->of_node = NULL; - codecs->dai_name = "snd-soc-dummy-dai"; - codecs->name = "snd-soc-dummy"; - - /* FE settings */ - dai_link->dynamic = 1; - dai_link->dpcm_merged_format = 1; - - dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; - - ret = asoc_simple_card_parse_graph_cpu(ep, dai_link); - if (ret) - return ret; - - ret = asoc_simple_card_parse_clk_cpu(dev, ep, dai_link, dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "fe.%s", - dai_link->cpu_dai_name); - if (ret < 0) - return ret; - - /* card->num_links includes Codec */ - asoc_simple_card_canonicalize_cpu(dai_link, - of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); - } else { - struct snd_soc_codec_conf *cconf; - - /* FE is dummy */ - dai_link->cpu_of_node = NULL; - dai_link->cpu_dai_name = "snd-soc-dummy-dai"; - dai_link->cpu_name = "snd-soc-dummy"; - - /* BE settings */ - dai_link->no_pcm = 1; - dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup; - - dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; - - cconf = - dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; - - ret = asoc_simple_card_parse_graph_codec(ep, dai_link); - if (ret < 0) - return ret; - - ret = asoc_simple_card_parse_clk_codec(dev, ep, dai_link, dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "be.%s", - dai_link->codecs->dai_name); - if (ret < 0) - return ret; - - /* check "prefix" from top node */ - snd_soc_of_parse_audio_prefix(card, cconf, - dai_link->codecs->of_node, - "prefix"); - /* check "prefix" from each node if top doesn't have */ - if (!cconf->of_node) - snd_soc_of_parse_node_prefix(node, cconf, - dai_link->codecs->of_node, - PREFIX "prefix"); - } - - asoc_simple_card_parse_convert(dev, node, PREFIX, &dai_props->adata); - - ret = asoc_simple_card_of_parse_tdm(ep, dai); - if (ret) - return ret; - - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - return ret; - - ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep, - NULL, &dai_link->dai_fmt); - if (ret < 0) - return ret; - - dai_link->dpcm_playback = 1; - dai_link->dpcm_capture = 1; - dai_link->ops = &asoc_graph_card_ops; - dai_link->init = asoc_graph_card_dai_init; - - return 0; -} - -static int asoc_graph_card_parse_of(struct graph_card_data *priv) -{ - struct of_phandle_iterator it; - struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_card *card = graph_priv_to_card(priv); - struct device_node *node = dev->of_node; - struct device_node *cpu_port; - struct device_node *cpu_ep; - struct device_node *codec_ep; - struct device_node *codec_port; - struct device_node *codec_port_old; - int dai_idx, link_idx, conf_idx, ret; - int rc, codec; - - if (!node) - return -EINVAL; - - /* - * we need to consider "widgets", "mclk-fs" around here - * see simple-card - */ - - ret = asoc_simple_card_of_parse_routing(card, NULL); - if (ret < 0) - return ret; - - asoc_simple_card_parse_convert(dev, node, NULL, &priv->adata); - - /* - * it supports multi CPU, single CODEC only here - * see asoc_graph_get_dais_count - */ - - link_idx = 0; - dai_idx = 0; - conf_idx = 0; - codec_port_old = NULL; - for (codec = 0; codec < 2; codec++) { - /* - * To listup valid sounds continuously, - * detect all CPU-dummy first, and - * detect all dummy-Codec second - */ - of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { - cpu_port = it.node; - cpu_ep = of_get_next_child(cpu_port, NULL); - codec_ep = of_graph_get_remote_endpoint(cpu_ep); - codec_port = of_graph_get_port_parent(codec_ep); - - of_node_put(cpu_ep); - of_node_put(codec_ep); - of_node_put(cpu_port); - of_node_put(codec_port); - it.node = NULL; - - if (codec) { - if (codec_port_old == codec_port) - continue; - - codec_port_old = codec_port; - } - - ret = asoc_graph_card_dai_link_of(cpu_ep, codec_ep, - priv, &dai_idx, - link_idx++, &conf_idx, - !codec); - if (ret < 0) - goto parse_of_err; - } - } - - ret = asoc_simple_card_parse_card_name(card, NULL); - if (ret) - goto parse_of_err; - - if ((card->num_links != link_idx) || - (card->num_configs != conf_idx)) { - dev_err(dev, "dai_link or codec_config wrong (%d/%d, %d/%d)\n", - card->num_links, link_idx, card->num_configs, conf_idx); - ret = -EINVAL; - goto parse_of_err; - } - - ret = 0; - -parse_of_err: - return ret; -} - -static void asoc_graph_get_dais_count(struct device *dev, - int *link_num, - int *dais_num, - int *ccnf_num) -{ - struct of_phandle_iterator it; - struct device_node *node = dev->of_node; - struct device_node *cpu_port; - struct device_node *cpu_ep; - struct device_node *codec_ep; - struct device_node *codec_port; - struct device_node *codec_port_old; - struct device_node *codec_port_old2; - int rc; - - /* - * link_num : number of links. - * CPU-Codec / CPU-dummy / dummy-Codec - * dais_num : number of DAIs - * ccnf_num : number of codec_conf - * same number for dummy-Codec - * - * ex1) - * CPU0 --- Codec0 link : 5 - * CPU1 --- Codec1 dais : 7 - * CPU2 -/ ccnf : 1 - * CPU3 --- Codec2 - * - * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec - * => 7 DAIs = 4xCPU + 3xCodec - * => 1 ccnf = 1xdummy-Codec - * - * ex2) - * CPU0 --- Codec0 link : 5 - * CPU1 --- Codec1 dais : 6 - * CPU2 -/ ccnf : 1 - * CPU3 -/ - * - * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec - * => 6 DAIs = 4xCPU + 2xCodec - * => 1 ccnf = 1xdummy-Codec - * - * ex3) - * CPU0 --- Codec0 link : 6 - * CPU1 -/ dais : 6 - * CPU2 --- Codec1 ccnf : 2 - * CPU3 -/ - * - * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec - * => 6 DAIs = 4xCPU + 2xCodec - * => 2 ccnf = 2xdummy-Codec - */ - codec_port_old = NULL; - codec_port_old2 = NULL; - of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { - cpu_port = it.node; - cpu_ep = of_get_next_child(cpu_port, NULL); - codec_ep = of_graph_get_remote_endpoint(cpu_ep); - codec_port = of_graph_get_port_parent(codec_ep); - - of_node_put(cpu_ep); - of_node_put(codec_ep); - of_node_put(codec_port); - - (*link_num)++; - (*dais_num)++; - - if (codec_port_old == codec_port) { - if (codec_port_old2 != codec_port_old) { - (*link_num)++; - (*ccnf_num)++; - } - - codec_port_old2 = codec_port_old; - continue; - } - - (*dais_num)++; - codec_port_old = codec_port; - } -} - -static int asoc_graph_card_probe(struct platform_device *pdev) -{ - struct graph_card_data *priv; - struct snd_soc_dai_link *dai_link; - struct graph_dai_props *dai_props; - struct asoc_simple_dai *dais; - struct device *dev = &pdev->dev; - struct snd_soc_card *card; - struct snd_soc_codec_conf *cconf; - int lnum = 0, dnum = 0, cnum = 0; - int ret, i; - - /* Allocate the private data and the DAI link array */ - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum); - if (!lnum || !dnum) - return -EINVAL; - - dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); - dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); - dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); - cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); - if (!dai_props || !dai_link || !dais) - return -ENOMEM; - - /* - * Use snd_soc_dai_link_component instead of legacy style - * It is codec only. but cpu/platform will be supported in the future. - * see - * soc-core.c :: snd_soc_init_multicodec() - */ - for (i = 0; i < lnum; i++) { - dai_link[i].codecs = &dai_props[i].codecs; - dai_link[i].num_codecs = 1; - dai_link[i].platform = &dai_props[i].platform; - } - - priv->dai_props = dai_props; - priv->dai_link = dai_link; - priv->dais = dais; - priv->codec_conf = cconf; - - /* Init snd_soc_card */ - card = graph_priv_to_card(priv); - card->owner = THIS_MODULE; - card->dev = dev; - card->dai_link = priv->dai_link; - card->num_links = lnum; - card->codec_conf = cconf; - card->num_configs = cnum; - - ret = asoc_graph_card_parse_of(priv); - if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "parse error %d\n", ret); - goto err; - } - - snd_soc_card_set_drvdata(card, priv); - - ret = devm_snd_soc_register_card(dev, card); - if (ret < 0) - goto err; - - return 0; -err: - asoc_simple_card_clean_reference(card); - - return ret; -} - -static int asoc_graph_card_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - return asoc_simple_card_clean_reference(card); -} - -static const struct of_device_id asoc_graph_of_match[] = { - { .compatible = "audio-graph-scu-card", }, - {}, -}; -MODULE_DEVICE_TABLE(of, asoc_graph_of_match); - -static struct platform_driver asoc_graph_card = { - .driver = { - .name = "asoc-audio-graph-scu-card", - .pm = &snd_soc_pm_ops, - .of_match_table = asoc_graph_of_match, - }, - .probe = asoc_graph_card_probe, - .remove = asoc_graph_card_remove, -}; -module_platform_driver(asoc_graph_card); - -MODULE_ALIAS("platform:asoc-audio-graph-scu-card"); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("ASoC Audio Graph SCU Sound Card"); -MODULE_AUTHOR("Kuninori Morimoto "); From 03c78dc6f8e4ece09f6c48f3765052aa9d9e7ef5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 18 Dec 2018 11:50:42 +0900 Subject: [PATCH 0957/1995] ASoC: simple-scu-card: remove simple-scu-card It is already merged into simple-card. simple-scu-card is no longer needed. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit c8ed6aca6b824018a39702a563f2f6591de20d64) --- sound/soc/generic/Kconfig | 8 - sound/soc/generic/Makefile | 2 - sound/soc/generic/simple-scu-card.c | 474 ---------------------------- 3 files changed, 484 deletions(-) delete mode 100644 sound/soc/generic/simple-scu-card.c diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig index 59190f42fc084c..83f1243145b00b 100644 --- a/sound/soc/generic/Kconfig +++ b/sound/soc/generic/Kconfig @@ -8,14 +8,6 @@ config SND_SIMPLE_CARD This option enables generic simple sound card support It also support DPCM of multi CPU single Codec ststem. -config SND_SIMPLE_SCU_CARD - tristate "ASoC Simple SCU sound card support" - depends on OF - select SND_SIMPLE_CARD_UTILS - help - This option enables generic simple SCU sound card support. - It supports DPCM of multi CPU single Codec system. - config SND_AUDIO_GRAPH_CARD tristate "ASoC Audio Graph sound card support" depends on OF diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile index 9fbfdd524b2456..21c29e5e0671e2 100644 --- a/sound/soc/generic/Makefile +++ b/sound/soc/generic/Makefile @@ -1,10 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 snd-soc-simple-card-utils-objs := simple-card-utils.o snd-soc-simple-card-objs := simple-card.o -snd-soc-simple-scu-card-objs := simple-scu-card.o snd-soc-audio-graph-card-objs := audio-graph-card.o obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) += snd-soc-simple-card-utils.o obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o -obj-$(CONFIG_SND_SIMPLE_SCU_CARD) += snd-soc-simple-scu-card.o obj-$(CONFIG_SND_AUDIO_GRAPH_CARD) += snd-soc-audio-graph-card.o diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c deleted file mode 100644 index 9d7299d536a887..00000000000000 --- a/sound/soc/generic/simple-scu-card.c +++ /dev/null @@ -1,474 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// -// ASoC simple SCU sound card support -// -// Copyright (C) 2015 Renesas Solutions Corp. -// Kuninori Morimoto -// -// based on ${LINUX}/sound/soc/generic/simple-card.c - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct simple_card_data { - struct snd_soc_card snd_card; - struct simple_dai_props { - struct asoc_simple_dai *cpu_dai; - struct asoc_simple_dai *codec_dai; - struct snd_soc_dai_link_component codecs; - struct snd_soc_dai_link_component platform; - struct asoc_simple_card_data adata; - struct snd_soc_codec_conf *codec_conf; - } *dai_props; - struct snd_soc_dai_link *dai_link; - struct asoc_simple_dai *dais; - struct asoc_simple_card_data adata; - struct snd_soc_codec_conf *codec_conf; -}; - -#define simple_priv_to_card(priv) (&(priv)->snd_card) -#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i)) -#define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev) -#define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i)) - -#define DAI "sound-dai" -#define CELL "#sound-dai-cells" -#define PREFIX "simple-audio-card," - -static int asoc_simple_card_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = - simple_priv_to_props(priv, rtd->num); - int ret; - - ret = asoc_simple_card_clk_enable(dai_props->cpu_dai); - if (ret) - return ret; - - ret = asoc_simple_card_clk_enable(dai_props->codec_dai); - if (ret) - asoc_simple_card_clk_disable(dai_props->cpu_dai); - - return ret; -} - -static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = - simple_priv_to_props(priv, rtd->num); - - asoc_simple_card_clk_disable(dai_props->cpu_dai); - - asoc_simple_card_clk_disable(dai_props->codec_dai); -} - -static const struct snd_soc_ops asoc_simple_card_ops = { - .startup = asoc_simple_card_startup, - .shutdown = asoc_simple_card_shutdown, -}; - -static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) -{ - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); - int ret; - - ret = asoc_simple_card_init_dai(rtd->codec_dai, - dai_props->codec_dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_init_dai(rtd->cpu_dai, - dai_props->cpu_dai); - if (ret < 0) - return ret; - - return 0; -} - -static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); - - asoc_simple_card_convert_fixup(&dai_props->adata, params); - - /* overwrite by top level adata if exist */ - asoc_simple_card_convert_fixup(&priv->adata, params); - - return 0; -} - -static int asoc_simple_card_dai_link_of(struct device_node *link, - struct device_node *np, - struct device_node *codec, - struct simple_card_data *priv, - int *dai_idx, int link_idx, - int *conf_idx, int is_fe, - bool is_top_level_node) -{ - struct device *dev = simple_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx); - struct snd_soc_card *card = simple_priv_to_card(priv); - struct asoc_simple_dai *dai; - char *prefix = ""; - int ret; - - /* For single DAI link & old style of DT node */ - if (is_top_level_node) - prefix = PREFIX; - - if (is_fe) { - int is_single_links = 0; - struct snd_soc_dai_link_component *codecs; - - /* BE is dummy */ - codecs = dai_link->codecs; - codecs->of_node = NULL; - codecs->dai_name = "snd-soc-dummy-dai"; - codecs->name = "snd-soc-dummy"; - - /* FE settings */ - dai_link->dynamic = 1; - dai_link->dpcm_merged_format = 1; - - dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; - - ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL, - &is_single_links); - if (ret) - return ret; - - ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "fe.%s", - dai_link->cpu_dai_name); - if (ret < 0) - return ret; - - asoc_simple_card_canonicalize_cpu(dai_link, is_single_links); - } else { - struct snd_soc_codec_conf *cconf; - - /* FE is dummy */ - dai_link->cpu_of_node = NULL; - dai_link->cpu_dai_name = "snd-soc-dummy-dai"; - dai_link->cpu_name = "snd-soc-dummy"; - - /* BE settings */ - dai_link->no_pcm = 1; - dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup; - - dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; - - cconf = - dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; - - ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL); - if (ret < 0) - return ret; - - ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai); - if (ret < 0) - return ret; - - ret = asoc_simple_card_set_dailink_name(dev, dai_link, - "be.%s", - dai_link->codecs->dai_name); - if (ret < 0) - return ret; - - /* check "prefix" from top node */ - snd_soc_of_parse_audio_prefix(card, cconf, - dai_link->codecs->of_node, - PREFIX "prefix"); - /* check "prefix" from each node if top doesn't have */ - if (!cconf->of_node) - snd_soc_of_parse_node_prefix(np, cconf, - dai_link->codecs->of_node, - "prefix"); - } - - asoc_simple_card_parse_convert(dev, link, prefix, &dai_props->adata); - - ret = asoc_simple_card_of_parse_tdm(np, dai); - if (ret) - return ret; - - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - return ret; - - ret = asoc_simple_card_parse_daifmt(dev, link, codec, - prefix, &dai_link->dai_fmt); - if (ret < 0) - return ret; - - dai_link->dpcm_playback = 1; - dai_link->dpcm_capture = 1; - dai_link->ops = &asoc_simple_card_ops; - dai_link->init = asoc_simple_card_dai_init; - - return 0; -} - -static int asoc_simple_card_parse_of(struct simple_card_data *priv) - -{ - struct device *dev = simple_priv_to_dev(priv); - struct device_node *top = dev->of_node; - struct device_node *node; - struct device_node *np; - struct device_node *codec; - struct snd_soc_card *card = simple_priv_to_card(priv); - bool is_fe; - int ret, loop; - int dai_idx, link_idx, conf_idx; - - if (!top) - return -EINVAL; - - ret = asoc_simple_card_of_parse_widgets(card, PREFIX); - if (ret < 0) - return ret; - - ret = asoc_simple_card_of_parse_routing(card, PREFIX); - if (ret < 0) - return ret; - - asoc_simple_card_parse_convert(dev, top, PREFIX, &priv->adata); - - loop = 1; - link_idx = 0; - dai_idx = 0; - conf_idx = 0; - node = of_get_child_by_name(top, PREFIX "dai-link"); - if (!node) { - node = dev->of_node; - loop = 0; - } - - do { - codec = of_get_child_by_name(node, - loop ? "codec" : PREFIX "codec"); - if (!codec) - return -ENODEV; - - for_each_child_of_node(node, np) { - is_fe = (np != codec); - - ret = asoc_simple_card_dai_link_of(node, np, codec, priv, - &dai_idx, link_idx++, - &conf_idx, - is_fe, !loop); - if (ret < 0) - return ret; - } - node = of_get_next_child(top, node); - } while (loop && node); - - ret = asoc_simple_card_parse_card_name(card, PREFIX); - if (ret < 0) - return ret; - - return 0; -} - -static void asoc_simple_card_get_dais_count(struct device *dev, - int *link_num, - int *dais_num, - int *ccnf_num) -{ - struct device_node *top = dev->of_node; - struct device_node *node; - int loop; - int num; - - /* - * link_num : number of links. - * CPU-Codec / CPU-dummy / dummy-Codec - * dais_num : number of DAIs - * ccnf_num : number of codec_conf - * same number for "dummy-Codec" - * - * ex1) - * CPU0 --- Codec0 link : 5 - * CPU1 --- Codec1 dais : 7 - * CPU2 -/ ccnf : 1 - * CPU3 --- Codec2 - * - * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec - * => 7 DAIs = 4xCPU + 3xCodec - * => 1 ccnf = 1xdummy-Codec - * - * ex2) - * CPU0 --- Codec0 link : 5 - * CPU1 --- Codec1 dais : 6 - * CPU2 -/ ccnf : 1 - * CPU3 -/ - * - * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec - * => 6 DAIs = 4xCPU + 2xCodec - * => 1 ccnf = 1xdummy-Codec - * - * ex3) - * CPU0 --- Codec0 link : 6 - * CPU1 -/ dais : 6 - * CPU2 --- Codec1 ccnf : 2 - * CPU3 -/ - * - * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec - * => 6 DAIs = 4xCPU + 2xCodec - * => 2 ccnf = 2xdummy-Codec - */ - if (!top) { - (*link_num) = 1; - (*dais_num) = 2; - (*ccnf_num) = 0; - return; - } - - loop = 1; - node = of_get_child_by_name(top, PREFIX "dai-link"); - if (!node) { - node = top; - loop = 0; - } - - do { - num = of_get_child_count(node); - (*dais_num) += num; - if (num > 2) { - (*link_num) += num; - (*ccnf_num)++; - } else { - (*link_num)++; - } - node = of_get_next_child(top, node); - } while (loop && node); -} - -static int asoc_simple_card_probe(struct platform_device *pdev) -{ - struct simple_card_data *priv; - struct snd_soc_dai_link *dai_link; - struct simple_dai_props *dai_props; - struct asoc_simple_dai *dais; - struct snd_soc_card *card; - struct snd_soc_codec_conf *cconf; - struct device *dev = &pdev->dev; - int ret, i; - int lnum = 0, dnum = 0, cnum = 0; - - /* Allocate the private data */ - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum); - if (!lnum || !dnum) - return -EINVAL; - - dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); - dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); - dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); - cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); - if (!dai_props || !dai_link || !dais) - return -ENOMEM; - - /* - * Use snd_soc_dai_link_component instead of legacy style - * It is codec only. but cpu/platform will be supported in the future. - * see - * soc-core.c :: snd_soc_init_multicodec() - */ - for (i = 0; i < lnum; i++) { - dai_link[i].codecs = &dai_props[i].codecs; - dai_link[i].num_codecs = 1; - dai_link[i].platform = &dai_props[i].platform; - } - - priv->dai_props = dai_props; - priv->dai_link = dai_link; - priv->dais = dais; - priv->codec_conf = cconf; - - /* Init snd_soc_card */ - card = simple_priv_to_card(priv); - card->owner = THIS_MODULE; - card->dev = dev; - card->dai_link = priv->dai_link; - card->num_links = lnum; - card->codec_conf = cconf; - card->num_configs = cnum; - - ret = asoc_simple_card_parse_of(priv); - if (ret < 0) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "parse error %d\n", ret); - goto err; - } - - snd_soc_card_set_drvdata(card, priv); - - ret = devm_snd_soc_register_card(dev, card); - if (ret < 0) - goto err; - - return 0; -err: - asoc_simple_card_clean_reference(card); - - return ret; -} - -static int asoc_simple_card_remove(struct platform_device *pdev) -{ - struct snd_soc_card *card = platform_get_drvdata(pdev); - - return asoc_simple_card_clean_reference(card); -} - -static const struct of_device_id asoc_simple_of_match[] = { - { .compatible = "renesas,rsrc-card", }, - { .compatible = "simple-scu-audio-card", }, - {}, -}; -MODULE_DEVICE_TABLE(of, asoc_simple_of_match); - -static struct platform_driver asoc_simple_card = { - .driver = { - .name = "simple-scu-audio-card", - .pm = &snd_soc_pm_ops, - .of_match_table = asoc_simple_of_match, - }, - .probe = asoc_simple_card_probe, - .remove = asoc_simple_card_remove, -}; - -module_platform_driver(asoc_simple_card); - -MODULE_ALIAS("platform:asoc-simple-scu-card"); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("ASoC Simple SCU Sound Card"); -MODULE_AUTHOR("Kuninori Morimoto "); From aa314e31e767d6ba5407990e3e6371cfd91befce Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:45:54 +0900 Subject: [PATCH 0958/1995] ASoC: audio-graph-card: add 1 CPU : 1 Codec support again audio-graph-card is now supporting normal sound and DPCM sound. For DPCM sound, original sound card (= audio-graph-scu) had been supported 1 CPU : 1 Codec connection which uses hw_params_fixup() for convert-rate/channel. But, merged audio-graph-card is completely forgeting about it. This patch re-support it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit de2949fe262197298036989924d05f5de6b9815a) --- sound/soc/generic/audio-graph-card.c | 44 ++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index c3e80bc27e803c..638333cdac662a 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -408,6 +408,7 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) struct device_node *codec_ep = NULL; struct device_node *codec_port = NULL; struct device_node *codec_port_old = NULL; + struct asoc_simple_card_data adata; int rc, ret; int link_idx, dai_idx, conf_idx; int cpu; @@ -453,7 +454,13 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) dev_dbg(dev, "%pOFf <-> %pOFf\n", cpu_ep, codec_ep); - if (of_get_child_count(codec_port) > 1) { + memset(&adata, 0, sizeof(adata)); + asoc_graph_card_get_conversion(dev, codec_ep, &adata); + asoc_graph_card_get_conversion(dev, cpu_ep, &adata); + + if ((of_get_child_count(codec_port) > 1) || + adata.convert_rate || + adata.convert_channels) { /* * for DPCM sound */ @@ -495,7 +502,7 @@ static void asoc_graph_get_dais_count(struct device *dev, struct device_node *codec_ep; struct device_node *codec_port; struct device_node *codec_port_old; - struct device_node *codec_port_old2; + struct asoc_simple_card_data adata; int rc; /* @@ -534,9 +541,17 @@ static void asoc_graph_get_dais_count(struct device *dev, * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec * => 6 DAIs = 4xCPU + 2xCodec * => 2 ccnf = 2xdummy-Codec + * + * ex4) + * CPU0 --- Codec0 (convert-rate) link : 3 + * CPU1 --- Codec1 dais : 4 + * ccnf : 1 + * + * => 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec + * => 4 DAIs = 2xCPU + 2xCodec + * => 1 ccnf = 1xdummy-Codec */ codec_port_old = NULL; - codec_port_old2 = NULL; of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { cpu_port = it.node; cpu_ep = NULL; @@ -554,17 +569,22 @@ static void asoc_graph_get_dais_count(struct device *dev, (*link_num)++; (*dais_num)++; - if (codec_port_old == codec_port) { - if (codec_port_old2 != codec_port_old) { - (*link_num)++; - (*ccnf_num)++; - } + memset(&adata, 0, sizeof(adata)); + asoc_graph_card_get_conversion(dev, codec_ep, &adata); + asoc_graph_card_get_conversion(dev, cpu_ep, &adata); - codec_port_old2 = codec_port_old; - continue; - } + if ((of_get_child_count(codec_port) > 1) || + adata.convert_rate || adata.convert_channels) { - (*dais_num)++; + if (codec_port_old == codec_port) + continue; + + (*link_num)++; + (*ccnf_num)++; + (*dais_num)++; + } else { + (*dais_num)++; + } codec_port_old = codec_port; } } From 648d8fe4c4ced52e3a41126ee0e76a8f6997a119 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:45:59 +0900 Subject: [PATCH 0959/1995] ASoC: audio-graph-card: add link_info Current audio-graph-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. To preparing cleanup code, this patch adds link_info which handles number of DAIs/Links/Codec Conf, and CPU/Codec turn. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 1e4771a62fd7a6bab058529c450d3d87a8bd5b1a) --- sound/soc/generic/audio-graph-card.c | 99 ++++++++++++++-------------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 638333cdac662a..cd9beb801fc1b8 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -39,6 +39,13 @@ struct graph_card_data { struct gpio_desc *pa_gpio; }; +struct link_info { + int dais; /* number of dai */ + int link; /* number of link */ + int conf; /* number of codec_conf */ + int cpu; /* turn for CPU / Codec */ +}; + #define graph_priv_to_card(priv) (&(priv)->snd_card) #define graph_priv_to_props(priv, i) ((priv)->dai_props + (i)) #define graph_priv_to_dev(priv) (graph_priv_to_card(priv)->dev) @@ -189,13 +196,12 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, struct device_node *cpu_ep, struct device_node *codec_ep, struct graph_card_data *priv, - int *dai_idx, int link_idx, - int *conf_idx, int is_cpu) + struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx); - struct device_node *ep = is_cpu ? cpu_ep : codec_ep; + struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); + struct device_node *ep = li->cpu ? cpu_ep : codec_ep; struct device_node *port = of_get_parent(ep); struct device_node *ports = of_get_parent(port); struct device_node *node = of_graph_get_port_parent(ep); @@ -203,7 +209,9 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, struct snd_soc_dai_link_component *codecs = dai_link->codecs; int ret; - dev_dbg(dev, "link_of DPCM (for %s)\n", is_cpu ? "CPU" : "Codec"); + li->link++; + + dev_dbg(dev, "link_of DPCM (%pOF)\n", ep); of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(ports, "mclk-fs", &dai_props->mclk_fs); @@ -215,7 +223,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, of_node_put(ports); of_node_put(port); - if (is_cpu) { + if (li->cpu) { /* BE is dummy */ codecs->of_node = NULL; @@ -227,7 +235,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, dai_link->dpcm_merged_format = 1; dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; + dai_props->cpu_dai = &priv->dais[li->dais++]; ret = asoc_simple_card_parse_graph_cpu(ep, dai_link); if (ret) @@ -259,10 +267,10 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup; dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; + dai_props->codec_dai = &priv->dais[li->dais++]; cconf = - dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; + dai_props->codec_conf = &priv->codec_conf[li->conf++]; ret = asoc_simple_card_parse_graph_codec(ep, dai_link); if (ret < 0) @@ -314,11 +322,11 @@ static int asoc_graph_card_dai_link_of(struct device_node *top, struct device_node *cpu_ep, struct device_node *codec_ep, struct graph_card_data *priv, - int *dai_idx, int link_idx) + struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, link_idx); - struct graph_dai_props *dai_props = graph_priv_to_props(priv, link_idx); + struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); + struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); struct device_node *cpu_port = of_get_parent(cpu_ep); struct device_node *codec_port = of_get_parent(codec_ep); struct device_node *cpu_ports = of_get_parent(cpu_port); @@ -327,12 +335,14 @@ static int asoc_graph_card_dai_link_of(struct device_node *top, struct asoc_simple_dai *codec_dai; int ret; - dev_dbg(dev, "link_of\n"); + dev_dbg(dev, "link_of (%pOF)\n", cpu_ep); + + li->link++; cpu_dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; + dai_props->cpu_dai = &priv->dais[li->dais++]; codec_dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; + dai_props->codec_dai = &priv->dais[li->dais++]; /* Factor to mclk, used in hw_params() */ of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs); @@ -409,9 +419,8 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) struct device_node *codec_port = NULL; struct device_node *codec_port_old = NULL; struct asoc_simple_card_data adata; + struct link_info li; int rc, ret; - int link_idx, dai_idx, conf_idx; - int cpu; ret = asoc_simple_card_of_parse_widgets(card, NULL); if (ret < 0) @@ -421,11 +430,9 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) if (ret < 0) return ret; - link_idx = 0; - dai_idx = 0; - conf_idx = 0; + memset(&li, 0, sizeof(li)); codec_port_old = NULL; - for (cpu = 1; cpu >= 0; cpu--) { + for (li.cpu = 1; li.cpu >= 0; li.cpu--) { /* * Detect all CPU first, and Detect all Codec 2nd. * @@ -464,22 +471,19 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) /* * for DPCM sound */ - if (!cpu) { + if (!li.cpu) { if (codec_port_old == codec_port) continue; codec_port_old = codec_port; } ret = asoc_graph_card_dai_link_of_dpcm( - top, cpu_ep, codec_ep, priv, - &dai_idx, link_idx++, - &conf_idx, cpu); - } else if (cpu) { + top, cpu_ep, codec_ep, priv, &li); + } else if (li.cpu) { /* * for Normal sound */ ret = asoc_graph_card_dai_link_of( - top, cpu_ep, codec_ep, priv, - &dai_idx, link_idx++); + top, cpu_ep, codec_ep, priv, &li); } if (ret < 0) return ret; @@ -491,9 +495,7 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) } static void asoc_graph_get_dais_count(struct device *dev, - int *link_num, - int *dais_num, - int *ccnf_num) + struct link_info *li) { struct of_phandle_iterator it; struct device_node *node = dev->of_node; @@ -566,8 +568,8 @@ static void asoc_graph_get_dais_count(struct device *dev, of_node_put(codec_ep); of_node_put(codec_port); - (*link_num)++; - (*dais_num)++; + li->link++; + li->dais++; memset(&adata, 0, sizeof(adata)); asoc_graph_card_get_conversion(dev, codec_ep, &adata); @@ -579,11 +581,11 @@ static void asoc_graph_get_dais_count(struct device *dev, if (codec_port_old == codec_port) continue; - (*link_num)++; - (*ccnf_num)++; - (*dais_num)++; + li->link++; + li->conf++; + li->dais++; } else { - (*dais_num)++; + li->dais++; } codec_port_old = codec_port; } @@ -615,7 +617,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct snd_soc_card *card; struct snd_soc_codec_conf *cconf; - int lnum = 0, dnum = 0, cnum = 0; + struct link_info li; int ret, i; /* Allocate the private data and the DAI link array */ @@ -623,14 +625,15 @@ static int asoc_graph_card_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - asoc_graph_get_dais_count(dev, &lnum, &dnum, &cnum); - if (!lnum || !dnum) + memset(&li, 0, sizeof(li)); + asoc_graph_get_dais_count(dev, &li); + if (!li.link || !li.dais) return -EINVAL; - dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); - dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); - dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); - cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); + dai_props = devm_kcalloc(dev, li.link, sizeof(*dai_props), GFP_KERNEL); + dai_link = devm_kcalloc(dev, li.link, sizeof(*dai_link), GFP_KERNEL); + dais = devm_kcalloc(dev, li.dais, sizeof(*dais), GFP_KERNEL); + cconf = devm_kcalloc(dev, li.conf, sizeof(*cconf), GFP_KERNEL); if (!dai_props || !dai_link || !dais) return -ENOMEM; @@ -640,7 +643,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) * see * soc-core.c :: snd_soc_init_multicodec() */ - for (i = 0; i < lnum; i++) { + for (i = 0; i < li.link; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; dai_link[i].platform = &dai_props[i].platform; @@ -663,12 +666,12 @@ static int asoc_graph_card_probe(struct platform_device *pdev) card->owner = THIS_MODULE; card->dev = dev; card->dai_link = dai_link; - card->num_links = lnum; + card->num_links = li.link; card->dapm_widgets = asoc_graph_card_dapm_widgets; card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets); card->probe = asoc_graph_soc_card_probe; card->codec_conf = cconf; - card->num_configs = cnum; + card->num_configs = li.conf; ret = asoc_graph_card_parse_of(priv); if (ret < 0) { From 9920480705320688844cb0cea9c38907be4872b5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:05 +0900 Subject: [PATCH 0960/1995] ASoC: audio-graph-card: cleanup DAI link loop method - step1 Current audio-graph-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. This patch adds/modifies counting and parsing function for "normal sound" and "DPCM sound", and call it from link loop. This is prepare for cleanup DAI link loop method. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit dd98fbc558a035728beed08a16c443f9fd37eb2b) --- sound/soc/generic/audio-graph-card.c | 134 ++++++++++++++++++--------- 1 file changed, 91 insertions(+), 43 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index cd9beb801fc1b8..fbd32129c5188f 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -192,23 +192,32 @@ static void asoc_graph_card_get_conversion(struct device *dev, asoc_simple_card_parse_convert(dev, ep, NULL, adata); } -static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, +static int asoc_graph_card_dai_link_of_dpcm(struct graph_card_data *priv, struct device_node *cpu_ep, struct device_node *codec_ep, - struct graph_card_data *priv, - struct link_info *li) + struct link_info *li, + int dup_codec) { struct device *dev = graph_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); + struct device_node *top = dev->of_node; struct device_node *ep = li->cpu ? cpu_ep : codec_ep; - struct device_node *port = of_get_parent(ep); - struct device_node *ports = of_get_parent(port); - struct device_node *node = of_graph_get_port_parent(ep); + struct device_node *port; + struct device_node *ports; + struct device_node *node; struct asoc_simple_dai *dai; struct snd_soc_dai_link_component *codecs = dai_link->codecs; int ret; + /* Do it all CPU endpoint, and 1st Codec endpoint */ + if (!li->cpu && dup_codec) + return 0; + + port = of_get_parent(ep); + ports = of_get_parent(port); + node = of_graph_get_port_parent(ep); + li->link++; dev_dbg(dev, "link_of DPCM (%pOF)\n", ep); @@ -222,6 +231,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, of_node_put(ports); of_node_put(port); + of_node_put(node); if (li->cpu) { @@ -318,23 +328,32 @@ static int asoc_graph_card_dai_link_of_dpcm(struct device_node *top, return 0; } -static int asoc_graph_card_dai_link_of(struct device_node *top, +static int asoc_graph_card_dai_link_of(struct graph_card_data *priv, struct device_node *cpu_ep, struct device_node *codec_ep, - struct graph_card_data *priv, struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); - struct device_node *cpu_port = of_get_parent(cpu_ep); - struct device_node *codec_port = of_get_parent(codec_ep); - struct device_node *cpu_ports = of_get_parent(cpu_port); - struct device_node *codec_ports = of_get_parent(codec_port); + struct device_node *top = dev->of_node; + struct device_node *cpu_port; + struct device_node *codec_port; + struct device_node *cpu_ports; + struct device_node *codec_ports; struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; int ret; + /* Do it only CPU turn */ + if (!li->cpu) + return 0; + + cpu_port = of_get_parent(cpu_ep); + cpu_ports = of_get_parent(cpu_port); + codec_port = of_get_parent(codec_ep); + codec_ports = of_get_parent(codec_port); + dev_dbg(dev, "link_of (%pOF)\n", cpu_ep); li->link++; @@ -471,22 +490,19 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) /* * for DPCM sound */ - if (!li.cpu) { - if (codec_port_old == codec_port) - continue; - codec_port_old = codec_port; - } ret = asoc_graph_card_dai_link_of_dpcm( - top, cpu_ep, codec_ep, priv, &li); + priv, cpu_ep, codec_ep, &li, + (codec_port_old == codec_port)); } else if (li.cpu) { /* * for Normal sound */ ret = asoc_graph_card_dai_link_of( - top, cpu_ep, codec_ep, priv, &li); + priv, cpu_ep, codec_ep, &li); } if (ret < 0) return ret; + codec_port_old = codec_port; } } } @@ -494,9 +510,47 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) return asoc_simple_card_parse_card_name(card, NULL); } -static void asoc_graph_get_dais_count(struct device *dev, +static int asoc_graph_card_count_noml(struct graph_card_data *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, struct link_info *li) { + struct device *dev = graph_priv_to_dev(priv); + + li->link += 1; /* 1xCPU-Codec */ + li->dais += 2; /* 1xCPU + 1xCodec */ + + dev_dbg(dev, "Count As Normal\n"); + + return 0; +} + +static int asoc_graph_card_count_dpcm(struct graph_card_data *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li, + int dup_codec) +{ + struct device *dev = graph_priv_to_dev(priv); + + li->link++; /* 1xCPU-dummy */ + li->dais++; /* 1xCPU */ + + if (!dup_codec) { + li->link++; /* 1xdummy-Codec */ + li->conf++; /* 1xdummy-Codec */ + li->dais++; /* 1xCodec */ + } + + dev_dbg(dev, "Count As DPCM\n"); + + return 0; +} + +static void asoc_graph_get_dais_count(struct graph_card_data *priv, + struct link_info *li) +{ + struct device *dev = graph_priv_to_dev(priv); struct of_phandle_iterator it; struct device_node *node = dev->of_node; struct device_node *cpu_port; @@ -568,24 +622,18 @@ static void asoc_graph_get_dais_count(struct device *dev, of_node_put(codec_ep); of_node_put(codec_port); - li->link++; - li->dais++; - memset(&adata, 0, sizeof(adata)); asoc_graph_card_get_conversion(dev, codec_ep, &adata); asoc_graph_card_get_conversion(dev, cpu_ep, &adata); if ((of_get_child_count(codec_port) > 1) || adata.convert_rate || adata.convert_channels) { - - if (codec_port_old == codec_port) - continue; - - li->link++; - li->conf++; - li->dais++; + asoc_graph_card_count_dpcm(priv, + cpu_ep, codec_ep, li, + (codec_port_old == codec_port)); } else { - li->dais++; + asoc_graph_card_count_noml(priv, + cpu_ep, codec_ep, li); } codec_port_old = codec_port; } @@ -625,8 +673,15 @@ static int asoc_graph_card_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + card = graph_priv_to_card(priv); + card->owner = THIS_MODULE; + card->dev = dev; + card->dapm_widgets = asoc_graph_card_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets); + card->probe = asoc_graph_soc_card_probe; + memset(&li, 0, sizeof(li)); - asoc_graph_get_dais_count(dev, &li); + asoc_graph_get_dais_count(priv, &li); if (!li.link || !li.dais) return -EINVAL; @@ -656,20 +711,13 @@ static int asoc_graph_card_probe(struct platform_device *pdev) return ret; } - priv->dai_props = dai_props; - priv->dai_link = dai_link; - priv->dais = dais; - priv->codec_conf = cconf; + priv->dai_props = dai_props; + priv->dai_link = dai_link; + priv->dais = dais; + priv->codec_conf = cconf; - /* Init snd_soc_card */ - card = graph_priv_to_card(priv); - card->owner = THIS_MODULE; - card->dev = dev; card->dai_link = dai_link; card->num_links = li.link; - card->dapm_widgets = asoc_graph_card_dapm_widgets; - card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets); - card->probe = asoc_graph_soc_card_probe; card->codec_conf = cconf; card->num_configs = li.conf; From 38c2af7971b22a4f4e81db54f9cede6b9766e593 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:20 +0900 Subject: [PATCH 0961/1995] ASoC: audio-graph-card: cleanup DAI link loop method - step2 Current audio-graph-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. This patch cleanups the code by using asoc_graph_card_for_each_link() which judges normal link / DPCM link. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit fce9b90c1ab7e915553c57353355700c79b39c86) --- sound/soc/generic/audio-graph-card.c | 168 ++++++++++++--------------- 1 file changed, 77 insertions(+), 91 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index fbd32129c5188f..1152de37110ed9 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -425,22 +425,80 @@ static int asoc_graph_card_dai_link_of(struct graph_card_data *priv, return 0; } -static int asoc_graph_card_parse_of(struct graph_card_data *priv) +static int asoc_graph_card_for_each_link(struct graph_card_data *priv, + struct link_info *li, + int (*func_noml)(struct graph_card_data *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li), + int (*func_dpcm)(struct graph_card_data *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li, int dup_codec)) { struct of_phandle_iterator it; struct device *dev = graph_priv_to_dev(priv); - struct snd_soc_card *card = graph_priv_to_card(priv); - struct device_node *top = dev->of_node; - struct device_node *node = top; + struct device_node *node = dev->of_node; struct device_node *cpu_port; - struct device_node *cpu_ep = NULL; - struct device_node *codec_ep = NULL; - struct device_node *codec_port = NULL; - struct device_node *codec_port_old = NULL; + struct device_node *cpu_ep; + struct device_node *codec_ep; + struct device_node *codec_port; + struct device_node *codec_port_old = NULL; struct asoc_simple_card_data adata; - struct link_info li; int rc, ret; + /* loop for all listed CPU port */ + of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { + cpu_port = it.node; + cpu_ep = NULL; + + /* loop for all CPU endpoint */ + while (1) { + cpu_ep = of_get_next_child(cpu_port, cpu_ep); + if (!cpu_ep) + break; + + /* get codec */ + codec_ep = of_graph_get_remote_endpoint(cpu_ep); + codec_port = of_get_parent(codec_ep); + + of_node_put(codec_ep); + of_node_put(codec_port); + + /* get convert-xxx property */ + memset(&adata, 0, sizeof(adata)); + asoc_graph_card_get_conversion(dev, codec_ep, &adata); + asoc_graph_card_get_conversion(dev, cpu_ep, &adata); + + /* + * It is DPCM + * if Codec port has many endpoints, + * or has convert-xxx property + */ + if ((of_get_child_count(codec_port) > 1) || + adata.convert_rate || adata.convert_channels) + ret = func_dpcm(priv, cpu_ep, codec_ep, li, + (codec_port_old == codec_port)); + /* else normal sound */ + else + ret = func_noml(priv, cpu_ep, codec_ep, li); + + if (ret < 0) + return ret; + + codec_port_old = codec_port; + } + } + + return 0; +} + +static int asoc_graph_card_parse_of(struct graph_card_data *priv) +{ + struct snd_soc_card *card = graph_priv_to_card(priv); + struct link_info li; + int ret; + ret = asoc_simple_card_of_parse_widgets(card, NULL); if (ret < 0) return ret; @@ -450,7 +508,6 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) return ret; memset(&li, 0, sizeof(li)); - codec_port_old = NULL; for (li.cpu = 1; li.cpu >= 0; li.cpu--) { /* * Detect all CPU first, and Detect all Codec 2nd. @@ -464,47 +521,11 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) * To avoid random sub-device numbering, * detect "dummy-Codec" in last; */ - of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { - cpu_port = it.node; - cpu_ep = NULL; - while (1) { - cpu_ep = of_get_next_child(cpu_port, cpu_ep); - if (!cpu_ep) - break; - - codec_ep = of_graph_get_remote_endpoint(cpu_ep); - codec_port = of_get_parent(codec_ep); - - of_node_put(codec_ep); - of_node_put(codec_port); - - dev_dbg(dev, "%pOFf <-> %pOFf\n", cpu_ep, codec_ep); - - memset(&adata, 0, sizeof(adata)); - asoc_graph_card_get_conversion(dev, codec_ep, &adata); - asoc_graph_card_get_conversion(dev, cpu_ep, &adata); - - if ((of_get_child_count(codec_port) > 1) || - adata.convert_rate || - adata.convert_channels) { - /* - * for DPCM sound - */ - ret = asoc_graph_card_dai_link_of_dpcm( - priv, cpu_ep, codec_ep, &li, - (codec_port_old == codec_port)); - } else if (li.cpu) { - /* - * for Normal sound - */ - ret = asoc_graph_card_dai_link_of( - priv, cpu_ep, codec_ep, &li); - } - if (ret < 0) - return ret; - codec_port_old = codec_port; - } - } + ret = asoc_graph_card_for_each_link(priv, &li, + asoc_graph_card_dai_link_of, + asoc_graph_card_dai_link_of_dpcm); + if (ret < 0) + return ret; } return asoc_simple_card_parse_card_name(card, NULL); @@ -551,15 +572,6 @@ static void asoc_graph_get_dais_count(struct graph_card_data *priv, struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); - struct of_phandle_iterator it; - struct device_node *node = dev->of_node; - struct device_node *cpu_port; - struct device_node *cpu_ep; - struct device_node *codec_ep; - struct device_node *codec_port; - struct device_node *codec_port_old; - struct asoc_simple_card_data adata; - int rc; /* * link_num : number of links. @@ -607,37 +619,11 @@ static void asoc_graph_get_dais_count(struct graph_card_data *priv, * => 4 DAIs = 2xCPU + 2xCodec * => 1 ccnf = 1xdummy-Codec */ - codec_port_old = NULL; - of_for_each_phandle(&it, rc, node, "dais", NULL, 0) { - cpu_port = it.node; - cpu_ep = NULL; - while (1) { - cpu_ep = of_get_next_child(cpu_port, cpu_ep); - if (!cpu_ep) - break; - - codec_ep = of_graph_get_remote_endpoint(cpu_ep); - codec_port = of_get_parent(codec_ep); - - of_node_put(codec_ep); - of_node_put(codec_port); - - memset(&adata, 0, sizeof(adata)); - asoc_graph_card_get_conversion(dev, codec_ep, &adata); - asoc_graph_card_get_conversion(dev, cpu_ep, &adata); - - if ((of_get_child_count(codec_port) > 1) || - adata.convert_rate || adata.convert_channels) { - asoc_graph_card_count_dpcm(priv, - cpu_ep, codec_ep, li, - (codec_port_old == codec_port)); - } else { - asoc_graph_card_count_noml(priv, - cpu_ep, codec_ep, li); - } - codec_port_old = codec_port; - } - } + asoc_graph_card_for_each_link(priv, li, + asoc_graph_card_count_noml, + asoc_graph_card_count_dpcm); + dev_dbg(dev, "link %d, dais %d, ccnf %d\n", + li->link, li->dais, li->conf); } static int asoc_graph_soc_card_probe(struct snd_soc_card *card) From a786c8f97a98f66d7832f0c8fe0e20e0fb0e8d09 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:33 +0900 Subject: [PATCH 0962/1995] ASoC: audio-graph-card: reduce naming prefix Current audio-graph-card is using asoc_graph_card_xxx() for function / data naming. Because of this long prefix, it is easy to be 80 character over. Let's reduce prefix from asoc_graph_card_xxx() to graph_xxx(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 97fe6ca4146583d8dccdde51c143c52b385c2682) --- sound/soc/generic/audio-graph-card.c | 164 +++++++++++++-------------- 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 1152de37110ed9..3ec96cdc683b5a 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -20,7 +20,7 @@ #include #include -struct graph_card_data { +struct graph_priv { struct snd_soc_card snd_card; struct graph_dai_props { struct asoc_simple_dai *cpu_dai; @@ -53,12 +53,12 @@ struct link_info { #define PREFIX "audio-graph-card," -static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event) +static int graph_outdrv_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) { struct snd_soc_dapm_context *dapm = w->dapm; - struct graph_card_data *priv = snd_soc_card_get_drvdata(dapm->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(dapm->card); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -74,16 +74,16 @@ static int asoc_graph_card_outdrv_event(struct snd_soc_dapm_widget *w, return 0; } -static const struct snd_soc_dapm_widget asoc_graph_card_dapm_widgets[] = { +static const struct snd_soc_dapm_widget graph_dapm_widgets[] = { SND_SOC_DAPM_OUT_DRV_E("Amplifier", SND_SOC_NOPM, - 0, 0, NULL, 0, asoc_graph_card_outdrv_event, + 0, 0, NULL, 0, graph_outdrv_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), }; -static int asoc_graph_card_startup(struct snd_pcm_substream *substream) +static int graph_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); int ret; @@ -98,10 +98,10 @@ static int asoc_graph_card_startup(struct snd_pcm_substream *substream) return ret; } -static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) +static void graph_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); asoc_simple_card_clk_disable(dai_props->cpu_dai); @@ -109,13 +109,13 @@ static void asoc_graph_card_shutdown(struct snd_pcm_substream *substream) asoc_simple_card_clk_disable(dai_props->codec_dai); } -static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int graph_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; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); unsigned int mclk, mclk_fs = 0; int ret = 0; @@ -140,15 +140,15 @@ static int asoc_graph_card_hw_params(struct snd_pcm_substream *substream, return ret; } -static const struct snd_soc_ops asoc_graph_card_ops = { - .startup = asoc_graph_card_startup, - .shutdown = asoc_graph_card_shutdown, - .hw_params = asoc_graph_card_hw_params, +static const struct snd_soc_ops graph_ops = { + .startup = graph_startup, + .shutdown = graph_shutdown, + .hw_params = graph_hw_params, }; -static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) +static int graph_dai_init(struct snd_soc_pcm_runtime *rtd) { - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); int ret = 0; @@ -165,10 +165,10 @@ static int asoc_graph_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) +static int graph_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) { - struct graph_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct graph_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct graph_dai_props *dai_props = graph_priv_to_props(priv, rtd->num); asoc_simple_card_convert_fixup(&dai_props->adata, params); @@ -176,9 +176,9 @@ static int asoc_graph_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static void asoc_graph_card_get_conversion(struct device *dev, - struct device_node *ep, - struct asoc_simple_card_data *adata) +static void graph_get_conversion(struct device *dev, + struct device_node *ep, + struct asoc_simple_card_data *adata) { struct device_node *top = dev->of_node; struct device_node *port = of_get_parent(ep); @@ -192,11 +192,11 @@ static void asoc_graph_card_get_conversion(struct device *dev, asoc_simple_card_parse_convert(dev, ep, NULL, adata); } -static int asoc_graph_card_dai_link_of_dpcm(struct graph_card_data *priv, - struct device_node *cpu_ep, - struct device_node *codec_ep, - struct link_info *li, - int dup_codec) +static int graph_dai_link_of_dpcm(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li, + int dup_codec) { struct device *dev = graph_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); @@ -227,7 +227,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct graph_card_data *priv, of_property_read_u32(port, "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(ep, "mclk-fs", &dai_props->mclk_fs); - asoc_graph_card_get_conversion(dev, ep, &dai_props->adata); + graph_get_conversion(dev, ep, &dai_props->adata); of_node_put(ports); of_node_put(port); @@ -274,7 +274,7 @@ static int asoc_graph_card_dai_link_of_dpcm(struct graph_card_data *priv, /* BE settings */ dai_link->no_pcm = 1; - dai_link->be_hw_params_fixup = asoc_graph_card_be_hw_params_fixup; + dai_link->be_hw_params_fixup = graph_be_hw_params_fixup; dai = dai_props->codec_dai = &priv->dais[li->dais++]; @@ -322,24 +322,24 @@ static int asoc_graph_card_dai_link_of_dpcm(struct graph_card_data *priv, dai_link->dpcm_playback = 1; dai_link->dpcm_capture = 1; - dai_link->ops = &asoc_graph_card_ops; - dai_link->init = asoc_graph_card_dai_init; + dai_link->ops = &graph_ops; + dai_link->init = graph_dai_init; return 0; } -static int asoc_graph_card_dai_link_of(struct graph_card_data *priv, - struct device_node *cpu_ep, - struct device_node *codec_ep, - struct link_info *li) +static int graph_dai_link_of(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = graph_priv_to_link(priv, li->link); struct graph_dai_props *dai_props = graph_priv_to_props(priv, li->link); struct device_node *top = dev->of_node; struct device_node *cpu_port; - struct device_node *codec_port; struct device_node *cpu_ports; + struct device_node *codec_port; struct device_node *codec_ports; struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; @@ -416,8 +416,8 @@ static int asoc_graph_card_dai_link_of(struct graph_card_data *priv, if (ret < 0) return ret; - dai_link->ops = &asoc_graph_card_ops; - dai_link->init = asoc_graph_card_dai_init; + dai_link->ops = &graph_ops; + dai_link->init = graph_dai_init; asoc_simple_card_canonicalize_cpu(dai_link, of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); @@ -425,13 +425,13 @@ static int asoc_graph_card_dai_link_of(struct graph_card_data *priv, return 0; } -static int asoc_graph_card_for_each_link(struct graph_card_data *priv, +static int graph_for_each_link(struct graph_priv *priv, struct link_info *li, - int (*func_noml)(struct graph_card_data *priv, + int (*func_noml)(struct graph_priv *priv, struct device_node *cpu_ep, struct device_node *codec_ep, struct link_info *li), - int (*func_dpcm)(struct graph_card_data *priv, + int (*func_dpcm)(struct graph_priv *priv, struct device_node *cpu_ep, struct device_node *codec_ep, struct link_info *li, int dup_codec)) @@ -467,8 +467,8 @@ static int asoc_graph_card_for_each_link(struct graph_card_data *priv, /* get convert-xxx property */ memset(&adata, 0, sizeof(adata)); - asoc_graph_card_get_conversion(dev, codec_ep, &adata); - asoc_graph_card_get_conversion(dev, cpu_ep, &adata); + graph_get_conversion(dev, codec_ep, &adata); + graph_get_conversion(dev, cpu_ep, &adata); /* * It is DPCM @@ -493,7 +493,7 @@ static int asoc_graph_card_for_each_link(struct graph_card_data *priv, return 0; } -static int asoc_graph_card_parse_of(struct graph_card_data *priv) +static int graph_parse_of(struct graph_priv *priv) { struct snd_soc_card *card = graph_priv_to_card(priv); struct link_info li; @@ -521,9 +521,9 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) * To avoid random sub-device numbering, * detect "dummy-Codec" in last; */ - ret = asoc_graph_card_for_each_link(priv, &li, - asoc_graph_card_dai_link_of, - asoc_graph_card_dai_link_of_dpcm); + ret = graph_for_each_link(priv, &li, + graph_dai_link_of, + graph_dai_link_of_dpcm); if (ret < 0) return ret; } @@ -531,10 +531,10 @@ static int asoc_graph_card_parse_of(struct graph_card_data *priv) return asoc_simple_card_parse_card_name(card, NULL); } -static int asoc_graph_card_count_noml(struct graph_card_data *priv, - struct device_node *cpu_ep, - struct device_node *codec_ep, - struct link_info *li) +static int graph_count_noml(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); @@ -546,11 +546,11 @@ static int asoc_graph_card_count_noml(struct graph_card_data *priv, return 0; } -static int asoc_graph_card_count_dpcm(struct graph_card_data *priv, - struct device_node *cpu_ep, - struct device_node *codec_ep, - struct link_info *li, - int dup_codec) +static int graph_count_dpcm(struct graph_priv *priv, + struct device_node *cpu_ep, + struct device_node *codec_ep, + struct link_info *li, + int dup_codec) { struct device *dev = graph_priv_to_dev(priv); @@ -568,8 +568,8 @@ static int asoc_graph_card_count_dpcm(struct graph_card_data *priv, return 0; } -static void asoc_graph_get_dais_count(struct graph_card_data *priv, - struct link_info *li) +static void graph_get_dais_count(struct graph_priv *priv, + struct link_info *li) { struct device *dev = graph_priv_to_dev(priv); @@ -619,16 +619,16 @@ static void asoc_graph_get_dais_count(struct graph_card_data *priv, * => 4 DAIs = 2xCPU + 2xCodec * => 1 ccnf = 1xdummy-Codec */ - asoc_graph_card_for_each_link(priv, li, - asoc_graph_card_count_noml, - asoc_graph_card_count_dpcm); + graph_for_each_link(priv, li, + graph_count_noml, + graph_count_dpcm); dev_dbg(dev, "link %d, dais %d, ccnf %d\n", li->link, li->dais, li->conf); } -static int asoc_graph_soc_card_probe(struct snd_soc_card *card) +static int graph_card_probe(struct snd_soc_card *card) { - struct graph_card_data *priv = snd_soc_card_get_drvdata(card); + struct graph_priv *priv = snd_soc_card_get_drvdata(card); int ret; ret = asoc_simple_card_init_hp(card, &priv->hp_jack, NULL); @@ -642,9 +642,9 @@ static int asoc_graph_soc_card_probe(struct snd_soc_card *card) return 0; } -static int asoc_graph_card_probe(struct platform_device *pdev) +static int graph_probe(struct platform_device *pdev) { - struct graph_card_data *priv; + struct graph_priv *priv; struct snd_soc_dai_link *dai_link; struct graph_dai_props *dai_props; struct asoc_simple_dai *dais; @@ -662,12 +662,12 @@ static int asoc_graph_card_probe(struct platform_device *pdev) card = graph_priv_to_card(priv); card->owner = THIS_MODULE; card->dev = dev; - card->dapm_widgets = asoc_graph_card_dapm_widgets; - card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets); - card->probe = asoc_graph_soc_card_probe; + card->dapm_widgets = graph_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(graph_dapm_widgets); + card->probe = graph_card_probe; memset(&li, 0, sizeof(li)); - asoc_graph_get_dais_count(priv, &li); + graph_get_dais_count(priv, &li); if (!li.link || !li.dais) return -EINVAL; @@ -707,7 +707,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev) card->codec_conf = cconf; card->num_configs = li.conf; - ret = asoc_graph_card_parse_of(priv); + ret = graph_parse_of(priv); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(dev, "parse error %d\n", ret); @@ -727,30 +727,30 @@ static int asoc_graph_card_probe(struct platform_device *pdev) return ret; } -static int asoc_graph_card_remove(struct platform_device *pdev) +static int graph_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); return asoc_simple_card_clean_reference(card); } -static const struct of_device_id asoc_graph_of_match[] = { +static const struct of_device_id graph_of_match[] = { { .compatible = "audio-graph-card", }, { .compatible = "audio-graph-scu-card", }, {}, }; -MODULE_DEVICE_TABLE(of, asoc_graph_of_match); +MODULE_DEVICE_TABLE(of, graph_of_match); -static struct platform_driver asoc_graph_card = { +static struct platform_driver graph_card = { .driver = { .name = "asoc-audio-graph-card", .pm = &snd_soc_pm_ops, - .of_match_table = asoc_graph_of_match, + .of_match_table = graph_of_match, }, - .probe = asoc_graph_card_probe, - .remove = asoc_graph_card_remove, + .probe = graph_probe, + .remove = graph_remove, }; -module_platform_driver(asoc_graph_card); +module_platform_driver(graph_card); MODULE_ALIAS("platform:asoc-audio-graph-card"); MODULE_LICENSE("GPL v2"); From 9e4c6fbb295c4d1caf95016ff74c785d03604f0f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:42 +0900 Subject: [PATCH 0963/1995] ASoC: simple-card: add asoc_simple_card_get_conversion() simple-card is now supporting normal sound and DPCM sound. For DPCM sound, original sound card (= simple-scu-card) had been supported 1 CPU : 1 Codec connection which uses hw_params_fixup() for convert-rate/channel. But, merged simple-card is completely forgeting about it. To re-support 1 CPU : 1 Codec DPCM for hw_params_fixup(), it need to judge whether it is DPCM by checking convert-rate/channel. For this purpose, this patch adds asoc_simple_card_get_conversion() as preparation Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 7e5e1f8bbaa82e6877d8bc121cb1b44cb1ce7ddf) --- sound/soc/generic/simple-card.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 3fe34417ec897d..2a9a2df0a1156a 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -165,6 +165,21 @@ static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } +static void asoc_simple_card_get_conversion(struct device *dev, + struct device_node *np, + struct asoc_simple_card_data *adata) +{ + struct device_node *top = dev->of_node; + struct device_node *node = of_get_parent(np); + + asoc_simple_card_parse_convert(dev, top, PREFIX, adata); + asoc_simple_card_parse_convert(dev, node, PREFIX, adata); + asoc_simple_card_parse_convert(dev, node, NULL, adata); + asoc_simple_card_parse_convert(dev, np, NULL, adata); + + of_node_put(node); +} + static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, struct device_node *node, struct device_node *np, @@ -260,9 +275,7 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, "prefix"); } - asoc_simple_card_parse_convert(dev, top, PREFIX, &dai_props->adata); - asoc_simple_card_parse_convert(dev, node, prefix, &dai_props->adata); - asoc_simple_card_parse_convert(dev, np, NULL, &dai_props->adata); + asoc_simple_card_get_conversion(dev, np, &dai_props->adata); ret = asoc_simple_card_of_parse_tdm(np, dai); if (ret) From 4ded7c5e3465143f5ab90341b715442d234d359f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:47 +0900 Subject: [PATCH 0964/1995] ASoC: simple-card: add 1 CPU : 1 Codec support again simple-card is now supporting normal sound and DPCM sound. For DPCM sound, original sound card (= simple-scu-card) had been supported 1 CPU : 1 Codec connection which uses hw_params_fixup() for convert-rate/channel. But, merged simple-card is completely forgeting about it. This patch re-support it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 7adee60ee2732f23f703ff83ee35caad561490ba) --- sound/soc/generic/simple-card.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 2a9a2df0a1156a..d65d6fd0e780a6 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -453,6 +453,7 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) struct device_node *node; struct device_node *np; struct device_node *codec; + struct asoc_simple_card_data adata; bool is_fe; int ret, loop; int dai_idx, link_idx, conf_idx; @@ -480,8 +481,13 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) } do { + memset(&adata, 0, sizeof(adata)); + for_each_child_of_node(node, np) + asoc_simple_card_get_conversion(dev, np, &adata); + /* DPCM */ - if (of_get_child_count(node) > 2) { + if (of_get_child_count(node) > 2 || + adata.convert_rate || adata.convert_channels) { for_each_child_of_node(node, np) { codec = of_get_child_by_name(node, loop ? "codec" : @@ -495,14 +501,16 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) top, node, np, codec, priv, &dai_idx, link_idx++, &conf_idx, is_fe, !loop); + if (ret < 0) + return ret; } } else { ret = asoc_simple_card_dai_link_of( top, node, priv, &dai_idx, link_idx++, !loop); + if (ret < 0) + return ret; } - if (ret < 0) - return ret; node = of_get_next_child(top, node); } while (loop && node); @@ -523,6 +531,8 @@ static void asoc_simple_card_get_dais_count(struct device *dev, { struct device_node *top = dev->of_node; struct device_node *node; + struct device_node *np; + struct asoc_simple_card_data adata; int loop; int num; @@ -562,6 +572,15 @@ static void asoc_simple_card_get_dais_count(struct device *dev, * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec * => 6 DAIs = 4xCPU + 2xCodec * => 2 ccnf = 2xdummy-Codec + * + * ex4) + * CPU0 --- Codec0 (convert-rate) link : 3 + * CPU1 --- Codec1 dais : 4 + * ccnf : 1 + * + * => 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec + * => 4 DAIs = 2xCPU + 2xCodec + * => 1 ccnf = 1xdummy-Codec */ if (!top) { (*link_num) = 1; @@ -578,9 +597,14 @@ static void asoc_simple_card_get_dais_count(struct device *dev, } do { + memset(&adata, 0, sizeof(adata)); + for_each_child_of_node(node, np) + asoc_simple_card_get_conversion(dev, np, &adata); + num = of_get_child_count(node); (*dais_num) += num; - if (num > 2) { + if (num > 2 || + adata.convert_rate || adata.convert_channels) { (*link_num) += num; (*ccnf_num)++; } else { From 6b54d727afe5abb014ee61ac1369c940a55953b9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:46:53 +0900 Subject: [PATCH 0965/1995] ASoC: simple-card: add link_info Current simple-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. To preparing cleanup code, this patch adds link_info which handles number of DAIs/Links/Codec Conf, and CPU/Codec turn. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 17029e494edc68337c9b99665e8f9b478f1d4ec5) --- sound/soc/generic/simple-card.c | 94 ++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index d65d6fd0e780a6..d79ddec8db24c6 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -33,6 +33,13 @@ struct simple_card_data { struct snd_soc_codec_conf *codec_conf; }; +struct link_info { + int dais; /* number of dai */ + int link; /* number of link */ + int conf; /* number of codec_conf */ + int cpu; /* turn for CPU / Codec */ +}; + #define simple_priv_to_card(priv) (&(priv)->snd_card) #define simple_priv_to_props(priv, i) ((priv)->dai_props + (i)) #define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev) @@ -185,25 +192,27 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, struct device_node *np, struct device_node *codec, struct simple_card_data *priv, - int *dai_idx, int link_idx, - int *conf_idx, int is_fe, + struct link_info *li, bool is_top_level_node) { struct device *dev = simple_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx); + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct asoc_simple_dai *dai; struct snd_soc_dai_link_component *codecs = dai_link->codecs; - char prop[128]; char *prefix = ""; int ret; + dev_dbg(dev, "link_of DPCM (%pOF)\n", np); + + li->link++; + /* For single DAI link & old style of DT node */ if (is_top_level_node) prefix = PREFIX; - if (is_fe) { + if (np != codec) { int is_single_links = 0; /* BE is dummy */ @@ -216,7 +225,7 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, dai_link->dpcm_merged_format = 1; dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; + dai_props->cpu_dai = &priv->dais[li->dais++]; ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL, &is_single_links); @@ -247,10 +256,10 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup; dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; + dai_props->codec_dai = &priv->dais[li->dais++]; cconf = - dai_props->codec_conf = &priv->codec_conf[(*conf_idx)++]; + dai_props->codec_conf = &priv->codec_conf[li->conf++]; ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL); if (ret < 0) @@ -306,12 +315,12 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, static int asoc_simple_card_dai_link_of(struct device_node *top, struct device_node *node, struct simple_card_data *priv, - int *dai_idx, int link_idx, + struct link_info *li, bool is_top_level_node) { struct device *dev = simple_priv_to_dev(priv); - struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, link_idx); - struct simple_dai_props *dai_props = simple_priv_to_props(priv, link_idx); + struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); + struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; struct device_node *cpu = NULL; @@ -321,6 +330,10 @@ static int asoc_simple_card_dai_link_of(struct device_node *top, char *prefix = ""; int ret, single_cpu; + li->link++; + + dev_dbg(dev, "link_of (%pOF)\n", node); + /* For single DAI link & old style of DT node */ if (is_top_level_node) prefix = PREFIX; @@ -347,9 +360,9 @@ static int asoc_simple_card_dai_link_of(struct device_node *top, } cpu_dai = - dai_props->cpu_dai = &priv->dais[(*dai_idx)++]; + dai_props->cpu_dai = &priv->dais[li->dais++]; codec_dai = - dai_props->codec_dai = &priv->dais[(*dai_idx)++]; + dai_props->codec_dai = &priv->dais[li->dais++]; ret = asoc_simple_card_parse_daifmt(dev, node, codec, prefix, &dai_link->dai_fmt); @@ -454,9 +467,8 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) struct device_node *np; struct device_node *codec; struct asoc_simple_card_data adata; - bool is_fe; + struct link_info li; int ret, loop; - int dai_idx, link_idx, conf_idx; if (!top) return -EINVAL; @@ -470,10 +482,8 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) return ret; /* Single/Muti DAI link(s) & New style of DT node */ + memset(&li, 0, sizeof(li)); loop = 1; - link_idx = 0; - dai_idx = 0; - conf_idx = 0; node = of_get_child_by_name(top, PREFIX "dai-link"); if (!node) { node = of_node_get(top); @@ -495,19 +505,16 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) if (!codec) return -ENODEV; - is_fe = (np != codec); - ret = asoc_simple_card_dai_link_of_dpcm( top, node, np, codec, priv, - &dai_idx, link_idx++, &conf_idx, - is_fe, !loop); + &li, !loop); if (ret < 0) return ret; } } else { ret = asoc_simple_card_dai_link_of( top, node, priv, - &dai_idx, link_idx++, !loop); + &li, !loop); if (ret < 0) return ret; } @@ -525,9 +532,7 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) } static void asoc_simple_card_get_dais_count(struct device *dev, - int *link_num, - int *dais_num, - int *ccnf_num) + struct link_info *li) { struct device_node *top = dev->of_node; struct device_node *node; @@ -583,9 +588,9 @@ static void asoc_simple_card_get_dais_count(struct device *dev, * => 1 ccnf = 1xdummy-Codec */ if (!top) { - (*link_num) = 1; - (*dais_num) = 2; - (*ccnf_num) = 0; + li->link = 1; + li->dais = 2; + li->conf = 0; return; } @@ -602,13 +607,13 @@ static void asoc_simple_card_get_dais_count(struct device *dev, asoc_simple_card_get_conversion(dev, np, &adata); num = of_get_child_count(node); - (*dais_num) += num; + li->dais += num; if (num > 2 || adata.convert_rate || adata.convert_channels) { - (*link_num) += num; - (*ccnf_num)++; + li->link += num; + li->conf++; } else { - (*link_num)++; + li->link++; } node = of_get_next_child(top, node); } while (loop && node); @@ -640,7 +645,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct snd_soc_card *card; struct snd_soc_codec_conf *cconf; - int lnum = 0, dnum = 0, cnum = 0; + struct link_info li; int ret, i; /* Allocate the private data and the DAI link array */ @@ -648,14 +653,15 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - asoc_simple_card_get_dais_count(dev, &lnum, &dnum, &cnum); - if (!lnum || !dnum) + memset(&li, 0, sizeof(li)); + asoc_simple_card_get_dais_count(dev, &li); + if (!li.link || !li.dais) return -EINVAL; - dai_props = devm_kcalloc(dev, lnum, sizeof(*dai_props), GFP_KERNEL); - dai_link = devm_kcalloc(dev, lnum, sizeof(*dai_link), GFP_KERNEL); - dais = devm_kcalloc(dev, dnum, sizeof(*dais), GFP_KERNEL); - cconf = devm_kcalloc(dev, cnum, sizeof(*cconf), GFP_KERNEL); + dai_props = devm_kcalloc(dev, li.link, sizeof(*dai_props), GFP_KERNEL); + dai_link = devm_kcalloc(dev, li.link, sizeof(*dai_link), GFP_KERNEL); + dais = devm_kcalloc(dev, li.dais, sizeof(*dais), GFP_KERNEL); + cconf = devm_kcalloc(dev, li.conf, sizeof(*cconf), GFP_KERNEL); if (!dai_props || !dai_link || !dais) return -ENOMEM; @@ -665,7 +671,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) * see * soc-core.c :: snd_soc_init_multicodec() */ - for (i = 0; i < lnum; i++) { + for (i = 0; i < li.link; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; dai_link[i].platform = &dai_props[i].platform; @@ -681,9 +687,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev) card->owner = THIS_MODULE; card->dev = dev; card->dai_link = priv->dai_link; - card->num_links = lnum; + card->num_links = li.link; card->codec_conf = cconf; - card->num_configs = cnum; + card->num_configs = li.conf; card->probe = asoc_simple_soc_card_probe; if (np && of_device_is_available(np)) { From b3b807bb69a98952d3a7b64faf0627c87d9ade23 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:47:23 +0900 Subject: [PATCH 0966/1995] ASoC: simple-card: cleanup DAI link loop method - step1 Current simple-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. This patch adds/modifies counting and parsing function for "normal sound" and "DPCM sound", and call it from link loop. This is prepare for cleanup DAI link loop method. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit d947cdfd4be29c48c6c529c2b5ce7b1988387c67) --- sound/soc/generic/simple-card.c | 210 +++++++++++++++++++++----------- 1 file changed, 137 insertions(+), 73 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index d79ddec8db24c6..23e295a4feebb4 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -187,32 +187,43 @@ static void asoc_simple_card_get_conversion(struct device *dev, of_node_put(node); } -static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, - struct device_node *node, +static int asoc_simple_card_dai_link_of_dpcm(struct simple_card_data *priv, struct device_node *np, struct device_node *codec, - struct simple_card_data *priv, struct link_info *li, - bool is_top_level_node) + bool is_top) { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct asoc_simple_dai *dai; struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct device_node *top = dev->of_node; + struct device_node *node = of_get_parent(np); char prop[128]; char *prefix = ""; int ret; + /* + * |CPU |Codec : turn + * CPU |Pass |return + * Codec |return|Pass + * np + */ + if (li->cpu == (np == codec)) + return 0; + dev_dbg(dev, "link_of DPCM (%pOF)\n", np); li->link++; + of_node_put(node); + /* For single DAI link & old style of DT node */ - if (is_top_level_node) + if (is_top) prefix = PREFIX; - if (np != codec) { + if (li->cpu) { int is_single_links = 0; /* BE is dummy */ @@ -312,53 +323,47 @@ static int asoc_simple_card_dai_link_of_dpcm(struct device_node *top, return 0; } -static int asoc_simple_card_dai_link_of(struct device_node *top, - struct device_node *node, - struct simple_card_data *priv, +static int asoc_simple_card_dai_link_of(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, struct link_info *li, - bool is_top_level_node) + bool is_top) { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; + struct device_node *top = dev->of_node; struct device_node *cpu = NULL; + struct device_node *node = NULL; struct device_node *plat = NULL; - struct device_node *codec = NULL; char prop[128]; char *prefix = ""; int ret, single_cpu; + /* + * |CPU |Codec : turn + * CPU |Pass |return + * Codec |return|return + * np + */ + if (!li->cpu || np == codec) + return 0; + + cpu = np; + node = of_get_parent(np); li->link++; dev_dbg(dev, "link_of (%pOF)\n", node); /* For single DAI link & old style of DT node */ - if (is_top_level_node) + if (is_top) prefix = PREFIX; - snprintf(prop, sizeof(prop), "%scpu", prefix); - cpu = of_get_child_by_name(node, prop); - - if (!cpu) { - ret = -EINVAL; - dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); - goto dai_link_of_err; - } - snprintf(prop, sizeof(prop), "%splat", prefix); plat = of_get_child_by_name(node, prop); - snprintf(prop, sizeof(prop), "%scodec", prefix); - codec = of_get_child_by_name(node, prop); - - if (!codec) { - ret = -EINVAL; - dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); - goto dai_link_of_err; - } - cpu_dai = dai_props->cpu_dai = &priv->dais[li->dais++]; codec_dai = @@ -421,8 +426,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *top, asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); dai_link_of_err: - of_node_put(cpu); - of_node_put(codec); + of_node_put(node); return ret; } @@ -464,9 +468,6 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) struct device_node *top = dev->of_node; struct snd_soc_card *card = simple_priv_to_card(priv); struct device_node *node; - struct device_node *np; - struct device_node *codec; - struct asoc_simple_card_data adata; struct link_info li; int ret, loop; @@ -483,6 +484,10 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) /* Single/Muti DAI link(s) & New style of DT node */ memset(&li, 0, sizeof(li)); + + /* FIXME */ + li.cpu = 1; +parse_loop: loop = 1; node = of_get_child_by_name(top, PREFIX "dai-link"); if (!node) { @@ -491,37 +496,59 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) } do { + struct asoc_simple_card_data adata; + struct device_node *codec; + struct device_node *np; + int num = of_get_child_count(node); + int ret; + + codec = of_get_child_by_name(node, !loop ? + PREFIX "codec" : "codec"); + if (!codec) + return -ENODEV; + + of_node_put(codec); + memset(&adata, 0, sizeof(adata)); for_each_child_of_node(node, np) asoc_simple_card_get_conversion(dev, np, &adata); - /* DPCM */ - if (of_get_child_count(node) > 2 || - adata.convert_rate || adata.convert_channels) { - for_each_child_of_node(node, np) { - codec = of_get_child_by_name(node, - loop ? "codec" : - PREFIX "codec"); - if (!codec) - return -ENODEV; - + /* + * Detect all CPU first, and Detect all Codec 2nd. + * + * In Normal sound case, all DAIs are detected + * as "CPU-Codec". + * + * In DPCM sound case, + * all CPUs are detected as "CPU-dummy", and + * all Codecs are detected as "dummy-Codec". + * To avoid random sub-device numbering, + * detect "dummy-Codec" in last; + */ + + /* loop for all CPU/Codec node */ + for_each_child_of_node(node, np) { + if (num > 2 || + adata.convert_rate || adata.convert_channels) { ret = asoc_simple_card_dai_link_of_dpcm( - top, node, np, codec, priv, - &li, !loop); + priv, np, codec, &li, !loop); + if (ret < 0) + return ret; + } else { + ret = asoc_simple_card_dai_link_of( + priv, np, codec, &li, !loop); if (ret < 0) return ret; } - } else { - ret = asoc_simple_card_dai_link_of( - top, node, priv, - &li, !loop); - if (ret < 0) - return ret; } - node = of_get_next_child(top, node); } while (loop && node); + /* FIXME */ + li.cpu--; + if (li.cpu >= 0) + goto parse_loop; + ret = asoc_simple_card_parse_card_name(card, PREFIX); if (ret < 0) return ret; @@ -531,12 +558,39 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) return ret; } -static void asoc_simple_card_get_dais_count(struct device *dev, +static int asoc_simple_card_count_noml(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top) +{ + li->dais++; /* CPU or Codec */ + if (np != codec) + li->link++; /* CPU-Codec */ + + return 0; +} + +static int asoc_simple_card_count_dpcm(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top) +{ + li->dais++; /* CPU or Codec */ + li->link++; /* CPU-dummy or dummy-Codec */ + if (np == codec) + li->conf++; + + return 0; +} + +static void asoc_simple_card_get_dais_count(struct simple_card_data *priv, struct link_info *li) { + struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; struct device_node *node; struct device_node *np; + struct device_node *codec; struct asoc_simple_card_data adata; int loop; int num; @@ -602,18 +656,28 @@ static void asoc_simple_card_get_dais_count(struct device *dev, } do { + num = of_get_child_count(node); + + codec = of_get_child_by_name(node, !loop ? + PREFIX "codec" : "codec"); + if (!codec) + return; + + of_node_put(codec); + memset(&adata, 0, sizeof(adata)); for_each_child_of_node(node, np) asoc_simple_card_get_conversion(dev, np, &adata); - num = of_get_child_count(node); - li->dais += num; - if (num > 2 || - adata.convert_rate || adata.convert_channels) { - li->link += num; - li->conf++; - } else { - li->link++; + for_each_child_of_node(node, np) { + if (num > 2 || + adata.convert_rate || adata.convert_channels) { + asoc_simple_card_count_dpcm(priv, np, codec, + li, !loop); + } else { + asoc_simple_card_count_noml(priv, np, codec, + li, !loop); + } } node = of_get_next_child(top, node); } while (loop && node); @@ -653,8 +717,13 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + card = simple_priv_to_card(priv); + card->owner = THIS_MODULE; + card->dev = dev; + card->probe = asoc_simple_soc_card_probe; + memset(&li, 0, sizeof(li)); - asoc_simple_card_get_dais_count(dev, &li); + asoc_simple_card_get_dais_count(priv, &li); if (!li.link || !li.dais) return -EINVAL; @@ -677,20 +746,15 @@ static int asoc_simple_card_probe(struct platform_device *pdev) dai_link[i].platform = &dai_props[i].platform; } - priv->dai_props = dai_props; - priv->dai_link = dai_link; - priv->dais = dais; - priv->codec_conf = cconf; + priv->dai_props = dai_props; + priv->dai_link = dai_link; + priv->dais = dais; + priv->codec_conf = cconf; - /* Init snd_soc_card */ - card = simple_priv_to_card(priv); - card->owner = THIS_MODULE; - card->dev = dev; card->dai_link = priv->dai_link; card->num_links = li.link; card->codec_conf = cconf; card->num_configs = li.conf; - card->probe = asoc_simple_soc_card_probe; if (np && of_device_is_available(np)) { From 29d77df0ee6e28fb60276c105008831cd807b0de Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:47:28 +0900 Subject: [PATCH 0967/1995] [BP_CONFLICT] ASoC: simple-card: cleanup DAI link loop method - step2 Current simple-card is parsing DAI link for both "normal sound" and "DPCM sound". On this driver, it needs to count and parse DAIs/Links/Codec Conf from each links. Then, counting/parsing link loop are very similar, but using different implementation. Because of this background, the link loop code is very mysterious. Mystery code will be trouble in the future. This patch cleanups the code by using asoc_simple_card_for_each_link() which judges normal link / DPCM link. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit c39291a76444e3177f7a89d603eae7f83fbdb9f9) --- sound/soc/generic/simple-card.c | 174 +++++++++++++++----------------- 1 file changed, 81 insertions(+), 93 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 23e295a4feebb4..e796b1516b4025 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -431,6 +431,74 @@ static int asoc_simple_card_dai_link_of(struct simple_card_data *priv, return ret; } +static int asoc_simple_card_for_each_link(struct simple_card_data *priv, + struct link_info *li, + int (*func_noml)(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top), + int (*func_dpcm)(struct simple_card_data *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top)) +{ + struct device *dev = simple_priv_to_dev(priv); + struct device_node *top = dev->of_node; + struct device_node *node; + bool is_top = 0; + + /* Check if it has dai-link */ + node = of_get_child_by_name(top, PREFIX "dai-link"); + if (!node) { + node = top; + is_top = 1; + } + + /* loop for all dai-link */ + do { + struct asoc_simple_card_data adata; + struct device_node *codec; + struct device_node *np; + int num = of_get_child_count(node); + int ret; + + /* get codec */ + codec = of_get_child_by_name(node, is_top ? + PREFIX "codec" : "codec"); + if (!codec) + return -ENODEV; + + of_node_put(codec); + + /* get convert-xxx property */ + memset(&adata, 0, sizeof(adata)); + for_each_child_of_node(node, np) + asoc_simple_card_get_conversion(dev, np, &adata); + + /* loop for all CPU/Codec node */ + for_each_child_of_node(node, np) { + /* + * It is DPCM + * if it has many CPUs, + * or has convert-xxx property + */ + if (num > 2 || + adata.convert_rate || adata.convert_channels) + ret = func_dpcm(priv, np, codec, li, is_top); + /* else normal sound */ + else + ret = func_noml(priv, np, codec, li, is_top); + + if (ret < 0) + return ret; + } + + node = of_get_next_child(top, node); + } while (!is_top && node); + + return 0; +} + static int asoc_simple_card_parse_aux_devs(struct device_node *node, struct simple_card_data *priv) { @@ -467,9 +535,8 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; struct snd_soc_card *card = simple_priv_to_card(priv); - struct device_node *node; struct link_info li; - int ret, loop; + int ret; if (!top) return -EINVAL; @@ -484,35 +551,7 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) /* Single/Muti DAI link(s) & New style of DT node */ memset(&li, 0, sizeof(li)); - - /* FIXME */ - li.cpu = 1; -parse_loop: - loop = 1; - node = of_get_child_by_name(top, PREFIX "dai-link"); - if (!node) { - node = of_node_get(top); - loop = 0; - } - - do { - struct asoc_simple_card_data adata; - struct device_node *codec; - struct device_node *np; - int num = of_get_child_count(node); - int ret; - - codec = of_get_child_by_name(node, !loop ? - PREFIX "codec" : "codec"); - if (!codec) - return -ENODEV; - - of_node_put(codec); - - memset(&adata, 0, sizeof(adata)); - for_each_child_of_node(node, np) - asoc_simple_card_get_conversion(dev, np, &adata); - + for (li.cpu = 1; li.cpu >= 0; li.cpu--) { /* * Detect all CPU first, and Detect all Codec 2nd. * @@ -525,29 +564,12 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) * To avoid random sub-device numbering, * detect "dummy-Codec" in last; */ - - /* loop for all CPU/Codec node */ - for_each_child_of_node(node, np) { - if (num > 2 || - adata.convert_rate || adata.convert_channels) { - ret = asoc_simple_card_dai_link_of_dpcm( - priv, np, codec, &li, !loop); - if (ret < 0) - return ret; - } else { - ret = asoc_simple_card_dai_link_of( - priv, np, codec, &li, !loop); - if (ret < 0) - return ret; - } - } - node = of_get_next_child(top, node); - } while (loop && node); - - /* FIXME */ - li.cpu--; - if (li.cpu >= 0) - goto parse_loop; + ret = asoc_simple_card_for_each_link(priv, &li, + asoc_simple_card_dai_link_of, + asoc_simple_card_dai_link_of_dpcm); + if (ret < 0) + return ret; + } ret = asoc_simple_card_parse_card_name(card, PREFIX); if (ret < 0) @@ -588,12 +610,6 @@ static void asoc_simple_card_get_dais_count(struct simple_card_data *priv, { struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; - struct device_node *node; - struct device_node *np; - struct device_node *codec; - struct asoc_simple_card_data adata; - int loop; - int num; /* * link_num : number of links. @@ -648,39 +664,11 @@ static void asoc_simple_card_get_dais_count(struct simple_card_data *priv, return; } - loop = 1; - node = of_get_child_by_name(top, PREFIX "dai-link"); - if (!node) { - node = top; - loop = 0; - } - - do { - num = of_get_child_count(node); - - codec = of_get_child_by_name(node, !loop ? - PREFIX "codec" : "codec"); - if (!codec) - return; - - of_node_put(codec); - - memset(&adata, 0, sizeof(adata)); - for_each_child_of_node(node, np) - asoc_simple_card_get_conversion(dev, np, &adata); - - for_each_child_of_node(node, np) { - if (num > 2 || - adata.convert_rate || adata.convert_channels) { - asoc_simple_card_count_dpcm(priv, np, codec, - li, !loop); - } else { - asoc_simple_card_count_noml(priv, np, codec, - li, !loop); - } - } - node = of_get_next_child(top, node); - } while (loop && node); + asoc_simple_card_for_each_link(priv, li, + asoc_simple_card_count_noml, + asoc_simple_card_count_dpcm); + dev_dbg(dev, "link %d, dais %d, ccnf %d\n", + li->link, li->dais, li->conf); } static int asoc_simple_soc_card_probe(struct snd_soc_card *card) From a6fee5a54a50df44f20518b176868f72fb661b13 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 20 Dec 2018 10:47:34 +0900 Subject: [PATCH 0968/1995] ASoC: simple-card: reduce naming prefix Current simple-card is using asoc_simple_card_xxx() for function / data naming. Because of this long prefix, it is easy to be 80 character over. Let's reduce prefix from asoc_simple_card_xxx() to simple_xxx(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 2d01a84605a55cf07ea9c6886049cc85c5e98454) --- sound/soc/generic/simple-card.c | 157 ++++++++++++++++---------------- 1 file changed, 79 insertions(+), 78 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index e796b1516b4025..479de236e694e2 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -15,7 +15,7 @@ #include #include -struct simple_card_data { +struct simple_priv { struct snd_soc_card snd_card; struct simple_dai_props { struct asoc_simple_dai *cpu_dai; @@ -49,10 +49,10 @@ struct link_info { #define CELL "#sound-dai-cells" #define PREFIX "simple-audio-card," -static int asoc_simple_card_startup(struct snd_pcm_substream *substream) +static int simple_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); int ret; @@ -68,10 +68,10 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) return ret; } -static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) +static void simple_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); @@ -80,8 +80,8 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) asoc_simple_card_clk_disable(dai_props->codec_dai); } -static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai, - unsigned long rate) +static int simple_set_clk_rate(struct asoc_simple_dai *simple_dai, + unsigned long rate) { if (!simple_dai) return 0; @@ -95,13 +95,13 @@ static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai, return clk_set_rate(simple_dai->clk, rate); } -static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static int simple_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; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); unsigned int mclk, mclk_fs = 0; @@ -113,11 +113,11 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, if (mclk_fs) { mclk = params_rate(params) * mclk_fs; - ret = asoc_simple_set_clk_rate(dai_props->codec_dai, mclk); + ret = simple_set_clk_rate(dai_props->codec_dai, mclk); if (ret < 0) return ret; - ret = asoc_simple_set_clk_rate(dai_props->cpu_dai, mclk); + ret = simple_set_clk_rate(dai_props->cpu_dai, mclk); if (ret < 0) return ret; @@ -136,15 +136,15 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, return ret; } -static const struct snd_soc_ops asoc_simple_card_ops = { - .startup = asoc_simple_card_startup, - .shutdown = asoc_simple_card_shutdown, - .hw_params = asoc_simple_card_hw_params, +static const struct snd_soc_ops simple_ops = { + .startup = simple_startup, + .shutdown = simple_shutdown, + .hw_params = simple_hw_params, }; -static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) +static int simple_dai_init(struct snd_soc_pcm_runtime *rtd) { - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); int ret; @@ -161,10 +161,10 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) +static int simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) { - struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->num); asoc_simple_card_convert_fixup(&dai_props->adata, params); @@ -172,9 +172,9 @@ static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static void asoc_simple_card_get_conversion(struct device *dev, - struct device_node *np, - struct asoc_simple_card_data *adata) +static void simple_get_conversion(struct device *dev, + struct device_node *np, + struct asoc_simple_card_data *adata) { struct device_node *top = dev->of_node; struct device_node *node = of_get_parent(np); @@ -187,11 +187,11 @@ static void asoc_simple_card_get_conversion(struct device *dev, of_node_put(node); } -static int asoc_simple_card_dai_link_of_dpcm(struct simple_card_data *priv, - struct device_node *np, - struct device_node *codec, - struct link_info *li, - bool is_top) +static int simple_dai_link_of_dpcm(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, + bool is_top) { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); @@ -264,7 +264,7 @@ static int asoc_simple_card_dai_link_of_dpcm(struct simple_card_data *priv, /* BE settings */ dai_link->no_pcm = 1; - dai_link->be_hw_params_fixup = asoc_simple_card_be_hw_params_fixup; + dai_link->be_hw_params_fixup = simple_be_hw_params_fixup; dai = dai_props->codec_dai = &priv->dais[li->dais++]; @@ -295,7 +295,7 @@ static int asoc_simple_card_dai_link_of_dpcm(struct simple_card_data *priv, "prefix"); } - asoc_simple_card_get_conversion(dev, np, &dai_props->adata); + simple_get_conversion(dev, np, &dai_props->adata); ret = asoc_simple_card_of_parse_tdm(np, dai); if (ret) @@ -317,17 +317,17 @@ static int asoc_simple_card_dai_link_of_dpcm(struct simple_card_data *priv, dai_link->dpcm_playback = 1; dai_link->dpcm_capture = 1; - dai_link->ops = &asoc_simple_card_ops; - dai_link->init = asoc_simple_card_dai_init; + dai_link->ops = &simple_ops; + dai_link->init = simple_dai_init; return 0; } -static int asoc_simple_card_dai_link_of(struct simple_card_data *priv, - struct device_node *np, - struct device_node *codec, - struct link_info *li, - bool is_top) +static int simple_dai_link_of(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, + bool is_top) { struct device *dev = simple_priv_to_dev(priv); struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); @@ -420,8 +420,8 @@ static int asoc_simple_card_dai_link_of(struct simple_card_data *priv, if (ret < 0) goto dai_link_of_err; - dai_link->ops = &asoc_simple_card_ops; - dai_link->init = asoc_simple_card_dai_init; + dai_link->ops = &simple_ops; + dai_link->init = simple_dai_init; asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); @@ -431,13 +431,13 @@ static int asoc_simple_card_dai_link_of(struct simple_card_data *priv, return ret; } -static int asoc_simple_card_for_each_link(struct simple_card_data *priv, +static int simple_for_each_link(struct simple_priv *priv, struct link_info *li, - int (*func_noml)(struct simple_card_data *priv, + int (*func_noml)(struct simple_priv *priv, struct device_node *np, struct device_node *codec, struct link_info *li, bool is_top), - int (*func_dpcm)(struct simple_card_data *priv, + int (*func_dpcm)(struct simple_priv *priv, struct device_node *np, struct device_node *codec, struct link_info *li, bool is_top)) @@ -473,7 +473,7 @@ static int asoc_simple_card_for_each_link(struct simple_card_data *priv, /* get convert-xxx property */ memset(&adata, 0, sizeof(adata)); for_each_child_of_node(node, np) - asoc_simple_card_get_conversion(dev, np, &adata); + simple_get_conversion(dev, np, &adata); /* loop for all CPU/Codec node */ for_each_child_of_node(node, np) { @@ -499,8 +499,8 @@ static int asoc_simple_card_for_each_link(struct simple_card_data *priv, return 0; } -static int asoc_simple_card_parse_aux_devs(struct device_node *node, - struct simple_card_data *priv) +static int simple_parse_aux_devs(struct device_node *node, + struct simple_priv *priv) { struct device *dev = simple_priv_to_dev(priv); struct device_node *aux_node; @@ -530,7 +530,7 @@ static int asoc_simple_card_parse_aux_devs(struct device_node *node, return 0; } -static int asoc_simple_card_parse_of(struct simple_card_data *priv) +static int simple_parse_of(struct simple_priv *priv) { struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; @@ -564,9 +564,9 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) * To avoid random sub-device numbering, * detect "dummy-Codec" in last; */ - ret = asoc_simple_card_for_each_link(priv, &li, - asoc_simple_card_dai_link_of, - asoc_simple_card_dai_link_of_dpcm); + ret = simple_for_each_link(priv, &li, + simple_dai_link_of, + simple_dai_link_of_dpcm); if (ret < 0) return ret; } @@ -575,15 +575,15 @@ static int asoc_simple_card_parse_of(struct simple_card_data *priv) if (ret < 0) return ret; - ret = asoc_simple_card_parse_aux_devs(top, priv); + ret = simple_parse_aux_devs(top, priv); return ret; } -static int asoc_simple_card_count_noml(struct simple_card_data *priv, - struct device_node *np, - struct device_node *codec, - struct link_info *li, bool is_top) +static int simple_count_noml(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top) { li->dais++; /* CPU or Codec */ if (np != codec) @@ -592,10 +592,10 @@ static int asoc_simple_card_count_noml(struct simple_card_data *priv, return 0; } -static int asoc_simple_card_count_dpcm(struct simple_card_data *priv, - struct device_node *np, - struct device_node *codec, - struct link_info *li, bool is_top) +static int simple_count_dpcm(struct simple_priv *priv, + struct device_node *np, + struct device_node *codec, + struct link_info *li, bool is_top) { li->dais++; /* CPU or Codec */ li->link++; /* CPU-dummy or dummy-Codec */ @@ -605,8 +605,8 @@ static int asoc_simple_card_count_dpcm(struct simple_card_data *priv, return 0; } -static void asoc_simple_card_get_dais_count(struct simple_card_data *priv, - struct link_info *li) +static void simple_get_dais_count(struct simple_priv *priv, + struct link_info *li) { struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; @@ -664,16 +664,17 @@ static void asoc_simple_card_get_dais_count(struct simple_card_data *priv, return; } - asoc_simple_card_for_each_link(priv, li, - asoc_simple_card_count_noml, - asoc_simple_card_count_dpcm); + simple_for_each_link(priv, li, + simple_count_noml, + simple_count_dpcm); + dev_dbg(dev, "link %d, dais %d, ccnf %d\n", li->link, li->dais, li->conf); } -static int asoc_simple_soc_card_probe(struct snd_soc_card *card) +static int simple_soc_probe(struct snd_soc_card *card) { - struct simple_card_data *priv = snd_soc_card_get_drvdata(card); + struct simple_priv *priv = snd_soc_card_get_drvdata(card); int ret; ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX); @@ -687,9 +688,9 @@ static int asoc_simple_soc_card_probe(struct snd_soc_card *card) return 0; } -static int asoc_simple_card_probe(struct platform_device *pdev) +static int simple_probe(struct platform_device *pdev) { - struct simple_card_data *priv; + struct simple_priv *priv; struct snd_soc_dai_link *dai_link; struct simple_dai_props *dai_props; struct asoc_simple_dai *dais; @@ -708,10 +709,10 @@ static int asoc_simple_card_probe(struct platform_device *pdev) card = simple_priv_to_card(priv); card->owner = THIS_MODULE; card->dev = dev; - card->probe = asoc_simple_soc_card_probe; + card->probe = simple_soc_probe; memset(&li, 0, sizeof(li)); - asoc_simple_card_get_dais_count(priv, &li); + simple_get_dais_count(priv, &li); if (!li.link || !li.dais) return -EINVAL; @@ -746,7 +747,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) if (np && of_device_is_available(np)) { - ret = asoc_simple_card_parse_of(priv); + ret = simple_parse_of(priv); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(dev, "parse error %d\n", ret); @@ -789,7 +790,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) dai_link->stream_name = cinfo->name; dai_link->cpu_dai_name = cinfo->cpu_dai.name; dai_link->dai_fmt = cinfo->daifmt; - dai_link->init = asoc_simple_card_dai_init; + dai_link->init = simple_dai_init; memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai, sizeof(*priv->dai_props->cpu_dai)); memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai, @@ -809,28 +810,28 @@ static int asoc_simple_card_probe(struct platform_device *pdev) return ret; } -static int asoc_simple_card_remove(struct platform_device *pdev) +static int simple_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); return asoc_simple_card_clean_reference(card); } -static const struct of_device_id asoc_simple_of_match[] = { +static const struct of_device_id simple_of_match[] = { { .compatible = "simple-audio-card", }, { .compatible = "simple-scu-audio-card", }, {}, }; -MODULE_DEVICE_TABLE(of, asoc_simple_of_match); +MODULE_DEVICE_TABLE(of, simple_of_match); static struct platform_driver asoc_simple_card = { .driver = { .name = "asoc-simple-card", .pm = &snd_soc_pm_ops, - .of_match_table = asoc_simple_of_match, + .of_match_table = simple_of_match, }, - .probe = asoc_simple_card_probe, - .remove = asoc_simple_card_remove, + .probe = simple_probe, + .remove = simple_remove, }; module_platform_driver(asoc_simple_card); From 044afd31f517c03dfe906bd49d5f7dbe0aebf63b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:26 +0100 Subject: [PATCH 0969/1995] ASoC: es8316: Add jack-detect support Adding jack-detect support may seem weird for a codec with only a single output, but it is necessary. The ES8316 appnote showing the intended usage uses a jack-receptacle which physically disconnects the speakers from the output when a jack is plugged in. But all 3 devices using the es8316 which I have (2 Cherry Trail devices and one Bay Trail CR device), use an analog mux to disconnect the speakers, driven by a GPIO. In order to enable/disable the speakers at the right time, we need jack-detect. The same goes for the microphone where we must correctly set the mux for the single ADC to either the internal or the headset microphone. All devices I have support the es8316's builtin jack-detect functionality. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit 822257661031faa437336058d8a32bf1844ad9c6) --- sound/soc/codecs/es8316.c | 195 +++++++++++++++++++++++++++++++++++++- sound/soc/codecs/es8316.h | 7 ++ 2 files changed, 198 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index e97d12d578b00c..26413851e43464 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -15,12 +15,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include "es8316.h" /* In slave mode at single speed, the codec is documented as accepting 5 @@ -33,6 +35,11 @@ static const unsigned int supported_mclk_lrck_ratios[] = { }; struct es8316_priv { + struct mutex lock; + struct regmap *regmap; + struct snd_soc_component *component; + struct snd_soc_jack *jack; + int irq; unsigned int sysclk; unsigned int allowed_rates[NR_SUPPORTED_MCLK_LRCK_RATIOS]; struct snd_pcm_hw_constraint_list sysclk_constraints; @@ -529,8 +536,162 @@ static struct snd_soc_dai_driver es8316_dai = { .symmetric_rates = 1, }; +static void es8316_enable_micbias_for_mic_gnd_short_detect( + struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Bias"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Analog power"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Mic Bias"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); + + msleep(20); +} + +static void es8316_disable_micbias_for_mic_gnd_short_detect( + struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Bias"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Analog power"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Bias"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); +} + +static irqreturn_t es8316_irq(int irq, void *data) +{ + struct es8316_priv *es8316 = data; + struct snd_soc_component *comp = es8316->component; + unsigned int flags; + + mutex_lock(&es8316->lock); + + regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags); + if (flags == 0x00) + goto out; /* Powered-down / reset */ + + /* Catch spurious IRQ before set_jack is called */ + if (!es8316->jack) + goto out; + + dev_dbg(comp->dev, "gpio flags %#04x\n", flags); + if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) { + /* Jack removed, or spurious IRQ? */ + if (es8316->jack->status & SND_JACK_MICROPHONE) + es8316_disable_micbias_for_mic_gnd_short_detect(comp); + + if (es8316->jack->status & SND_JACK_HEADPHONE) { + snd_soc_jack_report(es8316->jack, 0, + SND_JACK_HEADSET | SND_JACK_BTN_0); + dev_dbg(comp->dev, "jack unplugged\n"); + } + } else if (!(es8316->jack->status & SND_JACK_HEADPHONE)) { + /* Jack inserted, determine type */ + es8316_enable_micbias_for_mic_gnd_short_detect(comp); + regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags); + dev_dbg(comp->dev, "gpio flags %#04x\n", flags); + if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) { + /* Jack unplugged underneath us */ + es8316_disable_micbias_for_mic_gnd_short_detect(comp); + } else if (flags & ES8316_GPIO_FLAG_GM_NOT_SHORTED) { + /* Open, headset */ + snd_soc_jack_report(es8316->jack, + SND_JACK_HEADSET, + SND_JACK_HEADSET); + /* Keep mic-gnd-short detection on for button press */ + } else { + /* Shorted, headphones */ + snd_soc_jack_report(es8316->jack, + SND_JACK_HEADPHONE, + SND_JACK_HEADSET); + /* No longer need mic-gnd-short detection */ + es8316_disable_micbias_for_mic_gnd_short_detect(comp); + } + } else if (es8316->jack->status & SND_JACK_MICROPHONE) { + /* Interrupt while jack inserted, report button state */ + if (flags & ES8316_GPIO_FLAG_GM_NOT_SHORTED) { + /* Open, button release */ + snd_soc_jack_report(es8316->jack, 0, SND_JACK_BTN_0); + } else { + /* Short, button press */ + snd_soc_jack_report(es8316->jack, + SND_JACK_BTN_0, + SND_JACK_BTN_0); + } + } + +out: + mutex_unlock(&es8316->lock); + return IRQ_HANDLED; +} + +static void es8316_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack) +{ + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + mutex_lock(&es8316->lock); + + es8316->jack = jack; + + if (es8316->jack->status & SND_JACK_MICROPHONE) + es8316_enable_micbias_for_mic_gnd_short_detect(component); + + snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE, + ES8316_GPIO_ENABLE_INTERRUPT, + ES8316_GPIO_ENABLE_INTERRUPT); + + mutex_unlock(&es8316->lock); + + /* Enable irq and sync initial jack state */ + enable_irq(es8316->irq); + es8316_irq(es8316->irq, es8316); +} + +static void es8316_disable_jack_detect(struct snd_soc_component *component) +{ + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + disable_irq(es8316->irq); + + mutex_lock(&es8316->lock); + + snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE, + ES8316_GPIO_ENABLE_INTERRUPT, 0); + + if (es8316->jack->status & SND_JACK_MICROPHONE) { + es8316_disable_micbias_for_mic_gnd_short_detect(component); + snd_soc_jack_report(es8316->jack, 0, SND_JACK_BTN_0); + } + + es8316->jack = NULL; + + mutex_unlock(&es8316->lock); +} + +static int es8316_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *jack, void *data) +{ + if (jack) + es8316_enable_jack_detect(component, jack); + else + es8316_disable_jack_detect(component); + + return 0; +} + static int es8316_probe(struct snd_soc_component *component) { + struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + + es8316->component = component; + /* Reset codec and enable current state machine */ snd_soc_component_write(component, ES8316_RESET, 0x3f); usleep_range(5000, 5500); @@ -555,6 +716,7 @@ static int es8316_probe(struct snd_soc_component *component) static const struct snd_soc_component_driver soc_component_dev_es8316 = { .probe = es8316_probe, + .set_jack = es8316_set_jack, .controls = es8316_snd_controls, .num_controls = ARRAY_SIZE(es8316_snd_controls), .dapm_widgets = es8316_dapm_widgets, @@ -566,18 +728,29 @@ static const struct snd_soc_component_driver soc_component_dev_es8316 = { .non_legacy_dai_naming = 1, }; +static const struct regmap_range es8316_volatile_ranges[] = { + regmap_reg_range(ES8316_GPIO_FLAG, ES8316_GPIO_FLAG), +}; + +static const struct regmap_access_table es8316_volatile_table = { + .yes_ranges = es8316_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(es8316_volatile_ranges), +}; + static const struct regmap_config es8316_regmap = { .reg_bits = 8, .val_bits = 8, .max_register = 0x53, + .volatile_table = &es8316_volatile_table, .cache_type = REGCACHE_RBTREE, }; static int es8316_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { + struct device *dev = &i2c_client->dev; struct es8316_priv *es8316; - struct regmap *regmap; + int ret; es8316 = devm_kzalloc(&i2c_client->dev, sizeof(struct es8316_priv), GFP_KERNEL); @@ -586,9 +759,23 @@ static int es8316_i2c_probe(struct i2c_client *i2c_client, i2c_set_clientdata(i2c_client, es8316); - regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); + es8316->regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap); + if (IS_ERR(es8316->regmap)) + return PTR_ERR(es8316->regmap); + + es8316->irq = i2c_client->irq; + mutex_init(&es8316->lock); + + ret = devm_request_threaded_irq(dev, es8316->irq, NULL, es8316_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "es8316", es8316); + if (ret == 0) { + /* Gets re-enabled by es8316_set_jack() */ + disable_irq(es8316->irq); + } else { + dev_warn(dev, "Failed to get IRQ %d: %d\n", es8316->irq, ret); + es8316->irq = -ENXIO; + } return devm_snd_soc_register_component(&i2c_client->dev, &soc_component_dev_es8316, diff --git a/sound/soc/codecs/es8316.h b/sound/soc/codecs/es8316.h index 6bcdd63ea45948..439a0130cbb7d5 100644 --- a/sound/soc/codecs/es8316.h +++ b/sound/soc/codecs/es8316.h @@ -126,4 +126,11 @@ #define ES8316_SERDATA2_LEN_16 0x0c #define ES8316_SERDATA2_LEN_32 0x10 +/* ES8316_GPIO_DEBOUNCE */ +#define ES8316_GPIO_ENABLE_INTERRUPT 0x02 + +/* ES8316_GPIO_FLAG */ +#define ES8316_GPIO_FLAG_GM_NOT_SHORTED 0x02 +#define ES8316_GPIO_FLAG_HP_NOT_INSERTED 0x04 + #endif From a21a442a7b6972c810c3139458496d35abe4b9de Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:27 +0100 Subject: [PATCH 0970/1995] ASoC: es8316: Add DAC mono mix switch mixer control Export the DAC functionality to mix left + right together and then output the same (mixed) signal on both outputs. Various (x86) tablets with an ES8316 codec use a single speaker connected between the headhpone LOUT and ROUT pins, expecting the output to be in a mono differential mode. Presumably this is done to use the power of both the left and right outputs to allow the speaker to be louder. The ES8316 codec does not have a differential output mode, but we can emulate this by making both channels output the same through the mono mix switch, combined with setting the Playback Polarity control to "R Invert", which applias a 180 degrees phase inversion to the right channel. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit 24b53f17a3f24967b8b523243f9f7fc361427119) --- sound/soc/codecs/es8316.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 26413851e43464..98464ba1046c18 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -101,6 +101,7 @@ static const struct snd_kcontrol_new es8316_snd_controls[] = { SOC_SINGLE("DAC Notch Filter Switch", ES8316_DAC_SET2, 6, 1, 0), SOC_SINGLE("DAC Double Fs Switch", ES8316_DAC_SET2, 7, 1, 0), SOC_SINGLE("DAC Stereo Enhancement", ES8316_DAC_SET3, 0, 7, 0), + SOC_SINGLE("DAC Mono Mix Switch", ES8316_DAC_SET3, 3, 1, 0), SOC_ENUM("Capture Polarity", adcpol), SOC_SINGLE("Mic Boost Switch", ES8316_ADC_D2SEPGA, 0, 1, 0), From 058bb87f94207a1e2207e6207291b22d52ce69b7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:28 +0100 Subject: [PATCH 0971/1995] ASoC: Intel: bytcht_es8316: Sort includes alphabetically For lack of a better (non-random) way of sorting includes more and more files in the kernel are moving over to sorting the includes alphabetically. Move the bytcht_es8316 driver over to this sorting before we add a bunch of more includes. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 6ca382c4363d6c636200ccdd9ac95f44b1a498ea) --- sound/soc/intel/boards/bytcht_es8316.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index adc26dfc7d654d..5d8ecc100766c0 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -19,13 +19,13 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include +#include #include #include #include -#include #include #include -#include #include #include #include From 140e4b0b9f564cb615fb26f660dcd9b163d61912 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:29 +0100 Subject: [PATCH 0972/1995] ASoC: Intel: bytcht_es8316: Minor refactoring Some minor refactoring: 1) Group the code setting the card dev and prive pointers together with registering the card 2) Properly put the comment about registering the card at the place where we actually register the card and add a new comment for getting the clk 3) Add a struct device *dev helper variable (this will be used more in follow up commits) 4) Reword error message to have the same "foo failed: %d" wording as others Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 86909c8f77c5eda17a9b5dc954849e25df1ffe0f) --- sound/soc/intel/boards/bytcht_es8316.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 5d8ecc100766c0..e29f00560b008b 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -237,17 +237,18 @@ static char codec_name[SND_ACPI_I2C_ID_LEN]; static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { struct byt_cht_es8316_private *priv; + struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; const char *i2c_name = NULL; int dai_index = 0; int i; int ret = 0; - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - mach = (&pdev->dev)->platform_data; + mach = dev->platform_data; /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_cht_es8316_dais); i++) { if (!strcmp(byt_cht_es8316_dais[i].codec_name, @@ -265,26 +266,25 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_dais[dai_index].codec_name = codec_name; } - /* register the soc card */ - byt_cht_es8316_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); - - priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + /* get the clock */ + priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3"); if (IS_ERR(priv->mclk)) { ret = PTR_ERR(priv->mclk); - dev_err(&pdev->dev, - "Failed to get MCLK from pmc_plt_clk_3: %d\n", - ret); + dev_err(dev, "clk_get pmc_plt_clk_3 failed: %d\n", ret); return ret; } - ret = devm_snd_soc_register_card(&pdev->dev, &byt_cht_es8316_card); + /* register the soc card */ + byt_cht_es8316_card.dev = dev; + snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); + + ret = devm_snd_soc_register_card(dev, &byt_cht_es8316_card); if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); + dev_err(dev, "snd_soc_register_card failed: %d\n", ret); return ret; } platform_set_drvdata(pdev, &byt_cht_es8316_card); - return ret; + return 0; } static struct platform_driver snd_byt_cht_es8316_mc_driver = { From f2324bc1ef317a8356e9ff70004557b61e2ee9f0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:30 +0100 Subject: [PATCH 0973/1995] ASoC: Intel: bytcht_es8316: Add support for SSP0 (BYTCR) Add support for having the codec connected to SSP0 instead of SSP2. This is controlled through a new quirk parameter, similar to how this is done in the bytcr_rt5640 and bytcr_rt5651 machine drivers. Bay Trail CR (cost reduced) SoCs do not have an SSP2, so we default to SSP0 there. Note the SPP0 quirk gets BIT(16) because bits 0-15 are reserved for non boolean quirks like the input-map added in a later commit in this series. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 349e13862c9975c613aac9dc7fa953e70cff9d06) --- sound/soc/intel/boards/bytcht_es8316.c | 76 ++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index e29f00560b008b..3358d82499a3a6 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -37,6 +39,20 @@ struct byt_cht_es8316_private { struct clk *mclk; }; +#define BYT_CHT_ES8316_SSP0 BIT(16) + +static int quirk; + +static int quirk_override = -1; +module_param_named(quirk, quirk_override, int, 0444); +MODULE_PARM_DESC(quirk, "Board-specific quirk override"); + +static void log_quirks(struct device *dev) +{ + if (quirk & BYT_CHT_ES8316_SSP0) + dev_info(dev, "quirk SSP0 enabled"); +} + static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), @@ -55,7 +71,16 @@ static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, +}; + +static const struct snd_soc_dapm_route byt_cht_es8316_ssp0_map[] = { + {"Playback", NULL, "ssp0 Tx"}, + {"ssp0 Tx", NULL, "modem_out"}, + {"modem_in", NULL, "ssp0 Rx"}, + {"ssp0 Rx", NULL, "Capture"}, +}; +static const struct snd_soc_dapm_route byt_cht_es8316_ssp2_map[] = { {"Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, @@ -74,10 +99,23 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) { struct snd_soc_card *card = runtime->card; struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); + const struct snd_soc_dapm_route *custom_map; + int num_routes; int ret; card->dapm.idle_bias_off = true; + if (quirk & BYT_CHT_ES8316_SSP0) { + custom_map = byt_cht_es8316_ssp0_map; + num_routes = ARRAY_SIZE(byt_cht_es8316_ssp0_map); + } else { + custom_map = byt_cht_es8316_ssp2_map; + num_routes = ARRAY_SIZE(byt_cht_es8316_ssp2_map); + } + ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + if (ret) + return ret; + /* * The firmware might enable the clock at boot (this information * may or may not be reflected in the enable clock register). @@ -123,14 +161,21 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - int ret; + int ret, bits; /* The DSP will covert the FE rate to 48k, stereo */ rate->min = rate->max = 48000; channels->min = channels->max = 2; - /* set SSP2 to 24-bit */ - params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + if (quirk & BYT_CHT_ES8316_SSP0) { + /* set SSP0 to 16-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); + bits = 16; + } else { + /* set SSP2 to 24-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + bits = 24; + } /* * Default mode for SSP configuration is TDM 4 slot, override config @@ -147,7 +192,7 @@ static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, return ret; } - ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, bits); if (ret < 0) { dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); return ret; @@ -232,6 +277,11 @@ static struct snd_soc_card byt_cht_es8316_card = { .fully_routed = true, }; +static const struct x86_cpu_id baytrail_cpu_ids[] = { + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT }, /* Valleyview */ + {} +}; + static char codec_name[SND_ACPI_I2C_ID_LEN]; static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) @@ -266,6 +316,24 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_dais[dai_index].codec_name = codec_name; } + /* Check for BYTCR or other platform and setup quirks */ + if (x86_match_cpu(baytrail_cpu_ids) && + mach->mach_params.acpi_ipc_irq_index == 0) { + /* On BYTCR default to SSP0 */ + quirk = BYT_CHT_ES8316_SSP0; + } else { + quirk = 0; + } + if (quirk_override != -1) { + dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", quirk, + quirk_override); + quirk = quirk_override; + } + log_quirks(dev); + + if (quirk & BYT_CHT_ES8316_SSP0) + byt_cht_es8316_dais[dai_index].cpu_dai_name = "ssp0-port"; + /* get the clock */ priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3"); if (IS_ERR(priv->mclk)) { From ae4dbc30bd46af8b8108647d5ee4f141938762a2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:31 +0100 Subject: [PATCH 0974/1995] ASoC: Intel: bytcht_es8316: Add jack-detect support Hookup the jack-detect support added to the codec driver. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 4bf538b42933253296daf86aab7ede56b5fb97bf) --- sound/soc/intel/boards/bytcht_es8316.c | 67 +++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 3358d82499a3a6..905dd690471076 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -22,12 +22,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -37,6 +39,7 @@ struct byt_cht_es8316_private { struct clk *mclk; + struct snd_soc_jack jack; }; #define BYT_CHT_ES8316_SSP0 BIT(16) @@ -55,6 +58,7 @@ static void log_quirks(struct device *dev) static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), /* * The codec supports two analog microphone inputs. I have only @@ -68,6 +72,7 @@ static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { {"MIC1", NULL, "Microphone 1"}, {"MIC2", NULL, "Microphone 2"}, + {"MIC1", NULL, "Headset Mic"}, {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, @@ -91,12 +96,25 @@ static const struct snd_soc_dapm_route byt_cht_es8316_ssp2_map[] = { static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Microphone 1"), SOC_DAPM_PIN_SWITCH("Microphone 2"), }; +static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) { + struct snd_soc_component *codec = runtime->codec_dai->component; struct snd_soc_card *card = runtime->card; struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); const struct snd_soc_dapm_route *custom_map; @@ -143,6 +161,18 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) return ret; } + ret = snd_soc_card_jack_new(card, "Headset", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &priv->jack, byt_cht_es8316_jack_pins, + ARRAY_SIZE(byt_cht_es8316_jack_pins)); + if (ret) { + dev_err(card->dev, "jack creation failed %d\n", ret); + return ret; + } + + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_soc_component_set_jack(codec, &priv->jack, NULL); + return 0; } @@ -263,6 +293,39 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { /* SoC card */ +static char codec_name[SND_ACPI_I2C_ID_LEN]; + +static int byt_cht_es8316_suspend(struct snd_soc_card *card) +{ + struct snd_soc_component *component; + + for_each_card_components(card, component) { + if (!strcmp(component->name, codec_name)) { + dev_dbg(component->dev, "disabling jack detect before suspend\n"); + snd_soc_component_set_jack(component, NULL, NULL); + break; + } + } + + return 0; +} + +static int byt_cht_es8316_resume(struct snd_soc_card *card) +{ + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component; + + for_each_card_components(card, component) { + if (!strcmp(component->name, codec_name)) { + dev_dbg(component->dev, "re-enabling jack detect after resume\n"); + snd_soc_component_set_jack(component, &priv->jack, NULL); + break; + } + } + + return 0; +} + static struct snd_soc_card byt_cht_es8316_card = { .name = "bytcht-es8316", .owner = THIS_MODULE, @@ -275,6 +338,8 @@ static struct snd_soc_card byt_cht_es8316_card = { .controls = byt_cht_es8316_controls, .num_controls = ARRAY_SIZE(byt_cht_es8316_controls), .fully_routed = true, + .suspend_pre = byt_cht_es8316_suspend, + .resume_post = byt_cht_es8316_resume, }; static const struct x86_cpu_id baytrail_cpu_ids[] = { @@ -282,8 +347,6 @@ static const struct x86_cpu_id baytrail_cpu_ids[] = { {} }; -static char codec_name[SND_ACPI_I2C_ID_LEN]; - static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { struct byt_cht_es8316_private *priv; From 02f820393297dfcc1c9723a7e829960cdde4e7c7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:32 +0100 Subject: [PATCH 0975/1995] ASoC: Intel: bytcht_es8316: Add external speaker mux support The ES8316 only has a single (amplified) output. The ES8316 appnote showing the intended usage uses a jack-receptacle which physically disconnects the speakers from the output when a jack is plugged in. But all 3 devices using the es8316 which I have (2 Cherry Trail devices and one Bay Trail CR device), use an analog mux to disconnect the speakers, driven by a GPIO. This commit adds support for this, modelling this as a separate speaker widget / dapm pin-switch which sets the mux to drive the speakers when selected. The intend is for userspace to use the recently added jack-detect support and then automatically select either the Headphone or Speaker output based on that. Note this commit includes a workaround for an ACPI table bug which is present on 2 of the 3 devices I have, see the added comment in the code. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 0d3e91da0750835cfd5c16487ffb3cdd752ea53a) --- sound/soc/intel/boards/bytcht_es8316.c | 98 ++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 905dd690471076..8e504fca4624c8 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -19,8 +19,11 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +#include #include #include +#include +#include #include #include #include @@ -40,6 +43,8 @@ struct byt_cht_es8316_private { struct clk *mclk; struct snd_soc_jack jack; + struct gpio_desc *speaker_en_gpio; + bool speaker_en; }; #define BYT_CHT_ES8316_SSP0 BIT(16) @@ -56,7 +61,24 @@ static void log_quirks(struct device *dev) dev_info(dev, "quirk SSP0 enabled"); } +static int byt_cht_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_card *card = w->dapm->card; + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); + + if (SND_SOC_DAPM_EVENT_ON(event)) + priv->speaker_en = true; + else + priv->speaker_en = false; + + gpiod_set_value_cansleep(priv->speaker_en_gpio, priv->speaker_en); + + return 0; +} + static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", NULL), SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), @@ -67,6 +89,10 @@ static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { */ SND_SOC_DAPM_MIC("Microphone 1", NULL), SND_SOC_DAPM_MIC("Microphone 2", NULL), + + SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, + byt_cht_es8316_speaker_power_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), }; static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { @@ -76,6 +102,14 @@ static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, + + /* + * There is no separate speaker output instead the speakers are muxed to + * the HP outputs. The mux is controlled by the "Speaker Power" supply. + */ + {"Speaker", NULL, "HPOL"}, + {"Speaker", NULL, "HPOR"}, + {"Speaker", NULL, "Speaker Power"}, }; static const struct snd_soc_dapm_route byt_cht_es8316_ssp0_map[] = { @@ -95,6 +129,7 @@ static const struct snd_soc_dapm_route byt_cht_es8316_ssp2_map[] = { }; static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { + SOC_DAPM_PIN_SWITCH("Speaker"), SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Microphone 1"), @@ -323,6 +358,25 @@ static int byt_cht_es8316_resume(struct snd_soc_card *card) } } + /* + * Some Cherry Trail boards with an ES8316 codec have a bug in their + * ACPI tables where the MSSL1680 touchscreen's _PS0 and _PS3 methods + * wrongly also set the speaker-enable GPIO to 1/0. Testing has shown + * that this really is a bug and the GPIO has no influence on the + * touchscreen at all. + * + * The silead.c touchscreen driver does not support runtime suspend, so + * the GPIO can only be changed underneath us during a system suspend. + * This resume() function runs from a pm complete() callback, and thus + * is guaranteed to run after the touchscreen driver/ACPI-subsys has + * brought the touchscreen back up again (and thus changed the GPIO). + * + * So to work around this we pass GPIOD_FLAGS_BIT_NONEXCLUSIVE when + * requesting the GPIO and we set its value here to undo any changes + * done by the touchscreen's broken _PS0 ACPI method. + */ + gpiod_set_value_cansleep(priv->speaker_en_gpio, priv->speaker_en); + return 0; } @@ -347,12 +401,20 @@ static const struct x86_cpu_id baytrail_cpu_ids[] = { {} }; +static const struct acpi_gpio_params first_gpio = { 0, 0, false }; + +static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = { + { "speaker-enable-gpios", &first_gpio, 1 }, + { }, +}; + static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; const char *i2c_name = NULL; + struct device *codec_dev; int dai_index = 0; int i; int ret = 0; @@ -405,12 +467,39 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) return ret; } + /* get speaker enable GPIO */ + codec_dev = bus_find_device_by_name(&i2c_bus_type, NULL, codec_name); + if (!codec_dev) + return -EPROBE_DEFER; + + devm_acpi_dev_add_driver_gpios(codec_dev, byt_cht_es8316_gpios); + priv->speaker_en_gpio = + gpiod_get_index(codec_dev, "speaker-enable", 0, + /* see comment in byt_cht_es8316_resume */ + GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); + put_device(codec_dev); + + if (IS_ERR(priv->speaker_en_gpio)) { + ret = PTR_ERR(priv->speaker_en_gpio); + switch (ret) { + case -ENOENT: + priv->speaker_en_gpio = NULL; + break; + default: + dev_err(dev, "get speaker GPIO failed: %d\n", ret); + /* fall through */ + case -EPROBE_DEFER: + return ret; + } + } + /* register the soc card */ byt_cht_es8316_card.dev = dev; snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); ret = devm_snd_soc_register_card(dev, &byt_cht_es8316_card); if (ret) { + gpiod_put(priv->speaker_en_gpio); dev_err(dev, "snd_soc_register_card failed: %d\n", ret); return ret; } @@ -418,11 +507,20 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) return 0; } +static int snd_byt_cht_es8316_mc_remove(struct platform_device *pdev) +{ + struct byt_cht_es8316_private *priv = platform_get_drvdata(pdev); + + gpiod_put(priv->speaker_en_gpio); + return 0; +} + static struct platform_driver snd_byt_cht_es8316_mc_driver = { .driver = { .name = "bytcht_es8316", }, .probe = snd_byt_cht_es8316_mc_probe, + .remove = snd_byt_cht_es8316_mc_remove, }; module_platform_driver(snd_byt_cht_es8316_mc_driver); From 0a4f09a7a9a574a11f2348d2a420e1371d5fcd8c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:33 +0100 Subject: [PATCH 0976/1995] ASoC: Intel: bytcht_es8316: Add input-map support After adding jack-detect support we have 3 microphone input switches: "Microphone 1", "Microphone 2" and "Headset Mic". But the ES8316 has only 2 microphone inputs. In the app-note explaining how to use the codec and on the 3 boards I have one input is used for an internal microphone and one for the headset microphone. On the 2 CHT boards I have the internal mic is on on MIC1 and the headset mic is on MIC2, on the BYTCR board I have it is the other way around. This commit replaces the 2 "Microphone 1" and "Microphone 2" input switches with a single "Internal Mic" switch and adds support for selecting either possible input mapping. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 730501a91d94b652275e049e101ed44cdbfdf31b) --- sound/soc/intel/boards/bytcht_es8316.c | 58 ++++++++++++++++++-------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 8e504fca4624c8..941a66f94660e4 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -47,6 +47,12 @@ struct byt_cht_es8316_private { bool speaker_en; }; +enum { + BYT_CHT_ES8316_INTMIC_IN1_MAP, + BYT_CHT_ES8316_INTMIC_IN2_MAP, +}; + +#define BYT_CHT_ES8316_MAP(quirk) ((quirk) & GENMASK(3, 0)) #define BYT_CHT_ES8316_SSP0 BIT(16) static int quirk; @@ -57,6 +63,10 @@ MODULE_PARM_DESC(quirk, "Board-specific quirk override"); static void log_quirks(struct device *dev) { + if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN1_MAP) + dev_info(dev, "quirk IN1_MAP enabled"); + if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN2_MAP) + dev_info(dev, "quirk IN2_MAP enabled"); if (quirk & BYT_CHT_ES8316_SSP0) dev_info(dev, "quirk SSP0 enabled"); } @@ -81,14 +91,7 @@ static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { SND_SOC_DAPM_SPK("Speaker", NULL), SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), - - /* - * The codec supports two analog microphone inputs. I have only - * tested MIC1. A DMIC route could also potentially be added - * if such functionality is found on another platform. - */ - SND_SOC_DAPM_MIC("Microphone 1", NULL), - SND_SOC_DAPM_MIC("Microphone 2", NULL), + SND_SOC_DAPM_MIC("Internal Mic", NULL), SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, byt_cht_es8316_speaker_power_event, @@ -96,10 +99,6 @@ static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { }; static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { - {"MIC1", NULL, "Microphone 1"}, - {"MIC2", NULL, "Microphone 2"}, - {"MIC1", NULL, "Headset Mic"}, - {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, @@ -112,6 +111,16 @@ static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { {"Speaker", NULL, "Speaker Power"}, }; +static const struct snd_soc_dapm_route byt_cht_es8316_intmic_in1_map[] = { + {"MIC1", NULL, "Internal Mic"}, + {"MIC2", NULL, "Headset Mic"}, +}; + +static const struct snd_soc_dapm_route byt_cht_es8316_intmic_in2_map[] = { + {"MIC2", NULL, "Internal Mic"}, + {"MIC1", NULL, "Headset Mic"}, +}; + static const struct snd_soc_dapm_route byt_cht_es8316_ssp0_map[] = { {"Playback", NULL, "ssp0 Tx"}, {"ssp0 Tx", NULL, "modem_out"}, @@ -132,8 +141,7 @@ static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { SOC_DAPM_PIN_SWITCH("Speaker"), SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Microphone 1"), - SOC_DAPM_PIN_SWITCH("Microphone 2"), + SOC_DAPM_PIN_SWITCH("Internal Mic"), }; static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { @@ -158,6 +166,21 @@ static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) card->dapm.idle_bias_off = true; + switch (BYT_CHT_ES8316_MAP(quirk)) { + case BYT_CHT_ES8316_INTMIC_IN1_MAP: + default: + custom_map = byt_cht_es8316_intmic_in1_map; + num_routes = ARRAY_SIZE(byt_cht_es8316_intmic_in1_map); + break; + case BYT_CHT_ES8316_INTMIC_IN2_MAP: + custom_map = byt_cht_es8316_intmic_in2_map; + num_routes = ARRAY_SIZE(byt_cht_es8316_intmic_in2_map); + break; + } + ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + if (ret) + return ret; + if (quirk & BYT_CHT_ES8316_SSP0) { custom_map = byt_cht_es8316_ssp0_map; num_routes = ARRAY_SIZE(byt_cht_es8316_ssp0_map); @@ -444,10 +467,11 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) /* Check for BYTCR or other platform and setup quirks */ if (x86_match_cpu(baytrail_cpu_ids) && mach->mach_params.acpi_ipc_irq_index == 0) { - /* On BYTCR default to SSP0 */ - quirk = BYT_CHT_ES8316_SSP0; + /* On BYTCR default to SSP0, internal-mic-in2-map */ + quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP; } else { - quirk = 0; + /* Others default to internal-mic-in1-map */ + quirk = BYT_CHT_ES8316_INTMIC_IN1_MAP; } if (quirk_override != -1) { dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", quirk, From 710a29d37fcc339f3786ce3d6b3fb8a575362e68 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:34 +0100 Subject: [PATCH 0977/1995] ASoC: Intel: bytcht_es8316: Set card long_name based on quirks Depending on the input-map and on if 1 or 2 speakers are connected, userspace needs to use a different UCM profile. Since we already deal with quirks in the kernel driver and set the input-map from the kernel, add a quirk for devices with a single / mono speaker and set the card's long_name based on the input and speaker quirks, so that userspace can use the long_name to pick the right UCM profile. This change, including how the long_name is build-up mirrors how we do this in the bytcr_rt5640 and bytcr_rt5651 machine drivers. Note since all devices I have access to use a mono speaker setup I've chosen to default the speaker setting to mono. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 249d2fc9e55c324dda968252ea3ad0ac21c72b8f) --- sound/soc/intel/boards/bytcht_es8316.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 941a66f94660e4..cdf2061e7613d9 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -54,6 +54,7 @@ enum { #define BYT_CHT_ES8316_MAP(quirk) ((quirk) & GENMASK(3, 0)) #define BYT_CHT_ES8316_SSP0 BIT(16) +#define BYT_CHT_ES8316_MONO_SPEAKER BIT(17) static int quirk; @@ -69,6 +70,8 @@ static void log_quirks(struct device *dev) dev_info(dev, "quirk IN2_MAP enabled"); if (quirk & BYT_CHT_ES8316_SSP0) dev_info(dev, "quirk SSP0 enabled"); + if (quirk & BYT_CHT_ES8316_MONO_SPEAKER) + dev_info(dev, "quirk MONO_SPEAKER enabled\n"); } static int byt_cht_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, @@ -352,6 +355,7 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { /* SoC card */ static char codec_name[SND_ACPI_I2C_ID_LEN]; +static char long_name[50]; /* = "bytcht-es8316-*-spk-*-mic" */ static int byt_cht_es8316_suspend(struct snd_soc_card *card) { @@ -433,6 +437,7 @@ static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = { static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { + const char * const mic_name[] = { "in1", "in2" }; struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; @@ -467,11 +472,13 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) /* Check for BYTCR or other platform and setup quirks */ if (x86_match_cpu(baytrail_cpu_ids) && mach->mach_params.acpi_ipc_irq_index == 0) { - /* On BYTCR default to SSP0, internal-mic-in2-map */ - quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP; + /* On BYTCR default to SSP0, internal-mic-in2-map, mono-spk */ + quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP | + BYT_CHT_ES8316_MONO_SPEAKER; } else { - /* Others default to internal-mic-in1-map */ - quirk = BYT_CHT_ES8316_INTMIC_IN1_MAP; + /* Others default to internal-mic-in1-map, mono-speaker */ + quirk = BYT_CHT_ES8316_INTMIC_IN1_MAP | + BYT_CHT_ES8316_MONO_SPEAKER; } if (quirk_override != -1) { dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", quirk, @@ -518,6 +525,10 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) } /* register the soc card */ + snprintf(long_name, sizeof(long_name), "bytcht-es8316-%s-spk-%s-mic", + (quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "mono" : "stereo", + mic_name[BYT_CHT_ES8316_MAP(quirk)]); + byt_cht_es8316_card.long_name = long_name; byt_cht_es8316_card.dev = dev; snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); From 3c03d4b33df30bda2e3f1441f586f37354dfe76b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 3 Jan 2019 14:45:35 +0100 Subject: [PATCH 0978/1995] ASoC: Intel: Add ACPI match table entry for ES8316 codec on BYTCR platform Some BYTCR devices use an ES8316 codec, add an ACPI match table entry for this. Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 5198baf8817d7e6e0fe2f3e74ea2ead714b74d9c) --- sound/soc/intel/common/soc-acpi-intel-byt-match.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 097dc06377baaf..47a90909b95689 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -154,6 +154,15 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .sof_tplg_filename = "intel/sof-byt-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, + { + .id = "ESSX8316", + .drv_name = "bytcht_es8316", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcht_es8316", + .sof_fw_filename = "intel/sof-byt.ri", + .sof_tplg_filename = "intel/sof-byt-es8316.tplg", + .asoc_plat_name = "sst-mfld-platform", + }, /* some Baytrail platforms rely on RT5645, use CHT machine driver */ { .id = "10EC5645", From 613a494b6019be30c7e41a52ab4516612afc4bd5 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 2 Jan 2019 20:39:03 +0100 Subject: [PATCH 0979/1995] ASoC: Intel: sst: Simplify is_byt_cr() is_byt_cr() and its usage can be simplified by returning the bool directly, instead of through a pointer. This works because the return value is just treated as bytcr = false and is not used otherwise. This patch also removes the extra check of IS_ENABLED(CONFIG_IOSF_MBI) in favor of checking iosf_mbi_available() directly. The header already takes care of returning false if the config option is not enabled. No functional change. Signed-off-by: Stephan Gerhold Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit b97205ef95efddee018061dfee14c995be08dde3) --- sound/soc/intel/atom/sst/sst_acpi.c | 33 ++++++++++++----------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 3a95ebbfc45d30..9eaac450f8649a 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -255,18 +255,15 @@ static int is_byt(void) return status; } -static int is_byt_cr(struct device *dev, bool *bytcr) +static bool is_byt_cr(struct device *dev) { int status = 0; - if (IS_ENABLED(CONFIG_IOSF_MBI)) { - u32 bios_status; - - if (!is_byt() || !iosf_mbi_available()) { - /* bail silently */ - return status; - } + if (!is_byt()) + return false; + if (iosf_mbi_available()) { + u32 bios_status; status = iosf_mbi_read(BT_MBI_UNIT_PMC, /* 0x04 PUNIT */ MBI_REG_READ, /* 0x10 */ 0x006, /* BIOS_CONFIG */ @@ -278,15 +275,17 @@ static int is_byt_cr(struct device *dev, bool *bytcr) /* bits 26:27 mirror PMIC options */ bios_status = (bios_status >> 26) & 3; - if ((bios_status == 1) || (bios_status == 3)) - *bytcr = true; - else - dev_info(dev, "BYT-CR not detected\n"); + if (bios_status == 1 || bios_status == 3) { + dev_info(dev, "Detected Baytrail-CR platform\n"); + return true; + } + + dev_info(dev, "BYT-CR not detected\n"); } } else { - dev_info(dev, "IOSF_MBI not enabled, no BYT-CR detection\n"); + dev_info(dev, "IOSF_MBI not available, no BYT-CR detection\n"); } - return status; + return false; } @@ -301,7 +300,6 @@ static int sst_acpi_probe(struct platform_device *pdev) struct platform_device *plat_dev; struct sst_platform_info *pdata; unsigned int dev_id; - bool bytcr = false; id = acpi_match_device(dev->driver->acpi_match_table, dev); if (!id) @@ -333,10 +331,7 @@ static int sst_acpi_probe(struct platform_device *pdev) if (ret < 0) return ret; - ret = is_byt_cr(dev, &bytcr); - if (!(ret < 0 || !bytcr)) { - dev_info(dev, "Detected Baytrail-CR platform\n"); - + if (is_byt_cr(dev)) { /* override resource info */ byt_rvp_platform_data.res_info = &bytcr_res_info; } From 4bd6386f8cdecc06aa2bbcec8602b18d6728027d Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 2 Jan 2019 20:39:06 +0100 Subject: [PATCH 0980/1995] ASoC: Intel: sst: Fallback to BYT-CR if IRQ 5 is missing Some devices detected as BYT-T by the PMIC-type based detection have only a single IRQ listed in the 80860F28 ACPI device. This causes -ENXIO later when attempting to get the IRQ at index 5. It turns out these devices behave more like BYT-CR devices, and using the IRQ at index 0 makes sound work correctly. This patch adds a fallback for these devices to is_byt_cr(): If there is no IRQ resource at index 5, treating the device as BYT-T is guaranteed to fail later, so we can safely treat these devices as BYT-CR without breaking any working device. Link: http://mailman.alsa-project.org/pipermail/alsa-devel/2018-December/143176.html Signed-off-by: Stephan Gerhold Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit fee15714552dbf420264da6f88dd813b8502592b) --- sound/soc/intel/atom/sst/sst_acpi.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 9eaac450f8649a..ae17ce4677a5c0 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -255,8 +255,9 @@ static int is_byt(void) return status; } -static bool is_byt_cr(struct device *dev) +static bool is_byt_cr(struct platform_device *pdev) { + struct device *dev = &pdev->dev; int status = 0; if (!is_byt()) @@ -285,6 +286,17 @@ static bool is_byt_cr(struct device *dev) } else { dev_info(dev, "IOSF_MBI not available, no BYT-CR detection\n"); } + + if (platform_get_resource(pdev, IORESOURCE_IRQ, 5) == NULL) { + /* + * Some devices detected as BYT-T have only a single IRQ listed, + * causing platform_get_irq with index 5 to return -ENXIO. + * The correct IRQ in this case is at index 0, as on BYT-CR. + */ + dev_info(dev, "Falling back to Baytrail-CR platform\n"); + return true; + } + return false; } @@ -331,7 +343,7 @@ static int sst_acpi_probe(struct platform_device *pdev) if (ret < 0) return ret; - if (is_byt_cr(dev)) { + if (is_byt_cr(pdev)) { /* override resource info */ byt_rvp_platform_data.res_info = &bytcr_res_info; } From 1c80cec3376c850425c2b7f99b5121f079b89c91 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 2 Jan 2019 20:39:08 +0100 Subject: [PATCH 0981/1995] ASoC: Intel: bytcr_rt5640: Add quirks for ASUS MeMO Pad 7 (ME176C) Add quirks to select the correct input map, jack-detect options and channel map to make sound work on the ASUS MeMO Pad 7 (ME176C). Note: Although sound works out of the box, jack detection currently requires overriding the ACPI DSDT table. This is necessary because the rt5640 ACPI device (10EC5640) has the wrong GPIO listed as interrupt (one of the Bluetooth GPIOs). The correct GPIO is GPO2 0x0004 (listed as the first GPIO in the Intel(R) Audio Machine Driver - AMCR0F28 device). Signed-off-by: Stephan Gerhold Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 51a13e401a83ef37aa98c049c2c30bba885676c2) --- sound/soc/intel/boards/bytcr_rt5640.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index a22366ce33c403..ca8b4d5ff70f9f 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -428,6 +428,18 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF1 | BYT_RT5640_MCLK_EN), }, + { + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ME176C"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), From 8e657848256d7914819e2d9853ee48ec74171a8f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:29 -0600 Subject: [PATCH 0982/1995] ASoC: dmic: declare trigger function as static No reason why this is global, fix warnings with W=1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 902d82222270c957d12fa2e9856484d600a88d20) --- sound/soc/codecs/dmic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index da921da50ef0fc..de041369e5a749 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -44,8 +44,8 @@ struct dmic { int modeswitch_delay; }; -int dmic_daiops_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) +static int dmic_daiops_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; struct dmic *dmic = snd_soc_component_get_drvdata(component); From ffafb952fdb2974125baf41a8034cf2b1562d974 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:30 -0600 Subject: [PATCH 0983/1995] ASoC: max98090: remove unused constant variables Fix warnings with W=1 If these variables are useful then this driver should be modified to expose them. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 97d8f6b71f56865e52d472247fe728700ef7128d) --- sound/soc/codecs/max98090.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index c97f21836c66a2..30c242c38d9960 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -314,9 +314,6 @@ static const DECLARE_TLV_DB_SCALE(max98090_av_tlv, -1200, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_dvg_tlv, 0, 600, 0); static const DECLARE_TLV_DB_SCALE(max98090_dv_tlv, -1500, 100, 0); -static const DECLARE_TLV_DB_SCALE(max98090_sidetone_tlv, -6050, 200, 0); - -static const DECLARE_TLV_DB_SCALE(max98090_alc_tlv, -1500, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_alcmakeup_tlv, 0, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_alccomp_tlv, -3100, 100, 0); static const DECLARE_TLV_DB_SCALE(max98090_drcexp_tlv, -6600, 100, 0); @@ -817,18 +814,6 @@ static SOC_ENUM_SINGLE_VIRT_DECL(dmic_mux_enum, dmic_mux_text); static const struct snd_kcontrol_new max98090_dmic_mux = SOC_DAPM_ENUM("DMIC Mux", dmic_mux_enum); -static const char *max98090_micpre_text[] = { "Off", "On" }; - -static SOC_ENUM_SINGLE_DECL(max98090_pa1en_enum, - M98090_REG_MIC1_INPUT_LEVEL, - M98090_MIC_PA1EN_SHIFT, - max98090_micpre_text); - -static SOC_ENUM_SINGLE_DECL(max98090_pa2en_enum, - M98090_REG_MIC2_INPUT_LEVEL, - M98090_MIC_PA2EN_SHIFT, - max98090_micpre_text); - /* LINEA mixer switch */ static const struct snd_kcontrol_new max98090_linea_mixer_controls[] = { SOC_DAPM_SINGLE("IN1 Switch", M98090_REG_LINE_INPUT_CONFIG, From d4df48869c83932843ea8a53dc2d107f7492d860 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:31 -0600 Subject: [PATCH 0984/1995] ASoC: es8316: remove unused constant variables Fix warnings with W=1 If these variables are useful this driver should be modified to expose them. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 37b6f0350374e6c683bc2c2d8a54d4504bc04ec1) --- sound/soc/codecs/es8316.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 98464ba1046c18..6d4a323f786b00 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -167,8 +167,6 @@ static const char * const es8316_hpmux_texts[] = { "lin-rin with Boost and PGA" }; -static const unsigned int es8316_hpmux_values[] = { 0, 1, 2, 3 }; - static SOC_ENUM_SINGLE_DECL(es8316_left_hpmux_enum, ES8316_HPMIX_SEL, 4, es8316_hpmux_texts); @@ -199,8 +197,6 @@ static const char * const es8316_dacsrc_texts[] = { "RDATA TO LDAC, LDATA TO RDAC", }; -static const unsigned int es8316_dacsrc_values[] = { 0, 1, 2, 3 }; - static SOC_ENUM_SINGLE_DECL(es8316_dacsrc_mux_enum, ES8316_DAC_SET1, 6, es8316_dacsrc_texts); From 8c4ddb16fa278cbfff0c6ac088ccd72add971844 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:32 -0600 Subject: [PATCH 0985/1995] ASoC: codecs: fix kernel doc descriptions Missing or spurious parameter descriptions. Fix warnings with W=1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit dc22a4093f5d2973bef5f72b00da74ce61458bc0) --- sound/soc/codecs/nau8825.c | 1 + sound/soc/codecs/rt5514.c | 1 + sound/soc/codecs/rt5677.c | 8 ++++---- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 7bbcbf5f05c887..47e65cf9987925 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -351,6 +351,7 @@ static void nau8825_hpvol_ramp(struct nau8825 *nau8825, * Computes log10 of a value; the result is round off to 3 decimal. This func- * tion takes reference to dvb-math. The source code locates as the following. * Linux/drivers/media/dvb-core/dvb_math.c + * @value: input for log10 * * return log10(value) * 1000 */ diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index a67de68b6da6c6..f9ad6e36ab16bc 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -489,6 +489,7 @@ static const struct snd_kcontrol_new rt5514_sto2_dmic_mux = /** * rt5514_calc_dmic_clk - Calculate the frequency divider parameter of dmic. * + * @component: only used for dev_warn * @rate: base clock rate. * * Choose divider parameter that gives the highest possible DMIC frequency in diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 9b7a1833d3316c..6fc70e441458de 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -547,7 +547,7 @@ static bool rt5677_readable_register(struct device *dev, unsigned int reg) * @rt5677: Private Data. * @addr: Address index. * @value: Address data. - * + * @opcode: opcode value * * Returns 0 for success or negative error code. */ @@ -602,7 +602,7 @@ static int rt5677_dsp_mode_i2c_write_addr(struct rt5677_priv *rt5677, /** * rt5677_dsp_mode_i2c_read_addr - Read value from address on DSP mode. - * rt5677: Private Data. + * @rt5677: Private Data. * @addr: Address index. * @value: Address data. * @@ -651,7 +651,7 @@ static int rt5677_dsp_mode_i2c_read_addr( /** * rt5677_dsp_mode_i2c_write - Write register on DSP mode. - * rt5677: Private Data. + * @rt5677: Private Data. * @reg: Register index. * @value: Register data. * @@ -667,7 +667,7 @@ static int rt5677_dsp_mode_i2c_write(struct rt5677_priv *rt5677, /** * rt5677_dsp_mode_i2c_read - Read register on DSP mode. - * @codec: SoC audio codec device. + * @rt5677: Private Data * @reg: Register index. * @value: Register data. * From 255bfd335b2b934a754188824d5fc11738be153f Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 4 Jan 2019 20:02:33 -0600 Subject: [PATCH 0986/1995] ASoC: rt5645: remove unused mux define rt5645_if3_adc_in_mux, rt5645_inr_mux, and rt5645_inl_mux are not used. Remove them from the driver. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit c3db21324442137552041711a878d75358c993ae) --- sound/soc/codecs/rt5645.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index be674688dc4061..52ce380c8f3ac6 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -1288,30 +1288,6 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5645_dac_r2_mux = SOC_DAPM_ENUM("DAC2 R source", rt5645_dac2r_enum); - -/* INL/R source */ -static const char * const rt5645_inl_src[] = { - "IN2P", "MonoP" -}; - -static SOC_ENUM_SINGLE_DECL( - rt5645_inl_enum, RT5645_INL1_INR1_VOL, - RT5645_INL_SEL_SFT, rt5645_inl_src); - -static const struct snd_kcontrol_new rt5645_inl_mux = - SOC_DAPM_ENUM("INL source", rt5645_inl_enum); - -static const char * const rt5645_inr_src[] = { - "IN2N", "MonoN" -}; - -static SOC_ENUM_SINGLE_DECL( - rt5645_inr_enum, RT5645_INL1_INR1_VOL, - RT5645_INR_SEL_SFT, rt5645_inr_src); - -static const struct snd_kcontrol_new rt5645_inr_mux = - SOC_DAPM_ENUM("INR source", rt5645_inr_enum); - /* Stereo1 ADC source */ /* MX-27 [12] */ static const char * const rt5645_stereo_adc1_src[] = { @@ -1611,18 +1587,6 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt5645_if2_adc_in_mux = SOC_DAPM_ENUM("IF2 ADC IN source", rt5645_if2_adc_in_enum); -/* MX-2F [1:0] */ -static const char * const rt5645_if3_adc_in_src[] = { - "IF_ADC1", "IF_ADC2", "VAD_ADC" -}; - -static SOC_ENUM_SINGLE_DECL( - rt5645_if3_adc_in_enum, RT5645_DIG_INF1_DATA, - RT5645_IF3_ADC_IN_SFT, rt5645_if3_adc_in_src); - -static const struct snd_kcontrol_new rt5645_if3_adc_in_mux = - SOC_DAPM_ENUM("IF3 ADC IN source", rt5645_if3_adc_in_enum); - /* MX-31 [15] [13] [11] [9] */ static const char * const rt5645_pdm_src[] = { "Mono DAC", "Stereo DAC" From b215b74f21b55b1742d0fb5c50d59802da7b63ee Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 4 Jan 2019 20:02:34 -0600 Subject: [PATCH 0987/1995] ASoC: rt5670: remove unused mux/mixer define Some mux/mixer are not used. Remove them from the driver. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 6606f9df60bcb632e047e0f8a268e327cebcc3db) --- sound/soc/codecs/rt5670.c | 54 --------------------------------------- 1 file changed, 54 deletions(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 453328c988c0cf..9a037108b1aea5 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -1057,20 +1057,6 @@ static const struct snd_kcontrol_new rt5670_lout_mix[] = { RT5670_M_OV_R_LM_SFT, 1, 1), }; -static const struct snd_kcontrol_new rt5670_hpl_mix[] = { - SOC_DAPM_SINGLE("DAC L1 Switch", RT5670_HPO_MIXER, - RT5670_M_DACL1_HML_SFT, 1, 1), - SOC_DAPM_SINGLE("INL1 Switch", RT5670_HPO_MIXER, - RT5670_M_INL1_HML_SFT, 1, 1), -}; - -static const struct snd_kcontrol_new rt5670_hpr_mix[] = { - SOC_DAPM_SINGLE("DAC R1 Switch", RT5670_HPO_MIXER, - RT5670_M_DACR1_HMR_SFT, 1, 1), - SOC_DAPM_SINGLE("INR1 Switch", RT5670_HPO_MIXER, - RT5670_M_INR1_HMR_SFT, 1, 1), -}; - static const struct snd_kcontrol_new lout_l_enable_control = SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5670_LOUT1, RT5670_L_MUTE_SFT, 1, 1); @@ -1196,24 +1182,6 @@ static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc2_enum, RT5670_STO2_ADC_MIXER, static const struct snd_kcontrol_new rt5670_sto2_adc_2_mux = SOC_DAPM_ENUM("Stereo2 ADC 2 Mux", rt5670_stereo2_adc2_enum); - -/* MX-27 MX26 [10] */ -static const char * const rt5670_stereo_adc_src[] = { - "ADC1L ADC2R", "ADC3" -}; - -static SOC_ENUM_SINGLE_DECL(rt5670_stereo1_adc_enum, RT5670_STO1_ADC_MIXER, - RT5670_ADC_SRC_SFT, rt5670_stereo_adc_src); - -static const struct snd_kcontrol_new rt5670_sto_adc_mux = - SOC_DAPM_ENUM("Stereo1 ADC source", rt5670_stereo1_adc_enum); - -static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_adc_enum, RT5670_STO2_ADC_MIXER, - RT5670_ADC_SRC_SFT, rt5670_stereo_adc_src); - -static const struct snd_kcontrol_new rt5670_sto2_adc_mux = - SOC_DAPM_ENUM("Stereo2 ADC source", rt5670_stereo2_adc_enum); - /* MX-27 MX-26 [9:8] */ static const char * const rt5670_stereo_dmic_src[] = { "DMIC1", "DMIC2", "DMIC3" @@ -1231,17 +1199,6 @@ static SOC_ENUM_SINGLE_DECL(rt5670_stereo2_dmic_enum, RT5670_STO2_ADC_MIXER, static const struct snd_kcontrol_new rt5670_sto2_dmic_mux = SOC_DAPM_ENUM("Stereo2 DMIC source", rt5670_stereo2_dmic_enum); -/* MX-27 [0] */ -static const char * const rt5670_stereo_dmic3_src[] = { - "DMIC3", "PDM ADC" -}; - -static SOC_ENUM_SINGLE_DECL(rt5670_stereo_dmic3_enum, RT5670_STO1_ADC_MIXER, - RT5670_DMIC3_SRC_SFT, rt5670_stereo_dmic3_src); - -static const struct snd_kcontrol_new rt5670_sto_dmic3_mux = - SOC_DAPM_ENUM("Stereo DMIC3 source", rt5670_stereo_dmic3_enum); - /* Mono ADC source */ /* MX-28 [12] */ static const char * const rt5670_mono_adc_l1_src[] = { @@ -1334,17 +1291,6 @@ static SOC_ENUM_SINGLE_DECL(rt5670_if2_adc_in_enum, RT5670_DIG_INF1_DATA, static const struct snd_kcontrol_new rt5670_if2_adc_in_mux = SOC_DAPM_ENUM("IF2 ADC IN source", rt5670_if2_adc_in_enum); -/* MX-30 [5:4] */ -static const char * const rt5670_if4_adc_in_src[] = { - "IF_ADC1", "IF_ADC2", "IF_ADC3" -}; - -static SOC_ENUM_SINGLE_DECL(rt5670_if4_adc_in_enum, RT5670_DIG_INF2_DATA, - RT5670_IF4_ADC_IN_SFT, rt5670_if4_adc_in_src); - -static const struct snd_kcontrol_new rt5670_if4_adc_in_mux = - SOC_DAPM_ENUM("IF4 ADC IN source", rt5670_if4_adc_in_enum); - /* MX-31 [15] [13] [11] [9] */ static const char * const rt5670_pdm_src[] = { "Mono DAC", "Stereo DAC" From 9dcb9d8a3a752ed0584591783ac60af1dfcc4b1a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:35 -0600 Subject: [PATCH 0988/1995] ASoC: max98383: fix boolean assignments to true/false Reported by Coccinelle: sound/soc/codecs/max98373.c:411:2-20: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98373.c:922:2-27: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98373.c:924:2-27: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7c3727ba7de2b94a066e38776660e648fa4ed28a) --- sound/soc/codecs/max98373.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c index 9c8616a7b61c9d..528695cd6a1ca7 100644 --- a/sound/soc/codecs/max98373.c +++ b/sound/soc/codecs/max98373.c @@ -408,7 +408,7 @@ static int max98373_dac_event(struct snd_soc_dapm_widget *w, regmap_update_bits(max98373->regmap, MAX98373_R20FF_GLOBAL_SHDN, MAX98373_GLOBAL_EN_MASK, 0); - max98373->tdm_mode = 0; + max98373->tdm_mode = false; break; default: return 0; @@ -919,9 +919,9 @@ static int max98373_i2c_probe(struct i2c_client *i2c, /* update interleave mode info */ if (device_property_read_bool(&i2c->dev, "maxim,interleave_mode")) - max98373->interleave_mode = 1; + max98373->interleave_mode = true; else - max98373->interleave_mode = 0; + max98373->interleave_mode = false; /* regmap initialization */ From 0633323a6898b561a4a829bece9e95b842381707 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:37 -0600 Subject: [PATCH 0989/1995] ASoC: cs4271: fix boolean assignments Reported by Coccinelle: sound/soc/codecs/cs4271.c:226:2-16: WARNING: Assignment of bool to 0/1 sound/soc/codecs/cs4271.c:229:2-16: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 3c17bcfd35bca1bee34709e7509646b5bc88643f) --- sound/soc/codecs/cs4271.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 849fdb2cb26043..1104830edaf83d 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -223,10 +223,10 @@ static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai, switch (format & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: - cs4271->master = 0; + cs4271->master = false; break; case SND_SOC_DAIFMT_CBM_CFM: - cs4271->master = 1; + cs4271->master = true; val |= CS4271_MODE1_MASTER; break; default: From be9c641c6c72b97c2fcbc2f4d78c4e3637eb77c5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:38 -0600 Subject: [PATCH 0990/1995] ASoC: rt274: fix boolean tests Reported by Coccinelle: sound/soc/codecs/rt274.c:958:6-8: WARNING: Comparison to bool sound/soc/codecs/rt274.c:961:6-9: WARNING: Comparison to bool sound/soc/codecs/rt274.c:384:5-7: WARNING: Comparison to bool sound/soc/codecs/rt274.c:387:5-8: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit b793a1e4ebad5c9066f404dee13fec875fb9b4e5) --- sound/soc/codecs/rt274.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index e2855ab9a2c6b5..9e88f7b25d3808 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -381,10 +381,10 @@ static void rt274_jack_detect_work(struct work_struct *work) if (rt274_jack_detect(rt274, &hp, &mic) < 0) return; - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt274->jack, status, @@ -955,10 +955,10 @@ static irqreturn_t rt274_irq(int irq, void *data) ret = rt274_jack_detect(rt274, &hp, &mic); if (ret == 0) { - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt274->jack, status, From a5227fb8bfbf576c489f47d8c8347d5c97f07f9d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:39 -0600 Subject: [PATCH 0991/1995] ASoc: rt286: fix boolean tests Reported by Coccinelle: sound/soc/codecs/rt286.c:927:5-7: WARNING: Comparison to bool sound/soc/codecs/rt286.c:930:5-8: WARNING: Comparison to bool sound/soc/codecs/rt286.c:299:5-7: WARNING: Comparison to bool sound/soc/codecs/rt286.c:302:5-8: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit af3b2b54cb294b997ad9a2a88ed3c6c9af7d03c0) --- sound/soc/codecs/rt286.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 0b0f748bffbe70..c9457c247a03ca 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -296,10 +296,10 @@ static void rt286_jack_detect_work(struct work_struct *work) rt286_jack_detect(rt286, &hp, &mic); - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt286->jack, status, @@ -924,10 +924,10 @@ static irqreturn_t rt286_irq(int irq, void *data) /* Clear IRQ */ regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x1, 0x1); - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt286->jack, status, From 5ca576b8fd639edf596d59c6494d137cdced6ab4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:40 -0600 Subject: [PATCH 0992/1995] ASoC: rt5640: fix boolean assignments Reported by Coccinelle: sound/soc/codecs/rt5640.c:980:2-17: WARNING: Assignment of bool to 0/1 sound/soc/codecs/rt5640.c:984:2-17: WARNING: Assignment of bool to 0/1 sound/soc/codecs/rt5640.c:2825:1-16: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit e0a99927ff5f395f24e09e6297858cd2006793f7) --- sound/soc/codecs/rt5640.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index fc530481a6e476..b3580ecadecf5b 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -977,11 +977,11 @@ static int rt5640_hp_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: rt5640_pmu_depop(component); - rt5640->hp_mute = 0; + rt5640->hp_mute = false; break; case SND_SOC_DAPM_PRE_PMD: - rt5640->hp_mute = 1; + rt5640->hp_mute = true; msleep(70); break; @@ -2822,7 +2822,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5640->regmap, RT5640_DUMMY1, RT5640_MCLK_DET, RT5640_MCLK_DET); - rt5640->hp_mute = 1; + rt5640->hp_mute = true; rt5640->irq = i2c->irq; INIT_DELAYED_WORK(&rt5640->bp_work, rt5640_button_press_work); INIT_WORK(&rt5640->jack_work, rt5640_jack_work); From 5b3fa6bffe9ea01077f9109ab084f4897ebdd184 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:41 -0600 Subject: [PATCH 0993/1995] ASoC: max98927: fix boolean assignments Reported by Coccinelle: sound/soc/codecs/max98927.c:508:2-20: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98927.c:889:3-28: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98927.c:891:3-28: WARNING: Assignment of bool to 0/1 sound/soc/codecs/max98927.c:893:2-27: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 091cd877d8d6b2b934d565134172db771907d50a) --- sound/soc/codecs/max98927.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index 065303a465359b..e53d2007f3be77 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -505,7 +505,7 @@ static int max98927_dac_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: - max98927->tdm_mode = 0; + max98927->tdm_mode = false; break; case SND_SOC_DAPM_POST_PMU: regmap_update_bits(max98927->regmap, @@ -886,11 +886,11 @@ static int max98927_i2c_probe(struct i2c_client *i2c, if (!of_property_read_u32(i2c->dev.of_node, "interleave_mode", &value)) { if (value > 0) - max98927->interleave_mode = 1; + max98927->interleave_mode = true; else - max98927->interleave_mode = 0; + max98927->interleave_mode = false; } else - max98927->interleave_mode = 0; + max98927->interleave_mode = false; /* regmap initialization */ max98927->regmap From 6976bff30f8cb42d878d7d5c35b3cfcfd8486f43 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:42 -0600 Subject: [PATCH 0994/1995] ASoC: rt5651: fix boolean assignments Reported by Coccinelle: sound/soc/codecs/rt5651.c:750:2-17: WARNING: Assignment of bool to 0/1 sound/soc/codecs/rt5651.c:754:2-17: WARNING: Assignment of bool to 0/1 sound/soc/codecs/rt5651.c:2192:1-16: WARNING: Assignment of bool to 0/1 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 577dc32f9a6fc20cd404e0eb965659e9271c78be) --- sound/soc/codecs/rt5651.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index b7ba64350a07cc..3882e238ff99f0 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -747,11 +747,11 @@ static int rt5651_hp_event(struct snd_soc_dapm_widget *w, RT5651_HP_CP_PD | RT5651_HP_SG_EN); regmap_update_bits(rt5651->regmap, RT5651_PR_BASE + RT5651_CHPUMP_INT_REG1, 0x0700, 0x0400); - rt5651->hp_mute = 0; + rt5651->hp_mute = false; break; case SND_SOC_DAPM_PRE_PMD: - rt5651->hp_mute = 1; + rt5651->hp_mute = true; usleep_range(70000, 75000); break; @@ -2189,7 +2189,7 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); rt5651->irq = i2c->irq; - rt5651->hp_mute = 1; + rt5651->hp_mute = true; INIT_DELAYED_WORK(&rt5651->bp_work, rt5651_button_press_work); INIT_WORK(&rt5651->jack_detect_work, rt5651_jack_detect_work); From f67c75564bfdc13c221fd38a3255d6c45d87b0fe Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:43 -0600 Subject: [PATCH 0995/1995] ASoC: nau8824: fix boolean assignment Reported by Coccinelle: nau8824.c:810:6-12: ERROR: Assignment of bool to non-0/1 constant Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 290da7a7e349566f0e1541b14f25b722f58f236b) --- sound/soc/codecs/nau8824.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index 468d5143e2c4f7..87ed3dc496dc2d 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -807,7 +807,7 @@ static const struct snd_soc_dapm_route nau8824_dapm_routes[] = { static bool nau8824_is_jack_inserted(struct nau8824 *nau8824) { struct snd_soc_jack *jack = nau8824->jack; - bool insert = FALSE; + bool insert = false; if (nau8824->irq && jack) insert = jack->status & SND_JACK_HEADPHONE; From 9427920c8f9d0285e17abed02aefaf73905d136c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:44 -0600 Subject: [PATCH 0996/1995] ASoC: tscs42xx.c: fix boolean test Reported by Coccinelle: sound/soc/codecs/tscs42xx.c:392:5-31: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit f361ca36802031ae3abf9860a02e1d5931c04b63) --- sound/soc/codecs/tscs42xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c index 7396a6e5277e68..27b8c6ba72fa87 100644 --- a/sound/soc/codecs/tscs42xx.c +++ b/sound/soc/codecs/tscs42xx.c @@ -389,7 +389,7 @@ static int dac_event(struct snd_soc_dapm_widget *w, mutex_lock(&tscs42xx->coeff_ram_lock); - if (tscs42xx->coeff_ram_synced == false) { + if (!tscs42xx->coeff_ram_synced) { ret = write_coeff_ram(component, tscs42xx->coeff_ram, 0x00, COEFF_RAM_COEFF_COUNT); if (ret < 0) From 5efcaf103c6850abb572cbe08db75232136bc725 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:45 -0600 Subject: [PATCH 0997/1995] ASoC: mt6351: remove unneeded variable Reported by Coccinelle: mt6351.c:1418:5-8: Unneeded variable: "ret". Return "0" on line 1437 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit d61780c155e8bef8dceb3ac98d29f79c24e264eb) --- sound/soc/codecs/mt6351.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/mt6351.c b/sound/soc/codecs/mt6351.c index f73dcd753584f5..4b3ce01c5a93b6 100644 --- a/sound/soc/codecs/mt6351.c +++ b/sound/soc/codecs/mt6351.c @@ -1415,8 +1415,6 @@ static const struct snd_soc_dapm_route mt6351_dapm_routes[] = { static int mt6351_codec_init_reg(struct snd_soc_component *cmpnt) { - int ret = 0; - /* Disable CLKSQ 26MHz */ regmap_update_bits(cmpnt->regmap, MT6351_TOP_CLKSQ, 0x0001, 0x0); /* disable AUDGLB */ @@ -1434,7 +1432,7 @@ static int mt6351_codec_init_reg(struct snd_soc_component *cmpnt) /* Reverse the PMIC clock*/ regmap_update_bits(cmpnt->regmap, MT6351_AFE_PMIC_NEWIF_CFG2, 0x8000, 0x8000); - return ret; + return 0; } static int mt6351_codec_probe(struct snd_soc_component *cmpnt) From 0cac71094d105b6a8a37c11006c6cbb6b7c0f4c9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:46 -0600 Subject: [PATCH 0998/1995] ASoC: da7219: fix endianness issues Reported by Sparse. da7219.c:440:44: warning: cast to restricted __le16 da7219.c:461:13: warning: incorrect type in assignment (different base types) da7219.c:461:13: expected unsigned short [unsigned] [usertype] val da7219.c:461:13: got restricted __le16 [usertype] da7219.c:1451:16: warning: incorrect type in assignment (different base types) da7219.c:1451:16: expected unsigned short [unsigned] [usertype] offset da7219.c:1451:16: got restricted __le16 [usertype] da7219-aad.c:150:37: warning: incorrect type in assignment (different base types) da7219-aad.c:150:37: expected unsigned short [unsigned] [usertype] tonegen_freq_hptest da7219-aad.c:150:37: got restricted __le16 [usertype] da7219-aad.c:157:37: warning: incorrect type in assignment (different base types) da7219-aad.c:157:37: expected unsigned short [unsigned] [usertype] tonegen_freq_hptest da7219-aad.c:157:37: got restricted __le16 [usertype] Cc: Adam Thomson Signed-off-by: Pierre-Louis Bossart Reviewed-by: Adam Thomson Signed-off-by: Mark Brown (cherry picked from commit 123c3def3bc5ea9958b8191d8139f610ed972d18) --- sound/soc/codecs/da7219-aad.c | 2 +- sound/soc/codecs/da7219.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index 2c7d5088e6f275..e0964b20a38993 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -117,7 +117,7 @@ static void da7219_aad_hptest_work(struct work_struct *work) struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - u16 tonegen_freq_hptest; + __le16 tonegen_freq_hptest; u8 pll_srm_sts, pll_ctrl, gain_ramp_ctrl, accdet_cfg8; int report = 0, ret = 0; diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index e46e9f4bc99468..ce165047b9f936 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -423,7 +423,7 @@ static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mixer_ctrl = (struct soc_mixer_control *) kcontrol->private_value; unsigned int reg = mixer_ctrl->reg; - u16 val; + __le16 val; int ret; mutex_lock(&da7219->ctrl_lock); @@ -450,7 +450,7 @@ static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mixer_ctrl = (struct soc_mixer_control *) kcontrol->private_value; unsigned int reg = mixer_ctrl->reg; - u16 val; + __le16 val; int ret; /* @@ -1396,7 +1396,7 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, struct snd_soc_component *component = dai->component; struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); u8 dai_bclks_per_wclk; - u16 offset; + __le16 offset; u32 frame_size; /* No channels enabled so disable TDM, revert to 64-bit frames */ From 2da4386cdb9bce4d5c272d6c6efa766c64f22803 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:47 -0600 Subject: [PATCH 0999/1995] ASoC: da7219: use logical AND Reported by Sparse: da7219.c:841:57: warning: dubious: x & !y Cc: Adam Thomson Signed-off-by: Pierre-Louis Bossart Reviewed-by: Adam Thomson Signed-off-by: Mark Brown (cherry picked from commit b468f379e1e01b723825267431d3ba60f824fda2) --- sound/soc/codecs/da7219.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index ce165047b9f936..513ec036865363 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -838,7 +838,7 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w, ++i; msleep(50); } - } while ((i < DA7219_SRM_CHECK_RETRIES) & (!srm_lock)); + } while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock)); if (!srm_lock) dev_warn(component->dev, "SRM failed to lock\n"); From be31c9e2358d2899db82b85a65c0deddd29c48d8 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 4 Jan 2019 20:02:48 -0600 Subject: [PATCH 1000/1995] ASoC: rt5645: store eq kcontrol byte in __be The eq parameters binary is stored in __be. However, it is unsigned short in rt5645_eq_param_s{} which will cause incorrect type assignment. So add struct rt5645_eq_param_s_be16{} to store the eq binary and convert it to unsigned short in rt5645->eq_param. Cc: Oder Chiou Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 60b52ed627213d1782e70b9810f5668f61bba3a8) --- sound/soc/codecs/rt5645.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 52ce380c8f3ac6..9a0751978090a2 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -401,6 +401,11 @@ struct rt5645_eq_param_s { unsigned short val; }; +struct rt5645_eq_param_s_be16 { + __be16 reg; + __be16 val; +}; + static const char *const rt5645_supply_names[] = { "avdd", "cpvdd", @@ -672,8 +677,8 @@ static int rt5645_hweq_get(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component); - struct rt5645_eq_param_s *eq_param = - (struct rt5645_eq_param_s *)ucontrol->value.bytes.data; + struct rt5645_eq_param_s_be16 *eq_param = + (struct rt5645_eq_param_s_be16 *)ucontrol->value.bytes.data; int i; for (i = 0; i < RT5645_HWEQ_NUM; i++) { @@ -698,36 +703,33 @@ static int rt5645_hweq_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component); - struct rt5645_eq_param_s *eq_param = - (struct rt5645_eq_param_s *)ucontrol->value.bytes.data; + struct rt5645_eq_param_s_be16 *eq_param = + (struct rt5645_eq_param_s_be16 *)ucontrol->value.bytes.data; int i; for (i = 0; i < RT5645_HWEQ_NUM; i++) { - eq_param[i].reg = be16_to_cpu(eq_param[i].reg); - eq_param[i].val = be16_to_cpu(eq_param[i].val); + rt5645->eq_param[i].reg = be16_to_cpu(eq_param[i].reg); + rt5645->eq_param[i].val = be16_to_cpu(eq_param[i].val); } /* The final setting of the table should be RT5645_EQ_CTRL2 */ for (i = RT5645_HWEQ_NUM - 1; i >= 0; i--) { - if (eq_param[i].reg == 0) + if (rt5645->eq_param[i].reg == 0) continue; - else if (eq_param[i].reg != RT5645_EQ_CTRL2) + else if (rt5645->eq_param[i].reg != RT5645_EQ_CTRL2) return 0; else break; } for (i = 0; i < RT5645_HWEQ_NUM; i++) { - if (!rt5645_validate_hweq(eq_param[i].reg) && - eq_param[i].reg != 0) + if (!rt5645_validate_hweq(rt5645->eq_param[i].reg) && + rt5645->eq_param[i].reg != 0) return 0; - else if (eq_param[i].reg == 0) + else if (rt5645->eq_param[i].reg == 0) break; } - memcpy(rt5645->eq_param, eq_param, - RT5645_HWEQ_NUM * sizeof(struct rt5645_eq_param_s)); - return 0; } From 8a0e0bd60d385e626a338cd5d69ef62af7167678 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 4 Jan 2019 20:02:49 -0600 Subject: [PATCH 1001/1995] ASoC: rl6437a: use __be32 for a __be32 buf The buf in rl6347a_hw_read is __be32. Cc: Oder Chiou Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit b8e022e83ba99a0deb27e929033008402f863dd7) --- sound/soc/codecs/rl6347a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rl6347a.c b/sound/soc/codecs/rl6347a.c index 8f571cf8edd4d0..c0d729b4527724 100644 --- a/sound/soc/codecs/rl6347a.c +++ b/sound/soc/codecs/rl6347a.c @@ -64,8 +64,8 @@ int rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value) struct i2c_client *client = context; struct i2c_msg xfer[2]; int ret; - __be32 be_reg; - unsigned int index, vid, buf = 0x0; + __be32 be_reg, buf = 0x0; + unsigned int index, vid; /* handle index registers */ if (reg <= 0xff) { From 466cf406ba44856e99e2fd0bcef8758d0be157c5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Jan 2019 20:02:36 -0600 Subject: [PATCH 1002/1995] ASoC: rt298: fix boolean tests Reported by Coccinelle: sound/soc/codecs/rt298.c:992:6-8: WARNING: Comparison to bool sound/soc/codecs/rt298.c:995:6-9: WARNING: Comparison to bool sound/soc/codecs/rt298.c:317:5-7: WARNING: Comparison to bool sound/soc/codecs/rt298.c:320:5-8: WARNING: Comparison to bool sound/soc/codecs/rt298.c:348:5-7: WARNING: Comparison to bool sound/soc/codecs/rt298.c:351:5-8: WARNING: Comparison to bool Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit f0627d006047299e427f026942fed22b111f04f5) --- sound/soc/codecs/rt298.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index 06cdba4edfe2cd..bcf5bab3196916 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -314,10 +314,10 @@ static void rt298_jack_detect_work(struct work_struct *work) if (rt298_jack_detect(rt298, &hp, &mic) < 0) return; - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt298->jack, status, @@ -345,10 +345,10 @@ int rt298_mic_detect(struct snd_soc_component *component, struct snd_soc_jack *j regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2); rt298_jack_detect(rt298, &hp, &mic); - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt298->jack, status, @@ -989,10 +989,10 @@ static irqreturn_t rt298_irq(int irq, void *data) regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x1, 0x1); if (ret == 0) { - if (hp == true) + if (hp) status |= SND_JACK_HEADPHONE; - if (mic == true) + if (mic) status |= SND_JACK_MICROPHONE; snd_soc_jack_report(rt298->jack, status, From c8df31c6322384441d4c42e493d5555a30863038 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 25 Dec 2018 14:05:28 +0900 Subject: [PATCH 1003/1995] ASoC: rsnd: update BSDSR/BSDISR handling Current BSDSR/BSDISR are using temporary/generic settings, but it can't handle all SRCx/SoC. It needs to handle correctry. Otherwise, sampling rate converted sound channel will be broken if it was TDM. One note is that it needs to overwrite settings on E3 case. Signed-off-by: Kuninori Morimoto Tested-by: chaoliang qin Tested-by: Yusuke Goda Signed-off-by: Mark Brown (cherry picked from commit 7674bec4fc09e85803a8f2bd26a013d0076a80a9) --- sound/soc/sh/rcar/src.c | 125 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 115 insertions(+), 10 deletions(-) diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 50348a2c920317..db81e066b92ef9 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -14,6 +14,7 @@ */ #include "rsnd.h" +#include #define SRC_NAME "src" @@ -134,20 +135,83 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, return rate; } +const static u32 bsdsr_table_pattern1[] = { + 0x01800000, /* 6 - 1/6 */ + 0x01000000, /* 6 - 1/4 */ + 0x00c00000, /* 6 - 1/3 */ + 0x00800000, /* 6 - 1/2 */ + 0x00600000, /* 6 - 2/3 */ + 0x00400000, /* 6 - 1 */ +}; + +const static u32 bsdsr_table_pattern2[] = { + 0x02400000, /* 6 - 1/6 */ + 0x01800000, /* 6 - 1/4 */ + 0x01200000, /* 6 - 1/3 */ + 0x00c00000, /* 6 - 1/2 */ + 0x00900000, /* 6 - 2/3 */ + 0x00600000, /* 6 - 1 */ +}; + +const static u32 bsisr_table[] = { + 0x00100060, /* 6 - 1/6 */ + 0x00100040, /* 6 - 1/4 */ + 0x00100030, /* 6 - 1/3 */ + 0x00100020, /* 6 - 1/2 */ + 0x00100020, /* 6 - 2/3 */ + 0x00100020, /* 6 - 1 */ +}; + +const static u32 chan288888[] = { + 0x00000006, /* 1 to 2 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ +}; + +const static u32 chan244888[] = { + 0x00000006, /* 1 to 2 */ + 0x0000001e, /* 1 to 4 */ + 0x0000001e, /* 1 to 4 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ + 0x000001fe, /* 1 to 8 */ +}; + +const static u32 chan222222[] = { + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ + 0x00000006, /* 1 to 2 */ +}; + +static const struct soc_device_attribute ov_soc[] = { + { .soc_id = "r8a77990" }, /* E3 */ + { /* sentinel */ } +}; + static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct device *dev = rsnd_priv_to_dev(priv); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + const struct soc_device_attribute *soc = soc_device_match(ov_soc); int is_play = rsnd_io_is_play(io); int use_src = 0; u32 fin, fout; u32 ifscr, fsrate, adinr; u32 cr, route; - u32 bsdsr, bsisr; u32 i_busif, o_busif, tmp; + const u32 *bsdsr_table; + const u32 *chptn; uint ratio; + int chan; + int idx; if (!runtime) return; @@ -155,6 +219,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, fin = rsnd_src_get_in_rate(priv, io); fout = rsnd_src_get_out_rate(priv, io); + chan = rsnd_runtime_channel_original(io); + /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ if (fin == fout) ratio = 0; @@ -173,8 +239,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, /* * SRC_ADINR */ - adinr = rsnd_get_adinr_bit(mod, io) | - rsnd_runtime_channel_original(io); + adinr = rsnd_get_adinr_bit(mod, io) | chan; /* * SRC_IFSCR / SRC_IFSVR @@ -207,21 +272,56 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, /* * SRC_BSDSR / SRC_BSISR + * + * see + * Combination of Register Setting Related to + * FSO/FSI Ratio and Channel, Latency */ switch (rsnd_mod_id(mod)) { + case 0: + chptn = chan288888; + bsdsr_table = bsdsr_table_pattern1; + break; + case 1: + case 3: + case 4: + chptn = chan244888; + bsdsr_table = bsdsr_table_pattern1; + break; + case 2: + case 9: + chptn = chan222222; + bsdsr_table = bsdsr_table_pattern1; + break; case 5: case 6: case 7: case 8: - bsdsr = 0x02400000; /* 6 - 1/6 */ - bsisr = 0x00100060; /* 6 - 1/6 */ + chptn = chan222222; + bsdsr_table = bsdsr_table_pattern2; break; default: - bsdsr = 0x01800000; /* 6 - 1/6 */ - bsisr = 0x00100060 ;/* 6 - 1/6 */ - break; + goto convert_rate_err; } + /* + * E3 need to overwrite + */ + if (soc) + switch (rsnd_mod_id(mod)) { + case 0: + case 4: + chptn = chan222222; + } + + for (idx = 0; idx < ARRAY_SIZE(chan222222); idx++) + if (chptn[idx] & (1 << chan)) + break; + + if (chan > 8 || + idx >= ARRAY_SIZE(chan222222)) + goto convert_rate_err; + /* BUSIF_MODE */ tmp = rsnd_get_busif_shift(io, mod); i_busif = ( is_play ? tmp : 0) | 1; @@ -234,8 +334,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, rsnd_mod_write(mod, SRC_IFSCR, ifscr); rsnd_mod_write(mod, SRC_IFSVR, fsrate); rsnd_mod_write(mod, SRC_SRCCR, cr); - rsnd_mod_write(mod, SRC_BSDSR, bsdsr); - rsnd_mod_write(mod, SRC_BSISR, bsisr); + rsnd_mod_write(mod, SRC_BSDSR, bsdsr_table[idx]); + rsnd_mod_write(mod, SRC_BSISR, bsisr_table[idx]); rsnd_mod_write(mod, SRC_SRCIR, 0); /* cancel initialize */ rsnd_mod_write(mod, SRC_I_BUSIF_MODE, i_busif); @@ -244,6 +344,11 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout); + + return; + +convert_rate_err: + dev_err(dev, "unknown BSDSR/BSDIR settings\n"); } static int rsnd_src_irq(struct rsnd_mod *mod, From af84cf6f7c08c812d6a7a7856362cf30536e109e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:19 +0100 Subject: [PATCH 1004/1995] ASoC: Intel: common: Add quirk for PoV P1006W tablet The Point of View TAB-P1006W-232 (v1.0) tablet uses 10EC5640 as ACPI HID, but it has a rt5651 codec add a quirk for this. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit d3dcc5882ca95c9207b5232395c291d34a511627) --- .../intel/common/soc-acpi-intel-byt-match.c | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 47a90909b95689..96f9c553fe6c9f 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -21,6 +21,7 @@ static unsigned long byt_machine_id; #define BYT_THINKPAD_10 1 +#define BYT_POV_P1006W 2 static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id) { @@ -28,6 +29,11 @@ static int byt_thinkpad10_quirk_cb(const struct dmi_system_id *id) return 1; } +static int byt_pov_p1006w_quirk_cb(const struct dmi_system_id *id) +{ + byt_machine_id = BYT_POV_P1006W; + return 1; +} static const struct dmi_system_id byt_table[] = { { @@ -58,6 +64,17 @@ static const struct dmi_system_id byt_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Miix 2 10"), }, }, + { + /* Point of View mobii wintab p1006w (v1.0) */ + .callback = byt_pov_p1006w_quirk_cb, + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "BayTrail"), + /* Note 105b is Foxcon's USB/PCI vendor id */ + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "105B"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"), + }, + }, { } }; @@ -71,16 +88,30 @@ static struct snd_soc_acpi_mach byt_thinkpad_10 = { .asoc_plat_name = "sst-mfld-platform", }; +static struct snd_soc_acpi_mach byt_pov_p1006w = { + .id = "10EC5640", + .drv_name = "bytcr_rt5651", + .fw_filename = "intel/fw_sst_0f28.bin", + .board = "bytcr_rt5651", + .sof_fw_filename = "intel/sof-byt.ri", + .sof_tplg_filename = "intel/sof-byt-rt5651.tplg", + .asoc_plat_name = "sst-mfld-platform", +}; + static struct snd_soc_acpi_mach *byt_quirk(void *arg) { struct snd_soc_acpi_mach *mach = arg; dmi_check_system(byt_table); - if (byt_machine_id == BYT_THINKPAD_10) + switch (byt_machine_id) { + case BYT_THINKPAD_10: return &byt_thinkpad_10; - else + case BYT_POV_P1006W: + return &byt_pov_p1006w; + default: return mach; + } } struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_legacy_machines[] = { From 2237283e2cc56602a156351a7267e29de23dece0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:20 +0100 Subject: [PATCH 1005/1995] ASoC: rt5651: Add ACPI ID 10EC5640 Some BYT platforms have a RT5651 codec while using an ACPI node with a HID of 10EC5640 to describe the coded. Add the 10EC5640 HID to the acpi_device_id list, so that the rt5651 will bind to the codec on these devices. Like the rt5645 and rt5670 drivers which also have the 10EC5640 ACPI HID in their acpi_device_id list for similar reasons, the rt5651 driver checks the codecs device-id register so that it will only bind if the codec actually is a rt5651 and it will ignore actual rt5640 codecs. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit d306873589c5a4c13df7176cd73d66ebfa690064) --- sound/soc/codecs/rt5651.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 3882e238ff99f0..9a007c16263161 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -2138,6 +2138,7 @@ MODULE_DEVICE_TABLE(of, rt5651_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id rt5651_acpi_match[] = { { "10EC5651", 0 }, + { "10EC5640", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, rt5651_acpi_match); From e84f978237aa1eb8686f67adf395811ed7cf2d67 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:21 +0100 Subject: [PATCH 1006/1995] ASoC: rt5651: Add support for jack detect using an external GPIO Some board designs hook the jack-detect up to an external GPIO, rather then to one of the codec pins, add support for this. Figuring out which GPIO to use is pretty much board specific so I've chosen to let the machine driver pass the gpio_desc as data argument to snd_soc_component_set_jack() rather then add support for getting the GPIO to the codec driver. This keeps the codec code nice and clean. Note that using an external GPIO for this conflicts with button-press support, so this commit disables button-press support when an external GPIO is used. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit c2ec9d957d2bf49d69afb1b872cb2363c6cb5862) --- sound/soc/codecs/rt5651.c | 54 +++++++++++++++++++++++++++------------ sound/soc/codecs/rt5651.h | 1 + 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 9a007c16263161..75994297c8964a 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -1621,6 +1622,12 @@ static bool rt5651_jack_inserted(struct snd_soc_component *component) struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component); int val; + if (rt5651->gpiod_hp_det) { + val = gpiod_get_value_cansleep(rt5651->gpiod_hp_det); + dev_dbg(component->dev, "jack-detect gpio %d\n", val); + return val; + } + val = snd_soc_component_read32(component, RT5651_INT_IRQ_ST); dev_dbg(component->dev, "irq status %#04x\n", val); @@ -1761,6 +1768,13 @@ static int rt5651_detect_headset(struct snd_soc_component *component) return SND_JACK_HEADPHONE; } +static bool rt5651_support_button_press(struct rt5651_priv *rt5651) +{ + /* Button press support only works with internal jack-detection */ + return (rt5651->hp_jack->status & SND_JACK_MICROPHONE) && + rt5651->gpiod_hp_det == NULL; +} + static void rt5651_jack_detect_work(struct work_struct *work) { struct rt5651_priv *rt5651 = @@ -1785,15 +1799,15 @@ static void rt5651_jack_detect_work(struct work_struct *work) WARN_ON(rt5651->ovcd_irq_enabled); rt5651_enable_micbias1_for_ovcd(component); report = rt5651_detect_headset(component); - if (report == SND_JACK_HEADSET) { + dev_dbg(component->dev, "detect report %#02x\n", report); + snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET); + if (rt5651_support_button_press(rt5651)) { /* Enable ovcd IRQ for button press detect. */ rt5651_enable_micbias1_ovcd_irq(component); } else { /* No more need for overcurrent detect. */ rt5651_disable_micbias1_for_ovcd(component); } - dev_dbg(component->dev, "detect report %#02x\n", report); - snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET); } else if (rt5651->ovcd_irq_enabled && rt5651_micbias1_ovcd(component)) { dev_dbg(component->dev, "OVCD IRQ\n"); @@ -1837,16 +1851,20 @@ static void rt5651_cancel_work(void *data) } static void rt5651_enable_jack_detect(struct snd_soc_component *component, - struct snd_soc_jack *hp_jack) + struct snd_soc_jack *hp_jack, + struct gpio_desc *gpiod_hp_det) { struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component); - - /* IRQ output on GPIO1 */ - snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1, - RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ); + bool using_internal_jack_detect = true; /* Select jack detect source */ switch (rt5651->jd_src) { + case RT5651_JD_NULL: + rt5651->gpiod_hp_det = gpiod_hp_det; + if (!rt5651->gpiod_hp_det) + return; /* No jack detect */ + using_internal_jack_detect = false; + break; case RT5651_JD1_1: snd_soc_component_update_bits(component, RT5651_JD_CTRL2, RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_1); @@ -1865,16 +1883,20 @@ static void rt5651_enable_jack_detect(struct snd_soc_component *component, snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1, RT5651_JD2_IRQ_EN, RT5651_JD2_IRQ_EN); break; - case RT5651_JD_NULL: - return; default: dev_err(component->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n"); return; } - /* Enable jack detect power */ - snd_soc_component_update_bits(component, RT5651_PWR_ANLG2, - RT5651_PWR_JD_M, RT5651_PWR_JD_M); + if (using_internal_jack_detect) { + /* IRQ output on GPIO1 */ + snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1, + RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ); + + /* Enable jack detect power */ + snd_soc_component_update_bits(component, RT5651_PWR_ANLG2, + RT5651_PWR_JD_M, RT5651_PWR_JD_M); + } /* Set OVCD threshold current and scale-factor */ snd_soc_component_write(component, RT5651_PR_BASE + RT5651_BIAS_CUR4, @@ -1903,7 +1925,7 @@ static void rt5651_enable_jack_detect(struct snd_soc_component *component, RT5651_MB1_OC_STKY_MASK, RT5651_MB1_OC_STKY_EN); rt5651->hp_jack = hp_jack; - if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) { + if (rt5651_support_button_press(rt5651)) { rt5651_enable_micbias1_for_ovcd(component); rt5651_enable_micbias1_ovcd_irq(component); } @@ -1920,7 +1942,7 @@ static void rt5651_disable_jack_detect(struct snd_soc_component *component) disable_irq(rt5651->irq); rt5651_cancel_work(rt5651); - if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) { + if (rt5651_support_button_press(rt5651)) { rt5651_disable_micbias1_ovcd_irq(component); rt5651_disable_micbias1_for_ovcd(component); snd_soc_jack_report(rt5651->hp_jack, 0, SND_JACK_BTN_0); @@ -1933,7 +1955,7 @@ static int rt5651_set_jack(struct snd_soc_component *component, struct snd_soc_jack *jack, void *data) { if (jack) - rt5651_enable_jack_detect(component, jack); + rt5651_enable_jack_detect(component, jack, data); else rt5651_disable_jack_detect(component); diff --git a/sound/soc/codecs/rt5651.h b/sound/soc/codecs/rt5651.h index ac6de6fb541498..41fcb8b5eb4072 100644 --- a/sound/soc/codecs/rt5651.h +++ b/sound/soc/codecs/rt5651.h @@ -2073,6 +2073,7 @@ struct rt5651_priv { struct regmap *regmap; /* Jack and button detect data */ struct snd_soc_jack *hp_jack; + struct gpio_desc *gpiod_hp_det; struct work_struct jack_detect_work; struct delayed_work bp_work; bool ovcd_irq_enabled; From 8942b511034b3a388e93dc03a534837908470782 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:22 +0100 Subject: [PATCH 1007/1995] ASoC: Intel: bytcr_rt5651: Revert "Fix DMIC map headsetmic mapping" Commit 37c7401e8c1f ("ASoC: Intel: bytcr_rt5651: Fix DMIC map headsetmic mapping"), changed the headsetmic mapping from IN3P to IN2P, this was based on the observation that all bytcr_rt5651 devices I have access to (7 devices) where all using IN3P for the headsetmic. This was an attempt to unifify / simplify the mapping, but it was wrong. None of those devices was actually using a digital internal mic. Now I've access to a Point of View TAB-P1006W-232 (v1.0) tabler, which does use a DMIC and it does have its headsetmic connected to IN2P, showing that the original mapping was correct, so this commit reverts the change changing the mapping back to IN2P. Fixes: 37c7401e8c1f ("ASoC: Intel: bytcr_rt5651: Fix DMIC map ... mapping") Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit aee48a9ffa5a128bf4e433c57c39e015ea5b0208) --- sound/soc/intel/boards/bytcr_rt5651.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index e528995668b78e..0ed844f2ad01ae 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -266,7 +266,7 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = { static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic_map[] = { {"DMIC L1", NULL, "Internal Mic"}, {"DMIC R1", NULL, "Internal Mic"}, - {"IN3P", NULL, "Headset Mic"}, + {"IN2P", NULL, "Headset Mic"}, }; static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_map[] = { From 1ed72ac5f28b6f55e137a5b5765016dc11a56bed Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:23 +0100 Subject: [PATCH 1008/1995] ASoC: Intel: bytcr_rt5651: Add quirks module parameter Add quirks module parameter to allow manually specifying quirks from the kernel commandline (or modprobe.conf). Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit 7eb187313eef4c8faa49f70c9c7d8918e1052207) --- sound/soc/intel/boards/bytcr_rt5651.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 0ed844f2ad01ae..6d8ef9dd106ea3 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -98,6 +98,10 @@ struct byt_rt5651_private { static unsigned long byt_rt5651_quirk = BYT_RT5651_DEFAULT_QUIRKS | BYT_RT5651_IN2_MAP; +static unsigned int quirk_override; +module_param_named(quirk, quirk_override, uint, 0444); +MODULE_PARM_DESC(quirk, "Board-specific quirk override"); + static void log_quirks(struct device *dev) { if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_DMIC_MAP) @@ -973,6 +977,12 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) /* check quirks before creating card */ dmi_check_system(byt_rt5651_quirk_table); + if (quirk_override) { + dev_info(&pdev->dev, "Overriding quirk 0x%x => 0x%x\n", + (unsigned int)byt_rt5651_quirk, quirk_override); + byt_rt5651_quirk = quirk_override; + } + /* Must be called before register_card, also see declaration comment. */ ret_val = byt_rt5651_add_codec_device_props(codec_dev); if (ret_val) { From 57341a5b9e4b843f71f5b60f90ea3d7b58430509 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:24 +0100 Subject: [PATCH 1009/1995] ASoC: Intel: bytcr_rt5651: Add support for jack-detect using an external GPIO Some board designs hook the jack-detect up to an external GPIO, rather then to one of the codec pins, add support for this. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit 90768eaf064041937ef4d6ca95c7e86774cd34a4) --- sound/soc/intel/boards/bytcr_rt5651.c | 43 ++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 6d8ef9dd106ea3..9a2ee9080897e5 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -91,6 +91,7 @@ enum { struct byt_rt5651_private { struct clk *mclk; struct gpio_desc *ext_amp_gpio; + struct gpio_desc *hp_detect; struct snd_soc_jack jack; }; @@ -499,6 +500,7 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card); const struct snd_soc_dapm_route *custom_map; int num_routes; + int report; int ret; card->dapm.idle_bias_off = true; @@ -582,20 +584,27 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) dev_err(card->dev, "unable to set MCLK rate\n"); } - if (BYT_RT5651_JDSRC(byt_rt5651_quirk)) { + report = 0; + if (BYT_RT5651_JDSRC(byt_rt5651_quirk)) + report = SND_JACK_HEADSET | SND_JACK_BTN_0; + else if (priv->hp_detect) + report = SND_JACK_HEADSET; + + if (report) { ret = snd_soc_card_jack_new(runtime->card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &priv->jack, bytcr_jack_pins, + report, &priv->jack, bytcr_jack_pins, ARRAY_SIZE(bytcr_jack_pins)); if (ret) { dev_err(runtime->dev, "jack creation failed %d\n", ret); return ret; } - snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, - KEY_PLAYPAUSE); + if (report & SND_JACK_BTN_0) + snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, + KEY_PLAYPAUSE); - ret = snd_soc_component_set_jack(codec, &priv->jack, NULL); + ret = snd_soc_component_set_jack(codec, &priv->jack, + priv->hp_detect); if (ret) return ret; } @@ -767,7 +776,8 @@ static int byt_rt5651_resume(struct snd_soc_card *card) for_each_card_components(card, component) { if (!strcmp(component->name, byt_rt5651_codec_name)) { dev_dbg(component->dev, "re-enabling jack detect after resume\n"); - snd_soc_component_set_jack(component, &priv->jack, NULL); + snd_soc_component_set_jack(component, &priv->jack, + priv->hp_detect); break; } } @@ -1012,6 +1022,25 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) return ret_val; } } + priv->hp_detect = devm_fwnode_get_index_gpiod_from_child( + &pdev->dev, "hp-detect", 0, + codec_dev->fwnode, + GPIOD_IN, "hp-detect"); + if (IS_ERR(priv->hp_detect)) { + ret_val = PTR_ERR(priv->hp_detect); + switch (ret_val) { + case -ENOENT: + priv->hp_detect = NULL; + break; + default: + dev_err(&pdev->dev, "Failed to get hp-detect GPIO: %d\n", + ret_val); + /* fall through */ + case -EPROBE_DEFER: + put_device(codec_dev); + return ret_val; + } + } } put_device(codec_dev); From e3a82b6b4861dd01e2941403bbaae57f9f134861 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Dec 2018 00:00:25 +0100 Subject: [PATCH 1010/1995] ASoC: Intel: bytcr_rt5651: Add quirk for PoV TAB-P1006W-232 (v1.0) tablet Add a DMI quirk for the Point of View TAB-P1006W-232 (v1.0) tablet, this tablet is special in a number of ways: 1) It uses the 2nd GPIO resource in the ACPI tables for jack-detect rather then using the rt5651 codec's builtin jack-detect functionality 2) It uses the 3th GPIO resource in the ACPI tables to control the external amplifier rather then the usual first non GpioInt resource and the GPIO is active-low. 3) It is a BYTCR device, without a CHAN package and it uses SSP0-AIF1 rather then the default SSP0-AIF2. 4) Its internal mic is a digital mic (the first x86 rt5651 device that I'm aware of which does this), combined with having its headset-mic connected to IN2. Acked-by: Pierre-Louis Bossart Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit fee3e1cbd6cd74925286a571b567ec18728818a7) --- sound/soc/intel/boards/bytcr_rt5651.c | 48 ++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 9a2ee9080897e5..b618d984e2d566 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -95,6 +95,8 @@ struct byt_rt5651_private { struct snd_soc_jack jack; }; +static const struct acpi_gpio_mapping *byt_rt5651_gpios; + /* Default: jack-detect on JD1_1, internal mic on in2, headsetmic on in3 */ static unsigned long byt_rt5651_quirk = BYT_RT5651_DEFAULT_QUIRKS | BYT_RT5651_IN2_MAP; @@ -365,6 +367,22 @@ static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream, return byt_rt5651_prepare_and_enable_pll1(codec_dai, rate, bclk_ratio); } +static const struct acpi_gpio_params pov_p1006w_hp_detect = { 1, 0, false }; +static const struct acpi_gpio_params pov_p1006w_ext_amp_en = { 2, 0, true }; + +static const struct acpi_gpio_mapping byt_rt5651_pov_p1006w_gpios[] = { + { "hp-detect-gpios", &pov_p1006w_hp_detect, 1, }, + { "ext-amp-enable-gpios", &pov_p1006w_ext_amp_en, 1, }, + { }, +}; + +static int byt_rt5651_pov_p1006w_quirk_cb(const struct dmi_system_id *id) +{ + byt_rt5651_quirk = (unsigned long)id->driver_data; + byt_rt5651_gpios = byt_rt5651_pov_p1006w_gpios; + return 1; +} + static int byt_rt5651_quirk_cb(const struct dmi_system_id *id) { byt_rt5651_quirk = (unsigned long)id->driver_data; @@ -440,6 +458,23 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = { .driver_data = (void *)(BYT_RT5651_MCLK_EN | BYT_RT5651_IN1_MAP), }, + { + /* Point of View mobii wintab p1006w (v1.0) */ + .callback = byt_rt5651_pov_p1006w_quirk_cb, + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "BayTrail"), + /* Note 105b is Foxcon's USB/PCI vendor id */ + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "105B"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"), + }, + .driver_data = (void *)(BYT_RT5651_DMIC_MAP | + BYT_RT5651_OVCD_TH_2000UA | + BYT_RT5651_OVCD_SF_0P75 | + BYT_RT5651_DMIC_EN | + BYT_RT5651_MCLK_EN | + BYT_RT5651_SSP0_AIF1), + }, { /* VIOS LTH17 */ .callback = byt_rt5651_quirk_cb, @@ -848,7 +883,7 @@ static int snd_byt_rt5651_acpi_resource(struct acpi_resource *ares, void *arg) return 0; } -static void snd_byt_rt5651_mc_add_amp_en_gpio_mapping(struct device *codec) +static void snd_byt_rt5651_mc_pick_amp_en_gpio_mapping(struct device *codec) { struct byt_rt5651_acpi_resource_data data = { 0, -1 }; LIST_HEAD(resources); @@ -866,10 +901,10 @@ static void snd_byt_rt5651_mc_add_amp_en_gpio_mapping(struct device *codec) switch (data.gpio_int_idx) { case 0: - devm_acpi_dev_add_driver_gpios(codec, byt_rt5651_amp_en_second); + byt_rt5651_gpios = byt_rt5651_amp_en_second; break; case 1: - devm_acpi_dev_add_driver_gpios(codec, byt_rt5651_amp_en_first); + byt_rt5651_gpios = byt_rt5651_amp_en_first; break; default: dev_warn(codec, "Unknown GpioInt index %d, not adding external amplifier GPIO mapping\n", @@ -1001,8 +1036,11 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) } /* Cherry Trail devices use an external amplifier enable gpio */ - if (x86_match_cpu(cherrytrail_cpu_ids)) { - snd_byt_rt5651_mc_add_amp_en_gpio_mapping(codec_dev); + if (x86_match_cpu(cherrytrail_cpu_ids) && !byt_rt5651_gpios) + snd_byt_rt5651_mc_pick_amp_en_gpio_mapping(codec_dev); + + if (byt_rt5651_gpios) { + devm_acpi_dev_add_driver_gpios(codec_dev, byt_rt5651_gpios); priv->ext_amp_gpio = devm_fwnode_get_index_gpiod_from_child( &pdev->dev, "ext-amp-enable", 0, codec_dev->fwnode, From 479f6278b42e96921fd9747825cb90daebc0b319 Mon Sep 17 00:00:00 2001 From: Yizhuo Date: Mon, 7 Jan 2019 12:12:32 -0800 Subject: [PATCH 1011/1995] ASoC: rt274: Variable "buf" in function rt274_jack_detect() could be uninitialized In function rt274_jack_detect(), local variable "buf" could be uninitialized if function regmap_read() returns -EINVAL. However, it will be used to calculate "hp" and "mic" and make their value unpredictable while those value are used in the caller. This is potentially unsafe. Signed-off-by: Yizhuo Signed-off-by: Mark Brown (cherry picked from commit 4a8191aa9e057ea38279ef9e809265ba3966be40) --- sound/soc/codecs/rt274.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index 9e88f7b25d3808..adf59039a3b6ba 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -353,6 +353,7 @@ static void rt274_index_sync(struct snd_soc_component *component) static int rt274_jack_detect(struct rt274_priv *rt274, bool *hp, bool *mic) { unsigned int buf; + int ret; *hp = false; *mic = false; @@ -360,9 +361,15 @@ static int rt274_jack_detect(struct rt274_priv *rt274, bool *hp, bool *mic) if (!rt274->component) return -EINVAL; - regmap_read(rt274->regmap, RT274_GET_HP_SENSE, &buf); + ret = regmap_read(rt274->regmap, RT274_GET_HP_SENSE, &buf); + if (ret) + return ret; + *hp = buf & 0x80000000; - regmap_read(rt274->regmap, RT274_GET_MIC_SENSE, &buf); + ret = regmap_read(rt274->regmap, RT274_GET_MIC_SENSE, &buf); + if (ret) + return ret; + *mic = buf & 0x80000000; pr_debug("*hp = %d *mic = %d\n", *hp, *mic); From 7b6d47b4bdac7874aff6cb74b12b4adf5b5779aa Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Mon, 7 Jan 2019 16:11:46 +0000 Subject: [PATCH 1012/1995] ASoC: da7219: MCLK should be enabled before DAI clocks For platforms using the Common Clock Framework to control the codec's DAI clocks, MCLK should be enabled prior to DAI clocks being turned on. For some platforms the codec is already provided with an MCLK reference and can therefore control MCLK itself as it needs to. To improve functionality MCLK is now added as a parent to the DAI clocks, if MCLK was provided, so that if they are enabled MCLK will automatically be enabled as a prerequisite by the CCF. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown (cherry picked from commit a6028cc60aad18d5d7c25d99b5cb8c24399387c3) --- sound/soc/codecs/da7219.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 513ec036865363..a20a610c7ee557 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1804,7 +1804,7 @@ static const struct clk_ops da7219_dai_clks_ops = { .is_prepared = da7219_dai_clks_is_prepared, }; -static void da7219_register_dai_clks(struct snd_soc_component *component) +static int da7219_register_dai_clks(struct snd_soc_component *component) { struct device *dev = component->dev; struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); @@ -1812,9 +1812,17 @@ static void da7219_register_dai_clks(struct snd_soc_component *component) struct clk_init_data init = {}; struct clk *dai_clks; struct clk_lookup *dai_clks_lookup; + const char *parent_name; + + if (da7219->mclk) { + parent_name = __clk_get_name(da7219->mclk); + init.parent_names = &parent_name; + init.num_parents = 1; + } else { + init.parent_names = NULL; + init.num_parents = 0; + } - init.parent_names = NULL; - init.num_parents = 0; init.name = pdata->dai_clks_name; init.ops = &da7219_dai_clks_ops; da7219->dai_clks_hw.init = &init; @@ -1823,7 +1831,7 @@ static void da7219_register_dai_clks(struct snd_soc_component *component) if (IS_ERR(dai_clks)) { dev_warn(dev, "Failed to register DAI clocks: %ld\n", PTR_ERR(dai_clks)); - return; + return PTR_ERR(dai_clks); } da7219->dai_clks = dai_clks; @@ -1835,13 +1843,18 @@ static void da7219_register_dai_clks(struct snd_soc_component *component) dai_clks_lookup = clkdev_create(dai_clks, pdata->dai_clks_name, "%s", dev_name(dev)); if (!dai_clks_lookup) - dev_warn(dev, "Failed to create DAI clkdev"); + return -ENOMEM; else da7219->dai_clks_lookup = dai_clks_lookup; } + + return 0; } #else -static inline void da7219_register_dai_clks(struct snd_soc_component *component) {} +static inline int da7219_register_dai_clks(struct snd_soc_component *component) +{ + return 0; +} #endif /* CONFIG_COMMON_CLK */ static void da7219_handle_pdata(struct snd_soc_component *component) @@ -1854,8 +1867,6 @@ static void da7219_handle_pdata(struct snd_soc_component *component) da7219->wakeup_source = pdata->wakeup_source; - da7219_register_dai_clks(component); - /* Mic Bias voltages */ switch (pdata->micbias_lvl) { case DA7219_MICBIAS_1_6V: @@ -1947,6 +1958,11 @@ static int da7219_probe(struct snd_soc_component *component) } } + /* Register CCF DAI clock control */ + ret = da7219_register_dai_clks(component); + if (ret) + return ret; + /* Default PC counter to free-running */ snd_soc_component_update_bits(component, DA7219_PC_COUNT, DA7219_PC_FREERUN_MASK, DA7219_PC_FREERUN_MASK); From 93e822e2091f93b1b370a3485b155dcbe19d298b Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 8 Jan 2019 09:13:28 +0000 Subject: [PATCH 1013/1995] ASoC: da7219: Add recalc_rate function to return DAI clock rate By making MCLK parent of DAI clocks, when querying the rate of the clock the rate returned is now given from the parent clock so gives the MCLK rate rather than 0 as previously returned. This is a bit misleading, and actually there's no major reason why we can't at least return the DAI WCLK rate, as set in HW, so that's what we now do. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown (cherry picked from commit a58943abcb08cfbe6c36648602d796c5834ee8a9) --- sound/soc/codecs/da7219.c | 45 ++++++++++++++++++++++++++++++++++++--- sound/soc/codecs/da7219.h | 1 + 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index a20a610c7ee557..b1df4bb361050e 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1767,7 +1767,7 @@ static int da7219_dai_clks_prepare(struct clk_hw *hw) { struct da7219_priv *da7219 = container_of(hw, struct da7219_priv, dai_clks_hw); - struct snd_soc_component *component = da7219->aad->component; + struct snd_soc_component *component = da7219->component; snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, DA7219_DAI_CLK_EN_MASK, @@ -1780,7 +1780,7 @@ static void da7219_dai_clks_unprepare(struct clk_hw *hw) { struct da7219_priv *da7219 = container_of(hw, struct da7219_priv, dai_clks_hw); - struct snd_soc_component *component = da7219->aad->component; + struct snd_soc_component *component = da7219->component; snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, DA7219_DAI_CLK_EN_MASK, 0); @@ -1790,7 +1790,7 @@ static int da7219_dai_clks_is_prepared(struct clk_hw *hw) { struct da7219_priv *da7219 = container_of(hw, struct da7219_priv, dai_clks_hw); - struct snd_soc_component *component = da7219->aad->component; + struct snd_soc_component *component = da7219->component; u8 clk_reg; clk_reg = snd_soc_component_read32(component, DA7219_DAI_CLK_MODE); @@ -1798,10 +1798,47 @@ static int da7219_dai_clks_is_prepared(struct clk_hw *hw) return !!(clk_reg & DA7219_DAI_CLK_EN_MASK); } +static unsigned long da7219_dai_clks_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct da7219_priv *da7219 = + container_of(hw, struct da7219_priv, dai_clks_hw); + struct snd_soc_component *component = da7219->component; + u8 fs = snd_soc_component_read32(component, DA7219_SR); + + switch (fs & DA7219_SR_MASK) { + case DA7219_SR_8000: + return 8000; + case DA7219_SR_11025: + return 11025; + case DA7219_SR_12000: + return 12000; + case DA7219_SR_16000: + return 16000; + case DA7219_SR_22050: + return 22050; + case DA7219_SR_24000: + return 24000; + case DA7219_SR_32000: + return 32000; + case DA7219_SR_44100: + return 44100; + case DA7219_SR_48000: + return 48000; + case DA7219_SR_88200: + return 88200; + case DA7219_SR_96000: + return 96000; + default: + return 0; + } +} + static const struct clk_ops da7219_dai_clks_ops = { .prepare = da7219_dai_clks_prepare, .unprepare = da7219_dai_clks_unprepare, .is_prepared = da7219_dai_clks_is_prepared, + .recalc_rate = da7219_dai_clks_recalc_rate, }; static int da7219_register_dai_clks(struct snd_soc_component *component) @@ -1825,6 +1862,7 @@ static int da7219_register_dai_clks(struct snd_soc_component *component) init.name = pdata->dai_clks_name; init.ops = &da7219_dai_clks_ops; + init.flags = CLK_GET_RATE_NOCACHE; da7219->dai_clks_hw.init = &init; dai_clks = devm_clk_register(dev, &da7219->dai_clks_hw); @@ -1912,6 +1950,7 @@ static int da7219_probe(struct snd_soc_component *component) unsigned int rev; int ret; + da7219->component = component; mutex_init(&da7219->ctrl_lock); mutex_init(&da7219->pll_lock); diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index 3a006862f0e791..366cf46118a005 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -809,6 +809,7 @@ struct da7219_aad_priv; /* Private data */ struct da7219_priv { + struct snd_soc_component *component; struct da7219_aad_priv *aad; struct da7219_pdata *pdata; From a685074c1960e9281492266a893a7c2c2ef1d8cd Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 10 Jan 2019 01:43:09 +0000 Subject: [PATCH 1014/1995] ASoC: Intel: bytcht_es8316: use correct drvdata in snd_byt_cht_es8316_mc_remove() The snd_byt_cht_es8316_mc_remove() use the platform drvdata as a type of 'struct byt_cht_es8316_private', but snd_byt_cht_es8316_mc_probe() set it to 'struct snd_soc_card', as suggested by Dan Carpenter, fix the usage in snd_byt_cht_es8316_mc_remove(). Fixes: 0d3e91da0750 ("ASoC: Intel: bytcht_es8316: Add external speaker mux support") Signed-off-by: Wei Yongjun Acked-by: Pierre-Louis Bossart Reviewed-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit f833fe2056b3a6d69598ef029cede6e77dcc1b14) --- sound/soc/intel/boards/bytcht_es8316.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index cdf2061e7613d9..fa9c4cf97686d9 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -544,7 +544,8 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) static int snd_byt_cht_es8316_mc_remove(struct platform_device *pdev) { - struct byt_cht_es8316_private *priv = platform_get_drvdata(pdev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); gpiod_put(priv->speaker_en_gpio); return 0; From cd9a570bdcfe05567ae0e8fd2d075eb8e61870bd Mon Sep 17 00:00:00 2001 From: Bard liao Date: Thu, 17 Jan 2019 06:08:53 +0800 Subject: [PATCH 1015/1995] ASoC: rt5682: add default pdata for i2s mode Add a default pdata which can fit most HW design. So we don't need to add a lot of DMI checking in this driver. Signed-off-by: Bard liao Signed-off-by: Mark Brown (cherry picked from commit 3ac1b2e4158c73175278a27c5551fa331c260b48) --- sound/soc/codecs/rt5682.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index a9b91bcfcc0967..9d5acd2d04abd4 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -43,6 +43,12 @@ static const char *rt5682_supply_names[RT5682_NUM_SUPPLIES] = { "VBAT", }; +static const struct rt5682_platform_data i2s_default_platform_data = { + .dmic1_data_pin = RT5682_DMIC1_DATA_GPIO2, + .dmic1_clk_pin = RT5682_DMIC1_CLK_GPIO3, + .jd_src = RT5682_JD1, +}; + struct rt5682_priv { struct snd_soc_component *component; struct rt5682_platform_data pdata; @@ -2536,6 +2542,8 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, rt5682); + rt5682->pdata = i2s_default_platform_data; + if (pdata) rt5682->pdata = *pdata; else From e7909bd9eabb163834bf0f976d21a6cd0cdd2f6a Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 18 Jan 2019 10:55:04 +0100 Subject: [PATCH 1016/1995] ASoC: soc-core: remove error due to probe deferral Deferred probes shouldn't cause error messages in the boot log, so change the dev_err() to the more harmless dev_info(). Signed-off-by: Stefan Agner Signed-off-by: Mark Brown (cherry picked from commit 7c7e2d6a9ca3c74ba7ed4da2a75916b2f9ae38f0) --- sound/soc/soc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 50617db05c46b8..d553171db9c92b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -908,8 +908,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card, for (i = 0; i < rtd->num_codecs; i++) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { - dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", - codecs[i].dai_name); + dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", + codecs[i].dai_name); goto _err_defer; } snd_soc_rtdcom_add(rtd, codec_dais[i]->component); From d4b1e14ceb94b8c5ae77efb5d4b59a4c3350f9c0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 18 Jan 2019 11:20:41 +0900 Subject: [PATCH 1017/1995] ASoC: soc.h: add explanation of legacy/modern style of dai_link Current ALSA SoC is assuming 1 CPU 1 Platform (= DMA) style system. Because of this background, it is directly using xxx_name / xxx_of_node / xxx_dai_name on dai_link. Let's call it as legacy style here. More complex style system like multi CPU multi Platform (= DMA) will coming. To supporting it, we can use snd_soc_dai_link_component on dai_link. Let's call it as modern style here. But current ALSA SoC can't support it so far. Thus, we need to have multi CPU / multi Codec / multi Platform style in the future on ALSA SoC. Currently we already have multi Codec support. Platform is starting to use modern style on dai_link, but still style only. Multi Platform is not yet implemented. And we still don't have multi CPU support on ALSA SoC, and not have modern style either. Currently, if driver is using legacy style Codec/Platform, it will be converted to modern style on soc-core. This means, we are using glue code for legacy vs modern style so far on ALSA SoC. We can fully switch to modern style on all drivers if ALSA SoC supported modern style for CPU, and then, legacy style code will be removed from ALSA SoC. Untile then, we need to keep both legacy/modern style and its glue code. This patch adds such future plan and background on soc.h Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 62bc79d35ebb55451112979babea864975cfd16d) --- include/sound/soc.h | 36 ++++++++++++++++++++++++++++++++++++ sound/soc/soc-core.c | 20 ++++++++++++++++++-- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index e665f111b0d275..c31b6d122ff68c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -891,6 +891,18 @@ struct snd_soc_dai_link { /* config - must be set by machine driver */ const char *name; /* Codec name */ const char *stream_name; /* Stream name */ + + /* + * cpu_name + * cpu_of_node + * cpu_dai_name + * + * These are legacy style, and will be replaced to + * modern style (= snd_soc_dai_link_component) in the future, + * but, not yet supported so far. + * If modern style was supported for CPU, all driver will switch + * to use it, and, legacy style code will be removed from ALSA SoC. + */ /* * You MAY specify the link's CPU-side device, either by device name, * or by DT/OF node, but not both. If this information is omitted, @@ -906,6 +918,19 @@ struct snd_soc_dai_link { * only, which only works well when that device exposes a single DAI. */ const char *cpu_dai_name; + + /* + * codec_name + * codec_of_node + * codec_dai_name + * + * These are legacy style, it will be converted to modern style + * (= snd_soc_dai_link_component) automatically in soc-core + * if driver is using legacy style. + * Driver shouldn't use both legacy and modern style in the same time. + * If modern style was supported for CPU, all driver will switch + * to use it, and, legacy style code will be removed from ALSA SoC. + */ /* * You MUST specify the link's codec, either by device name, or by * DT/OF node, but not both. @@ -918,6 +943,17 @@ struct snd_soc_dai_link { struct snd_soc_dai_link_component *codecs; unsigned int num_codecs; + /* + * platform_name + * platform_of_node + * + * These are legacy style, it will be converted to modern style + * (= snd_soc_dai_link_component) automatically in soc-core + * if driver is using legacy style. + * Driver shouldn't use both legacy and modern style in the same time. + * If modern style was supported for CPU, all driver will switch + * to use it, and, legacy style code will be removed from ALSA SoC. + */ /* * You MAY specify the link's platform/PCM/DMA driver, either by * device name, or by DT/OF node, but not both. Some forms of link diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d553171db9c92b..4797e8cf8aa5d5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1034,9 +1034,14 @@ static int snd_soc_init_platform(struct snd_soc_card *card, struct snd_soc_dai_link_component *platform = dai_link->platform; /* - * FIXME + * REMOVE ME * - * this function should be removed in the future + * This is glue code for Legacy vs Modern dai_link. + * This function will be removed if all derivers are switched to + * modern style dai_link. + * Driver shouldn't use both legacy and modern style in the same time. + * see + * soc.h :: struct snd_soc_dai_link */ /* convert Legacy platform link */ if (!platform || dai_link->legacy_platform) { @@ -1064,6 +1069,17 @@ static int snd_soc_init_platform(struct snd_soc_card *card, static int snd_soc_init_multicodec(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { + /* + * REMOVE ME + * + * This is glue code for Legacy vs Modern dai_link. + * This function will be removed if all derivers are switched to + * modern style dai_link. + * Driver shouldn't use both legacy and modern style in the same time. + * see + * soc.h :: struct snd_soc_dai_link + */ + /* Legacy codec/codec_dai link is a single entry in multicodec */ if (dai_link->codec_name || dai_link->codec_of_node || dai_link->codec_dai_name) { From b7f7875ed04f0eec5400adebcd65c3223b5e8e1c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:32 +0900 Subject: [PATCH 1018/1995] ASoC: soc-core: add .num_platform for dai_link Current snd_soc_dai_link is starting to use snd_soc_dai_link_component (= modern) style for Platform, but it is still assuming single Platform so far. We will need to have multi Platform support in the not far future. Currently only simple card is using it as sound card driver, and other drivers are converted to it from legacy style by snd_soc_init_platform(). To avoid future problem of multi Platform support, let's add num_platforms before it is too late. In the same time, to make it same naming mothed, "platform" should be "platforms". This patch fixup it too. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 910fdcabedd2354d161b1beab6ad7dc7e859651d) --- include/sound/simple_card_utils.h | 2 +- include/sound/soc.h | 3 ++- sound/soc/generic/audio-graph-card.c | 5 +++-- sound/soc/generic/simple-card-utils.c | 4 ++-- sound/soc/generic/simple-card.c | 7 ++++--- sound/soc/soc-core.c | 23 ++++++++++++++++------- 6 files changed, 28 insertions(+), 16 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 6d69ed2bd7b111..ab5a2ba09c0779 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -75,7 +75,7 @@ void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai); &dai_link->codec_dai_name, \ list_name, cells_name, NULL) #define asoc_simple_card_parse_platform(node, dai_link, list_name, cells_name) \ - asoc_simple_card_parse_dai(node, dai_link->platform, \ + asoc_simple_card_parse_dai(node, dai_link->platforms, \ &dai_link->platform_of_node, \ NULL, list_name, cells_name, NULL) int asoc_simple_card_parse_dai(struct device_node *node, diff --git a/include/sound/soc.h b/include/sound/soc.h index c31b6d122ff68c..3089257ead9544 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -961,7 +961,8 @@ struct snd_soc_dai_link { */ const char *platform_name; struct device_node *platform_of_node; - struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link_component *platforms; + unsigned int num_platforms; int id; /* optional ID for machine driver link identification */ diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 3ec96cdc683b5a..42b077c6be4c4a 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -26,7 +26,7 @@ struct graph_priv { struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; struct snd_soc_dai_link_component codecs; /* single codec */ - struct snd_soc_dai_link_component platform; + struct snd_soc_dai_link_component platforms; struct asoc_simple_card_data adata; struct snd_soc_codec_conf *codec_conf; unsigned int mclk_fs; @@ -687,7 +687,8 @@ static int graph_probe(struct platform_device *pdev) for (i = 0; i < li.link; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; - dai_link[i].platform = &dai_props[i].platform; + dai_link[i].platforms = &dai_props[i].platforms; + dai_link[i].num_platforms = 1; } priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 336895f7fd1e9e..3c0901df57960a 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -397,8 +397,8 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai); int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link) { /* Assumes platform == cpu */ - if (!dai_link->platform->of_node) - dai_link->platform->of_node = dai_link->cpu_of_node; + if (!dai_link->platforms->of_node) + dai_link->platforms->of_node = dai_link->cpu_of_node; return 0; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 479de236e694e2..d8a0d1ec256e06 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -21,7 +21,7 @@ struct simple_priv { struct asoc_simple_dai *cpu_dai; struct asoc_simple_dai *codec_dai; struct snd_soc_dai_link_component codecs; /* single codec */ - struct snd_soc_dai_link_component platform; + struct snd_soc_dai_link_component platforms; struct asoc_simple_card_data adata; struct snd_soc_codec_conf *codec_conf; unsigned int mclk_fs; @@ -732,7 +732,8 @@ static int simple_probe(struct platform_device *pdev) for (i = 0; i < li.link; i++) { dai_link[i].codecs = &dai_props[i].codecs; dai_link[i].num_codecs = 1; - dai_link[i].platform = &dai_props[i].platform; + dai_link[i].platforms = &dai_props[i].platforms; + dai_link[i].num_platforms = 1; } priv->dai_props = dai_props; @@ -782,7 +783,7 @@ static int simple_probe(struct platform_device *pdev) codecs->name = cinfo->codec; codecs->dai_name = cinfo->codec_dai.name; - platform = dai_link->platform; + platform = dai_link->platforms; platform->name = cinfo->platform; card->name = (cinfo->card) ? cinfo->card : cinfo->name; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4797e8cf8aa5d5..5d8597961e0b20 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -920,7 +920,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, /* find one from the set of registered platforms */ for_each_component(component) { - if (!snd_soc_is_matching_component(dai_link->platform, + if (!snd_soc_is_matching_component(dai_link->platforms, component)) continue; @@ -1031,7 +1031,7 @@ static void soc_remove_dai_links(struct snd_soc_card *card) static int snd_soc_init_platform(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { - struct snd_soc_dai_link_component *platform = dai_link->platform; + struct snd_soc_dai_link_component *platform = dai_link->platforms; /* * REMOVE ME @@ -1051,7 +1051,8 @@ static int snd_soc_init_platform(struct snd_soc_card *card, if (!platform) return -ENOMEM; - dai_link->platform = platform; + dai_link->platforms = platform; + dai_link->num_platforms = 1; dai_link->legacy_platform = 1; platform->name = dai_link->platform_name; platform->of_node = dai_link->platform_of_node; @@ -1141,11 +1142,19 @@ static int soc_init_dai_link(struct snd_soc_card *card, } } + /* FIXME */ + if (link->num_platforms > 1) { + dev_err(card->dev, + "ASoC: multi platform is not yet supported %s\n", + link->name); + return -EINVAL; + } + /* * Platform may be specified by either name or OF node, but * can be left unspecified, and a dummy platform will be used. */ - if (link->platform->name && link->platform->of_node) { + if (link->platforms->name && link->platforms->of_node) { dev_err(card->dev, "ASoC: Both platform name/of_node are set for %s\n", link->name); @@ -1156,8 +1165,8 @@ static int soc_init_dai_link(struct snd_soc_card *card, * Defer card registartion if platform dai component is not added to * component list. */ - if ((link->platform->of_node || link->platform->name) && - !soc_find_component(link->platform->of_node, link->platform->name)) + if ((link->platforms->of_node || link->platforms->name) && + !soc_find_component(link->platforms->of_node, link->platforms->name)) return -EPROBE_DEFER; /* @@ -1961,7 +1970,7 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) dev_err(card->dev, "init platform error"); continue; } - dai_link->platform->name = component->name; + dai_link->platforms->name = component->name; /* convert non BE into BE */ dai_link->no_pcm = 1; From 275d6208c02c2d6c7cf12ca97bbe507cc6713bf0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:37 +0900 Subject: [PATCH 1019/1995] ASoC: soc-core: add new snd_soc_flush_all_delayed_work() soc-core is calling flush_delayed_work() many times for same purpose. Same code in many places makes code un-understandable. This patch adds new snd_soc_flush_all_delayed_work() for it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 65462e445f78cb2f9378443be7ba8b7e07300694) --- sound/soc/soc-core.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 5d8597961e0b20..7b45c5efadda90 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -425,6 +425,14 @@ struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); +static void snd_soc_flush_all_delayed_work(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + + for_each_card_rtds(card, rtd) + flush_delayed_work(&rtd->delayed_work); +} + static void codec2codec_close_delayed_work(struct work_struct *work) { /* @@ -494,8 +502,7 @@ int snd_soc_suspend(struct device *dev) } /* close any waiting streams */ - for_each_card_rtds(card, rtd) - flush_delayed_work(&rtd->delayed_work); + snd_soc_flush_all_delayed_work(card); for_each_card_rtds(card, rtd) { @@ -2233,11 +2240,8 @@ static int soc_probe(struct platform_device *pdev) static int soc_cleanup_card_resources(struct snd_soc_card *card) { - struct snd_soc_pcm_runtime *rtd; - /* make sure any delayed work runs */ - for_each_card_rtds(card, rtd) - flush_delayed_work(&rtd->delayed_work); + snd_soc_flush_all_delayed_work(card); /* free the ALSA card at first; this syncs with pending operations */ snd_card_free(card->snd_card); @@ -2280,8 +2284,7 @@ int snd_soc_poweroff(struct device *dev) * Flush out pmdown_time work - we actually do want to run it * now, we're shutting down so no imminent restart. */ - for_each_card_rtds(card, rtd) - flush_delayed_work(&rtd->delayed_work); + snd_soc_flush_all_delayed_work(card); snd_soc_dapm_shutdown(card); From 0a4cd11bb00f1d8d5047ec3e1e9c83e76a8fee21 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:42 +0900 Subject: [PATCH 1020/1995] ASoC: soc-core: merge card resources cleanup method We need to cleanup card resources when snd_soc_instantiate_card() was failed, or when snd_soc_unbind_card() was called. But they are cleanuping card resources on each way. Same code in many places makes code un-understandable. This patch reuses soc_cleanup_card_resources() for cleanuping code resource. Then, it makes avoiding cleanup order. It will be called from snd_soc_instantiate_card() and snd_soc_unbind_card(). Then, original soc_cleanup_card_resources() included snd_soc_flush_all_delayed_work(), but it is now separated. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 53e947a0e1f770b9707febb7054b856878945d50) --- sound/soc/soc-core.c | 103 ++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 60 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7b45c5efadda90..722a4e29385d29 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2013,6 +2013,29 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) } } +static int soc_cleanup_card_resources(struct snd_soc_card *card) +{ + /* free the ALSA card at first; this syncs with pending operations */ + if (card->snd_card) + snd_card_free(card->snd_card); + + /* remove and free each DAI */ + soc_remove_dai_links(card); + soc_remove_pcm_runtimes(card); + + /* remove auxiliary devices */ + soc_remove_aux_devices(card); + + snd_soc_dapm_free(&card->dapm); + soc_cleanup_card_debugfs(card); + + /* remove the card */ + if (card->remove) + card->remove(card); + + return 0; +} + static int snd_soc_instantiate_card(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; @@ -2022,6 +2045,11 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) mutex_lock(&client_mutex); mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT); + card->dapm.bias_level = SND_SOC_BIAS_OFF; + card->dapm.dev = card->dev; + card->dapm.card = card; + list_add(&card->dapm.list, &card->dapm_list); + /* check whether any platform is ignore machine FE and using topology */ soc_check_tplg_fes(card); @@ -2029,14 +2057,14 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) for_each_card_prelinks(card, i, dai_link) { ret = soc_bind_dai_link(card, dai_link); if (ret != 0) - goto base_error; + goto probe_end; } /* bind aux_devs too */ for (i = 0; i < card->num_aux_devs; i++) { ret = soc_bind_aux_dev(card, i); if (ret != 0) - goto base_error; + goto probe_end; } /* add predefined DAI links to the list */ @@ -2050,16 +2078,11 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dev_err(card->dev, "ASoC: can't create sound card for card %s: %d\n", card->name, ret); - goto base_error; + goto probe_end; } soc_init_card_debugfs(card); - card->dapm.bias_level = SND_SOC_BIAS_OFF; - card->dapm.dev = card->dev; - card->dapm.card = card; - list_add(&card->dapm.list, &card->dapm_list); - #ifdef CONFIG_DEBUG_FS snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root); #endif @@ -2081,7 +2104,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (card->probe) { ret = card->probe(card); if (ret < 0) - goto card_probe_error; + goto probe_end; } /* probe all components used by DAI links on this card */ @@ -2092,7 +2115,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dev_err(card->dev, "ASoC: failed to instantiate card %d\n", ret); - goto probe_dai_err; + goto probe_end; } } } @@ -2100,7 +2123,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* probe auxiliary components */ ret = soc_probe_aux_devices(card); if (ret < 0) - goto probe_dai_err; + goto probe_end; /* * Find new DAI links added during probing components and bind them. @@ -2112,10 +2135,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) ret = soc_init_dai_link(card, dai_link); if (ret) - goto probe_dai_err; + goto probe_end; ret = soc_bind_dai_link(card, dai_link); if (ret) - goto probe_dai_err; + goto probe_end; } /* probe all DAI links on this card */ @@ -2126,7 +2149,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) dev_err(card->dev, "ASoC: failed to instantiate card %d\n", ret); - goto probe_dai_err; + goto probe_end; } } } @@ -2173,7 +2196,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (ret < 0) { dev_err(card->dev, "ASoC: %s late_probe() failed: %d\n", card->name, ret); - goto probe_aux_dev_err; + goto probe_end; } } @@ -2183,33 +2206,17 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) if (ret < 0) { dev_err(card->dev, "ASoC: failed to register soundcard %d\n", ret); - goto probe_aux_dev_err; + goto probe_end; } card->instantiated = 1; dapm_mark_endpoints_dirty(card); snd_soc_dapm_sync(&card->dapm); - mutex_unlock(&card->mutex); - mutex_unlock(&client_mutex); - - return 0; -probe_aux_dev_err: - soc_remove_aux_devices(card); - -probe_dai_err: - soc_remove_dai_links(card); - -card_probe_error: - if (card->remove) - card->remove(card); - - snd_soc_dapm_free(&card->dapm); - soc_cleanup_card_debugfs(card); - snd_card_free(card->snd_card); +probe_end: + if (ret < 0) + soc_cleanup_card_resources(card); -base_error: - soc_remove_pcm_runtimes(card); mutex_unlock(&card->mutex); mutex_unlock(&client_mutex); @@ -2238,31 +2245,6 @@ static int soc_probe(struct platform_device *pdev) return snd_soc_register_card(card); } -static int soc_cleanup_card_resources(struct snd_soc_card *card) -{ - /* make sure any delayed work runs */ - snd_soc_flush_all_delayed_work(card); - - /* free the ALSA card at first; this syncs with pending operations */ - snd_card_free(card->snd_card); - - /* remove and free each DAI */ - soc_remove_dai_links(card); - soc_remove_pcm_runtimes(card); - - /* remove auxiliary devices */ - soc_remove_aux_devices(card); - - snd_soc_dapm_free(&card->dapm); - soc_cleanup_card_debugfs(card); - - /* remove the card */ - if (card->remove) - card->remove(card); - - return 0; -} - /* removes a socdev */ static int soc_remove(struct platform_device *pdev) { @@ -2828,6 +2810,7 @@ static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) if (card->instantiated) { card->instantiated = false; snd_soc_dapm_shutdown(card); + snd_soc_flush_all_delayed_work(card); soc_cleanup_card_resources(card); if (!unregister) list_add(&card->list, &unbind_card_list); From 77bc5fb1aba91328f393056c68a30e7870212908 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:50 +0900 Subject: [PATCH 1021/1995] ASoC: soc-core: reduce if/else nest on soc_probe_link_dais Deep nested codec is not readable. Let's reduce if/else nest. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 52293596f5afff10d14e033aa3edfc801a31b3a1) --- sound/soc/soc-core.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 722a4e29385d29..69944658322065 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1617,27 +1617,24 @@ static int soc_probe_link_dais(struct snd_soc_card *card, dai_link->stream_name); return ret; } - } else { - - if (!dai_link->params) { - /* create the pcm */ - ret = soc_new_pcm(rtd, num); - if (ret < 0) { - dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", - dai_link->stream_name, ret); - return ret; - } - ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); - if (ret < 0) - return ret; - ret = soc_link_dai_pcm_new(rtd->codec_dais, - rtd->num_codecs, rtd); - if (ret < 0) - return ret; - } else { - INIT_DELAYED_WORK(&rtd->delayed_work, - codec2codec_close_delayed_work); + } else if (!dai_link->params) { + /* create the pcm */ + ret = soc_new_pcm(rtd, num); + if (ret < 0) { + dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", + dai_link->stream_name, ret); + return ret; } + ret = soc_link_dai_pcm_new(&cpu_dai, 1, rtd); + if (ret < 0) + return ret; + ret = soc_link_dai_pcm_new(rtd->codec_dais, + rtd->num_codecs, rtd); + if (ret < 0) + return ret; + } else { + INIT_DELAYED_WORK(&rtd->delayed_work, + codec2codec_close_delayed_work); } return 0; From 579d3e1fac0f92a0cbb72d2b52482d2abed05984 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:55 +0900 Subject: [PATCH 1022/1995] ASoC: soc-core: add soc_cleanup_component() We need to cleanup component when soc_probe_component() was failed, or when soc_remove_component() was called. But they are cleanuping component on each way. (And soc_probe_component() doesn't call snd_soc_dapm_free(), but it should). Same code in many places makes code un-understandable. This patch adds new soc_cleanup_component() and call it from snd_probe_component() and snd_remove_component(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 22d1423187e5b4d9d5a9851f24466fc0f585a36f) --- sound/soc/soc-core.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 69944658322065..779fc6b2461350 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -942,21 +942,24 @@ static int soc_bind_dai_link(struct snd_soc_card *card, return -EPROBE_DEFER; } +static void soc_cleanup_component(struct snd_soc_component *component) +{ + list_del(&component->card_list); + snd_soc_dapm_free(snd_soc_component_get_dapm(component)); + soc_cleanup_component_debugfs(component); + component->card = NULL; + module_put(component->dev->driver->owner); +} + static void soc_remove_component(struct snd_soc_component *component) { if (!component->card) return; - list_del(&component->card_list); - if (component->driver->remove) component->driver->remove(component); - snd_soc_dapm_free(snd_soc_component_get_dapm(component)); - - soc_cleanup_component_debugfs(component); - component->card = NULL; - module_put(component->dev->driver->owner); + soc_cleanup_component(component); } static void soc_remove_dai(struct snd_soc_dai *dai, int order) @@ -1365,6 +1368,8 @@ static int soc_probe_component(struct snd_soc_card *card, component->card = card; dapm->card = card; + INIT_LIST_HEAD(&component->card_list); + INIT_LIST_HEAD(&dapm->list); soc_set_name_prefix(card, component); soc_init_component_debugfs(component); @@ -1427,12 +1432,9 @@ static int soc_probe_component(struct snd_soc_card *card, /* see for_each_card_components */ list_add(&component->card_list, &card->component_dev_list); - return 0; - err_probe: - soc_cleanup_component_debugfs(component); - component->card = NULL; - module_put(component->dev->driver->owner); + if (ret < 0) + soc_cleanup_component(component); return ret; } From 7161196b2dc7f48c1ff606f139eaf49aca014323 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 09:32:59 +0900 Subject: [PATCH 1023/1995] ASoC: soc-core: use for_each_link_codecs() for dai_link codecs We can use for_each_link_codecs() without waiting for_each_rtd_codec_dai() on soc_bind_dai_link(). Let's use for_each macro Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 10dff9b0ddf70bebe9523fc311ec77a872ce0a9c) --- sound/soc/soc-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 779fc6b2461350..63ba03c2abe55c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -875,7 +875,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct snd_soc_dai_link_component *codecs; struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; struct snd_soc_dai **codec_dais; @@ -910,9 +910,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ - /* we can use for_each_rtd_codec_dai() after this */ codec_dais = rtd->codec_dais; - for (i = 0; i < rtd->num_codecs; i++) { + for_each_link_codecs(dai_link, i, codecs) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", From 295724ed7eacb3e9adf0f378f4f5b887d8ad5de4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 21 Jan 2019 16:40:59 +0900 Subject: [PATCH 1024/1995] ASoC: simple-card: rename to asoc_simple_card_canonicalize_platform() Current simple-card is using asoc_simple_card_canonicalize_dailink(). Its naming is "dailink", but is for "platform". We already have asoc_simple_card_canonicalize_cpu() for "cpu", let's follow same naming rule. It never return error, so, void function is better idea. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit fe7ed4dec2e6289eab81dd18c0d613c0851d85a1) --- include/sound/simple_card_utils.h | 2 +- sound/soc/generic/audio-graph-card.c | 11 +++-------- sound/soc/generic/simple-card-utils.c | 7 ++----- sound/soc/generic/simple-card.c | 11 +++-------- 4 files changed, 9 insertions(+), 22 deletions(-) diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index ab5a2ba09c0779..7afe45389972d4 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -108,7 +108,7 @@ int asoc_simple_card_parse_graph_dai(struct device_node *ep, int asoc_simple_card_init_dai(struct snd_soc_dai *dai, struct asoc_simple_dai *simple_dai); -int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link); +void asoc_simple_card_canonicalize_platform(struct snd_soc_dai_link *dai_link); void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link, int is_single_links); diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 42b077c6be4c4a..bb12351330e8c0 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -307,14 +307,12 @@ static int graph_dai_link_of_dpcm(struct graph_priv *priv, "prefix"); } + asoc_simple_card_canonicalize_platform(dai_link); + ret = asoc_simple_card_of_parse_tdm(ep, dai); if (ret) return ret; - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - return ret; - ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep, NULL, &dai_link->dai_fmt); if (ret < 0) @@ -405,10 +403,6 @@ static int graph_dai_link_of(struct graph_priv *priv, if (ret < 0) return ret; - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - return ret; - ret = asoc_simple_card_set_dailink_name(dev, dai_link, "%s-%s", dai_link->cpu_dai_name, @@ -419,6 +413,7 @@ static int graph_dai_link_of(struct graph_priv *priv, dai_link->ops = &graph_ops; dai_link->init = graph_dai_init; + asoc_simple_card_canonicalize_platform(dai_link); asoc_simple_card_canonicalize_cpu(dai_link, of_graph_get_endpoint_count(dai_link->cpu_of_node) == 1); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 3c0901df57960a..5c1424f036202f 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -394,16 +394,13 @@ int asoc_simple_card_init_dai(struct snd_soc_dai *dai, } EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai); -int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link) +void asoc_simple_card_canonicalize_platform(struct snd_soc_dai_link *dai_link) { /* Assumes platform == cpu */ if (!dai_link->platforms->of_node) dai_link->platforms->of_node = dai_link->cpu_of_node; - - return 0; - } -EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_dailink); +EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_platform); void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link, int is_single_links) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index d8a0d1ec256e06..08df261024cfa6 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -297,14 +297,12 @@ static int simple_dai_link_of_dpcm(struct simple_priv *priv, simple_get_conversion(dev, np, &dai_props->adata); + asoc_simple_card_canonicalize_platform(dai_link); + ret = asoc_simple_card_of_parse_tdm(np, dai); if (ret) return ret; - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - return ret; - snprintf(prop, sizeof(prop), "%smclk-fs", prefix); of_property_read_u32(top, PREFIX "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(node, prop, &dai_props->mclk_fs); @@ -409,10 +407,6 @@ static int simple_dai_link_of(struct simple_priv *priv, if (ret < 0) goto dai_link_of_err; - ret = asoc_simple_card_canonicalize_dailink(dai_link); - if (ret < 0) - goto dai_link_of_err; - ret = asoc_simple_card_set_dailink_name(dev, dai_link, "%s-%s", dai_link->cpu_dai_name, @@ -424,6 +418,7 @@ static int simple_dai_link_of(struct simple_priv *priv, dai_link->init = simple_dai_init; asoc_simple_card_canonicalize_cpu(dai_link, single_cpu); + asoc_simple_card_canonicalize_platform(dai_link); dai_link_of_err: of_node_put(node); From bf43930d34c367ce066d2e9a38e5410231dbf035 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 22 Jan 2019 17:36:11 +0000 Subject: [PATCH 1025/1995] ASoC: core: Fix multi-CODEC setups Revert 10dff9b0d (ASoC: soc-core: use for_each_link_codecs() for dai_link codecs) for now as Sylwester Nawrocki reports that it causes oopses on at least Odroid boards. Reported-by: Sylwester Nawrocki Signed-off-by: Mark Brown (cherry picked from commit 3f6a125230d8bfcbfe0c06ff0b8eaccbc727acd7) --- sound/soc/soc-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 63ba03c2abe55c..779fc6b2461350 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -875,7 +875,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai_link_component *codecs; + struct snd_soc_dai_link_component *codecs = dai_link->codecs; struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; struct snd_soc_dai **codec_dais; @@ -910,8 +910,9 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ + /* we can use for_each_rtd_codec_dai() after this */ codec_dais = rtd->codec_dais; - for_each_link_codecs(dai_link, i, codecs) { + for (i = 0; i < rtd->num_codecs; i++) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", From 5d558ee51b0f8f69130cc41bbe6033136c1a6d8e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 24 Jan 2019 17:37:35 +0000 Subject: [PATCH 1026/1995] ASoC: Intel: make const arrays static, reduces object code size Don't populate the const arrays on the stack but instead make it static. Makes the object code smaller, for example: Before: text data bss dec hex filename 14107 8832 224 23163 5a7b bytcht_es8316.o After: text data bss dec hex filename 14015 8896 224 23135 5a5f bytcht_es8316.o (gcc version 8.2.0 x86_64) Signed-off-by: Colin Ian King Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 4ffdca62e2deee7a27613571c9bd18c95b8eac84) --- sound/soc/intel/boards/bytcht_es8316.c | 2 +- sound/soc/intel/boards/bytcr_rt5640.c | 2 +- sound/soc/intel/boards/bytcr_rt5651.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index fa9c4cf97686d9..1364e4e601d837 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -437,7 +437,7 @@ static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = { static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { - const char * const mic_name[] = { "in1", "in2" }; + static const char * const mic_name[] = { "in1", "in2" }; struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index ca8b4d5ff70f9f..a79466c8fb2961 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1149,7 +1149,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { - const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; + static const char * const map_name[] = { "dmic1", "dmic2", "in1", "in3" }; const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index b618d984e2d566..e6945d11c8abde 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -919,7 +919,7 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) { - const char * const mic_name[] = { "dmic", "in1", "in2", "in12" }; + static const char * const mic_name[] = { "dmic", "in1", "in2", "in12" }; struct byt_rt5651_private *priv; struct snd_soc_acpi_mach *mach; struct device *codec_dev; From e2cb4613f9cbbcb55ddf92d5ea92d7b46c8df47d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 28 Jan 2019 11:24:34 +0900 Subject: [PATCH 1027/1995] [BP_CONFLICT] ASoC: Fixup build error for mt6358 This patch fixup build error for commit 6a8d4198ca8 ("ASoC: mediatek: mt6358: add codec driver") Fixes: commit 6a8d4198ca8 ("ASoC: mediatek: mt6358: add codec driver") Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 141474c6ac7f279824780453d3f9c75d6193dc85) --- sound/soc/codecs/Kconfig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 62bdb7e333b84f..38d08a7e618049 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1325,6 +1325,12 @@ config SND_SOC_ML26124 config SND_SOC_MT6351 tristate "MediaTek MT6351 Codec" +config SND_SOC_MT6358 + tristate "MediaTek MT6358 Codec" + help + Enable support for the platform which uses MT6358 as + external codec device. + config SND_SOC_NAU8540 tristate "Nuvoton Technology Corporation NAU85L40 CODEC" depends on I2C From 6f0723f0d93314b93de11345e44ec7532099d12e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 28 Jan 2019 10:40:24 +0900 Subject: [PATCH 1028/1995] ASoC: soc-core: use for_each_link_codecs() for dai_link codecs V2 We can use for_each_link_codecs() without waiting for_each_rtd_codec_dai() on soc_bind_dai_link(). Let's use for_each macro. Fixes: 50acc7e49 ("ASoC: core: Fix multi-CODEC setups") Fixes: 10dff9b0d ("ASoC: soc-core: use for_each_link_codecs() for dai_link codecs") Signed-off-by: Kuninori Morimoto Tested-by: Sylwester Nawrocki Signed-off-by: Mark Brown (cherry picked from commit 720734a0b66f9ca42ec6663a48702b16e49552ee) --- sound/soc/soc-core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 779fc6b2461350..9dad2b1498c1db 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -875,7 +875,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai_link_component *codecs = dai_link->codecs; + struct snd_soc_dai_link_component *codecs; struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_component *component; struct snd_soc_dai **codec_dais; @@ -910,13 +910,12 @@ static int soc_bind_dai_link(struct snd_soc_card *card, rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ - /* we can use for_each_rtd_codec_dai() after this */ codec_dais = rtd->codec_dais; - for (i = 0; i < rtd->num_codecs; i++) { - codec_dais[i] = snd_soc_find_dai(&codecs[i]); + for_each_link_codecs(dai_link, i, codecs) { + codec_dais[i] = snd_soc_find_dai(codecs); if (!codec_dais[i]) { dev_info(card->dev, "ASoC: CODEC DAI %s not registered\n", - codecs[i].dai_name); + codecs->dai_name); goto _err_defer; } snd_soc_rtdcom_add(rtd, codec_dais[i]->component); From 417055c91f8f34f3d5ba425e186b681e11ba4f99 Mon Sep 17 00:00:00 2001 From: Dimitris Papavasiliou Date: Sat, 26 Jan 2019 15:17:01 +0200 Subject: [PATCH 1029/1995] ASoC: pcm512x: Implement the set_bclk_ratio interface Some boards, such as the HiFiBerry DAC+ Pro, use a pair of external oscillators, to generate 44.1 or 48kHz multiples and are forced to resort to hacks [1] in order to support 24-bit data without ending up with fractional dividers. This patch allows the machine driver to use 32-bit frames for 24-bit data to avoid such issues. Although the datasheet (p. 15) seems to suggest that only a handful of ratios are supported, it's not very explicit about it, so we allow the full range of values supported by the underlying register in the callback, to avoid needlessly rejecting potentially usable configurations. [1] http://mailman.alsa-project.org/pipermail/alsa-devel/2018-December/143442.html Signed-off-by: Dimitris Papavasiliou Signed-off-by: Mark Brown (cherry picked from commit ccc8d6c7b6d2f521a4b10c7f6d027f46c7a686bf) --- sound/soc/codecs/pcm512x.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 4cc24a5d5c3167..ce8c5dbd21641e 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -55,6 +55,7 @@ struct pcm512x_priv { unsigned long overclock_dsp; int mute; struct mutex mutex; + unsigned int bclk_ratio; }; /* @@ -915,10 +916,15 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, int fssp; int gpio; - lrclk_div = snd_soc_params_to_frame_size(params); - if (lrclk_div == 0) { - dev_err(dev, "No LRCLK?\n"); - return -EINVAL; + if (pcm512x->bclk_ratio > 0) { + lrclk_div = pcm512x->bclk_ratio; + } else { + lrclk_div = snd_soc_params_to_frame_size(params); + + if (lrclk_div == 0) { + dev_err(dev, "No LRCLK?\n"); + return -EINVAL; + } } if (!pcm512x->pll_out) { @@ -1383,6 +1389,19 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static int pcm512x_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + struct snd_soc_component *component = dai->component; + struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component); + + if (ratio > 256) + return -EINVAL; + + pcm512x->bclk_ratio = ratio; + + return 0; +} + static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_component *component = dai->component; @@ -1435,6 +1454,7 @@ static const struct snd_soc_dai_ops pcm512x_dai_ops = { .hw_params = pcm512x_hw_params, .set_fmt = pcm512x_set_fmt, .digital_mute = pcm512x_digital_mute, + .set_bclk_ratio = pcm512x_set_bclk_ratio, }; static struct snd_soc_dai_driver pcm512x_dai = { From 74eb545def8a19ab959758518ab3dbd1e10f98ae Mon Sep 17 00:00:00 2001 From: Dimitris Papavasiliou Date: Sat, 26 Jan 2019 15:23:45 +0200 Subject: [PATCH 1030/1995] ASoC: pcm512x: Fix clocking calculations when not using the PLL The rationale behind the current calculation is somewhat obscure [1] and can yield slightly wrong dividers in certain cases, which the machine drivers for some boards (like the HiFiBerry DAC+ Pro) seemingly try to circumvent, by updating the rate fraction so as to suit this calculation. The updated calculation should correctly yield the smallest bit clock rate that would fit the frame. [1] http://mailman.alsa-project.org/pipermail/alsa-devel/2019-January/144219.html Signed-off-by: Dimitris Papavasiliou Signed-off-by: Mark Brown (cherry picked from commit 51b033c2608147efe3a5368bfa64837e772d8c55) --- sound/soc/codecs/pcm512x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index ce8c5dbd21641e..ae3bd533eadb5a 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -929,8 +929,8 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, if (!pcm512x->pll_out) { sck_rate = clk_get_rate(pcm512x->sclk); - bclk_div = params->rate_den * 64 / lrclk_div; - bclk_rate = DIV_ROUND_CLOSEST(sck_rate, bclk_div); + bclk_rate = params_rate(params) * lrclk_div; + bclk_div = DIV_ROUND_CLOSEST(sck_rate, bclk_rate); mck_rate = sck_rate; } else { From fceb29eae97245228f8a1b3990f50fef88fd80f4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:16:17 -0600 Subject: [PATCH 1031/1995] ASoC: soc-acpi: add static inline fallbacks when CONFIG_ACPI=n Fix compilation issues reported by 0day-Kbuild with sparc64 w/ SOF. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 5e484ec1758b95e6420787fc17f0e8c5e152c264) --- include/sound/soc-acpi.h | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 266e64e3c24c4f..6cbbeed9cdd0c8 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -22,20 +22,37 @@ struct snd_soc_acpi_package_context { #define SND_ACPI_I2C_ID_LEN (4 + ACPI_ID_LEN + 3 + 1) #if IS_ENABLED(CONFIG_ACPI) +/* acpi match */ +struct snd_soc_acpi_mach * +snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines); + bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], struct snd_soc_acpi_package_context *ctx); + +/* check all codecs */ +struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg); + #else +/* acpi match */ +static inline struct snd_soc_acpi_mach * +snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines) +{ + return NULL; +} + static inline bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], struct snd_soc_acpi_package_context *ctx) { return false; } -#endif -/* acpi match */ -struct snd_soc_acpi_mach * -snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines); +/* check all codecs */ +static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) +{ + return NULL; +} +#endif /** * snd_soc_acpi_mach_params: interface for machine driver configuration @@ -105,7 +122,4 @@ struct snd_soc_acpi_codecs { u8 codecs[SND_SOC_ACPI_MAX_CODECS][ACPI_ID_LEN]; }; -/* check all codecs */ -struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg); - #endif From bad2e8aeaf71261ae88153e37d44954a1457d118 Mon Sep 17 00:00:00 2001 From: Yizhuo Date: Fri, 25 Jan 2019 10:45:37 -0800 Subject: [PATCH 1032/1995] ASoC: rt5651: Variable "ret" in function rt5651_i2c_probe() could be uninitialized In function rt5651_i2c_probe(), local variable "ret" could be uninitialized if function regmap_read() returns -EINVAL. However, this value is used in if statement. This is potentially unsafe. Signed-off-by: Yizhuo Signed-off-by: Mark Brown (cherry picked from commit e20bfeb0b7d808bc05e7c4cb1f492cd31d837da0) --- sound/soc/codecs/rt5651.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 75994297c8964a..29b2d60076b022 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -2181,6 +2181,7 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, { struct rt5651_priv *rt5651; int ret; + int err; rt5651 = devm_kzalloc(&i2c->dev, sizeof(*rt5651), GFP_KERNEL); @@ -2197,7 +2198,10 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, return ret; } - regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret); + err = regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret); + if (err) + return err; + if (ret != RT5651_DEVICE_ID_VALUE) { dev_err(&i2c->dev, "Device with ID register %#x is not rt5651\n", ret); From 1b31cfe8bb1c5d196bf08c08c1464630a4a33fda Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:55 -0600 Subject: [PATCH 1033/1995] ASoC: add helper to change platform name for all dailinks To reuse the same machine drivers with Atom/SST, Skylake and SOF, we need to change the default platform_name (or platforms->name in the "modern" representation). So far, this override was done with an automatic override, which was broken by a set of changes for DT platforms related to deferred probe handling. This automatic override is actually not really needed, the machine driver can already receive the platform name as a platform_data parameter. This is used e.g. for HDaudio support where we have different PCI aliases used for different platforms. We can reuse the same mechanism and modify the machine drivers to override the dailinks prior to registrating the card. This will require additional work for SOF, but with this helper it'll be just two lines of additional code per machine driver which is reused, not the end of the world. This helper can be simplified when all drivers have transitioned to the "modern" representation of dailinks. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit cb50358b83846e4dcb37137c431327c4dd68561b) --- include/sound/soc.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 3089257ead9544..95689680336bd1 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1580,6 +1580,37 @@ struct snd_soc_dai *snd_soc_card_get_codec_dai(struct snd_soc_card *card, return NULL; } +static inline +int snd_soc_fixup_dai_links_platform_name(struct snd_soc_card *card, + const char *platform_name) +{ + struct snd_soc_dai_link *dai_link; + const char *name; + int i; + + if (!platform_name) /* nothing to do */ + return 0; + + /* set platform name for each dailink */ + for_each_card_prelinks(card, i, dai_link) { + name = devm_kstrdup(card->dev, platform_name, GFP_KERNEL); + if (!name) + return -ENOMEM; + + if (dai_link->platforms) + /* only single platform is supported for now */ + dai_link->platforms->name = name; + else + /* + * legacy mode, this case will be removed when all + * derivers are switched to modern style dai_link. + */ + dai_link->platform_name = name; + } + + return 0; +} + #ifdef CONFIG_DEBUG_FS extern struct dentry *snd_soc_debugfs_root; #endif From d8ce36f991b67f91a136d600358886a08b42638e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:56 -0600 Subject: [PATCH 1034/1995] ASoC: Intel: haswell: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit e87055d732e34d8f5fa95da686958b30a03da5b4) --- sound/soc/intel/boards/haswell.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index a4022983a7ce00..971226d420420b 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "../common/sst-dsp.h" @@ -189,8 +190,22 @@ static struct snd_soc_card haswell_rt5640 = { static int haswell_audio_probe(struct platform_device *pdev) { + struct snd_soc_acpi_mach *mach; + const char *platform_name = NULL; + int ret; + haswell_rt5640.dev = &pdev->dev; + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + if (mach) /* extra check since legacy does not pass parameters */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&haswell_rt5640, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, &haswell_rt5640); } From da5356cfea1a3deb09c33c55f495b8a96bdd0449 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:57 -0600 Subject: [PATCH 1035/1995] ASoC: Intel: broadwell: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 2d067b2807f9d3381a37acef1b2f43682a868c7a) --- sound/soc/intel/boards/broadwell.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 99f2a0156ae88c..b86c746d9b7a86 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "../common/sst-dsp.h" #include "../haswell/sst-haswell-ipc.h" @@ -267,7 +268,22 @@ static struct snd_soc_card broadwell_rt286 = { static int broadwell_audio_probe(struct platform_device *pdev) { + struct snd_soc_acpi_mach *mach; + const char *platform_name = NULL; + int ret; + broadwell_rt286.dev = &pdev->dev; + + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + if (mach) /* extra check since legacy does not pass parameters */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&broadwell_rt286, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, &broadwell_rt286); } From c2954f28240f52c4ac0708ee90569c127f2df1fc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:58 -0600 Subject: [PATCH 1036/1995] ASoC: Intel: bdw-rt5677: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7e40ddcf974a970e750420f88365174cfd207b24) --- sound/soc/intel/boards/bdw-rt5677.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index efcfd906c8562b..1844c88ea4e2a0 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "../common/sst-dsp.h" #include "../haswell/sst-haswell-ipc.h" @@ -339,6 +340,9 @@ static struct snd_soc_card bdw_rt5677_card = { static int bdw_rt5677_probe(struct platform_device *pdev) { struct bdw_rt5677_priv *bdw_rt5677; + struct snd_soc_acpi_mach *mach; + const char *platform_name = NULL; + int ret; bdw_rt5677_card.dev = &pdev->dev; @@ -350,6 +354,16 @@ static int bdw_rt5677_probe(struct platform_device *pdev) return -ENOMEM; } + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + if (mach) /* extra check since legacy does not pass parameters */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&bdw_rt5677_card, + platform_name); + if (ret) + return ret; + snd_soc_card_set_drvdata(&bdw_rt5677_card, bdw_rt5677); return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5677_card); From ac36b6fc5e13d9c927b0c876134e5ac0a96a83d5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:34:59 -0600 Subject: [PATCH 1037/1995] ASoC: Intel: bytcr_rt5640: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit bd7661b761bc7f585aad4fc6e5b62d684bdad75b) --- sound/soc/intel/boards/bytcr_rt5640.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index a79466c8fb2961..940eb27158da7e 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1153,6 +1153,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) const struct dmi_system_id *dmi_id; struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; + const char *platform_name; const char *i2c_name = NULL; int ret_val = 0; int dai_index = 0; @@ -1317,6 +1318,14 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); byt_rt5640_card.long_name = byt_rt5640_long_name; + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&byt_rt5640_card, + platform_name); + if (ret_val) + return ret_val; + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); if (ret_val) { From 8bfc3d1d2103458346eee4af85e0c5abe4e08f80 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:00 -0600 Subject: [PATCH 1038/1995] ASoC: Intel: bytcr_rt5651: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 0b2c2093fc3a1f89f2ef15d945c0439ce7b9dd9d) --- sound/soc/intel/boards/bytcr_rt5651.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index e6945d11c8abde..c3b7732929cc76 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -922,6 +922,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) static const char * const mic_name[] = { "dmic", "in1", "in2", "in12" }; struct byt_rt5651_private *priv; struct snd_soc_acpi_mach *mach; + const char *platform_name; struct device *codec_dev; const char *i2c_name = NULL; const char *hp_swapped; @@ -1137,6 +1138,14 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) mic_name[BYT_RT5651_MAP(byt_rt5651_quirk)], hp_swapped); byt_rt5651_card.long_name = byt_rt5651_long_name; + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&byt_rt5651_card, + platform_name); + if (ret_val) + return ret_val; + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card); if (ret_val) { From d837e2c336717b0eb5f4226c07e8ae26f2c25800 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:01 -0600 Subject: [PATCH 1039/1995] ASoC: Intel: bytcht_da7213: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 686338c12a2bd2d27f8444901fb9ce1a4c0c0b58) --- sound/soc/intel/boards/bytcht_da7213.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index 2179dedb28ad6d..b8e884803777b3 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -225,6 +225,7 @@ static int bytcht_da7213_probe(struct platform_device *pdev) { struct snd_soc_card *card; struct snd_soc_acpi_mach *mach; + const char *platform_name; const char *i2c_name = NULL; int dai_index = 0; int ret_val = 0; @@ -250,6 +251,13 @@ static int bytcht_da7213_probe(struct platform_device *pdev) dailink[dai_index].codec_name = codec_name; } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(card, platform_name); + if (ret_val) + return ret_val; + ret_val = devm_snd_soc_register_card(&pdev->dev, card); if (ret_val) { dev_err(&pdev->dev, From 6a705e8984808807347d36bac03c0fb548049b13 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:02 -0600 Subject: [PATCH 1040/1995] ASoC: Intel: bytcht_es8316: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit e4bc6b1195f64d345646709c4a65edf1fc4d3228) --- sound/soc/intel/boards/bytcht_es8316.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 1364e4e601d837..d2a7e6ba11aec1 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -441,6 +441,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; + const char *platform_name; const char *i2c_name = NULL; struct device *codec_dev; int dai_index = 0; @@ -469,6 +470,14 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_dais[dai_index].codec_name = codec_name; } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&byt_cht_es8316_card, + platform_name); + if (ret) + return ret; + /* Check for BYTCR or other platform and setup quirks */ if (x86_match_cpu(baytrail_cpu_ids) && mach->mach_params.acpi_ipc_irq_index == 0) { From a09e1c84143ecd9985b3f5712d25ca43f5eb57a0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:03 -0600 Subject: [PATCH 1041/1995] ASoC: Intel: cht_bsw_max98090_ti: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7e7e24d7c7ff0e85956288915aaa7e682e2ccd55) --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 08a5152e635ac8..3263b0495853c2 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "../../codecs/max98090.h" #include "../atom/sst-atom-controls.h" @@ -420,6 +421,8 @@ static int snd_cht_mc_probe(struct platform_device *pdev) int ret_val = 0; struct cht_mc_private *drv; const char *mclk_name; + struct snd_soc_acpi_mach *mach; + const char *platform_name; int quirks = 0; dmi_id = dmi_first_match(cht_max98090_quirk_table); @@ -442,6 +445,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev) dev_dbg(dev, "Unable to add GPIO mapping table\n"); } + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, + platform_name); + if (ret_val) + return ret_val; + /* register the soc card */ snd_soc_card_cht.dev = &pdev->dev; snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); From a82f4fa9488beaefc2d3e73df30521da8886d276 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:04 -0600 Subject: [PATCH 1042/1995] ASoC: Intel: cht_bsw_nau8824: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 4506db8043341f2351e03d45c0e96c8e1a141dfa) --- sound/soc/intel/boards/cht_bsw_nau8824.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c index 30c46977d53c28..02c2fa23933107 100644 --- a/sound/soc/intel/boards/cht_bsw_nau8824.c +++ b/sound/soc/intel/boards/cht_bsw_nau8824.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include "../atom/sst-atom-controls.h" @@ -246,6 +247,8 @@ static struct snd_soc_card snd_soc_card_cht = { static int snd_cht_mc_probe(struct platform_device *pdev) { struct cht_mc_private *drv; + struct snd_soc_acpi_mach *mach; + const char *platform_name; int ret_val; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); @@ -253,6 +256,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev) return -ENOMEM; snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, + platform_name); + if (ret_val) + return ret_val; + /* register the soc card */ snd_soc_card_cht.dev = &pdev->dev; ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); From 61341adcdffdf09e4a04c2daaa769ef6838c0b38 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:05 -0600 Subject: [PATCH 1043/1995] ASoC: Intel: cht_bsw_rt5645: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 3a934e7c75b446a104bdea3dd676d7199db9a7bd) --- sound/soc/intel/boards/cht_bsw_rt5645.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 250a356a0cbf08..cbc2d458483f3d 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -530,6 +530,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) { struct snd_soc_card *card = snd_soc_cards[0].soc_card; struct snd_soc_acpi_mach *mach; + const char *platform_name; struct cht_mc_private *drv; const char *i2c_name = NULL; bool found = false; @@ -663,6 +664,14 @@ static int snd_cht_mc_probe(struct platform_device *pdev) cht_rt5645_cpu_dai_name; } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(card, + platform_name); + if (ret_val) + return ret_val; + drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); if (IS_ERR(drv->mclk)) { dev_err(&pdev->dev, From 58b89a00b44f55b1a45d4caf6e1e0cc1d7aa4b02 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:06 -0600 Subject: [PATCH 1044/1995] ASoC: Intel: cht_bsw_rt5672: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit f403906da05cdea38c222ef472fdc4df29ece47f) --- sound/soc/intel/boards/cht_bsw_rt5672.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 9de64f447e7bed..f1c1f9dd5353db 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -400,6 +400,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) int ret_val = 0; struct cht_mc_private *drv; struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; + const char *platform_name; const char *i2c_name; int i; @@ -426,6 +427,14 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } } + /* override plaform name, if required */ + platform_name = mach->mach_params.platform; + + ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht, + platform_name); + if (ret_val) + return ret_val; + drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); if (IS_ERR(drv->mclk)) { dev_err(&pdev->dev, From 27234a4a47991194987a987460d39d58bf9a2933 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:07 -0600 Subject: [PATCH 1045/1995] ASoC: Intel: bxt_da7219_max98357a: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7ebf2528eacae2a9c1edff575c3c58b75095ce08) --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 6f052fc8d1e25a..c00925f9da7340 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "../../codecs/hdac_hdmi.h" #include "../../codecs/da7219.h" #include "../../codecs/da7219-aad.h" @@ -584,6 +585,9 @@ static struct snd_soc_card broxton_audio_card = { static int broxton_audio_probe(struct platform_device *pdev) { struct bxt_card_private *ctx; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -594,6 +598,15 @@ static int broxton_audio_probe(struct platform_device *pdev) broxton_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&broxton_audio_card, ctx); + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(&broxton_audio_card, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card); } From 4a7810e07947c39b00dd62414f9a646c33b0fa92 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:08 -0600 Subject: [PATCH 1046/1995] ASoC: Intel: bxt_rt298: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit fbe2c2736e295bf866110c9278504c42498318c5) --- sound/soc/intel/boards/bxt_rt298.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index 27308337ab127a..e91057f83d2058 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include "../../codecs/hdac_hdmi.h" @@ -576,6 +577,9 @@ static int broxton_audio_probe(struct platform_device *pdev) struct bxt_rt286_private *ctx; struct snd_soc_card *card = (struct snd_soc_card *)pdev->id_entry->driver_data; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + int ret; int i; for (i = 0; i < ARRAY_SIZE(broxton_rt298_dais); i++) { @@ -602,6 +606,15 @@ static int broxton_audio_probe(struct platform_device *pdev) card->dev = &pdev->dev; snd_soc_card_set_drvdata(card, ctx); + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(card, + platform_name); + if (ret) + return ret; + return devm_snd_soc_register_card(&pdev->dev, card); } From 3a5453b993b42c967cbd6ef76016c1987034e7c3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Jan 2019 14:35:09 -0600 Subject: [PATCH 1047/1995] ASoC: Intel: glk_rt5682_max98357a: platform name fixup support Add helper to override dailink platform name, if passed as parameter Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 5b14aa718f5993b0ecee3bbd61557468ac2420bf) --- sound/soc/intel/boards/glk_rt5682_max98357a.c | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c index f6597c216fa8d3..d17126f7757cc6 100644 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "../skylake/skl.h" #include "../../codecs/rt5682.h" #include "../../codecs/hdac_hdmi.h" @@ -571,6 +572,10 @@ static struct snd_soc_card glk_audio_card_rt5682_m98357a = { static int geminilake_audio_probe(struct platform_device *pdev) { struct glk_card_private *ctx; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + struct snd_soc_card *card; + int ret; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -578,11 +583,19 @@ static int geminilake_audio_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - glk_audio_card_rt5682_m98357a.dev = &pdev->dev; - snd_soc_card_set_drvdata(&glk_audio_card_rt5682_m98357a, ctx); + card = &glk_audio_card_rt5682_m98357a; + card->dev = &pdev->dev; + snd_soc_card_set_drvdata(card, ctx); + + /* override plaform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(card, platform_name); + if (ret) + return ret; - return devm_snd_soc_register_card(&pdev->dev, - &glk_audio_card_rt5682_m98357a); + return devm_snd_soc_register_card(&pdev->dev, card); } static const struct platform_device_id glk_board_ids[] = { From ffe56ac45b880c8d1d065ab8e1dfc098acf27600 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 29 Jan 2019 09:42:20 -0600 Subject: [PATCH 1048/1995] ASoC: Intel: cht_bsw_rt5672: remove useless test For some reason we test if the machine is passed as a parameter before fixing up the codec name. This is unnecessary, generates false positives in static analysis tools and done only in this machine driver, remove and adjust indentation. Reported-by: Colin Ian King Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 53b6d0adffb0505db5332589e78da1c66f7e626a) --- sound/soc/intel/boards/cht_bsw_rt5672.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index f1c1f9dd5353db..3d5a2b3a06f081 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -411,18 +411,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev) strcpy(drv->codec_name, RT5672_I2C_DEFAULT); /* fixup codec name based on HID */ - if (mach) { - i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); - if (i2c_name) { - snprintf(drv->codec_name, sizeof(drv->codec_name), - "i2c-%s", i2c_name); - for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { - if (!strcmp(cht_dailink[i].codec_name, - RT5672_I2C_DEFAULT)) { - cht_dailink[i].codec_name = - drv->codec_name; - break; - } + i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); + if (i2c_name) { + snprintf(drv->codec_name, sizeof(drv->codec_name), + "i2c-%s", i2c_name); + for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { + if (!strcmp(cht_dailink[i].codec_name, + RT5672_I2C_DEFAULT)) { + cht_dailink[i].codec_name = drv->codec_name; + break; } } } From f9a4e74988e46c5fd68e97365a794e6a4a170ab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Fri, 25 Jan 2019 14:06:42 -0600 Subject: [PATCH 1049/1995] ASoC: topology: Reduce number of dereferences when accessing dobj MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already have passed dobj, there is no reason to access it through containing structs. Signed-off-by: Amadeusz Sławiński Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 33ae6ae2111c3118d8d15eba331b6ba5932825c9) --- sound/soc/soc-topology.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 731b963b6995f6..78b929073f38e7 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -382,10 +382,10 @@ static void remove_mixer(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->control_unload) dobj->ops->control_unload(comp, dobj); - if (sm->dobj.control.kcontrol->tlv.p) - p = sm->dobj.control.kcontrol->tlv.p; - snd_ctl_remove(card, sm->dobj.control.kcontrol); - list_del(&sm->dobj.list); + if (dobj->control.kcontrol->tlv.p) + p = dobj->control.kcontrol->tlv.p; + snd_ctl_remove(card, dobj->control.kcontrol); + list_del(&dobj->list); kfree(sm); kfree(p); } @@ -404,12 +404,12 @@ static void remove_enum(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->control_unload) dobj->ops->control_unload(comp, dobj); - snd_ctl_remove(card, se->dobj.control.kcontrol); - list_del(&se->dobj.list); + snd_ctl_remove(card, dobj->control.kcontrol); + list_del(&dobj->list); - kfree(se->dobj.control.dvalues); + kfree(dobj->control.dvalues); for (i = 0; i < se->items; i++) - kfree(se->dobj.control.dtexts[i]); + kfree(dobj->control.dtexts[i]); kfree(se); } @@ -427,8 +427,8 @@ static void remove_bytes(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->control_unload) dobj->ops->control_unload(comp, dobj); - snd_ctl_remove(card, sb->dobj.control.kcontrol); - list_del(&sb->dobj.list); + snd_ctl_remove(card, dobj->control.kcontrol); + list_del(&dobj->list); kfree(sb); } @@ -464,9 +464,9 @@ static void remove_widget(struct snd_soc_component *comp, snd_ctl_remove(card, kcontrol); - kfree(se->dobj.control.dvalues); + kfree(dobj->control.dvalues); for (j = 0; j < se->items; j++) - kfree(se->dobj.control.dtexts[j]); + kfree(dobj->control.dtexts[j]); kfree(se); kfree(w->kcontrol_news[i].name); From 05b388339a6daa1d674440b0289c7096b3e744ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Fri, 25 Jan 2019 14:06:43 -0600 Subject: [PATCH 1050/1995] ASoC: topology: Remove widgets from dobj list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently when we unload and reload machine driver few times we end with corrupted list and try to cleanup no longer existing objects. Fix this by removing dobj from the list. Signed-off-by: Amadeusz Sławiński Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit a46e8393d128d4e5f722b47f708a0d5de91e0176) --- sound/soc/soc-topology.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 78b929073f38e7..b3b1f37f81d3a6 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -493,6 +493,8 @@ static void remove_widget(struct snd_soc_component *comp, free_news: kfree(w->kcontrol_news); + list_del(&dobj->list); + /* widget w is freed by soc-dapm.c */ } From b7f10f06ef2e42b7c1cd7a822b309b8697c0b5bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Fri, 25 Jan 2019 14:06:44 -0600 Subject: [PATCH 1051/1995] ASoC: topology: Fix memory leak from soc_tplg_denum_create_texts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dtexts is two dimensional array, so we also need to free it after freeing its fields. Signed-off-by: Amadeusz Sławiński Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 34db6a3e91d8f6f6fefbbd9ad7e1efc6f8d440e0) --- sound/soc/soc-topology.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index b3b1f37f81d3a6..9103bcf8a4c5d7 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -410,6 +410,7 @@ static void remove_enum(struct snd_soc_component *comp, kfree(dobj->control.dvalues); for (i = 0; i < se->items; i++) kfree(dobj->control.dtexts[i]); + kfree(dobj->control.dtexts); kfree(se); } @@ -467,6 +468,7 @@ static void remove_widget(struct snd_soc_component *comp, kfree(dobj->control.dvalues); for (j = 0; j < se->items; j++) kfree(dobj->control.dtexts[j]); + kfree(dobj->control.dtexts); kfree(se); kfree(w->kcontrol_news[i].name); @@ -1366,6 +1368,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( kfree(se->dobj.control.dvalues); for (j = 0; j < ec->items; j++) kfree(se->dobj.control.dtexts[j]); + kfree(se->dobj.control.dtexts); kfree(se); kfree(kc[i].name); From 27c8aca45736fa43493456d6057034da2713dda1 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 25 Jan 2019 14:06:45 -0600 Subject: [PATCH 1052/1995] ASoC: topology: fix memory leak in soc_tplg_dapm_widget_create template.sname and template.name are only freed when an error occur. They should be freed in the success return case, too. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7620fe9161cec2722db880affe03f5e9e2bb93d5) --- sound/soc/soc-topology.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 9103bcf8a4c5d7..d8632f0710b845 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1588,6 +1588,9 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, if (ret < 0) goto ready_err; + kfree(template.sname); + kfree(template.name); + return 0; ready_err: From a12460fa52ee221c92a01b7211d4dca64881a89f Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 25 Jan 2019 14:06:46 -0600 Subject: [PATCH 1053/1995] ASoC: topology: add SND_SOC_DOBJ_GRAPH type for dapm routes Add a new dobj type SND_SOC_DOBJ_GRAPH for dapm routes and add snd_soc_dobj member to struct snd_soc_dapm_route. This enables device drivers to save driver specific data pertaining to dapm routes and also be able to clean up the data when the driver module is unloaded. Also, reorder the snd_soc_dobj_type types to align with matching topology header types. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 5c30f43f0625a792c30e465f21dbeb1bb4dfc40b) --- include/sound/soc-dapm.h | 2 ++ include/sound/soc-topology.h | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index bd8163f151cb85..46f2ba3ffcb7c1 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -540,6 +540,8 @@ struct snd_soc_dapm_route { /* Note: currently only supported for links where source is a supply */ int (*connected)(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink); + + struct snd_soc_dobj dobj; }; /* dapm audio path between two widgets */ diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index fa4b8413d2e222..8c43cfc240fa33 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -38,12 +38,13 @@ struct snd_soc_dapm_route; enum snd_soc_dobj_type { SND_SOC_DOBJ_NONE = 0, /* object is not dynamic */ SND_SOC_DOBJ_MIXER, - SND_SOC_DOBJ_ENUM, SND_SOC_DOBJ_BYTES, - SND_SOC_DOBJ_PCM, + SND_SOC_DOBJ_ENUM, + SND_SOC_DOBJ_GRAPH, + SND_SOC_DOBJ_WIDGET, SND_SOC_DOBJ_DAI_LINK, + SND_SOC_DOBJ_PCM, SND_SOC_DOBJ_CODEC_LINK, - SND_SOC_DOBJ_WIDGET, }; /* dynamic control object */ From a91bdf07e0e74b1025fe76ee049bcb8692d00997 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 25 Jan 2019 14:06:47 -0600 Subject: [PATCH 1054/1995] ASoC: topology: modify dapm route loading routine and add dapm route unloading struct snd_soc_dapm_route has been modified to be a dynamic object so that it can be used to save driver specific data while parsing topology and clean up driver-specific data during driver unloading. This patch makes the following changes to accomplish the above: 1. Set the dobj member of snd_soc_dapm_route during the SOC_TPLG_PASS_GRAPH pass of topology parsing. 2. Add the remove_route() routine that will be called while removing all dynamic objects from the component driver. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7df04ea7a31eaa75bdad2905f07cc097b15558ee) --- sound/soc/soc-topology.c | 102 +++++++++++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 16 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index d8632f0710b845..52d0c4e82210e0 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -433,6 +433,23 @@ static void remove_bytes(struct snd_soc_component *comp, kfree(sb); } +/* remove a route */ +static void remove_route(struct snd_soc_component *comp, + struct snd_soc_dobj *dobj, int pass) +{ + struct snd_soc_dapm_route *route = + container_of(dobj, struct snd_soc_dapm_route, dobj); + + if (pass != SOC_TPLG_PASS_GRAPH) + return; + + if (dobj->ops && dobj->ops->dapm_route_unload) + dobj->ops->dapm_route_unload(comp, dobj); + + list_del(&dobj->list); + kfree(route); +} + /* remove a widget and it's kcontrols - routes must be removed first */ static void remove_widget(struct snd_soc_component *comp, struct snd_soc_dobj *dobj, int pass) @@ -1124,9 +1141,10 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, struct snd_soc_tplg_hdr *hdr) { struct snd_soc_dapm_context *dapm = &tplg->comp->dapm; - struct snd_soc_dapm_route route; struct snd_soc_tplg_dapm_graph_elem *elem; - int count = hdr->count, i; + struct snd_soc_dapm_route **routes; + int count = hdr->count, i, j; + int ret = 0; if (tplg->pass != SOC_TPLG_PASS_GRAPH) { tplg->pos += hdr->size + hdr->payload_size; @@ -1145,36 +1163,85 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, dev_dbg(tplg->dev, "ASoC: adding %d DAPM routes for index %d\n", count, hdr->index); + /* allocate memory for pointer to array of dapm routes */ + routes = kcalloc(count, sizeof(struct snd_soc_dapm_route *), + GFP_KERNEL); + if (!routes) + return -ENOMEM; + + /* + * allocate memory for each dapm route in the array. + * This needs to be done individually so that + * each route can be freed when it is removed in remove_route(). + */ + for (i = 0; i < count; i++) { + routes[i] = kzalloc(sizeof(*routes[i]), GFP_KERNEL); + if (!routes[i]) { + /* free previously allocated memory */ + for (j = 0; j < i; j++) + kfree(routes[j]); + + kfree(routes); + return -ENOMEM; + } + } + for (i = 0; i < count; i++) { elem = (struct snd_soc_tplg_dapm_graph_elem *)tplg->pos; tplg->pos += sizeof(struct snd_soc_tplg_dapm_graph_elem); /* validate routes */ if (strnlen(elem->source, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { + ret = -EINVAL; + break; + } if (strnlen(elem->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { + ret = -EINVAL; + break; + } if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return -EINVAL; + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) { + ret = -EINVAL; + break; + } + + routes[i]->source = elem->source; + routes[i]->sink = elem->sink; - route.source = elem->source; - route.sink = elem->sink; - route.connected = NULL; /* set to NULL atm for tplg users */ + /* set to NULL atm for tplg users */ + routes[i]->connected = NULL; if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0) - route.control = NULL; + routes[i]->control = NULL; else - route.control = elem->control; + routes[i]->control = elem->control; + + /* add route dobj to dobj_list */ + routes[i]->dobj.type = SND_SOC_DOBJ_GRAPH; + routes[i]->dobj.ops = tplg->ops; + routes[i]->dobj.index = tplg->index; + list_add(&routes[i]->dobj.list, &tplg->comp->dobj_list); - soc_tplg_add_route(tplg, &route); + soc_tplg_add_route(tplg, routes[i]); /* add route, but keep going if some fail */ - snd_soc_dapm_add_routes(dapm, &route, 1); + snd_soc_dapm_add_routes(dapm, routes[i], 1); } - return 0; + /* free memory allocated for all dapm routes in case of error */ + if (ret < 0) + for (i = 0; i < count ; i++) + kfree(routes[i]); + + /* + * free pointer to array of dapm routes as this is no longer needed. + * The memory allocated for each dapm route will be freed + * when it is removed in remove_route(). + */ + kfree(routes); + + return ret; } static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( @@ -2581,6 +2648,9 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) case SND_SOC_DOBJ_BYTES: remove_bytes(comp, dobj, pass); break; + case SND_SOC_DOBJ_GRAPH: + remove_route(comp, dobj, pass); + break; case SND_SOC_DOBJ_WIDGET: remove_widget(comp, dobj, pass); break; From ff962dd37cd808b3834bb0ef34fc5bc1ca4ab38e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 1 Feb 2019 16:46:27 +0900 Subject: [PATCH 1055/1995] ASoC: rsnd: synchronize connection check for simple-card/audio-graph Current rsnd driver has below function to check connection rsnd_parse_connect_simple() rsnd_parse_connect_graph() But these have different parameters. This patch synchronize these for cleanup. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit f497c88b195eaee8733a304f2a1dc27fb319c9c3) --- sound/soc/sh/rcar/core.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index e819e965e1dbe9..d7ecbfd8504fc9 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1032,16 +1032,13 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { }; static void rsnd_parse_connect_simple(struct rsnd_priv *priv, - struct device_node *dai_np, - int dai_i, int is_play) + struct rsnd_dai_stream *io, + struct device_node *dai_np) { struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); - struct rsnd_dai_stream *io = is_play ? - &rdai->playback : - &rdai->capture; struct device_node *ssiu_np = rsnd_ssiu_of_node(priv); struct device_node *np; + int is_play = rsnd_io_is_play(io); int i, j; if (!ssiu_np) @@ -1292,8 +1289,10 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) for_each_child_of_node(dai_node, dai_np) { __rsnd_dai_probe(priv, dai_np, dai_i); if (rsnd_is_gen3(priv)) { - rsnd_parse_connect_simple(priv, dai_np, dai_i, 1); - rsnd_parse_connect_simple(priv, dai_np, dai_i, 0); + struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); + + rsnd_parse_connect_simple(priv, &rdai->playback, dai_np); + rsnd_parse_connect_simple(priv, &rdai->capture, dai_np); } dai_i++; } From d2f5eaf86dbdf98182422b61805dfb4c6fde5d94 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 1 Feb 2019 16:47:25 +0900 Subject: [PATCH 1056/1995] ASoC: rsnd: fixup TDM Split mode check for CTU Renesas sound card need to judge that whether it is using "TDM Split mode". To judge it and for other purpose, it has rsnd_parse_connect_simple() and rsnd_parse_connect_graph(), but these are using different judgement policy for TDM Split mode. It is pointless and confusable. This patch add new rsnd_parse_tdm_split_mode() and use common judgement policy for simple-card/audio-graph. Without this patch, CTU will be judged as TDM Split mode on audio-graph card. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 2264cf2e5db99cdff995592bf80ab6dea567ea91) --- sound/soc/sh/rcar/core.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index d7ecbfd8504fc9..9834474684b1ba 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1031,7 +1031,7 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { .prepare = rsnd_soc_dai_prepare, }; -static void rsnd_parse_connect_simple(struct rsnd_priv *priv, +static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, struct rsnd_dai_stream *io, struct device_node *dai_np) { @@ -1044,9 +1044,6 @@ static void rsnd_parse_connect_simple(struct rsnd_priv *priv, if (!ssiu_np) return; - if (!rsnd_io_to_mod_ssi(io)) - return; - /* * This driver assumes that it is TDM Split mode * if it includes ssiu node @@ -1071,12 +1068,21 @@ static void rsnd_parse_connect_simple(struct rsnd_priv *priv, } } +static void rsnd_parse_connect_simple(struct rsnd_priv *priv, + struct rsnd_dai_stream *io, + struct device_node *dai_np) +{ + if (!rsnd_io_to_mod_ssi(io)) + return; + + rsnd_parse_tdm_split_mode(priv, io, dai_np); +} + static void rsnd_parse_connect_graph(struct rsnd_priv *priv, struct rsnd_dai_stream *io, struct device_node *endpoint) { struct device *dev = rsnd_priv_to_dev(priv); - struct device_node *remote_port = of_graph_get_remote_port(endpoint); struct device_node *remote_node = of_graph_get_remote_port_parent(endpoint); if (!rsnd_io_to_mod_ssi(io)) @@ -1094,14 +1100,7 @@ static void rsnd_parse_connect_graph(struct rsnd_priv *priv, dev_dbg(dev, "%s connected to HDMI1\n", io->name); } - /* - * This driver assumes that it is TDM Split mode - * if remote node has multi endpoint - */ - if (of_get_child_count(remote_port) > 1) { - rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT); - dev_dbg(dev, "%s is part of TDM Split\n", io->name); - } + rsnd_parse_tdm_split_mode(priv, io, endpoint); } void rsnd_parse_connect_common(struct rsnd_dai *rdai, From 2b22c8a8e18f59fff45c2dc5341518ad4996af80 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Feb 2019 11:05:12 -0600 Subject: [PATCH 1057/1995] ASoC: dapm: fix use-after-free issue with dailink sname Commit 7620fe9161ce ("ASoC: topology: fix memory leak in soc_tplg_dapm_widget_create") fixed a memory leak issue, but additional tests and KASAN reports show a use-after-free in soc-dapm. The widgets are created with a kmemdup operating on a template. The "name" string is also duplicated, but the "sname" string is not. As a result, when the template is freed after widget creation, its sname string is still used. Fix by explicitly duplicating the "sname" string, and freeing it when required. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 199ed3e81c49a621ce6fcb630ab9f30d92db6718) --- sound/soc/soc-dapm.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 20bad755888b11..05fa5b9b82d827 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -319,7 +319,22 @@ EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty); static inline struct snd_soc_dapm_widget *dapm_cnew_widget( const struct snd_soc_dapm_widget *_widget) { - return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); + struct snd_soc_dapm_widget *w; + + w = kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); + if (!w) + return NULL; + + /* + * w->name is duplicated in caller, but w->sname isn't. + * Duplicate it here if defined + */ + if (_widget->sname) { + w->sname = kstrdup_const(_widget->sname, GFP_KERNEL); + if (!w->sname) + return NULL; + } + return w; } struct dapm_kcontrol_data { @@ -2436,6 +2451,7 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) kfree(w->kcontrols); kfree_const(w->name); + kfree_const(w->sname); kfree(w); } @@ -3493,6 +3509,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, else w->name = kstrdup_const(widget->name, GFP_KERNEL); if (w->name == NULL) { + kfree_const(w->sname); kfree(w); return ERR_PTR(-ENOMEM); } From e6339338f9c93edc530012be95ed5ad0ed6ee5d5 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 31 Jan 2019 13:30:18 +0000 Subject: [PATCH 1058/1995] ASoC: dapm: Only power up active channels from a DAI Currently all widgets attached to a DAI link will be powered up when the DAI is active, however this may include routes that are not actually in use if there are unused channels available on the DAI. The macros for creating AIF widgets already include an entry for slot, it is proposed to change that to channel. The effective difference here being respresenting the logical channel index rather than the physical slot index. The CODECs currently using the slot entry on the DAPM_AIF macros are using it in a manner consistent with this, the CODECs not using it just have the field set to zero. A variable is added to snd_soc_dapm_widget to represent this channel index and then for each AIF widget attached to a DAI this is compared against the number of channels on the stream. Enabling the links for those which will be in use. This has the nice property that the CODECs which haven't used the slot/channel entry in the macro will function exactly as before due to all the AIF widgets having a channel of zero and a stream by definition having at least one channel. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit 078a85f2806f0ffd11289009462a6a390f9adb5c) --- include/sound/soc-dapm.h | 22 +++++++----- sound/soc/soc-dapm.c | 76 ++++++++++++++++++++++++++++++++++++++++ sound/soc/soc-pcm.c | 4 +++ 3 files changed, 94 insertions(+), 8 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 46f2ba3ffcb7c1..79b4ddfb8e9e22 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -214,21 +214,21 @@ struct device; .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD} /* stream domain */ -#define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \ +#define SND_SOC_DAPM_AIF_IN(wname, stname, wchan, wreg, wshift, winvert) \ { .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ - SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } -#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \ + .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } +#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wchan, wreg, wshift, winvert, \ wevent, wflags) \ { .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ - SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ + .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags } -#define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \ +#define SND_SOC_DAPM_AIF_OUT(wname, stname, wchan, wreg, wshift, winvert) \ { .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ - SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } -#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \ + .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), } +#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wchan, wreg, wshift, winvert, \ wevent, wflags) \ { .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ - SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ + .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ .event = wevent, .event_flags = wflags } #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \ { .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \ @@ -407,6 +407,10 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card); void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card); +int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); + /* dapm path setup */ int snd_soc_dapm_new_widgets(struct snd_soc_card *card); void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm); @@ -627,6 +631,8 @@ struct snd_soc_dapm_widget { int endpoints[2]; struct clk *clk; + + int channel; }; struct snd_soc_dapm_update { diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 05fa5b9b82d827..e228b12dcdd19c 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2565,6 +2565,78 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) } EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); +static int dapm_update_dai_chan(struct snd_soc_dapm_path *p, + struct snd_soc_dapm_widget *w, + int channels) +{ + switch (w->id) { + case snd_soc_dapm_aif_out: + case snd_soc_dapm_aif_in: + break; + default: + return 0; + } + + dev_dbg(w->dapm->dev, "%s DAI route %s -> %s\n", + w->channel < channels ? "Connecting" : "Disconnecting", + p->source->name, p->sink->name); + + if (w->channel < channels) + soc_dapm_connect_path(p, true, "dai update"); + else + soc_dapm_connect_path(p, false, "dai update"); + + return 0; +} + +static int dapm_update_dai_unlocked(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + int dir = substream->stream; + int channels = params_channels(params); + struct snd_soc_dapm_path *p; + struct snd_soc_dapm_widget *w; + int ret; + + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + w = dai->playback_widget; + else + w = dai->capture_widget; + + dev_dbg(dai->dev, "Update DAI routes for %s %s\n", dai->name, + dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture"); + + snd_soc_dapm_widget_for_each_sink_path(w, p) { + ret = dapm_update_dai_chan(p, p->sink, channels); + if (ret < 0) + return ret; + } + + snd_soc_dapm_widget_for_each_source_path(w, p) { + ret = dapm_update_dai_chan(p, p->source, channels); + if (ret < 0) + return ret; + } + + return 0; +} + +int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int ret; + + mutex_lock_nested(&rtd->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + ret = dapm_update_dai_unlocked(substream, params, dai); + mutex_unlock(&rtd->card->dapm_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_update_dai); + /* * dapm_update_widget_flags() - Re-compute widget sink and source flags * @w: The widget for which to update the flags @@ -3730,6 +3802,8 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, ret = soc_dai_hw_params(&substream, params, source); if (ret < 0) goto out; + + dapm_update_dai_unlocked(&substream, params, source); } substream.stream = SNDRV_PCM_STREAM_PLAYBACK; @@ -3750,6 +3824,8 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, ret = soc_dai_hw_params(&substream, params, sink); if (ret < 0) goto out; + + dapm_update_dai_unlocked(&substream, params, sink); } break; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 03f36e534050f4..a5b40e82dea4ac 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -969,6 +969,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, codec_dai->channels = params_channels(&codec_params); codec_dai->sample_bits = snd_pcm_format_physical_width( params_format(&codec_params)); + + snd_soc_dapm_update_dai(substream, &codec_params, codec_dai); } ret = soc_dai_hw_params(substream, params, cpu_dai); @@ -998,6 +1000,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, cpu_dai->sample_bits = snd_pcm_format_physical_width(params_format(params)); + snd_soc_dapm_update_dai(substream, params, cpu_dai); + ret = soc_pcm_params_symmetry(substream, params); if (ret) goto component_err; From af79808f02f52e0b63567ea59a6efc7429dd6295 Mon Sep 17 00:00:00 2001 From: Zhiwei Jiang Date: Thu, 31 Jan 2019 19:30:05 +0800 Subject: [PATCH 1059/1995] ASoC: dapm: Add warnings for widget overwrite when adding route Currently, in some complex cases, more than one widgets have same name and registed from differnt dapm context, and route add from another context too. When snd_soc_dapm_add_route, the previous registered widget will overwritten by the latest same name widget, will cause unexpect error. For Asoc framework we cant avoid this situation and we cant decide which widget that wanted with route. At least we can give users a notice. Signed-off-by: Zhiwei Jiang Signed-off-by: Mark Brown (cherry picked from commit 411db2ab7df35804422e4b26c5849b3868e6a038) --- sound/soc/soc-dapm.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index e228b12dcdd19c..2bf5bab579deee 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2853,6 +2853,8 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, char prefixed_sink[80]; char prefixed_source[80]; const char *prefix; + unsigned int sink_ref = 0; + unsigned int source_ref = 0; int ret; prefix = soc_dapm_prefix(dapm); @@ -2886,6 +2888,11 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, if (wsource) break; } + sink_ref++; + if (sink_ref > 1) + dev_warn(dapm->dev, + "ASoC: sink widget %s overwritten\n", + w->name); continue; } if (!wsource && !(strcmp(w->name, source))) { @@ -2895,6 +2902,11 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, if (wsink) break; } + source_ref++; + if (source_ref > 1) + dev_warn(dapm->dev, + "ASoC: source widget %s overwritten\n", + w->name); } } /* use widget from another DAPM context if not found from this */ From 73670aa5ef61155acfa07026c6a3cacf1269aa2f Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Tue, 29 Jan 2019 13:47:09 -0800 Subject: [PATCH 1060/1995] ASoC: soc-core: clear platform pointers on error Originally snd_soc_init_platform was not cleaning up its pointers, this was fixed to always reallocate dynamic memory but created a memory leak when snd_soc_init_platform was called multiple times during the same probe attempt and also threw away any changes made to the struct between calls. In order to avoid reallocating memory that is still valid, the behaviour will be changed to clear the dynamically set pointers on a probe error and a unregister event and snd_soc_init_platform will go back to its original behaviour of only allocating null pointers so it will stop throwing away valid changes. Signed-off-by: Curtis Malainey Signed-off-by: Mark Brown (cherry picked from commit 78a24e10cd94420f1b4e2dc5923ae7109e2aaba1) --- sound/soc/soc-core.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9dad2b1498c1db..994d21d7ba0f69 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1053,7 +1053,7 @@ static int snd_soc_init_platform(struct snd_soc_card *card, * soc.h :: struct snd_soc_dai_link */ /* convert Legacy platform link */ - if (!platform || dai_link->legacy_platform) { + if (!platform) { platform = devm_kzalloc(card->dev, sizeof(struct snd_soc_dai_link_component), GFP_KERNEL); @@ -1076,6 +1076,24 @@ static int snd_soc_init_platform(struct snd_soc_card *card, return 0; } +static void soc_cleanup_platform(struct snd_soc_card *card) +{ + struct snd_soc_dai_link *link; + int i; + /* + * FIXME + * + * this function should be removed with snd_soc_init_platform + */ + + for_each_card_prelinks(card, i, link) { + if (link->legacy_platform) { + link->legacy_platform = 0; + link->platforms = NULL; + } + } +} + static int snd_soc_init_multicodec(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { @@ -2020,6 +2038,7 @@ static int soc_cleanup_card_resources(struct snd_soc_card *card) /* remove and free each DAI */ soc_remove_dai_links(card); soc_remove_pcm_runtimes(card); + soc_cleanup_platform(card); /* remove auxiliary devices */ soc_remove_aux_devices(card); From 38ebfabbfec0be4ce9f0d40131e119fbaf13cad0 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 1 Feb 2019 11:07:40 -0600 Subject: [PATCH 1061/1995] ASoC: topology: unload physical dai link in remove soc_tplg_link_config() will find the physical dai link and call soc_tplg_dai_link_load() to load the BE dai link. Currently remove_link() is only used to remove the FE dai link which is created by the topology. The BE dai link cannot however be unloaded in snd_soc_tplg_component _remove(), which is problematic if anything needs to be released or reinitialized. This patch aligns the definitions of dynamic types with the existing UAPI and adds a new remove_backend_link() routine to unload the the BE dai link when snd_soc_tplg_component_remove() is invoked. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit adfebb51e1750c5df9e5d42f505b73c5542a879d) --- include/sound/soc-topology.h | 1 + sound/soc/soc-topology.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index 8c43cfc240fa33..5223896de26f51 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -45,6 +45,7 @@ enum snd_soc_dobj_type { SND_SOC_DOBJ_DAI_LINK, SND_SOC_DOBJ_PCM, SND_SOC_DOBJ_CODEC_LINK, + SND_SOC_DOBJ_BACKEND_LINK, }; /* dynamic control object */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 52d0c4e82210e0..25fca7055464a8 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -562,6 +562,25 @@ static void remove_link(struct snd_soc_component *comp, kfree(link); } +/* unload dai link */ +static void remove_backend_link(struct snd_soc_component *comp, + struct snd_soc_dobj *dobj, int pass) +{ + if (pass != SOC_TPLG_PASS_LINK) + return; + + if (dobj->ops && dobj->ops->link_unload) + dobj->ops->link_unload(comp, dobj); + + /* + * We don't free the link here as what remove_link() do since BE + * links are not allocated by topology. + * We however need to reset the dobj type to its initial values + */ + dobj->type = SND_SOC_DOBJ_NONE; + list_del(&dobj->list); +} + /* bind a kcontrol to it's IO handlers */ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, struct snd_kcontrol_new *k, @@ -2168,6 +2187,12 @@ static int soc_tplg_link_config(struct soc_tplg *tplg, return ret; } + /* for unloading it in snd_soc_tplg_component_remove */ + link->dobj.index = tplg->index; + link->dobj.ops = tplg->ops; + link->dobj.type = SND_SOC_DOBJ_BACKEND_LINK; + list_add(&link->dobj.list, &tplg->comp->dobj_list); + return 0; } @@ -2660,6 +2685,13 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index) case SND_SOC_DOBJ_DAI_LINK: remove_link(comp, dobj, pass); break; + case SND_SOC_DOBJ_BACKEND_LINK: + /* + * call link_unload ops if extra + * deinitialization is needed. + */ + remove_backend_link(comp, dobj, pass); + break; default: dev_err(comp->dev, "ASoC: invalid component type %d for removal\n", dobj->type); From 05290ed24f169f148f205415f08531f8d8ed5cdd Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 6 Feb 2019 11:13:59 +0000 Subject: [PATCH 1062/1995] ASoC: dapm: Check for NULL widget in dapm_update_dai_unlocked DAIs linked to the dummy will not have an associated playback/capture widget, so we need to skip the update in that case. Fixes: 078a85f2806f ("ASoC: dapm: Only power up active channels from a DAI") Reported-by: Krzysztof Kozlowski Signed-off-by: Charles Keepax Tested-by: Sylwester Nawrocki Tested-by: Krzysztof Kozlowski Signed-off-by: Mark Brown (cherry picked from commit cf17a5ffd27234371d10748bf1c716ef172877f3) --- sound/soc/soc-dapm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 2bf5bab579deee..40e7190f533a99 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2604,6 +2604,9 @@ static int dapm_update_dai_unlocked(struct snd_pcm_substream *substream, else w = dai->capture_widget; + if (!w) + return 0; + dev_dbg(dai->dev, "Update DAI routes for %s %s\n", dai->name, dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture"); From 40c606d058421ec935d689246dff1337874b8e89 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 5 Feb 2019 11:18:12 +0000 Subject: [PATCH 1063/1995] ASoC: compress: Clarify the intent of current compressed ops handling For callbacks configuring the state of the components (trigger, set_params, ack and set_metadata) simplify the code a little and make intention clearer by aborting as soon as an error is encountered. The operation has already failed and there is nothing to be gained from processing the callbacks on additional components. The operations currently abort after the callbacks, so this simply shortens the error path. For callbacks returning information from the driver (copy, get_metadata, pointer, get_codec_caps, get_caps and get_params) only look for the first callback provided, currently the code will call every callback only returning the information provided by the last. Since we can only return one set of data, it makes no sense to request the data from every component. Again this just makes the currently supported feature set a little more clear. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit 52cadf1fdbe87a3a3eee11d9cc4873796903c934) --- sound/soc/soc-compress.c | 106 ++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 58 deletions(-) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 699397a091670d..fc8742383b2302 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -353,7 +353,7 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -364,12 +364,10 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) !component->driver->compr_ops->trigger) continue; - __ret = component->driver->compr_ops->trigger(cstream, cmd); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->trigger(cstream, cmd); + if (ret < 0) + goto out; } - if (ret < 0) - goto out; if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai); @@ -394,7 +392,7 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = fe->cpu_dai; - int ret = 0, __ret, stream; + int ret, stream; if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || cmd == SND_COMPR_TRIGGER_DRAIN) { @@ -406,9 +404,10 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) !component->driver->compr_ops->trigger) continue; - __ret = component->driver->compr_ops->trigger(cstream, cmd); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->trigger(cstream, + cmd); + if (ret < 0) + return ret; } return ret; } @@ -433,12 +432,10 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) !component->driver->compr_ops->trigger) continue; - __ret = component->driver->compr_ops->trigger(cstream, cmd); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->trigger(cstream, cmd); + if (ret < 0) + goto out; } - if (ret < 0) - goto out; fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; @@ -472,7 +469,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -496,12 +493,10 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, !component->driver->compr_ops->set_params) continue; - __ret = component->driver->compr_ops->set_params(cstream, params); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->set_params(cstream, params); + if (ret < 0) + goto err; } - if (ret < 0) - goto err; if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { ret = rtd->dai_link->compr_ops->set_params(cstream); @@ -522,7 +517,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, cancel_delayed_work_sync(&rtd->delayed_work); - return ret; + return 0; err: mutex_unlock(&rtd->pcm_mutex); @@ -538,7 +533,7 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = fe->cpu_dai; - int ret = 0, __ret, stream; + int ret, stream; if (cstream->direction == SND_COMPRESS_PLAYBACK) stream = SNDRV_PCM_STREAM_PLAYBACK; @@ -578,12 +573,10 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, !component->driver->compr_ops->set_params) continue; - __ret = component->driver->compr_ops->set_params(cstream, params); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->set_params(cstream, params); + if (ret < 0) + goto out; } - if (ret < 0) - goto out; if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) { ret = fe->dai_link->compr_ops->set_params(cstream); @@ -607,7 +600,7 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -624,9 +617,8 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, !component->driver->compr_ops->get_params) continue; - __ret = component->driver->compr_ops->get_params(cstream, params); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->get_params(cstream, params); + break; } err: @@ -640,7 +632,7 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -651,9 +643,8 @@ static int soc_compr_get_caps(struct snd_compr_stream *cstream, !component->driver->compr_ops->get_caps) continue; - __ret = component->driver->compr_ops->get_caps(cstream, caps); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->get_caps(cstream, caps); + break; } mutex_unlock(&rtd->pcm_mutex); @@ -666,7 +657,7 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -677,9 +668,9 @@ static int soc_compr_get_codec_caps(struct snd_compr_stream *cstream, !component->driver->compr_ops->get_codec_caps) continue; - __ret = component->driver->compr_ops->get_codec_caps(cstream, codec); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->get_codec_caps(cstream, + codec); + break; } mutex_unlock(&rtd->pcm_mutex); @@ -692,7 +683,7 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -709,9 +700,9 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) !component->driver->compr_ops->ack) continue; - __ret = component->driver->compr_ops->ack(cstream, bytes); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->ack(cstream, bytes); + if (ret < 0) + goto err; } err: @@ -725,7 +716,7 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - int ret = 0, __ret; + int ret = 0; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -740,9 +731,8 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, !component->driver->compr_ops->pointer) continue; - __ret = component->driver->compr_ops->pointer(cstream, tstamp); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->pointer(cstream, tstamp); + break; } mutex_unlock(&rtd->pcm_mutex); @@ -781,7 +771,7 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret; if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_metadata) { ret = cpu_dai->driver->cops->set_metadata(cstream, metadata, cpu_dai); @@ -796,12 +786,13 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream, !component->driver->compr_ops->set_metadata) continue; - __ret = component->driver->compr_ops->set_metadata(cstream, metadata); - if (__ret < 0) - ret = __ret; + ret = component->driver->compr_ops->set_metadata(cstream, + metadata); + if (ret < 0) + return ret; } - return ret; + return 0; } static int soc_compr_get_metadata(struct snd_compr_stream *cstream, @@ -811,7 +802,7 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream, struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0, __ret; + int ret; if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_metadata) { ret = cpu_dai->driver->cops->get_metadata(cstream, metadata, cpu_dai); @@ -826,12 +817,11 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream, !component->driver->compr_ops->get_metadata) continue; - __ret = component->driver->compr_ops->get_metadata(cstream, metadata); - if (__ret < 0) - ret = __ret; + return component->driver->compr_ops->get_metadata(cstream, + metadata); } - return ret; + return 0; } /* ASoC Compress operations */ From 848feb8129b8e431044951ba3f01be01860b7273 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 5 Feb 2019 11:18:13 +0000 Subject: [PATCH 1064/1995] ASoC: compress: Add helper functions for component trigger/set_params The trigger and set_params callbacks are called from 3 and 2 separate loops respectively, tidy up the code a little by factoring these out into helper functions. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown (cherry picked from commit 4ef0ecb80e348f1888b0c7ebfa8f7c1ec3ed9006) --- sound/soc/soc-compress.c | 117 ++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 63 deletions(-) diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index fc8742383b2302..03d5b9ccd3fc96 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -345,17 +345,13 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) return 0; } -static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) +static int soc_compr_components_trigger(struct snd_compr_stream *cstream, + int cmd) { - struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int ret = 0; - - mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + int ret; for_each_rtdcom(rtd, rtdcom) { component = rtdcom->component; @@ -366,9 +362,25 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) ret = component->driver->compr_ops->trigger(cstream, cmd); if (ret < 0) - goto out; + return ret; } + return 0; +} + +static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret; + + mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + + ret = soc_compr_components_trigger(cstream, cmd); + if (ret < 0) + goto out; + if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai); @@ -389,28 +401,12 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) { struct snd_soc_pcm_runtime *fe = cstream->private_data; - struct snd_soc_component *component; - struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = fe->cpu_dai; int ret, stream; if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || - cmd == SND_COMPR_TRIGGER_DRAIN) { - - for_each_rtdcom(fe, rtdcom) { - component = rtdcom->component; - - if (!component->driver->compr_ops || - !component->driver->compr_ops->trigger) - continue; - - ret = component->driver->compr_ops->trigger(cstream, - cmd); - if (ret < 0) - return ret; - } - return ret; - } + cmd == SND_COMPR_TRIGGER_DRAIN) + return soc_compr_components_trigger(cstream, cmd); if (cstream->direction == SND_COMPRESS_PLAYBACK) stream = SNDRV_PCM_STREAM_PLAYBACK; @@ -425,17 +421,9 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) goto out; } - for_each_rtdcom(fe, rtdcom) { - component = rtdcom->component; - - if (!component->driver->compr_ops || - !component->driver->compr_ops->trigger) - continue; - - ret = component->driver->compr_ops->trigger(cstream, cmd); - if (ret < 0) - goto out; - } + ret = soc_compr_components_trigger(cstream, cmd); + if (ret < 0) + goto out; fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; @@ -462,12 +450,33 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) return ret; } -static int soc_compr_set_params(struct snd_compr_stream *cstream, - struct snd_compr_params *params) +static int soc_compr_components_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_component *component; struct snd_soc_rtdcom_list *rtdcom; + int ret; + + for_each_rtdcom(rtd, rtdcom) { + component = rtdcom->component; + + if (!component->driver->compr_ops || + !component->driver->compr_ops->set_params) + continue; + + ret = component->driver->compr_ops->set_params(cstream, params); + if (ret < 0) + return ret; + } + + return 0; +} + +static int soc_compr_set_params(struct snd_compr_stream *cstream, + struct snd_compr_params *params) +{ + struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret; @@ -486,17 +495,9 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, goto err; } - for_each_rtdcom(rtd, rtdcom) { - component = rtdcom->component; - - if (!component->driver->compr_ops || - !component->driver->compr_ops->set_params) - continue; - - ret = component->driver->compr_ops->set_params(cstream, params); - if (ret < 0) - goto err; - } + ret = soc_compr_components_set_params(cstream, params); + if (ret < 0) + goto err; if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) { ret = rtd->dai_link->compr_ops->set_params(cstream); @@ -530,8 +531,6 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_pcm_substream *fe_substream = fe->pcm->streams[cstream->direction].substream; - struct snd_soc_component *component; - struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_dai *cpu_dai = fe->cpu_dai; int ret, stream; @@ -566,17 +565,9 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, goto out; } - for_each_rtdcom(fe, rtdcom) { - component = rtdcom->component; - - if (!component->driver->compr_ops || - !component->driver->compr_ops->set_params) - continue; - - ret = component->driver->compr_ops->set_params(cstream, params); - if (ret < 0) - goto out; - } + ret = soc_compr_components_set_params(cstream, params); + if (ret < 0) + goto out; if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) { ret = fe->dai_link->compr_ops->set_params(cstream); From 959b6452d1af8741f64f2fd32455d5cc50991d77 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Feb 2019 10:22:28 -0600 Subject: [PATCH 1065/1995] ASoC: dapm: harden use of lookup tables To detect potential errors, let's add: a) build-time warnings when the table size isn't aligned with the enum list b) run-time warnings when the values are not initialized. This requires an increase by one of all values to avoid the default 0. Suggested-by: Takashi Iwai Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit f13d4b5f85e1c436c9bf21205509266b5a81a320) --- include/sound/soc-dapm.h | 3 + sound/soc/soc-dapm.c | 158 ++++++++++++++++++++------------------- 2 files changed, 85 insertions(+), 76 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 79b4ddfb8e9e22..c00a0b8ade0861 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -523,6 +523,9 @@ enum snd_soc_dapm_type { snd_soc_dapm_asrc, /* DSP/CODEC ASRC component */ snd_soc_dapm_encoder, /* FW/SW audio encoder component */ snd_soc_dapm_decoder, /* FW/SW audio decoder component */ + + /* Don't edit below this line */ + SND_SOC_DAPM_TYPE_COUNT }; enum snd_soc_dapm_subclass { diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 40e7190f533a99..d31d295b540fcc 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -64,85 +64,85 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, /* dapm power sequences - make this per codec in the future */ static int dapm_up_seq[] = { - [snd_soc_dapm_pre] = 0, - [snd_soc_dapm_regulator_supply] = 1, - [snd_soc_dapm_pinctrl] = 1, - [snd_soc_dapm_clock_supply] = 1, - [snd_soc_dapm_supply] = 2, - [snd_soc_dapm_micbias] = 3, - [snd_soc_dapm_vmid] = 3, - [snd_soc_dapm_dai_link] = 2, - [snd_soc_dapm_dai_in] = 4, - [snd_soc_dapm_dai_out] = 4, - [snd_soc_dapm_aif_in] = 4, - [snd_soc_dapm_aif_out] = 4, - [snd_soc_dapm_mic] = 5, - [snd_soc_dapm_siggen] = 5, - [snd_soc_dapm_input] = 5, - [snd_soc_dapm_output] = 5, - [snd_soc_dapm_mux] = 6, - [snd_soc_dapm_demux] = 6, - [snd_soc_dapm_dac] = 7, - [snd_soc_dapm_switch] = 8, - [snd_soc_dapm_mixer] = 8, - [snd_soc_dapm_mixer_named_ctl] = 8, - [snd_soc_dapm_pga] = 9, - [snd_soc_dapm_buffer] = 9, - [snd_soc_dapm_scheduler] = 9, - [snd_soc_dapm_effect] = 9, - [snd_soc_dapm_src] = 9, - [snd_soc_dapm_asrc] = 9, - [snd_soc_dapm_encoder] = 9, - [snd_soc_dapm_decoder] = 9, - [snd_soc_dapm_adc] = 10, - [snd_soc_dapm_out_drv] = 11, - [snd_soc_dapm_hp] = 11, - [snd_soc_dapm_spk] = 11, - [snd_soc_dapm_line] = 11, - [snd_soc_dapm_sink] = 11, - [snd_soc_dapm_kcontrol] = 12, - [snd_soc_dapm_post] = 13, + [snd_soc_dapm_pre] = 1, + [snd_soc_dapm_regulator_supply] = 2, + [snd_soc_dapm_pinctrl] = 2, + [snd_soc_dapm_clock_supply] = 2, + [snd_soc_dapm_supply] = 3, + [snd_soc_dapm_micbias] = 4, + [snd_soc_dapm_vmid] = 4, + [snd_soc_dapm_dai_link] = 3, + [snd_soc_dapm_dai_in] = 5, + [snd_soc_dapm_dai_out] = 5, + [snd_soc_dapm_aif_in] = 5, + [snd_soc_dapm_aif_out] = 5, + [snd_soc_dapm_mic] = 6, + [snd_soc_dapm_siggen] = 6, + [snd_soc_dapm_input] = 6, + [snd_soc_dapm_output] = 6, + [snd_soc_dapm_mux] = 7, + [snd_soc_dapm_demux] = 7, + [snd_soc_dapm_dac] = 8, + [snd_soc_dapm_switch] = 9, + [snd_soc_dapm_mixer] = 9, + [snd_soc_dapm_mixer_named_ctl] = 9, + [snd_soc_dapm_pga] = 10, + [snd_soc_dapm_buffer] = 10, + [snd_soc_dapm_scheduler] = 10, + [snd_soc_dapm_effect] = 10, + [snd_soc_dapm_src] = 10, + [snd_soc_dapm_asrc] = 10, + [snd_soc_dapm_encoder] = 10, + [snd_soc_dapm_decoder] = 10, + [snd_soc_dapm_adc] = 11, + [snd_soc_dapm_out_drv] = 12, + [snd_soc_dapm_hp] = 12, + [snd_soc_dapm_spk] = 12, + [snd_soc_dapm_line] = 12, + [snd_soc_dapm_sink] = 12, + [snd_soc_dapm_kcontrol] = 13, + [snd_soc_dapm_post] = 14, }; static int dapm_down_seq[] = { - [snd_soc_dapm_pre] = 0, - [snd_soc_dapm_kcontrol] = 1, - [snd_soc_dapm_adc] = 2, - [snd_soc_dapm_hp] = 3, - [snd_soc_dapm_spk] = 3, - [snd_soc_dapm_line] = 3, - [snd_soc_dapm_out_drv] = 3, - [snd_soc_dapm_sink] = 3, - [snd_soc_dapm_pga] = 4, - [snd_soc_dapm_buffer] = 4, - [snd_soc_dapm_scheduler] = 4, - [snd_soc_dapm_effect] = 4, - [snd_soc_dapm_src] = 4, - [snd_soc_dapm_asrc] = 4, - [snd_soc_dapm_encoder] = 4, - [snd_soc_dapm_decoder] = 4, - [snd_soc_dapm_switch] = 5, - [snd_soc_dapm_mixer_named_ctl] = 5, - [snd_soc_dapm_mixer] = 5, - [snd_soc_dapm_dac] = 6, - [snd_soc_dapm_mic] = 7, - [snd_soc_dapm_siggen] = 7, - [snd_soc_dapm_input] = 7, - [snd_soc_dapm_output] = 7, - [snd_soc_dapm_micbias] = 8, - [snd_soc_dapm_vmid] = 8, - [snd_soc_dapm_mux] = 9, - [snd_soc_dapm_demux] = 9, - [snd_soc_dapm_aif_in] = 10, - [snd_soc_dapm_aif_out] = 10, - [snd_soc_dapm_dai_in] = 10, - [snd_soc_dapm_dai_out] = 10, - [snd_soc_dapm_dai_link] = 11, - [snd_soc_dapm_supply] = 12, - [snd_soc_dapm_clock_supply] = 13, - [snd_soc_dapm_pinctrl] = 13, - [snd_soc_dapm_regulator_supply] = 13, - [snd_soc_dapm_post] = 14, + [snd_soc_dapm_pre] = 1, + [snd_soc_dapm_kcontrol] = 2, + [snd_soc_dapm_adc] = 3, + [snd_soc_dapm_hp] = 4, + [snd_soc_dapm_spk] = 4, + [snd_soc_dapm_line] = 4, + [snd_soc_dapm_out_drv] = 4, + [snd_soc_dapm_sink] = 4, + [snd_soc_dapm_pga] = 5, + [snd_soc_dapm_buffer] = 5, + [snd_soc_dapm_scheduler] = 5, + [snd_soc_dapm_effect] = 5, + [snd_soc_dapm_src] = 5, + [snd_soc_dapm_asrc] = 5, + [snd_soc_dapm_encoder] = 5, + [snd_soc_dapm_decoder] = 5, + [snd_soc_dapm_switch] = 6, + [snd_soc_dapm_mixer_named_ctl] = 6, + [snd_soc_dapm_mixer] = 6, + [snd_soc_dapm_dac] = 7, + [snd_soc_dapm_mic] = 8, + [snd_soc_dapm_siggen] = 8, + [snd_soc_dapm_input] = 8, + [snd_soc_dapm_output] = 8, + [snd_soc_dapm_micbias] = 9, + [snd_soc_dapm_vmid] = 9, + [snd_soc_dapm_mux] = 10, + [snd_soc_dapm_demux] = 10, + [snd_soc_dapm_aif_in] = 11, + [snd_soc_dapm_aif_out] = 11, + [snd_soc_dapm_dai_in] = 11, + [snd_soc_dapm_dai_out] = 11, + [snd_soc_dapm_dai_link] = 12, + [snd_soc_dapm_supply] = 13, + [snd_soc_dapm_clock_supply] = 14, + [snd_soc_dapm_pinctrl] = 14, + [snd_soc_dapm_regulator_supply] = 14, + [snd_soc_dapm_post] = 15, }; static void dapm_assert_locked(struct snd_soc_dapm_context *dapm) @@ -1425,11 +1425,17 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a, { int *sort; + BUILD_BUG_ON(ARRAY_SIZE(dapm_up_seq) != SND_SOC_DAPM_TYPE_COUNT); + BUILD_BUG_ON(ARRAY_SIZE(dapm_down_seq) != SND_SOC_DAPM_TYPE_COUNT); + if (power_up) sort = dapm_up_seq; else sort = dapm_down_seq; + WARN_ONCE(sort[a->id] == 0, "offset a->id %d not initialized\n", a->id); + WARN_ONCE(sort[b->id] == 0, "offset b->id %d not initialized\n", b->id); + if (sort[a->id] != sort[b->id]) return sort[a->id] - sort[b->id]; if (a->subseq != b->subseq) { From 12da2e3ddc30d20a26071107fb6ad23d014a93c2 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 8 Feb 2019 14:45:20 +0100 Subject: [PATCH 1066/1995] ASoC: regulator notifier registration should be managed Regulator notifiers, that were registered during codec driver probing, must be unregistered during driver release, or device managed versions have to be used. This patch fixes codec drivers, that weren't explicitly unregistering notifiers and simplifies those, that did that manually. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mark Brown (cherry picked from commit 0bb423f2eaafedf89715c482a543dcd629ba3946) --- sound/soc/codecs/max9860.c | 3 ++- sound/soc/codecs/pcm512x.c | 5 +++-- sound/soc/codecs/tlv320aic31xx.c | 16 +++------------- sound/soc/codecs/tlv320aic3x.c | 25 ++++--------------------- sound/soc/codecs/wm8770.c | 18 +++--------------- sound/soc/codecs/wm8962.c | 9 +++------ sound/soc/codecs/wm8995.c | 29 +++++++---------------------- sound/soc/codecs/wm8996.c | 9 +++------ 8 files changed, 28 insertions(+), 86 deletions(-) diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c index de3d44e9199b03..8be636fe655206 100644 --- a/sound/soc/codecs/max9860.c +++ b/sound/soc/codecs/max9860.c @@ -615,7 +615,8 @@ static int max9860_probe(struct i2c_client *i2c) max9860->dvddio_nb.notifier_call = max9860_dvddio_event; - ret = regulator_register_notifier(max9860->dvddio, &max9860->dvddio_nb); + ret = devm_regulator_register_notifier(max9860->dvddio, + &max9860->dvddio_nb); if (ret) dev_err(dev, "Failed to register DVDDIO notifier: %d\n", ret); diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index ae3bd533eadb5a..62d05b01711f12 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1540,8 +1540,9 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap) pcm512x->supply_nb[2].notifier_call = pcm512x_regulator_event_2; for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) { - ret = regulator_register_notifier(pcm512x->supplies[i].consumer, - &pcm512x->supply_nb[i]); + ret = devm_regulator_register_notifier( + pcm512x->supplies[i].consumer, + &pcm512x->supply_nb[i]); if (ret != 0) { dev_err(dev, "Failed to register regulator notifier: %d\n", diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index c6048d95c6d351..c544a1e35f5e03 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1274,8 +1274,9 @@ static int aic31xx_codec_probe(struct snd_soc_component *component) aic31xx->disable_nb[i].nb.notifier_call = aic31xx_regulator_event; aic31xx->disable_nb[i].aic31xx = aic31xx; - ret = regulator_register_notifier(aic31xx->supplies[i].consumer, - &aic31xx->disable_nb[i].nb); + ret = devm_regulator_register_notifier( + aic31xx->supplies[i].consumer, + &aic31xx->disable_nb[i].nb); if (ret) { dev_err(component->dev, "Failed to request regulator notifier: %d\n", @@ -1298,19 +1299,8 @@ static int aic31xx_codec_probe(struct snd_soc_component *component) return 0; } -static void aic31xx_codec_remove(struct snd_soc_component *component) -{ - struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component); - int i; - - for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) - regulator_unregister_notifier(aic31xx->supplies[i].consumer, - &aic31xx->disable_nb[i].nb); -} - static const struct snd_soc_component_driver soc_codec_driver_aic31xx = { .probe = aic31xx_codec_probe, - .remove = aic31xx_codec_remove, .set_bias_level = aic31xx_set_bias_level, .controls = common31xx_snd_controls, .num_controls = ARRAY_SIZE(common31xx_snd_controls), diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 6aa0edf8c5ef92..283583d1db6055 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1615,13 +1615,14 @@ static int aic3x_probe(struct snd_soc_component *component) for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) { aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event; aic3x->disable_nb[i].aic3x = aic3x; - ret = regulator_register_notifier(aic3x->supplies[i].consumer, - &aic3x->disable_nb[i].nb); + ret = devm_regulator_register_notifier( + aic3x->supplies[i].consumer, + &aic3x->disable_nb[i].nb); if (ret) { dev_err(component->dev, "Failed to request regulator notifier: %d\n", ret); - goto err_notif; + return ret; } } @@ -1679,29 +1680,11 @@ static int aic3x_probe(struct snd_soc_component *component) aic3x_add_widgets(component); return 0; - -err_notif: - while (i--) - regulator_unregister_notifier(aic3x->supplies[i].consumer, - &aic3x->disable_nb[i].nb); - return ret; -} - -static void aic3x_remove(struct snd_soc_component *component) -{ - struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component); - int i; - - list_del(&aic3x->list); - for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) - regulator_unregister_notifier(aic3x->supplies[i].consumer, - &aic3x->disable_nb[i].nb); } static const struct snd_soc_component_driver soc_component_dev_aic3x = { .set_bias_level = aic3x_set_bias_level, .probe = aic3x_probe, - .remove = aic3x_remove, .controls = aic3x_snd_controls, .num_controls = ARRAY_SIZE(aic3x_snd_controls), .dapm_widgets = aic3x_dapm_widgets, diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index 806245c70f8beb..37467c51259774 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -666,8 +666,9 @@ static int wm8770_spi_probe(struct spi_device *spi) /* This should really be moved into the regulator core */ for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) { - ret = regulator_register_notifier(wm8770->supplies[i].consumer, - &wm8770->disable_nb[i]); + ret = devm_regulator_register_notifier( + wm8770->supplies[i].consumer, + &wm8770->disable_nb[i]); if (ret) { dev_err(&spi->dev, "Failed to register regulator notifier: %d\n", @@ -687,25 +688,12 @@ static int wm8770_spi_probe(struct spi_device *spi) return ret; } -static int wm8770_spi_remove(struct spi_device *spi) -{ - struct wm8770_priv *wm8770 = spi_get_drvdata(spi); - int i; - - for (i = 0; i < ARRAY_SIZE(wm8770->supplies); ++i) - regulator_unregister_notifier(wm8770->supplies[i].consumer, - &wm8770->disable_nb[i]); - - return 0; -} - static struct spi_driver wm8770_spi_driver = { .driver = { .name = "wm8770", .of_match_table = wm8770_of_match, }, .probe = wm8770_spi_probe, - .remove = wm8770_spi_remove }; module_spi_driver(wm8770_spi_driver); diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index efd8910b1ff77a..467ed78dd2df4e 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3424,8 +3424,9 @@ static int wm8962_probe(struct snd_soc_component *component) /* This should really be moved into the regulator core */ for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) { - ret = regulator_register_notifier(wm8962->supplies[i].consumer, - &wm8962->disable_nb[i]); + ret = devm_regulator_register_notifier( + wm8962->supplies[i].consumer, + &wm8962->disable_nb[i]); if (ret != 0) { dev_err(component->dev, "Failed to register regulator notifier: %d\n", @@ -3467,15 +3468,11 @@ static int wm8962_probe(struct snd_soc_component *component) static void wm8962_remove(struct snd_soc_component *component) { struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component); - int i; cancel_delayed_work_sync(&wm8962->mic_work); wm8962_free_gpio(component); wm8962_free_beep(component); - for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++) - regulator_unregister_notifier(wm8962->supplies[i].consumer, - &wm8962->disable_nb[i]); } static const struct snd_soc_component_driver soc_component_dev_wm8962 = { diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 68c99fe3709741..79ee91906bb937 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -1995,20 +1995,6 @@ static int wm8995_set_bias_level(struct snd_soc_component *component, return 0; } -static void wm8995_remove(struct snd_soc_component *component) -{ - struct wm8995_priv *wm8995; - int i; - - wm8995 = snd_soc_component_get_drvdata(component); - - for (i = 0; i < ARRAY_SIZE(wm8995->supplies); ++i) - regulator_unregister_notifier(wm8995->supplies[i].consumer, - &wm8995->disable_nb[i]); - - regulator_bulk_free(ARRAY_SIZE(wm8995->supplies), wm8995->supplies); -} - static int wm8995_probe(struct snd_soc_component *component) { struct wm8995_priv *wm8995; @@ -2021,8 +2007,9 @@ static int wm8995_probe(struct snd_soc_component *component) for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++) wm8995->supplies[i].supply = wm8995_supply_names[i]; - ret = regulator_bulk_get(component->dev, ARRAY_SIZE(wm8995->supplies), - wm8995->supplies); + ret = devm_regulator_bulk_get(component->dev, + ARRAY_SIZE(wm8995->supplies), + wm8995->supplies); if (ret) { dev_err(component->dev, "Failed to request supplies: %d\n", ret); return ret; @@ -2039,8 +2026,9 @@ static int wm8995_probe(struct snd_soc_component *component) /* This should really be moved into the regulator core */ for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++) { - ret = regulator_register_notifier(wm8995->supplies[i].consumer, - &wm8995->disable_nb[i]); + ret = devm_regulator_register_notifier( + wm8995->supplies[i].consumer, + &wm8995->disable_nb[i]); if (ret) { dev_err(component->dev, "Failed to register regulator notifier: %d\n", @@ -2052,7 +2040,7 @@ static int wm8995_probe(struct snd_soc_component *component) wm8995->supplies); if (ret) { dev_err(component->dev, "Failed to enable supplies: %d\n", ret); - goto err_reg_get; + return ret; } ret = snd_soc_component_read32(component, WM8995_SOFTWARE_RESET); @@ -2099,8 +2087,6 @@ static int wm8995_probe(struct snd_soc_component *component) err_reg_enable: regulator_bulk_disable(ARRAY_SIZE(wm8995->supplies), wm8995->supplies); -err_reg_get: - regulator_bulk_free(ARRAY_SIZE(wm8995->supplies), wm8995->supplies); return ret; } @@ -2188,7 +2174,6 @@ static struct snd_soc_dai_driver wm8995_dai[] = { static const struct snd_soc_component_driver soc_component_dev_wm8995 = { .probe = wm8995_probe, - .remove = wm8995_remove, .set_bias_level = wm8995_set_bias_level, .controls = wm8995_snd_controls, .num_controls = ARRAY_SIZE(wm8995_snd_controls), diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 91711f8958c562..ab04ea18c31276 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2801,8 +2801,9 @@ static int wm8996_i2c_probe(struct i2c_client *i2c, /* This should really be moved into the regulator core */ for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) { - ret = regulator_register_notifier(wm8996->supplies[i].consumer, - &wm8996->disable_nb[i]); + ret = devm_regulator_register_notifier( + wm8996->supplies[i].consumer, + &wm8996->disable_nb[i]); if (ret != 0) { dev_err(&i2c->dev, "Failed to register regulator notifier: %d\n", @@ -3071,16 +3072,12 @@ static int wm8996_i2c_probe(struct i2c_client *i2c, static int wm8996_i2c_remove(struct i2c_client *client) { struct wm8996_priv *wm8996 = i2c_get_clientdata(client); - int i; wm8996_free_gpio(wm8996); if (wm8996->pdata.ldo_ena > 0) { gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); gpio_free(wm8996->pdata.ldo_ena); } - for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) - regulator_unregister_notifier(wm8996->supplies[i].consumer, - &wm8996->disable_nb[i]); return 0; } From 5a8b202d2db5f4e5ed2b3405ab50a65207b79953 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 6 Feb 2019 22:49:46 +0200 Subject: [PATCH 1067/1995] gpiolib: acpi: Introduce ACPI_GPIO_QUIRK_ONLY_GPIOIO New quirk enforces search for GPIO based on its type, i.e. iterate over GpioIo resources only. Signed-off-by: Andy Shevchenko Acked-by: Mika Westerberg Acked-by: Linus Walleij Tested-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit 4d1f7a6eabd45639d9de22a8a004f3c208d13c1a) --- drivers/gpio/gpiolib-acpi.c | 15 ++++-- include/linux/acpi.h | 7 +++ sound/soc/intel/boards/bytcr_rt5651.c | 74 ++++----------------------- 3 files changed, 27 insertions(+), 69 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 259cf6ab969b0d..4d291b75cb9fdb 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -530,17 +530,24 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data) if (ares->type != ACPI_RESOURCE_TYPE_GPIO) return 1; - if (lookup->n++ == lookup->index && !lookup->desc) { + if (!lookup->desc) { const struct acpi_resource_gpio *agpio = &ares->data.gpio; - int pin_index = lookup->pin_index; + bool gpioint = agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; + int pin_index; + if (lookup->info.quirks & ACPI_GPIO_QUIRK_ONLY_GPIOIO && gpioint) + lookup->index++; + + if (lookup->n++ != lookup->index) + return 1; + + pin_index = lookup->pin_index; if (pin_index >= agpio->pin_table_length) return 1; lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr, agpio->pin_table[pin_index]); - lookup->info.gpioint = - agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; + lookup->info.gpioint = gpioint; /* * Polarity and triggering are only specified for GpioInt diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 87715f20b69a07..03b4c4f225d002 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -1014,6 +1014,13 @@ struct acpi_gpio_mapping { /* Ignore IoRestriction field */ #define ACPI_GPIO_QUIRK_NO_IO_RESTRICTION BIT(0) +/* + * When ACPI GPIO mapping table is in use the index parameter inside it + * refers to the GPIO resource in _CRS method. That index has no + * distinction of actual type of the resource. When consumer wants to + * get GpioIo type explicitly, this quirk may be used. + */ +#define ACPI_GPIO_QUIRK_ONLY_GPIOIO BIT(1) unsigned int quirks; }; diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index c3b7732929cc76..b0a4d297176e02 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -844,74 +844,18 @@ static const struct x86_cpu_id cherrytrail_cpu_ids[] = { {} }; -static const struct acpi_gpio_params first_gpio = { 0, 0, false }; -static const struct acpi_gpio_params second_gpio = { 1, 0, false }; +static const struct acpi_gpio_params ext_amp_enable_gpios = { 0, 0, false }; -static const struct acpi_gpio_mapping byt_rt5651_amp_en_first[] = { - { "ext-amp-enable-gpios", &first_gpio, 1 }, - { }, -}; - -static const struct acpi_gpio_mapping byt_rt5651_amp_en_second[] = { - { "ext-amp-enable-gpios", &second_gpio, 1 }, +static const struct acpi_gpio_mapping cht_rt5651_gpios[] = { + /* + * Some boards have I2cSerialBusV2, GpioIo, GpioInt as ACPI resources, + * other boards may have I2cSerialBusV2, GpioInt, GpioIo instead. + * We want the GpioIo one for the ext-amp-enable-gpio. + */ + { "ext-amp-enable-gpios", &ext_amp_enable_gpios, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO }, { }, }; -/* - * Some boards have I2cSerialBusV2, GpioIo, GpioInt as ACPI resources, other - * boards may have I2cSerialBusV2, GpioInt, GpioIo instead. We want the - * GpioIo one for the ext-amp-enable-gpio and both count for the index in - * acpi_gpio_params index. So we have 2 different mappings and the code - * below figures out which one to use. - */ -struct byt_rt5651_acpi_resource_data { - int gpio_count; - int gpio_int_idx; -}; - -static int snd_byt_rt5651_acpi_resource(struct acpi_resource *ares, void *arg) -{ - struct byt_rt5651_acpi_resource_data *data = arg; - - if (ares->type != ACPI_RESOURCE_TYPE_GPIO) - return 0; - - if (ares->data.gpio.connection_type == ACPI_RESOURCE_GPIO_TYPE_INT) - data->gpio_int_idx = data->gpio_count; - - data->gpio_count++; - return 0; -} - -static void snd_byt_rt5651_mc_pick_amp_en_gpio_mapping(struct device *codec) -{ - struct byt_rt5651_acpi_resource_data data = { 0, -1 }; - LIST_HEAD(resources); - int ret; - - ret = acpi_dev_get_resources(ACPI_COMPANION(codec), &resources, - snd_byt_rt5651_acpi_resource, &data); - if (ret < 0) { - dev_warn(codec, "Failed to get ACPI resources, not adding external amplifier GPIO mapping\n"); - return; - } - - /* All info we need is gathered during the walk */ - acpi_dev_free_resource_list(&resources); - - switch (data.gpio_int_idx) { - case 0: - byt_rt5651_gpios = byt_rt5651_amp_en_second; - break; - case 1: - byt_rt5651_gpios = byt_rt5651_amp_en_first; - break; - default: - dev_warn(codec, "Unknown GpioInt index %d, not adding external amplifier GPIO mapping\n", - data.gpio_int_idx); - } -} - struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ u64 aif_value; /* 1: AIF1, 2: AIF2 */ u64 mclock_value; /* usually 25MHz (0x17d7940), ignored */ @@ -1038,7 +982,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) /* Cherry Trail devices use an external amplifier enable gpio */ if (x86_match_cpu(cherrytrail_cpu_ids) && !byt_rt5651_gpios) - snd_byt_rt5651_mc_pick_amp_en_gpio_mapping(codec_dev); + byt_rt5651_gpios = cht_rt5651_gpios; if (byt_rt5651_gpios) { devm_acpi_dev_add_driver_gpios(codec_dev, byt_rt5651_gpios); From d40704ba18fd469f4234179ba2731b65b3cd5872 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Feb 2019 11:22:23 -0600 Subject: [PATCH 1068/1995] ASoC: core: don't increase component module refcount unconditionally The ASoC core has for the longest time increased the module reference counts, even before the transition to the component model. This is probably fine on most platforms, but it introduces a deadlock case on Intel devices with the Skylake and SOF drivers which cannot be removed due to their reference counts being modified by the core. In these 2 cases, the PCI or ACPI driver .probe creates a platform device to let the machine driver .probe register the audio card. Conversely the PCI or ACPI driver .remove will unregister the platform device which results in the card being removed by the machine driver .remove. With ascii art, this can be represented as modprobe snd_soc_skl/ soc-pci-dev/sof-acpci-dev ----------> pci/acpi probe ^ | | ---------------| | | | | V V increase register register machine refcount component platform_device ^ | | | | V component <---- register card <---- probe probe The issue is that by playing with the component's module reference counts during the card registration, it's no longer possible to remove the module which controls the component. This can be shown, e.g. with the following error: root@plb-XPS-13-9350:~# lsmod | grep snd_soc_skl snd_soc_skl 110592 1 root@plb-XPS-13-9350:~# rmmod snd_soc_skl rmmod: ERROR: Module snd_soc_skl is in use Increasing the reference count during the component probe is not useful. If the PCI/ACPI module is removed, the card will be removed anyway. To avoid breaking existing platforms and allowing Intel platforms to safely deal with module load/unload cases, this patch introduces a flag which needs to be set during the component initialization. This is a strictly opt-in capability that should only be used when the handling of the component module does not require a reference count increase to prevent removal during use. Note that this solution is not directly applicable to the legacy Atom/SST driver, which uses a different device hierarchy. There are however additional refcount issues which prevent the ACPI driver from being removed. This is a different issue which would need a different patch. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit b450b87847b157d69dbf9af7aefb4cec29e89cc9) --- include/sound/soc.h | 3 +++ sound/soc/soc-core.c | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 95689680336bd1..eb7db605955b85 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -802,6 +802,9 @@ struct snd_soc_component_driver { int probe_order; int remove_order; + /* signal if the module handling the component cannot be removed */ + unsigned int ignore_module_refcount:1; + /* bits */ unsigned int idle_bias_on:1; unsigned int suspend_bias_off:1; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 994d21d7ba0f69..93d316d5bf8e3c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -947,7 +947,8 @@ static void soc_cleanup_component(struct snd_soc_component *component) snd_soc_dapm_free(snd_soc_component_get_dapm(component)); soc_cleanup_component_debugfs(component); component->card = NULL; - module_put(component->dev->driver->owner); + if (!component->driver->ignore_module_refcount) + module_put(component->dev->driver->owner); } static void soc_remove_component(struct snd_soc_component *component) @@ -1380,7 +1381,8 @@ static int soc_probe_component(struct snd_soc_card *card, return 0; } - if (!try_module_get(component->dev->driver->owner)) + if (!component->driver->ignore_module_refcount && + !try_module_get(component->dev->driver->owner)) return -ENODEV; component->card = card; From 42f3c739f396c53315d3ce9feb1446ab74ed93d8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Feb 2019 11:22:24 -0600 Subject: [PATCH 1069/1995] ASoC: Intel: Skylake: set .ignore_module_refcount field in component There is no risk of the module being removed while the platform components are in use. This solves the problem of the snd_soc_skl module not being removable with rmmod Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit e0771fc98909096b65c9781c438ac9d9c98ac41a) --- sound/soc/intel/skylake/skl-pcm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 8e589d698c588e..a4284778f117d6 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1464,6 +1464,7 @@ static const struct snd_soc_component_driver skl_component = { .ops = &skl_platform_ops, .pcm_new = skl_pcm_new, .pcm_free = skl_pcm_free, + .ignore_module_refcount = 1, /* do not increase the refcount in core */ }; int skl_platform_register(struct device *dev) From b8325d45f63d3c7cae8b97d3b6ccc9429544a8ac Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:26:53 -0600 Subject: [PATCH 1070/1995] ASoC: hdac_hdmi: use devm_kzalloc for all structures Loading/unloading modules exposes issues with memory allocation, which is a mix of devm_kzalloc and manual kzalloc. Move to devm_k routines everywhere to simplify all this. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit c7ba4e5396fbe998502390e4fc7935163b189c50) --- sound/soc/codecs/hdac_hdmi.c | 87 ++++++++---------------------------- 1 file changed, 18 insertions(+), 69 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index b19d7a3e7a2cc0..5eeb0fe836a9a9 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1176,13 +1176,15 @@ static int hdac_hdmi_add_cvt(struct hdac_device *hdev, hda_nid_t nid) struct hdac_hdmi_cvt *cvt; char name[NAME_SIZE]; - cvt = kzalloc(sizeof(*cvt), GFP_KERNEL); + cvt = devm_kzalloc(&hdev->dev, sizeof(*cvt), GFP_KERNEL); if (!cvt) return -ENOMEM; cvt->nid = nid; sprintf(name, "cvt %d", cvt->nid); - cvt->name = kstrdup(name, GFP_KERNEL); + cvt->name = devm_kstrdup(&hdev->dev, name, GFP_KERNEL); + if (!cvt->name) + return -ENOMEM; list_add_tail(&cvt->head, &hdmi->cvt_list); hdmi->num_cvt++; @@ -1287,8 +1289,8 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, mutex_unlock(&hdmi->pin_mutex); } -static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi, - struct hdac_hdmi_pin *pin) +static int hdac_hdmi_add_ports(struct hdac_device *hdev, + struct hdac_hdmi_pin *pin) { struct hdac_hdmi_port *ports; int max_ports = HDA_MAX_PORTS; @@ -1300,7 +1302,7 @@ static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi, * implemented. */ - ports = kcalloc(max_ports, sizeof(*ports), GFP_KERNEL); + ports = devm_kcalloc(&hdev->dev, max_ports, sizeof(*ports), GFP_KERNEL); if (!ports) return -ENOMEM; @@ -1319,14 +1321,14 @@ static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid) struct hdac_hdmi_pin *pin; int ret; - pin = kzalloc(sizeof(*pin), GFP_KERNEL); + pin = devm_kzalloc(&hdev->dev, sizeof(*pin), GFP_KERNEL); if (!pin) return -ENOMEM; pin->nid = nid; pin->mst_capable = false; pin->hdev = hdev; - ret = hdac_hdmi_add_ports(hdmi, pin); + ret = hdac_hdmi_add_ports(hdev, pin); if (ret < 0) return ret; @@ -1468,8 +1470,6 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev, { hda_nid_t nid; int i, num_nodes; - struct hdac_hdmi_cvt *temp_cvt, *cvt_next; - struct hdac_hdmi_pin *temp_pin, *pin_next; struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); int ret; @@ -1497,51 +1497,35 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev, case AC_WID_AUD_OUT: ret = hdac_hdmi_add_cvt(hdev, nid); if (ret < 0) - goto free_widgets; + return ret; break; case AC_WID_PIN: ret = hdac_hdmi_add_pin(hdev, nid); if (ret < 0) - goto free_widgets; + return ret; break; } } if (!hdmi->num_pin || !hdmi->num_cvt) { ret = -EIO; - goto free_widgets; + dev_err(&hdev->dev, "Bad pin/cvt setup in %s\n", __func__); + return ret; } ret = hdac_hdmi_create_dais(hdev, dais, hdmi, hdmi->num_cvt); if (ret) { dev_err(&hdev->dev, "Failed to create dais with err: %d\n", - ret); - goto free_widgets; + ret); + return ret; } *num_dais = hdmi->num_cvt; ret = hdac_hdmi_init_dai_map(hdev); if (ret < 0) - goto free_widgets; - - return ret; - -free_widgets: - list_for_each_entry_safe(temp_cvt, cvt_next, &hdmi->cvt_list, head) { - list_del(&temp_cvt->head); - kfree(temp_cvt->name); - kfree(temp_cvt); - } - - list_for_each_entry_safe(temp_pin, pin_next, &hdmi->pin_list, head) { - for (i = 0; i < temp_pin->num_ports; i++) - temp_pin->ports[i].pin = NULL; - kfree(temp_pin->ports); - list_del(&temp_pin->head); - kfree(temp_pin); - } - + dev_err(&hdev->dev, "Failed to init DAI map with err: %d\n", + ret); return ret; } @@ -1782,7 +1766,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, * this is a new PCM device, create new pcm and * add to the pcm list */ - pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); + pcm = devm_kzalloc(&hdev->dev, sizeof(*pcm), GFP_KERNEL); if (!pcm) return -ENOMEM; pcm->pcm_id = device; @@ -1798,7 +1782,6 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device, dev_err(&hdev->dev, "chmap control add failed with err: %d for pcm: %d\n", err, device); - kfree(pcm); return err; } } @@ -2075,42 +2058,8 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev) static int hdac_hdmi_dev_remove(struct hdac_device *hdev) { - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); - struct hdac_hdmi_pin *pin, *pin_next; - struct hdac_hdmi_cvt *cvt, *cvt_next; - struct hdac_hdmi_pcm *pcm, *pcm_next; - struct hdac_hdmi_port *port, *port_next; - int i; - snd_hdac_display_power(hdev->bus, hdev->addr, false); - list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { - pcm->cvt = NULL; - if (list_empty(&pcm->port_list)) - continue; - - list_for_each_entry_safe(port, port_next, - &pcm->port_list, head) - list_del(&port->head); - - list_del(&pcm->head); - kfree(pcm); - } - - list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) { - list_del(&cvt->head); - kfree(cvt->name); - kfree(cvt); - } - - list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) { - for (i = 0; i < pin->num_ports; i++) - pin->ports[i].pin = NULL; - kfree(pin->ports); - list_del(&pin->head); - kfree(pin); - } - return 0; } From e50f6db4df5fe5c593a0bc363e57fd1d834179d8 Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Wed, 23 Jan 2019 20:41:30 +0100 Subject: [PATCH 1071/1995] ASoC: Use __printf markup to silence compiler Silence warnings (triggered at W=1) by adding relevant __printf attributes. sound/soc/soc-dapm.c:149:2: warning: function 'pop_dbg' might be a candidate for 'gnu_printf' format attribute [-Wsuggest-attribute=format] Signed-off-by: Mathieu Malaterre Signed-off-by: Mark Brown (cherry picked from commit 595d2f74cd3caedb704a118bd09c1b4dfbfc0ec0) --- sound/soc/soc-dapm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d31d295b540fcc..dea6fc2353e47b 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -157,6 +157,7 @@ static void pop_wait(u32 pop_time) schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time)); } +__printf(3, 4) static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...) { va_list args; From 952c36b88924f001cfe8d838469187b80cd847ca Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Feb 2019 18:00:09 +0100 Subject: [PATCH 1072/1995] ASoC: dmaengine: Improve of_node test in dmaengine_pcm_request_chan_of() Currently when of_node of the "PCM" device is null dmaengine_pcm_request_chan_of() function will bail out, including cases when custom DMA device is intended to be used. To have the channels properly requested when custom DMA device is provided extend the of_node test to also consider dma_dev->of_node. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown (cherry picked from commit 51256d348c9af1bf544a4432abc1d5f2fd3ef34b) --- sound/soc/soc-generic-dmaengine-pcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 30e791a5335280..6d7638c1233d62 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -415,7 +415,8 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT | SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) || - !dev->of_node) + (!dev->of_node && !(config && config->dma_dev && + config->dma_dev->of_node))) return 0; if (config && config->dma_dev) { From 5882507f4a8654bce185e8402025104c4f987030 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Feb 2019 18:00:10 +0100 Subject: [PATCH 1073/1995] ASoC: dmaengine: Extend use of chan_names provided in custom DMA config There are currently two ways to specify custom DMA channel names: - through the SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME flag and snd_dmaengine_dai_dma_data data structure, - through chan_names field of struct snd_dmaengine_pcm_config. In order to replace the DAI DMA data method with the custom DMA config one on non-DT platforms the dmaengine_pcm_new() function is extended to also consider channel names specified in the custom DMA config. If both config->chan_names and dma_data->chan_name are provided the former will be used. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown (cherry picked from commit 10cbf3507bcb9baa82bf3445502e8ccafaa09fc8) --- sound/soc/soc-generic-dmaengine-pcm.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 6d7638c1233d62..1b44e363c50c7e 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -288,9 +288,16 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if (!pcm->chan[i] && - (pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) + ((pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME) || + (config && config->chan_names[i]))) { + const char *chan_name = dma_data->chan_name; + + if (config && config->chan_names[i]) + chan_name = config->chan_names[i]; + pcm->chan[i] = dma_request_slave_channel(dev, - dma_data->chan_name); + chan_name); + } if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) { pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd, From 811aa03df4b9cd35f9dd58b85bbea275bbc3d4c3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:41 -0600 Subject: [PATCH 1074/1995] ASoC: Intel: bxt-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit e529a9d44a9778b851a1683e6689c2f52d6750ac) --- .../intel/common/soc-acpi-intel-bxt-match.c | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c index 61dedc103b1966..c0e5780e2ad165 100644 --- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c @@ -51,8 +51,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .id = "INT343A", .drv_name = "bxt_alc298s_i2s", .fw_filename = "intel/dsp_fw_bxtn.bin", - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-rt298.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-rt298.tplg", .asoc_plat_name = "0000:00:0e.0", }, { @@ -61,30 +61,30 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .fw_filename = "intel/dsp_fw_bxtn.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &bxt_codecs, - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-da7219.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-da7219.tplg", .asoc_plat_name = "0000:00:0e.0", }, { .id = "104C5122", .drv_name = "bxt-pcm512x", - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-pcm512x.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-pcm512x.tplg", .asoc_plat_name = "0000:00:0e.0", }, { .id = "1AEC8804", .drv_name = "bxt-wm8804", - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-wm8804.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-wm8804.tplg", .asoc_plat_name = "0000:00:0e.0", }, { .id = "INT34C3", .drv_name = "bxt_tdf8532", .machine_quirk = apl_quirk, - .sof_fw_filename = "intel/sof-apl.ri", - .sof_tplg_filename = "intel/sof-apl-tdf8532.tplg", + .sof_fw_filename = "sof-apl.ri", + .sof_tplg_filename = "sof-apl-tdf8532.tplg", .asoc_plat_name = "0000:00:0e.0", }, {}, From b18f2ac2f49e426d2a63bbefde93e626712a3730 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:42 -0600 Subject: [PATCH 1075/1995] ASoC: Intel: byt-match.c: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 528f07152a7840b5affe1c8844ddd1ee9d3aabd7) --- .../intel/common/soc-acpi-intel-byt-match.c | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index 96f9c553fe6c9f..a46a3514a0f00b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -83,8 +83,8 @@ static struct snd_soc_acpi_mach byt_thinkpad_10 = { .drv_name = "cht-bsw-rt5672", .fw_filename = "intel/fw_sst_0f28.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5670.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5670.tplg", .asoc_plat_name = "sst-mfld-platform", }; @@ -93,8 +93,8 @@ static struct snd_soc_acpi_mach byt_pov_p1006w = { .drv_name = "bytcr_rt5651", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5651", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5651.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5651.tplg", .asoc_plat_name = "sst-mfld-platform", }; @@ -136,8 +136,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5640", .machine_quirk = byt_quirk, - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5640.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -145,8 +145,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcr_rt5640", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5640", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5640.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -154,8 +154,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcr_rt5640", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5640", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5640.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -163,8 +163,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcr_rt5651", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcr_rt5651", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5651.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5651.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -172,8 +172,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcht_da7213", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcht_da7213", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-da7213.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -181,8 +181,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcht_da7213", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcht_da7213", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-da7213.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -190,8 +190,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "bytcht_es8316", .fw_filename = "intel/fw_sst_0f28.bin", .board = "bytcht_es8316", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-es8316.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-es8316.tplg", .asoc_plat_name = "sst-mfld-platform", }, /* some Baytrail platforms rely on RT5645, use CHT machine driver */ @@ -200,8 +200,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_0f28.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5645.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -209,8 +209,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_0f28.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-rt5645.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, /* use CHT driver to Baytrail Chromebooks */ @@ -219,8 +219,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .drv_name = "cht-bsw-max98090", .fw_filename = "intel/fw_sst_0f28.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-byt.ri", - .sof_tplg_filename = "intel/sof-byt-max98090.tplg", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt-max98090.tplg", .asoc_plat_name = "sst-mfld-platform", }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) From 35df2a117a41f1d7ced2380fe9e4f6f41b6ab79f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:43 -0600 Subject: [PATCH 1076/1995] ASoC: Intel: cht-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 2e441dea9fee379e85dca15988671c23d6013d1c) --- .../intel/common/soc-acpi-intel-cht-match.c | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c index 91bb99b69601dd..21ce4bcbf25b7e 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -44,8 +44,8 @@ static struct snd_soc_acpi_mach cht_surface_mach = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5645.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }; @@ -68,8 +68,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5672", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5670.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5670.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -77,8 +77,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5672", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5670.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5670.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -86,8 +86,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5645.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -95,8 +95,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5645.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -104,8 +104,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-rt5645", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5645.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5645.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -113,8 +113,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-max98090", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-max98090.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-max98090.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -122,8 +122,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "cht-bsw-nau8824", .fw_filename = "intel/fw_sst_22a8.bin", .board = "cht-bsw", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-nau8824.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-nau8824.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -131,8 +131,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcht_da7213", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcht_da7213", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-da7213.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -140,8 +140,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcht_da7213", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcht_da7213", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-da7213.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-da7213.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -149,8 +149,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcht_es8316", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcht_es8316", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-es8316.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-es8316.tplg", .asoc_plat_name = "sst-mfld-platform", }, /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ @@ -160,8 +160,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcr_rt5640", .machine_quirk = cht_quirk, - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5640.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, { @@ -169,8 +169,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcr_rt5640", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcr_rt5640", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5640.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5640.tplg", .asoc_plat_name = "sst-mfld-platform", }, /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */ @@ -179,8 +179,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .drv_name = "bytcr_rt5651", .fw_filename = "intel/fw_sst_22a8.bin", .board = "bytcr_rt5651", - .sof_fw_filename = "intel/sof-cht.ri", - .sof_tplg_filename = "intel/sof-cht-rt5651.tplg", + .sof_fw_filename = "sof-cht.ri", + .sof_tplg_filename = "sof-cht-rt5651.tplg", .asoc_plat_name = "sst-mfld-platform", }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) From fafdfbbddf173e9a95ba4076358438b4a0a7f9a2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:44 -0600 Subject: [PATCH 1077/1995] ASoC: Intel: cnl-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7466e749a3b4e838882cc8728bc66a39df0e9dfa) --- sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index ec8e28e7b937aa..b80b50ddb22b12 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -20,8 +20,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .drv_name = "cnl_rt274", .fw_filename = "intel/dsp_fw_cnl.bin", .pdata = &cnl_pdata, - .sof_fw_filename = "intel/sof-cnl.ri", - .sof_tplg_filename = "intel/sof-cnl-rt274.tplg", + .sof_fw_filename = "sof-cnl.ri", + .sof_tplg_filename = "sof-cnl-rt274.tplg", .asoc_plat_name = "0000:00:1f.3", }, {}, From 352787178b2c1ee5245875a3cbac9ec0f638b3ee Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:45 -0600 Subject: [PATCH 1078/1995] ASoC: Intel: glk-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 6d356d52297ded6b1bae86c54b364d7784c0a528) --- sound/soc/intel/common/soc-acpi-intel-glk-match.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c index 305875af71caee..75bc0109166a0a 100644 --- a/sound/soc/intel/common/soc-acpi-intel-glk-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c @@ -19,8 +19,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { .id = "INT343A", .drv_name = "glk_alc298s_i2s", .fw_filename = "intel/dsp_fw_glk.bin", - .sof_fw_filename = "intel/sof-glk.ri", - .sof_tplg_filename = "intel/sof-glk-alc298.tplg", + .sof_fw_filename = "sof-glk.ri", + .sof_tplg_filename = "sof-glk-alc298.tplg", .asoc_plat_name = "0000:00:0e.0", }, { @@ -29,8 +29,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { .fw_filename = "intel/dsp_fw_glk.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &glk_codecs, - .sof_fw_filename = "intel/sof-glk.ri", - .sof_tplg_filename = "intel/sof-glk-da7219.tplg", + .sof_fw_filename = "sof-glk.ri", + .sof_tplg_filename = "sof-glk-da7219.tplg", .asoc_plat_name = "0000:00:0e.0", }, {}, From 55d6093b508fba5f82e61036c1259b34f2a7db72 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:46 -0600 Subject: [PATCH 1079/1995] ASoC: Intel: hda-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit e576b097918f8ee563fbfde7d4186f09df856fe9) --- sound/soc/intel/common/soc-acpi-intel-hda-match.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-hda-match.c b/sound/soc/intel/common/soc-acpi-intel-hda-match.c index 533c1064f84b33..68ae43f7b4b288 100644 --- a/sound/soc/intel/common/soc-acpi-intel-hda-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-hda-match.c @@ -23,7 +23,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[] = { /* .sof_fw_filename is dynamically set in sof/intel driver */ - .sof_tplg_filename = "intel/sof-hda-generic.tplg", + .sof_tplg_filename = "sof-hda-generic.tplg", /* * .machine_quirk and .quirk_data are not used here but From b7bb894b3c846fb72e54674a45226375b0b56281 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:47 -0600 Subject: [PATCH 1080/1995] ASoC: Intel: hsw-bdw-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit bb2538e28a54f97455597eca01e1b9452c67a5d4) --- .../intel/common/soc-acpi-intel-hsw-bdw-match.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c index 494a0ea9b02903..ddfe4250c2bcb9 100644 --- a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c @@ -23,8 +23,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_haswell_machines[] = { .id = "INT33CA", .drv_name = "haswell-audio", .fw_filename = "intel/IntcSST1.bin", - .sof_fw_filename = "intel/sof-hsw.ri", - .sof_tplg_filename = "intel/sof-hsw.tplg", + .sof_fw_filename = "sof-hsw.ri", + .sof_tplg_filename = "sof-hsw.tplg", .asoc_plat_name = "haswell-pcm-audio", }, {} @@ -36,24 +36,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { .id = "INT343A", .drv_name = "broadwell-audio", .fw_filename = "intel/IntcSST2.bin", - .sof_fw_filename = "intel/sof-bdw.ri", - .sof_tplg_filename = "intel/sof-bdw-rt286.tplg", + .sof_fw_filename = "sof-bdw.ri", + .sof_tplg_filename = "sof-bdw-rt286.tplg", .asoc_plat_name = "haswell-pcm-audio", }, { .id = "RT5677CE", .drv_name = "bdw-rt5677", .fw_filename = "intel/IntcSST2.bin", - .sof_fw_filename = "intel/sof-bdw.ri", - .sof_tplg_filename = "intel/sof-bdw-rt5677.tplg", + .sof_fw_filename = "sof-bdw.ri", + .sof_tplg_filename = "sof-bdw-rt5677.tplg", .asoc_plat_name = "haswell-pcm-audio", }, { .id = "INT33CA", .drv_name = "haswell-audio", .fw_filename = "intel/IntcSST2.bin", - .sof_fw_filename = "intel/sof-bdw.ri", - .sof_tplg_filename = "intel/sof-bdw-rt5640.tplg", + .sof_fw_filename = "sof-bdw.ri", + .sof_tplg_filename = "sof-bdw-rt5640.tplg", .asoc_plat_name = "haswell-pcm-audio", }, {} From 0ad1e9bb0f1e87300cc3d6e6922890d3bd5d3244 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:48 -0600 Subject: [PATCH 1081/1995] ASoC: Intel: icl-match: remove prefix for SOF files Prefix is now handled in the code. This allows for default and alternate paths, and more flexibility for OEMs and distros Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit a5b1e2284567c487b1023b580656de4a19cc1a83) --- sound/soc/intel/common/soc-acpi-intel-icl-match.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c index 33b441dca4d308..bf6e25257a398a 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -20,8 +20,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { .drv_name = "icl_rt274", .fw_filename = "intel/dsp_fw_icl.bin", .pdata = &icl_pdata, - .sof_fw_filename = "intel/sof-icl.ri", - .sof_tplg_filename = "intel/sof-icl-rt274.tplg", + .sof_fw_filename = "sof-icl.ri", + .sof_tplg_filename = "sof-icl-rt274.tplg", .asoc_plat_name = "0000:00:1f.3", }, {}, From 62a0ac62d1b4258821845885d5d35b1c0af2dda7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:49 -0600 Subject: [PATCH 1082/1995] ASoC: Intel: soc-acpi: bxt-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit dcc9de2ebe86791a041a92cdf9806bde004706c6) --- sound/soc/intel/common/soc-acpi-intel-bxt-match.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c index c0e5780e2ad165..229e395868684e 100644 --- a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c @@ -53,7 +53,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .fw_filename = "intel/dsp_fw_bxtn.bin", .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-rt298.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "DLGS7219", @@ -63,21 +62,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .quirk_data = &bxt_codecs, .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-da7219.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "104C5122", .drv_name = "bxt-pcm512x", .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-pcm512x.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "1AEC8804", .drv_name = "bxt-wm8804", .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-wm8804.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "INT34C3", @@ -85,7 +81,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = { .machine_quirk = apl_quirk, .sof_fw_filename = "sof-apl.ri", .sof_tplg_filename = "sof-apl-tdf8532.tplg", - .asoc_plat_name = "0000:00:0e.0", }, {}, }; From b9866d1c66b40fe1940556e620090fb914ef1050 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:50 -0600 Subject: [PATCH 1083/1995] ASoC: Intel: soc-acpi: byt-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit f01d00c30095f420ad8b447ba21c9492da93cebf) --- sound/soc/intel/common/soc-acpi-intel-byt-match.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c index a46a3514a0f00b..fe812a909db4a9 100644 --- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c @@ -85,7 +85,6 @@ static struct snd_soc_acpi_mach byt_thinkpad_10 = { .board = "cht-bsw", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5670.tplg", - .asoc_plat_name = "sst-mfld-platform", }; static struct snd_soc_acpi_mach byt_pov_p1006w = { @@ -95,7 +94,6 @@ static struct snd_soc_acpi_mach byt_pov_p1006w = { .board = "bytcr_rt5651", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5651.tplg", - .asoc_plat_name = "sst-mfld-platform", }; static struct snd_soc_acpi_mach *byt_quirk(void *arg) @@ -138,7 +136,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .machine_quirk = byt_quirk, .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5642", @@ -147,7 +144,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcr_rt5640", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "INTCCFFD", @@ -156,7 +152,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcr_rt5640", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5651", @@ -165,7 +160,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcr_rt5651", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5651.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "DLGS7212", @@ -174,7 +168,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcht_da7213", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-da7213.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "DLGS7213", @@ -183,7 +176,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcht_da7213", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-da7213.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "ESSX8316", @@ -192,7 +184,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "bytcht_es8316", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-es8316.tplg", - .asoc_plat_name = "sst-mfld-platform", }, /* some Baytrail platforms rely on RT5645, use CHT machine driver */ { @@ -202,7 +193,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5648", @@ -211,7 +201,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, /* use CHT driver to Baytrail Chromebooks */ { @@ -221,7 +210,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-byt.ri", .sof_tplg_filename = "sof-byt-max98090.tplg", - .asoc_plat_name = "sst-mfld-platform", }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) /* From 7f7f576c9367c314cf5bafa242a5f4985d460cc0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:51 -0600 Subject: [PATCH 1084/1995] ASoC: Intel: soc-acpi: cht-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 9eebe4372f4a608e51b7a2c0b064069e78a6ce5b) --- sound/soc/intel/common/soc-acpi-intel-cht-match.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c index 21ce4bcbf25b7e..deafd87cc76466 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -46,7 +46,6 @@ static struct snd_soc_acpi_mach cht_surface_mach = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }; static struct snd_soc_acpi_mach *cht_quirk(void *arg) @@ -70,7 +69,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5670.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5672", @@ -79,7 +77,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5670.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5645", @@ -88,7 +85,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC5650", @@ -97,7 +93,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC3270", @@ -106,7 +101,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5645.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "193C9890", @@ -115,7 +109,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-max98090.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10508824", @@ -124,7 +117,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "cht-bsw", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-nau8824.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "DLGS7212", @@ -133,7 +125,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcht_da7213", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-da7213.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "DLGS7213", @@ -142,7 +133,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcht_da7213", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-da7213.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "ESSX8316", @@ -151,7 +141,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcht_es8316", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-es8316.tplg", - .asoc_plat_name = "sst-mfld-platform", }, /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ { @@ -162,7 +151,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .machine_quirk = cht_quirk, .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, { .id = "10EC3276", @@ -171,7 +159,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcr_rt5640", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5640.tplg", - .asoc_plat_name = "sst-mfld-platform", }, /* some CHT-T platforms rely on RT5651, use Baytrail machine driver */ { @@ -181,7 +168,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = { .board = "bytcr_rt5651", .sof_fw_filename = "sof-cht.ri", .sof_tplg_filename = "sof-cht-rt5651.tplg", - .asoc_plat_name = "sst-mfld-platform", }, #if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) /* From 72decbf6b8300d7f289747c82445712d5ee8313d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:52 -0600 Subject: [PATCH 1085/1995] ASoC: Intel: soc-acpi: glk-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 3f4d9d67c3399bde7e08aeeb9758868852413343) --- sound/soc/intel/common/soc-acpi-intel-glk-match.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c index 75bc0109166a0a..3f2061475ae426 100644 --- a/sound/soc/intel/common/soc-acpi-intel-glk-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c @@ -21,7 +21,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { .fw_filename = "intel/dsp_fw_glk.bin", .sof_fw_filename = "sof-glk.ri", .sof_tplg_filename = "sof-glk-alc298.tplg", - .asoc_plat_name = "0000:00:0e.0", }, { .id = "DLGS7219", @@ -31,7 +30,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { .quirk_data = &glk_codecs, .sof_fw_filename = "sof-glk.ri", .sof_tplg_filename = "sof-glk-da7219.tplg", - .asoc_plat_name = "0000:00:0e.0", }, {}, }; From a059af114819b6defc74cdf25b4e93c900317e27 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:53 -0600 Subject: [PATCH 1086/1995] ASoC: Intel: soc-acpi: hsw-bdw-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 2eddca128be282f600347ea07ef0b516dbc4e7ce) --- sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c index ddfe4250c2bcb9..690b305a255b4b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c @@ -25,7 +25,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_haswell_machines[] = { .fw_filename = "intel/IntcSST1.bin", .sof_fw_filename = "sof-hsw.ri", .sof_tplg_filename = "sof-hsw.tplg", - .asoc_plat_name = "haswell-pcm-audio", }, {} }; @@ -38,7 +37,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { .fw_filename = "intel/IntcSST2.bin", .sof_fw_filename = "sof-bdw.ri", .sof_tplg_filename = "sof-bdw-rt286.tplg", - .asoc_plat_name = "haswell-pcm-audio", }, { .id = "RT5677CE", @@ -46,7 +44,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { .fw_filename = "intel/IntcSST2.bin", .sof_fw_filename = "sof-bdw.ri", .sof_tplg_filename = "sof-bdw-rt5677.tplg", - .asoc_plat_name = "haswell-pcm-audio", }, { .id = "INT33CA", @@ -54,7 +51,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = { .fw_filename = "intel/IntcSST2.bin", .sof_fw_filename = "sof-bdw.ri", .sof_tplg_filename = "sof-bdw-rt5640.tplg", - .asoc_plat_name = "haswell-pcm-audio", }, {} }; From 7cc568432755539dfa735a82c210792ffb863945 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:54 -0600 Subject: [PATCH 1087/1995] ASoC: Intel: soc-acpi: icl-match: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit fc906fda39c1705c2d89937fce13a6c11a5955bb) --- sound/soc/intel/common/soc-acpi-intel-icl-match.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c index bf6e25257a398a..e5a6be5bc0ee62 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -22,7 +22,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { .pdata = &icl_pdata, .sof_fw_filename = "sof-icl.ri", .sof_tplg_filename = "sof-icl-rt274.tplg", - .asoc_plat_name = "0000:00:1f.3", }, {}, }; From 67852fda14135de84d5f5b0e59f288029732fb0d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:55 -0600 Subject: [PATCH 1088/1995] ASoC: Intel: soc-acpi: cnl-match.c: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit c5898050fe801443dc66cd0302c21ceefa313916) --- sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index b80b50ddb22b12..a914dd238d0a46 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -22,7 +22,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .pdata = &cnl_pdata, .sof_fw_filename = "sof-cnl.ri", .sof_tplg_filename = "sof-cnl-rt274.tplg", - .asoc_plat_name = "0000:00:1f.3", }, {}, }; From 47e3268ffeabe5b0029fc18c8db2d55ed9afef88 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:56 -0600 Subject: [PATCH 1089/1995] ASoC: soc-acpi: remove asoc_plat_name field This field was never used, let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit ecefff3e5b9b6a427a1a78c0c3f5eb147fd2d761) --- include/sound/soc-acpi.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 6cbbeed9cdd0c8..655e4e010cc821 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -86,8 +86,6 @@ struct snd_soc_acpi_mach_params { * is not constant since this field may be updated at run-time * @sof_fw_filename: Sound Open Firmware file name, if enabled * @sof_tplg_filename: Sound Open Firmware topology file name, if enabled - * @asoc_plat_name: ASoC platform name, used for binding machine drivers - * if non NULL * @new_mach_data: machine driver private data fixup */ /* Descriptor for SST ASoC machine driver */ @@ -102,7 +100,6 @@ struct snd_soc_acpi_mach { struct snd_soc_acpi_mach_params mach_params; const char *sof_fw_filename; const char *sof_tplg_filename; - const char *asoc_plat_name; struct platform_device * (*new_mach_data)(void *pdata); }; From 30dce5cfec8efd61a8df10fd65475c2a17fb4f5c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Feb 2019 17:45:57 -0600 Subject: [PATCH 1090/1995] ASoC: soc-acpi: remove new_mach_data field We never used this field (or in older SOF implementations), let's remove it Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit b3d8f7cad1b41411de443018cc5323070db06ab2) --- include/sound/soc-acpi.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 655e4e010cc821..35b38e41e5b296 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -86,7 +86,6 @@ struct snd_soc_acpi_mach_params { * is not constant since this field may be updated at run-time * @sof_fw_filename: Sound Open Firmware file name, if enabled * @sof_tplg_filename: Sound Open Firmware topology file name, if enabled - * @new_mach_data: machine driver private data fixup */ /* Descriptor for SST ASoC machine driver */ struct snd_soc_acpi_mach { @@ -100,7 +99,6 @@ struct snd_soc_acpi_mach { struct snd_soc_acpi_mach_params mach_params; const char *sof_fw_filename; const char *sof_tplg_filename; - struct platform_device * (*new_mach_data)(void *pdata); }; #define SND_SOC_ACPI_MAX_CODECS 3 From 97f79f1539a5d4ea35b905a0b9130280126149c0 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Thu, 14 Feb 2019 10:13:29 +0000 Subject: [PATCH 1091/1995] ASoC: da7219: Add support for master mode BCLK rate adjustment Previously the driver would default the BCLK periods per WCLK to 64, to cover all possible non-TDM scenarios when the codec was DAI clock master. However some devices require a lower BCLK rate to operate correctly so with this in mind, this commit updates the code to be more dynamic, with BCLK rate now based on SR and word length provided to hw_params(). Signed-off-by: Adam Thomson Signed-off-by: Mark Brown (cherry picked from commit 9fd729542cf4aff3c70b8e5be6f510e6722bc369) --- sound/soc/codecs/da7219.c | 36 ++++++++++++++++++++++++++---------- sound/soc/codecs/da7219.h | 1 + 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index b1df4bb361050e..c599aa9f609b6e 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1376,11 +1376,7 @@ static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } - /* By default 64 BCLKs per WCLK is supported */ - dai_clk_mode |= DA7219_DAI_BCLKS_PER_WCLK_64; - snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, - DA7219_DAI_BCLKS_PER_WCLK_MASK | DA7219_DAI_CLK_POL_MASK | DA7219_DAI_WCLK_POL_MASK, dai_clk_mode); snd_soc_component_update_bits(component, DA7219_DAI_CTRL, DA7219_DAI_FORMAT_MASK, @@ -1399,14 +1395,12 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, __le16 offset; u32 frame_size; - /* No channels enabled so disable TDM, revert to 64-bit frames */ + /* No channels enabled so disable TDM */ if (!tx_mask) { snd_soc_component_update_bits(component, DA7219_DAI_TDM_CTRL, DA7219_DAI_TDM_CH_EN_MASK | DA7219_DAI_TDM_MODE_EN_MASK, 0); - snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, - DA7219_DAI_BCLKS_PER_WCLK_MASK, - DA7219_DAI_BCLKS_PER_WCLK_64); + da7219->tdm_en = false; return 0; } @@ -1458,6 +1452,8 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, (tx_mask << DA7219_DAI_TDM_CH_EN_SHIFT) | DA7219_DAI_TDM_MODE_EN_MASK); + da7219->tdm_en = true; + return 0; } @@ -1466,10 +1462,13 @@ static int da7219_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; - u8 dai_ctrl = 0, fs; + struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); + u8 dai_ctrl = 0, dai_bclks_per_wclk = 0, fs; unsigned int channels; + int word_len = params_width(params); + int frame_size; - switch (params_width(params)) { + switch (word_len) { case 16: dai_ctrl |= DA7219_DAI_WORD_LENGTH_S16_LE; break; @@ -1533,6 +1532,23 @@ static int da7219_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + /* + * If we're master, then we have a limited set of BCLK rates we + * support. For slave mode this isn't the case and the codec can detect + * the BCLK rate automatically. + */ + if (da7219->master && !da7219->tdm_en) { + frame_size = word_len * 2; + if (frame_size <= 32) + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32; + else + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64; + + snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, + DA7219_DAI_BCLKS_PER_WCLK_MASK, + dai_bclks_per_wclk); + } + snd_soc_component_update_bits(component, DA7219_DAI_CTRL, DA7219_DAI_WORD_LENGTH_MASK | DA7219_DAI_CH_NUM_MASK, diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index 366cf46118a005..018819c631fbe4 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -830,6 +830,7 @@ struct da7219_priv { int clk_src; bool master; + bool tdm_en; bool alc_en; bool micbias_on_event; unsigned int mic_pga_delay; From 8cb9eb5c2fea4976dad28223e27d5a28201385b1 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Thu, 14 Feb 2019 10:13:30 +0000 Subject: [PATCH 1092/1995] ASoC: da7219: Update TDM usage to be more flexible The previous implementatation was restrictive with regards to BCLK rates for slave mode where the driver would not allow rates the codec couldn't provide itself as clock master. The codec is able to automatically determine and handle whatever rate is provided so this restriction isn't necessary for slave mode. The code was also flawed with regards to setting of the frame offset as using rx_mask to explicitly set the offset has the knock on effect of impacting the min and max channels for the codec, in soc_pcm_hw_params() through the call to soc_pcm_codec_params_fixup(). With this update, the driver now only limits frame size if codec is clock master, and dynamically determines the BCLK offset relating to WCLK using the tx_mask for slot offset along with the slot width provided. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown (cherry picked from commit 541ccdc113f000d51858ee7e135889e4096a3316) --- sound/soc/codecs/da7219.c | 80 +++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index c599aa9f609b6e..121a8190f93edc 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1391,8 +1391,10 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, { struct snd_soc_component *component = dai->component; struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - u8 dai_bclks_per_wclk; - __le16 offset; + unsigned int ch_mask; + u8 dai_bclks_per_wclk, slot_offset; + u16 offset; + __le16 dai_offset; u32 frame_size; /* No channels enabled so disable TDM */ @@ -1405,51 +1407,63 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, } /* Check we have valid slots */ - if (fls(tx_mask) > DA7219_DAI_TDM_MAX_SLOTS) { - dev_err(component->dev, "Invalid number of slots, max = %d\n", + slot_offset = ffs(tx_mask) - 1; + ch_mask = (tx_mask >> slot_offset); + if (fls(ch_mask) > DA7219_DAI_TDM_MAX_SLOTS) { + dev_err(component->dev, + "Invalid number of slots, max = %d\n", DA7219_DAI_TDM_MAX_SLOTS); return -EINVAL; } - /* Check we have a valid offset given */ - if (rx_mask > DA7219_DAI_OFFSET_MAX) { - dev_err(component->dev, "Invalid slot offset, max = %d\n", - DA7219_DAI_OFFSET_MAX); + /* + * Ensure we have a valid offset into the frame, based on slot width + * and slot offset of first slot we're interested in. + */ + offset = slot_offset * slot_width; + if (offset > DA7219_DAI_OFFSET_MAX) { + dev_err(component->dev, "Invalid frame offset %d\n", offset); return -EINVAL; } - /* Calculate & validate frame size based on slot info provided. */ - frame_size = slots * slot_width; - switch (frame_size) { - case 32: - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32; - break; - case 64: - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64; - break; - case 128: - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128; - break; - case 256: - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256; - break; - default: - dev_err(component->dev, "Invalid frame size %d\n", frame_size); - return -EINVAL; - } + /* + * If we're master, calculate & validate frame size based on slot info + * provided as we have a limited set of rates available. + */ + if (da7219->master) { + frame_size = slots * slot_width; + switch (frame_size) { + case 32: + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32; + break; + case 64: + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64; + break; + case 128: + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128; + break; + case 256: + dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256; + break; + default: + dev_err(component->dev, "Invalid frame size %d\n", + frame_size); + return -EINVAL; + } - snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, - DA7219_DAI_BCLKS_PER_WCLK_MASK, - dai_bclks_per_wclk); + snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, + DA7219_DAI_BCLKS_PER_WCLK_MASK, + dai_bclks_per_wclk); + } - offset = cpu_to_le16(rx_mask); + dai_offset = cpu_to_le16(offset); regmap_bulk_write(da7219->regmap, DA7219_DAI_OFFSET_LOWER, - &offset, sizeof(offset)); + &dai_offset, sizeof(dai_offset)); snd_soc_component_update_bits(component, DA7219_DAI_TDM_CTRL, DA7219_DAI_TDM_CH_EN_MASK | DA7219_DAI_TDM_MODE_EN_MASK, - (tx_mask << DA7219_DAI_TDM_CH_EN_SHIFT) | + (ch_mask << DA7219_DAI_TDM_CH_EN_SHIFT) | DA7219_DAI_TDM_MODE_EN_MASK); da7219->tdm_en = true; From b24ea4d2d2283a6acfb2245125e502a364d0bdda Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 16:45:55 +0100 Subject: [PATCH 1093/1995] ASoC: dmaengine: Remove unused SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME flag There is now no users of this flag so remove it together with related code. The chan_name field of snd_dmaengine_dai_dma_data data structure is not removed as it is still in use by the PXA platform. Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown (cherry picked from commit 76d9c68b360f852e784170f10cb431e4713c7d0b) --- include/sound/dmaengine_pcm.h | 4 ---- sound/soc/soc-generic-dmaengine-pcm.c | 21 ++++----------------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 2c4cfaa135a62e..c679f611658022 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -99,10 +99,6 @@ void snd_dmaengine_pcm_set_config_from_dai_data( * playback. */ #define SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX BIT(3) -/* - * The PCM streams have custom channel names specified. - */ -#define SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME BIT(4) /** * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 1b44e363c50c7e..f1ab6285a08510 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -265,7 +265,6 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) struct dmaengine_pcm *pcm = soc_component_to_pcm(component); const struct snd_dmaengine_pcm_config *config = pcm->config; struct device *dev = component->dev; - struct snd_dmaengine_dai_dma_data *dma_data; struct snd_pcm_substream *substream; size_t prealloc_buffer_size; size_t max_buffer_size; @@ -285,19 +284,9 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) if (!substream) continue; - dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - - if (!pcm->chan[i] && - ((pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME) || - (config && config->chan_names[i]))) { - const char *chan_name = dma_data->chan_name; - - if (config && config->chan_names[i]) - chan_name = config->chan_names[i]; - + if (!pcm->chan[i] && config && config->chan_names[i]) pcm->chan[i] = dma_request_slave_channel(dev, - chan_name); - } + config->chan_names[i]); if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) { pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd, @@ -420,10 +409,8 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, const char *name; struct dma_chan *chan; - if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT | - SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) || - (!dev->of_node && !(config && config->dma_dev && - config->dma_dev->of_node))) + if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_DT) || (!dev->of_node && + !(config && config->dma_dev && config->dma_dev->of_node))) return 0; if (config && config->dma_dev) { From 5f939f58e11a6c3e6d62beb14678d18266b8dc89 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Sat, 16 Feb 2019 10:09:42 +0000 Subject: [PATCH 1094/1995] ASoC: simple-card: Fix refcount underflow of_get_child_by_name() takes a reference we'll need to drop later so when we substitute in top we need to take a reference as well as just assigning. Without this patch we hit the following error: [ 1.246852] OF: ERROR: Bad of_node_put() on /sound-wm8524 [ 1.262261] Hardware name: NXP i.MX8MQ EVK (DT) [ 1.266807] Workqueue: events deferred_probe_work_func [ 1.271950] Call trace: [ 1.274406] dump_backtrace+0x0/0x158 [ 1.278074] show_stack+0x14/0x20 [ 1.281396] dump_stack+0xa8/0xcc [ 1.284717] of_node_release+0xb0/0xc8 [ 1.288474] kobject_put+0x74/0xf0 [ 1.291879] of_node_put+0x14/0x28 [ 1.295286] __of_get_next_child+0x44/0x70 [ 1.299387] of_get_next_child+0x3c/0x60 [ 1.303315] simple_for_each_link+0x1dc/0x230 [ 1.307676] simple_probe+0x80/0x540 [ 1.311256] platform_drv_probe+0x50/0xa0 This patch is based on an earlier version posted by Kuninori Morimoto and commit message includes explanations from Mark Brown. https://patchwork.kernel.org/patch/10814255/ Reported-by: Vicente Bergas Signed-off-by: Daniel Baluta Signed-off-by: Mark Brown (cherry picked from commit 461d854c0dba3cdf63cce37ffb9423eca0793a47) --- sound/soc/generic/simple-card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 08df261024cfa6..dc18c44929557d 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -445,7 +445,7 @@ static int simple_for_each_link(struct simple_priv *priv, /* Check if it has dai-link */ node = of_get_child_by_name(top, PREFIX "dai-link"); if (!node) { - node = top; + node = of_node_get(top); is_top = 1; } From a2fd65780e98bf0c4932c1336f202b2caa14ea6b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 19 Feb 2019 15:04:27 +0300 Subject: [PATCH 1095/1995] ASoC: dapm: Potential small memory leak in dapm_cnew_widget() We should free "w" on the error path. Fixes: 199ed3e81c49 ("ASoC: dapm: fix use-after-free issue with dailink sname") Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown (cherry picked from commit a6d9cef30eb11b2de8cbfed9065e3dc5b1f829a8) --- sound/soc/soc-dapm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index dea6fc2353e47b..1ec06ef6d16160 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -332,8 +332,10 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( */ if (_widget->sname) { w->sname = kstrdup_const(_widget->sname, GFP_KERNEL); - if (!w->sname) + if (!w->sname) { + kfree(w); return NULL; + } } return w; } From ef402a7fceae730ff2706a49d763b8b33fdcdf74 Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Wed, 13 Feb 2019 17:08:51 -0600 Subject: [PATCH 1096/1995] ASoC: Intel: Headset button support in broxton machine driver Map the 4 headset buttons to KEY_PAUSE, KEY_VOLUMEUP, KEY_VOLUMEDOWN and KEY_VOICECOMMAND. Acked-by: Pierre-Louis Bossart Signed-off-by: Naveen Manohar Signed-off-by: Yong Zhi Signed-off-by: Mark Brown (cherry picked from commit 9dd9b210f8c6104690ba48a630bbe9af2f32c292) --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index c00925f9da7340..30311b81a5436d 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -193,6 +194,12 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) return ret; } + snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_3, + KEY_VOICECOMMAND); + da7219_aad_jack_det(component, &broxton_headset); snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); From ca9be3deafff0ee4ef36a77a958946ee4b93e47c Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Wed, 13 Feb 2019 17:08:52 -0600 Subject: [PATCH 1097/1995] ASoC: Intel: Add Geminilake Dialog Maxim machine driver This patch enables support for GeminiLake with the DA7219 codec and MAX98357A amplifier. To avoid duplicating code, the existing machine driver for ApolloLake is reused with only changes in hardware connectivity (SSP2 for DA7219 and SSP1 for MAX98357A). The dailinks are directly modified in this patch. Using a helper would be nicer, but it'll be done in a follow-up step with validation done across multiple machine drivers. Acked-by: Pierre-Louis Bossart Signed-off-by: Yong Zhi Signed-off-by: Naveen Manohar Signed-off-by: Harsha Priya Signed-off-by: Mark Brown (cherry picked from commit c011245a197017f8e9e9d140b658bdb2b702a0c5) --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 79 ++++++++++++++++--- 1 file changed, 67 insertions(+), 12 deletions(-) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 30311b81a5436d..407b0cfc516711 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -104,7 +105,7 @@ static const struct snd_soc_dapm_widget broxton_widgets[] = { 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 audio_map[] = { /* HP jack connectors - unknown if we have jack detection */ {"Headphone Jack", NULL, "HPL"}, {"Headphone Jack", NULL, "HPR"}, @@ -119,15 +120,6 @@ static const struct snd_soc_dapm_route broxton_map[] = { {"DMic", NULL, "SoC DMIC"}, /* CODEC BE connections */ - {"HiFi Playback", NULL, "ssp5 Tx"}, - {"ssp5 Tx", NULL, "codec0_out"}, - - {"Playback", NULL, "ssp1 Tx"}, - {"ssp1 Tx", NULL, "codec1_out"}, - - {"codec0_in", NULL, "ssp1 Rx"}, - {"ssp1 Rx", NULL, "Capture"}, - {"HDMI1", NULL, "hif5-0 Output"}, {"HDMI2", NULL, "hif6-0 Output"}, {"HDMI2", NULL, "hif7-0 Output"}, @@ -147,6 +139,28 @@ static const struct snd_soc_dapm_route broxton_map[] = { { "Headset Mic", NULL, "Platform Clock" }, }; +static const struct snd_soc_dapm_route broxton_map[] = { + {"HiFi Playback", NULL, "ssp5 Tx"}, + {"ssp5 Tx", NULL, "codec0_out"}, + + {"Playback", NULL, "ssp1 Tx"}, + {"ssp1 Tx", NULL, "codec1_out"}, + + {"codec0_in", NULL, "ssp1 Rx"}, + {"ssp1 Rx", NULL, "Capture"}, +}; + +static const struct snd_soc_dapm_route gemini_map[] = { + {"HiFi Playback", NULL, "ssp1 Tx"}, + {"ssp1 Tx", NULL, "codec0_out"}, + + {"Playback", NULL, "ssp2 Tx"}, + {"ssp2 Tx", NULL, "codec1_out"}, + + {"codec0_in", NULL, "ssp2 Rx"}, + {"ssp2 Rx", NULL, "Capture"}, +}; + static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -539,6 +553,11 @@ static struct snd_soc_dai_link broxton_dais[] = { }, }; +static const struct x86_cpu_id glk_ids[] = { + { X86_VENDOR_INTEL, 6, 0x7A }, /* Geminilake CPU_ID */ + {} +}; + #define NAME_SIZE 32 static int bxt_card_late_probe(struct snd_soc_card *card) { @@ -548,6 +567,13 @@ static int bxt_card_late_probe(struct snd_soc_card *card) int err, i = 0; char jack_name[NAME_SIZE]; + if (x86_match_cpu(glk_ids)) + snd_soc_dapm_add_routes(&card->dapm, gemini_map, + ARRAY_SIZE(gemini_map)); + else + snd_soc_dapm_add_routes(&card->dapm, broxton_map, + ARRAY_SIZE(broxton_map)); + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { component = pcm->codec_dai->component; snprintf(jack_name, sizeof(jack_name), @@ -583,8 +609,8 @@ static struct snd_soc_card broxton_audio_card = { .num_controls = ARRAY_SIZE(broxton_controls), .dapm_widgets = broxton_widgets, .num_dapm_widgets = ARRAY_SIZE(broxton_widgets), - .dapm_routes = broxton_map, - .num_dapm_routes = ARRAY_SIZE(broxton_map), + .dapm_routes = audio_map, + .num_dapm_routes = ARRAY_SIZE(audio_map), .fully_routed = true, .late_probe = bxt_card_late_probe, }; @@ -604,6 +630,26 @@ static int broxton_audio_probe(struct platform_device *pdev) broxton_audio_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&broxton_audio_card, ctx); + if (x86_match_cpu(glk_ids)) { + unsigned int i; + + broxton_audio_card.name = "glkda7219max"; + /* Fixup the SSP entries for geminilake */ + for (i = 0; i < ARRAY_SIZE(broxton_dais); i++) { + /* MAXIM_CODEC is connected to SSP1. */ + if (!strcmp(broxton_dais[i].codec_dai_name, + BXT_MAXIM_CODEC_DAI)) { + broxton_dais[i].name = "SSP1-Codec"; + broxton_dais[i].cpu_dai_name = "SSP1 Pin"; + } + /* DIALOG_CODE is connected to SSP2 */ + else if (!strcmp(broxton_dais[i].codec_dai_name, + BXT_DIALOG_CODEC_DAI)) { + broxton_dais[i].name = "SSP2-Codec"; + broxton_dais[i].cpu_dai_name = "SSP2 Pin"; + } + } + } /* override plaform name, if required */ mach = (&pdev->dev)->platform_data; @@ -617,12 +663,19 @@ static int broxton_audio_probe(struct platform_device *pdev) return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card); } +static const struct platform_device_id bxt_board_ids[] = { + { .name = "bxt_da7219_max98357a" }, + { .name = "glk_da7219_max98357a" }, + { } +}; + static struct platform_driver broxton_audio = { .probe = broxton_audio_probe, .driver = { .name = "bxt_da7219_max98357a", .pm = &snd_soc_pm_ops, }, + .id_table = bxt_board_ids, }; module_platform_driver(broxton_audio) @@ -632,5 +685,7 @@ MODULE_AUTHOR("Sathyanarayana Nujella "); MODULE_AUTHOR("Rohit Ainapure "); MODULE_AUTHOR("Harsha Priya "); MODULE_AUTHOR("Conrad Cooke "); +MODULE_AUTHOR("Naveen Manohar "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:bxt_da7219_max98357a"); +MODULE_ALIAS("platform:glk_da7219_max98357a"); From 0667be9c419a2b67cfdf20e9e3f860944a3abca1 Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Wed, 13 Feb 2019 17:08:53 -0600 Subject: [PATCH 1098/1995] ASoC: Intel: glk: Add DAI links for Multi-Playback Add FE DAI link to support parallel playback on 2 ports simultaneously. Acked-by: Pierre-Louis Bossart Signed-off-by: Naveen Manohar Signed-off-by: Yong Zhi Signed-off-by: Mark Brown (cherry picked from commit bc3523a3acb3ba311d5d9939901ff2b7f8833e44) --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 407b0cfc516711..5cadb7f654f3a0 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -51,6 +51,7 @@ struct bxt_card_private { enum { BXT_DPCM_AUDIO_PB = 0, BXT_DPCM_AUDIO_CP, + BXT_DPCM_AUDIO_HS_PB, BXT_DPCM_AUDIO_REF_CP, BXT_DPCM_AUDIO_DMIC_CP, BXT_DPCM_AUDIO_HDMI1_PB, @@ -405,6 +406,20 @@ static struct snd_soc_dai_link broxton_dais[] = { .dpcm_capture = 1, .ops = &broxton_da7219_fe_ops, }, + [BXT_DPCM_AUDIO_HS_PB] = { + .name = "Bxt Audio Headset Playback", + .stream_name = "Headset Playback", + .cpu_dai_name = "System Pin2", + .platform_name = "0000:00:0e.0", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &broxton_da7219_fe_ops, + }, [BXT_DPCM_AUDIO_REF_CP] = { .name = "Bxt Audio Reference cap", From 827209aede1d58b376c1c7e39adc28684fa8cf6a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 19 Feb 2019 16:46:48 +0100 Subject: [PATCH 1099/1995] ASoC: simple-card: Fix missing of_node_put() at simple_dai_link_of() We forgot to unreference the platform node object obtained from of_get_child_by_name(). This leads to the unbalance of node refcount. Fixes: e0ae225b7e96 ("ASoC: simple-card: support platform in dts parse") Signed-off-by: Takashi Iwai Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 44662f90cda7ce0b65e77a7f1eefe45fb9053a4e) --- sound/soc/generic/simple-card.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index dc18c44929557d..092963e90e1ef8 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -421,6 +421,7 @@ static int simple_dai_link_of(struct simple_priv *priv, asoc_simple_card_canonicalize_platform(dai_link); dai_link_of_err: + of_node_put(plat); of_node_put(node); return ret; From 1c9cf8d8270b3aed126624390cee44bcc817e2ba Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 19 Feb 2019 16:46:49 +0100 Subject: [PATCH 1100/1995] ASoC: simple-card: Fix of-node refcount unbalance in DAI-link parser The function simple_for_each_link() has a few missing places that forgot unrefereing of-nodes after the use. The main do-while loop may abort when loop=0, and this leaves the node object still referenced. A similar leak is found in the error handling of NULL codec that aborts the loop as well. Last but not least, the inner for_each_child_of_node() loop may abort in the middle, and this leaks the refcount of the iterator node. This patch addresses these missing refcount issues. Signed-off-by: Takashi Iwai Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown (cherry picked from commit 0b9c9ed6dd3b61b1d3ef1638786a7216006f67c5) --- sound/soc/generic/simple-card.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 092963e90e1ef8..7147bba45a2a61 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -442,6 +442,7 @@ static int simple_for_each_link(struct simple_priv *priv, struct device_node *top = dev->of_node; struct device_node *node; bool is_top = 0; + int ret = 0; /* Check if it has dai-link */ node = of_get_child_by_name(top, PREFIX "dai-link"); @@ -456,13 +457,14 @@ static int simple_for_each_link(struct simple_priv *priv, struct device_node *codec; struct device_node *np; int num = of_get_child_count(node); - int ret; /* get codec */ codec = of_get_child_by_name(node, is_top ? PREFIX "codec" : "codec"); - if (!codec) - return -ENODEV; + if (!codec) { + ret = -ENODEV; + goto error; + } of_node_put(codec); @@ -485,14 +487,18 @@ static int simple_for_each_link(struct simple_priv *priv, else ret = func_noml(priv, np, codec, li, is_top); - if (ret < 0) - return ret; + if (ret < 0) { + of_node_put(np); + goto error; + } } node = of_get_next_child(top, node); } while (!is_top && node); - return 0; + error: + of_node_put(node); + return ret; } static int simple_parse_aux_devs(struct device_node *node, From c2ed40849ca4ef37207a76aff9dfa3c57b9056af Mon Sep 17 00:00:00 2001 From: Jenny TC Date: Mon, 25 Feb 2019 22:17:31 +0530 Subject: [PATCH 1101/1995] ASoC: Intel: Boards: Add Maxim98373 support This patch enables the reuse of kbl_da7219_max98927 machine driver to support max98373. The same machine driver is modified for cases where one amplifier is swapped out with another. Most of the changes are about renaming the codec and codec_dai names, with minor differences due to support for 24 bits in one case and 16 in the other. Signed-off-by: Jenny TC Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 716d53cc7837aec7f439ce2a20fc2597a89dae53) --- sound/soc/intel/boards/Kconfig | 1 + sound/soc/intel/boards/kbl_da7219_max98927.c | 203 ++++++++++++++++-- .../intel/common/soc-acpi-intel-kbl-match.c | 19 ++ 3 files changed, 200 insertions(+), 23 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 0a7e40d0639572..12d6b73e9531d7 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -293,6 +293,7 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_DA7219 select SND_SOC_MAX98927 + select SND_SOC_MAX98373 select SND_SOC_DMIC select SND_SOC_HDAC_HDMI help diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 6dd5c69671b3f6..2768a572d0651b 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -2,7 +2,7 @@ // Copyright(c) 2018 Intel Corporation. /* - * Intel Kabylake I2S Machine Driver with MAX98927 & DA7219 Codecs + * Intel Kabylake I2S Machine Driver with MAX98927, MAX98373 & DA7219 Codecs * * Modified from: * Intel Kabylake I2S Machine driver supporting MAX98927 and @@ -24,8 +24,14 @@ #define KBL_DIALOG_CODEC_DAI "da7219-hifi" #define MAX98927_CODEC_DAI "max98927-aif1" -#define MAXIM_DEV0_NAME "i2c-MX98927:00" -#define MAXIM_DEV1_NAME "i2c-MX98927:01" +#define MAX98927_DEV0_NAME "i2c-MX98927:00" +#define MAX98927_DEV1_NAME "i2c-MX98927:01" + +#define MAX98373_CODEC_DAI "max98373-aif1" +#define MAX98373_DEV0_NAME "i2c-MX98373:00" +#define MAX98373_DEV1_NAME "i2c-MX98373:01" + + #define DUAL_CHANNEL 2 #define QUAD_CHANNEL 4 #define NAME_SIZE 32 @@ -176,20 +182,38 @@ static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, for (j = 0; j < runtime->num_codecs; j++) { struct snd_soc_dai *codec_dai = runtime->codec_dais[j]; - if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { + if (!strcmp(codec_dai->component->name, MAX98927_DEV0_NAME)) { ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); if (ret < 0) { dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret); return ret; } } - if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { + if (!strcmp(codec_dai->component->name, MAX98927_DEV1_NAME)) { ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); if (ret < 0) { dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret); return ret; } } + if (!strcmp(codec_dai->component->name, MAX98373_DEV0_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + 0x03, 3, 8, 24); + if (ret < 0) { + dev_err(runtime->dev, + "DEV0 TDM slot err:%d\n", ret); + return ret; + } + } + if (!strcmp(codec_dai->component->name, MAX98373_DEV1_NAME)) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + 0x0C, 3, 8, 24); + if (ret < 0) { + dev_err(runtime->dev, + "DEV0 TDM slot err:%d\n", ret); + return ret; + } + } } return 0; @@ -212,6 +236,25 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai_link *fe_dai_link = dpcm->fe->dai_link; struct snd_soc_dai_link *be_dai_link = dpcm->be->dai_link; + /* + * Topology for kblda7219m98373 & kblmax98373 supports only S24_LE, + * where as kblda7219m98927 & kblmax98927 supports S16_LE by default. + * Skipping the port wise FE and BE configuration for kblda7219m98373 & + * kblmax98373 as the topology (FE & BE) supports S24_LE only. + */ + + if (!strcmp(rtd->card->name, "kblda7219m98373") || + !strcmp(rtd->card->name, "kblmax98373")) { + /* The ADSP will convert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = DUAL_CHANNEL; + + /* set SSP to 24 bit */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + return 0; + } + /* * The ADSP will convert the FE rate to 48k, stereo, 24 bit */ @@ -352,20 +395,31 @@ static struct snd_pcm_hw_constraint_list constraints_channels_quad = { static int kbl_fe_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *soc_rt = substream->private_data; /* * On this platform for PCM device we support, * 48Khz * stereo - * 16 bit audio */ runtime->hw.channels_max = DUAL_CHANNEL; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + /* + * Setup S24_LE (32 bit container and 24 bit valid data) for + * kblda7219m98373 & kblmax98373. For kblda7219m98927 & + * kblmax98927 keeping it as 16/16 due to topology FW dependency. + */ + if (!strcmp(soc_rt->card->name, "kblda7219m98373") || + !strcmp(soc_rt->card->name, "kblmax98373")) { + runtime->hw.formats = SNDRV_PCM_FMTBIT_S24_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); + + } else { + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + } snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); @@ -398,11 +452,23 @@ static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, static int kabylake_dmic_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *soc_rt = substream->private_data; runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &constraints_channels_quad); + /* + * Topology for kblda7219m98373 & kblmax98373 supports only S24_LE. + * The DMIC also configured for S24_LE. Forcing the DMIC format to + * S24_LE due to the topology FW dependency. + */ + if (!strcmp(soc_rt->card->name, "kblda7219m98373") || + !strcmp(soc_rt->card->name, "kblmax98373")) { + runtime->hw.formats = SNDRV_PCM_FMTBIT_S24_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); + } + return snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } @@ -448,29 +514,55 @@ static struct snd_soc_ops skylake_refcap_ops = { static struct snd_soc_codec_conf max98927_codec_conf[] = { { - .dev_name = MAXIM_DEV0_NAME, + .dev_name = MAX98927_DEV0_NAME, + .name_prefix = "Right", + }, + + { + .dev_name = MAX98927_DEV1_NAME, + .name_prefix = "Left", + }, +}; + +static struct snd_soc_codec_conf max98373_codec_conf[] = { + + { + .dev_name = MAX98373_DEV0_NAME, .name_prefix = "Right", }, { - .dev_name = MAXIM_DEV1_NAME, + .dev_name = MAX98373_DEV1_NAME, .name_prefix = "Left", }, }; -static struct snd_soc_dai_link_component ssp0_codec_components[] = { +static struct snd_soc_dai_link_component max98927_ssp0_codec_components[] = { { /* Left */ - .name = MAXIM_DEV0_NAME, + .name = MAX98927_DEV0_NAME, .dai_name = MAX98927_CODEC_DAI, }, { /* For Right */ - .name = MAXIM_DEV1_NAME, + .name = MAX98927_DEV1_NAME, .dai_name = MAX98927_CODEC_DAI, }, }; +static struct snd_soc_dai_link_component max98373_ssp0_codec_components[] = { + { /* Left */ + .name = MAX98373_DEV0_NAME, + .dai_name = MAX98373_CODEC_DAI, + }, + + { /* For Right */ + .name = MAX98373_DEV1_NAME, + .dai_name = MAX98373_CODEC_DAI, + }, + +}; + /* kabylake digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link kabylake_dais[] = { /* Front End DAI links */ @@ -607,8 +699,8 @@ static struct snd_soc_dai_link kabylake_dais[] = { .cpu_dai_name = "SSP0 Pin", .platform_name = "0000:00:1f.3", .no_pcm = 1, - .codecs = ssp0_codec_components, - .num_codecs = ARRAY_SIZE(ssp0_codec_components), + .codecs = max98927_ssp0_codec_components, + .num_codecs = ARRAY_SIZE(max98927_ssp0_codec_components), .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, @@ -683,7 +775,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { }; /* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_max98927_dais[] = { +static struct snd_soc_dai_link kabylake_max98_927_373_dais[] = { /* Front End DAI links */ [KBL_DPCM_AUDIO_PB] = { .name = "Kbl Audio Port", @@ -802,8 +894,8 @@ static struct snd_soc_dai_link kabylake_max98927_dais[] = { .cpu_dai_name = "SSP0 Pin", .platform_name = "0000:00:1f.3", .no_pcm = 1, - .codecs = ssp0_codec_components, - .num_codecs = ARRAY_SIZE(ssp0_codec_components), + .codecs = max98927_ssp0_codec_components, + .num_codecs = ARRAY_SIZE(max98927_ssp0_codec_components), .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, @@ -917,8 +1009,8 @@ static struct snd_soc_card kbl_audio_card_da7219_m98927 = { static struct snd_soc_card kbl_audio_card_max98927 = { .name = "kblmax98927", .owner = THIS_MODULE, - .dai_link = kabylake_max98927_dais, - .num_links = ARRAY_SIZE(kabylake_max98927_dais), + .dai_link = kabylake_max98_927_373_dais, + .num_links = ARRAY_SIZE(kabylake_max98_927_373_dais), .controls = kabylake_controls, .num_controls = ARRAY_SIZE(kabylake_controls), .dapm_widgets = kabylake_widgets, @@ -931,9 +1023,46 @@ static struct snd_soc_card kbl_audio_card_max98927 = { .late_probe = kabylake_card_late_probe, }; +static struct snd_soc_card kbl_audio_card_da7219_m98373 = { + .name = "kblda7219m98373", + .owner = THIS_MODULE, + .dai_link = kabylake_dais, + .num_links = ARRAY_SIZE(kabylake_dais), + .controls = kabylake_controls, + .num_controls = ARRAY_SIZE(kabylake_controls), + .dapm_widgets = kabylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), + .dapm_routes = kabylake_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_map), + .codec_conf = max98373_codec_conf, + .num_configs = ARRAY_SIZE(max98373_codec_conf), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + +static struct snd_soc_card kbl_audio_card_max98373 = { + .name = "kblmax98373", + .owner = THIS_MODULE, + .dai_link = kabylake_max98_927_373_dais, + .num_links = ARRAY_SIZE(kabylake_max98_927_373_dais), + .controls = kabylake_controls, + .num_controls = ARRAY_SIZE(kabylake_controls), + .dapm_widgets = kabylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), + .dapm_routes = kabylake_map, + .num_dapm_routes = ARRAY_SIZE(kabylake_map), + .codec_conf = max98373_codec_conf, + .num_configs = ARRAY_SIZE(max98373_codec_conf), + .fully_routed = true, + .late_probe = kabylake_card_late_probe, +}; + static int kabylake_audio_probe(struct platform_device *pdev) { struct kbl_codec_private *ctx; + struct snd_soc_dai_link *kbl_dai_link; + struct snd_soc_dai_link_component **codecs; + int i = 0; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -944,6 +1073,22 @@ static int kabylake_audio_probe(struct platform_device *pdev) kabylake_audio_card = (struct snd_soc_card *)pdev->id_entry->driver_data; + kbl_dai_link = kabylake_audio_card->dai_link; + + /* Update codecs for SSP0 with max98373 codec info */ + if (!strcmp(pdev->name, "kbl_da7219_max98373") || + (!strcmp(pdev->name, "kbl_max98373"))) { + for (i = 0; i < kabylake_audio_card->num_links; ++i) { + if (strcmp(kbl_dai_link[i].name, "SSP0-Codec")) + continue; + + codecs = &(kbl_dai_link[i].codecs); + *codecs = max98373_ssp0_codec_components; + kbl_dai_link[i].num_codecs = + ARRAY_SIZE(max98373_ssp0_codec_components); + break; + } + } kabylake_audio_card->dev = &pdev->dev; snd_soc_card_set_drvdata(kabylake_audio_card, ctx); @@ -961,13 +1106,23 @@ static const struct platform_device_id kbl_board_ids[] = { .driver_data = (kernel_ulong_t)&kbl_audio_card_max98927, }, + { + .name = "kbl_da7219_max98373", + .driver_data = + (kernel_ulong_t)&kbl_audio_card_da7219_m98373, + }, + { + .name = "kbl_max98373", + .driver_data = + (kernel_ulong_t)&kbl_audio_card_max98373, + }, { } }; static struct platform_driver kabylake_audio = { .probe = kabylake_audio_probe, .driver = { - .name = "kbl_da7219_max98927", + .name = "kbl_da7219_max98_927_373", .pm = &snd_soc_pm_ops, }, .id_table = kbl_board_ids, @@ -976,8 +1131,10 @@ static struct platform_driver kabylake_audio = { module_platform_driver(kabylake_audio) /* Module information */ -MODULE_DESCRIPTION("Audio KabyLake Machine driver for MAX98927 & DA7219"); +MODULE_DESCRIPTION("Audio KabyLake Machine driver for MAX98927/MAX98373 & DA7219"); MODULE_AUTHOR("Mac Chiang "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:kbl_da7219_max98927"); MODULE_ALIAS("platform:kbl_max98927"); +MODULE_ALIAS("platform:kbl_da7219_max98373"); +MODULE_ALIAS("platform:kbl_max98373"); diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c index e6fa6f470526dc..4b331058e8070a 100644 --- a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c @@ -37,6 +37,11 @@ static struct snd_soc_acpi_codecs kbl_7219_98927_codecs = { .codecs = {"MX98927"} }; +static struct snd_soc_acpi_codecs kbl_7219_98373_codecs = { + .num_codecs = 1, + .codecs = {"MX98373"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { { .id = "INT343A", @@ -106,6 +111,20 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .drv_name = "kbl_rt5660", .fw_filename = "intel/dsp_fw_kbl.bin", }, + { + .id = "DLGS7219", + .drv_name = "kbl_da7219_max98373", + .fw_filename = "intel/dsp_fw_kbl.bin", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &kbl_7219_98373_codecs, + .pdata = &skl_dmic_data + }, + { + .id = "MX98373", + .drv_name = "kbl_max98373", + .fw_filename = "intel/dsp_fw_kbl.bin", + .pdata = &skl_dmic_data + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines); From 29b936309ea813444654787a02b7f67cedb18b2b Mon Sep 17 00:00:00 2001 From: Jonathan Hunter Date: Mon, 4 Mar 2019 13:31:14 +0000 Subject: [PATCH 1102/1995] ASoC: soc-core: Fix probe deferral following prelink failure Commit 78a24e10cd94 ("ASoC: soc-core: clear platform pointers on error") re-worked the clean-up of any platform pointers that may have been initialised by the function snd_soc_init_platform(). This commit missed one error path where if any of the prelinks for a soundcard failed to initialise, then these platform pointers would not be cleaned-up. This then prevents the soundcard from being initialised following a probe deferral when any of the soundcard prelinks cannot be found. Fix this by ensuring that soc_cleanup_platform() is called when initialising the soundcard prelinks fails. Fixes: 78a24e10cd94 ("ASoC: soc-core: clear platform pointers on error") Signed-off-by: Jonathan Hunter Signed-off-by: Mark Brown (cherry picked from commit c342febcde452f817cbd3896dc40953ab17c309d) --- sound/soc/soc-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 93d316d5bf8e3c..5a5764dba1479c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2797,6 +2797,7 @@ int snd_soc_register_card(struct snd_soc_card *card) ret = soc_init_dai_link(card, link); if (ret) { + soc_cleanup_platform(card); dev_err(card->dev, "ASoC: failed to init link %s\n", link->name); mutex_unlock(&client_mutex); From 0dce3b5433da970739d3e0407c577895e4829ccd Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 8 Feb 2019 17:29:53 -0600 Subject: [PATCH 1103/1995] ALSA: PCM: check if ops are defined before suspending PCM BE dai links only have internal PCM's and their substream ops may not be set. Suspending these PCM's will result in their ops->trigger() being invoked and cause a kernel oops. So skip suspending PCM's if their ops are NULL. [ NOTE: this change is required now for following the recent PCM core change to get rid of snd_pcm_suspend() call. Since DPCM BE takes the runtime carried from FE while keeping NULL ops, it can hit this bug. See details at: https://github.com/thesofproject/linux/pull/582 -- tiwai ] Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai (cherry picked from commit d9c0b2afe820fa3b3f8258a659daee2cc71ca3ef) (cherry picked from commit 1bde5ed6fa67c1ee48fa59d257f860fb290b33e3) --- sound/core/pcm_native.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 818dff1de545fa..b6e158ce6650de 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1506,6 +1506,14 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm) /* FIXME: the open/close code should lock this as well */ if (substream->runtime == NULL) continue; + + /* + * Skip BE dai link PCM's that are internal and may + * not have their substream ops set. + */ + if (!substream->ops) + continue; + err = snd_pcm_suspend(substream); if (err < 0 && err != -EBUSY) return err; From 2aa04decb4c714341acae21b136bd8df9a40bb13 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 8 Feb 2019 08:41:53 +0100 Subject: [PATCH 1104/1995] regulator: fix device unlinking Device links are refcounted, device_link_remove() has to be called as many times as device_link_add(). Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mark Brown (cherry picked from commit 82874ba4c6455ca8a90a8fe59834baa4cd4a1e50) --- drivers/regulator/core.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b9d7b45c729545..2994ee023b40db 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2058,15 +2058,7 @@ static void _regulator_put(struct regulator *regulator) debugfs_remove_recursive(regulator->debugfs); if (regulator->dev) { - int count = 0; - struct regulator *r; - - list_for_each_entry(r, &rdev->consumer_list, list) - if (r->dev == regulator->dev) - count++; - - if (count == 1) - device_link_remove(regulator->dev, &rdev->dev); + device_link_remove(regulator->dev, &rdev->dev); /* remove any sysfs entries */ sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); From 24f3e954b4b5de95d634da8bbd40c1664ff46884 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 9 Jan 2019 16:20:51 +0800 Subject: [PATCH 1105/1995] ALSA: hda: Fix a mask wrong issue in snd_hdac_stream_start() To enable SIE(Stream Interrupt Enable) in snd_hdac_stream_start(), we should set both mask and value to be "1 << azx_dev->index" for register update, the mask was 0, here fix it. Signed-off-by: Keyon Jie Signed-off-by: Takashi Iwai (cherry picked from commit fc2a6cf060d0c6feeb3719bf40088e48c5926e40) --- sound/hda/hdac_stream.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index eee422390d8e26..ba73a33480b66f 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -56,7 +56,9 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start) azx_dev->start_wallclk -= azx_dev->period_wallclk; /* enable SIE */ - snd_hdac_chip_updatel(bus, INTCTL, 0, 1 << azx_dev->index); + snd_hdac_chip_updatel(bus, INTCTL, + 1 << azx_dev->index, + 1 << azx_dev->index); /* set DMA start and interrupt mask */ snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_DMA_START | SD_INT_MASK); From 8a1086c3f8eb4379169df101fe76657ec272a2b3 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Mon, 4 Mar 2019 08:17:06 +0800 Subject: [PATCH 1106/1995] ASoC: SOF: check fw before requesting fw sdev->pdata->fw is only released by snd_sof_device_remove(). If we request fw more than one time, we will lost the previous one and lead to memory leak. Signed-off-by: Bard liao --- sound/soc/sof/core.c | 1 + sound/soc/sof/loader.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index fad3fd1aea0307..70cb1a06529ea3 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -470,6 +470,7 @@ int snd_sof_device_remove(struct device *dev) /* release firmware */ release_firmware(pdata->fw); + pdata->fw = NULL; return 0; } diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 230fb696e8fb1f..60802a1fca7644 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -232,6 +232,10 @@ int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev) /* set code loading condition to true */ sdev->code_loading = 1; + /* Don't request firmware again if firmware is already requested */ + if (plat_data->fw) + return 0; + fw_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, "%s/%s", plat_data->fw_filename_prefix, @@ -283,6 +287,7 @@ int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev) error: release_firmware(plat_data->fw); + plat_data->fw = NULL; return ret; } From db5c436fd93d95df427d29eae4070b83a4785457 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Sun, 3 Mar 2019 22:55:58 +0800 Subject: [PATCH 1107/1995] ASoC: topology: free stream_name of dai_drv The stream_name is allocated by kstrdup. We have to free it when the dai is removed or return from error. Signed-off-by: Bard liao --- sound/soc/soc-topology.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 40fa2a48fa1d5b..bf14982edc694f 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -535,6 +535,8 @@ static void remove_dai(struct snd_soc_component *comp, if (dai->driver == dai_drv) dai->driver = NULL; + kfree(dai_drv->playback.stream_name); + kfree(dai_drv->capture.stream_name); kfree(dai_drv->name); list_del(&dobj->list); kfree(dai_drv); @@ -1807,6 +1809,9 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL); if (ret < 0) { dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n"); + kfree(dai_drv->playback.stream_name); + kfree(dai_drv->capture.stream_name); + kfree(dai_drv->name); kfree(dai_drv); return ret; } From 91df763ea5204aaa0352bed4385384ef9a225517 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Mon, 4 Mar 2019 03:16:41 +0800 Subject: [PATCH 1108/1995] ASoC: topology: free link string in error Some strings are allocated by kstrdup, but not freed when error happened. Signed-off-by: Bard liao --- sound/soc/soc-topology.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index bf14982edc694f..e3506b056358e1 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1882,6 +1882,9 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, ret = soc_tplg_dai_link_load(tplg, link, NULL); if (ret < 0) { dev_err(tplg->comp->dev, "ASoC: FE link loading failed\n"); + kfree(link->name); + kfree(link->stream_name); + kfree(link->cpu_dai_name); kfree(link); return ret; } From a224c249cbdd3933f57b8407db051e2f3ce1079d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 1 Mar 2019 16:15:41 +0100 Subject: [PATCH 1109/1995] sof: void * doesn't need to be type-cast Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/hda-dsp.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index df2ea5d55fca82..9606094c614fb0 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -250,8 +250,7 @@ int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev) { - struct sof_intel_hda_dev *hda = - (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; /* enable IPC DONE interrupt */ @@ -271,8 +270,7 @@ void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev) void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) { - struct sof_intel_hda_dev *hda = - (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; /* disable IPC interrupt */ @@ -290,8 +288,7 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) static int hda_suspend(struct snd_sof_dev *sdev, int state) { - struct sof_intel_hda_dev *hda = - (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_bus *bus = sof_to_bus(sdev); From 124256d73b5868ad27b669cbce029fd228f63c02 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 1 Mar 2019 16:18:24 +0100 Subject: [PATCH 1110/1995] sof: merge register writes HIPCCTL has no requirement for setting its bitssequentially. Set or clear DONE and BUSY bits in one operation. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/hda-dsp.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 9606094c614fb0..c50dcc135e3871 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -253,15 +253,10 @@ void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev) struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; - /* enable IPC DONE interrupt */ + /* enable IPC DONE and BUSY interrupts */ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, - HDA_DSP_REG_HIPCCTL_DONE, - HDA_DSP_REG_HIPCCTL_DONE); - - /* enable IPC BUSY interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, - HDA_DSP_REG_HIPCCTL_BUSY, - HDA_DSP_REG_HIPCCTL_BUSY); + HDA_DSP_REG_HIPCCTL_DONE | HDA_DSP_REG_HIPCCTL_BUSY, + HDA_DSP_REG_HIPCCTL_DONE | HDA_DSP_REG_HIPCCTL_BUSY); /* enable IPC interrupt */ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, @@ -277,13 +272,9 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, HDA_DSP_ADSPIC_IPC, 0); - /* disable IPC BUSY interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, - HDA_DSP_REG_HIPCCTL_BUSY, 0); - - /* disable IPC DONE interrupt */ + /* disable IPC BUSY and DONE interrupt */ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, - HDA_DSP_REG_HIPCCTL_DONE, 0); + HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0); } static int hda_suspend(struct snd_sof_dev *sdev, int state) From 0d62d5b4640fb3972b34ae9a2bdf9454b2e797a7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Mar 2019 20:01:44 -0600 Subject: [PATCH 1111/1995] ASoC: SOF: PCM: remove set-but-unused ring buffer offset field We set this field to zero and never used it again. The firmware does not use it. Yank. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pcm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 9534411450075a..8f9743b3a955fe 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -93,7 +93,6 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, pcm.params.buffer.phy_addr = spcm->stream[substream->stream].page_table.addr; pcm.params.buffer.size = runtime->dma_bytes; - pcm.params.buffer.offset = 0; pcm.params.direction = substream->stream; pcm.params.sample_valid_bytes = params_width(params) >> 3; pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED; From 1d394f7fec0c3427e8e313d926666786ccb0b98a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Mar 2019 20:12:54 -0600 Subject: [PATCH 1112/1995] ASoC: SOF: trace: remove set-but-unused ring buffer offset field We set this field to zero and never used it again. The firmware does not use it. Yank. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/trace.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 890dba4c7c2661..0b5c6a18328bb8 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -142,7 +142,6 @@ int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) params.hdr.cmd = SOF_IPC_GLB_TRACE_MSG | SOF_IPC_TRACE_DMA_PARAMS; params.buffer.phy_addr = sdev->dmatp.addr; params.buffer.size = sdev->dmatb.bytes; - params.buffer.offset = 0; params.buffer.pages = sdev->dma_trace_pages; params.stream_tag = 0; From 19fe5aafc5968a869b289b42fb50f7cec4ae7d85 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 5 Mar 2019 20:02:51 -0600 Subject: [PATCH 1113/1995] ASoC: SOF: uapi: reclaim unused offset field in host buffer This field doesn't seem to be used by anyone, reclaim as reserved. Signed-off-by: Pierre-Louis Bossart --- include/sound/sof/stream.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/sound/sof/stream.h b/include/sound/sof/stream.h index 0b436649f1e471..643f175cb479a4 100644 --- a/include/sound/sof/stream.h +++ b/include/sound/sof/stream.h @@ -68,8 +68,7 @@ struct sof_ipc_host_buffer { uint32_t phy_addr; uint32_t pages; uint32_t size; - uint32_t offset; - uint32_t reserved[2]; + uint32_t reserved[3]; } __packed; struct sof_ipc_stream_params { From a8b8b11326e2cffd0ed9e322e318257da6915be4 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 22 Feb 2019 16:01:08 +0800 Subject: [PATCH 1114/1995] ASoC:soc-pcm:fix a codec fixup issue in TDM case On HDaudio platforms, if playback is started when capture is working, there is no audible output. This can be root-caused to the use of the rx|tx_mask to store an HDaudio stream tag. If capture is stared before playback, rx_mask would be non-zero on HDaudio platform, then the channel number of playback, which is in the same codec dai with the capture, would be changed by soc_pcm_codec_params_fixup based on the tx_mask at first, then overwritten by this function based on rx_mask at last. According to the author of tx|rx_mask, tx_mask is for playback and rx_mask is for capture. And stream direction is checked at all other references of tx|rx_mask in ASoC, so here should be an error. This patch checks stream direction for tx|rx_mask for fixup function. This issue would affect not only HDaudio+ASoC, but also I2S codecs if the channel number based on rx_mask is not equal to the one for tx_mask. It could be rarely reproduecd because most drivers in kernel set the same channel number to tx|rx_mask or rx_mask is zero. Tested on all platforms using stream_tag & HDaudio and intel I2S platforms. Signed-off-by: Rander Wang --- sound/soc/soc-pcm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index a5b40e82dea4ac..e70555a4ea0696 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -954,10 +954,13 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, codec_params = *params; /* fixup params based on TDM slot masks */ - if (codec_dai->tx_mask) + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + codec_dai->tx_mask) soc_pcm_codec_params_fixup(&codec_params, codec_dai->tx_mask); - if (codec_dai->rx_mask) + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && + codec_dai->rx_mask) soc_pcm_codec_params_fixup(&codec_params, codec_dai->rx_mask); From aab9bf9d5d3f45bea4fe932acf64298b410c0495 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 25 Feb 2019 14:22:59 +0800 Subject: [PATCH 1115/1995] ASoC:sof:fix a simultaneous playback & capture issue on hda platform If playback and capture are enabled concurrently, when the capture stops the output becomes inaudile. The playback application will become stuck and underrun after a timeout. This is caused by mistaken use of the stream_id, which should only be set for playback and not for capture Tested on Whiskylake. Signed-off-by: Rander Wang --- sound/soc/sof/intel/hda-dai.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 5e04aba0c0518b..e7ecbb23eb055d 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -92,9 +92,10 @@ static int hda_link_dma_params(struct hdac_ext_stream *stream, struct hda_pipe_params *params) { struct hdac_stream *hstream = &stream->hstream; + unsigned char stream_tag = hstream->stream_tag; struct hdac_bus *bus = hstream->bus; - unsigned int format_val; struct hdac_ext_link *link; + unsigned int format_val; snd_hdac_ext_stream_decouple(bus, stream, true); snd_hdac_ext_link_stream_reset(stream); @@ -108,10 +109,12 @@ static int hda_link_dma_params(struct hdac_ext_stream *stream, snd_hdac_ext_link_stream_setup(stream, format_val); - list_for_each_entry(link, &bus->hlink_list, list) { - if (link->index == params->link_index) - snd_hdac_ext_link_set_stream_id(link, - hstream->stream_tag); + if (stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) { + list_for_each_entry(link, &bus->hlink_list, list) { + if (link->index == params->link_index) + snd_hdac_ext_link_set_stream_id(link, + stream_tag); + } } stream->link_prepared = 1; @@ -220,8 +223,10 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream, if (!link) return -EINVAL; - stream_tag = hdac_stream(link_dev)->stream_tag; - snd_hdac_ext_link_clear_stream_id(link, stream_tag); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + stream_tag = hdac_stream(link_dev)->stream_tag; + snd_hdac_ext_link_clear_stream_id(link, stream_tag); + } link_dev->link_prepared = 0; } else { From 89312e84a353eb34ed66ad6acb3f1ff13024b964 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 25 Feb 2019 14:40:33 +0800 Subject: [PATCH 1116/1995] ASoC:intel:skl:fix a simultaneous playback & capture issue on hda platform If playback and capture are enabled concurrently, when the capture stops the output becomes inaudile. The playback application will become stuck and underrun after a timeout. This is caused by mistaken use of the stream_id, which should only be set for playback and not for capture Tested on Apollolake and Kabylake with SST driver. Signed-off-by: Rander Wang --- sound/soc/intel/skylake/skl-pcm.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index a4284778f117d6..bb463ee6ff842a 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -181,6 +181,7 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) struct hdac_stream *hstream; struct hdac_ext_stream *stream; struct hdac_ext_link *link; + unsigned char stream_tag; hstream = snd_hdac_get_stream(bus, params->stream, params->link_dma_id + 1); @@ -199,10 +200,13 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) snd_hdac_ext_link_stream_setup(stream, format_val); - list_for_each_entry(link, &bus->hlink_list, list) { - if (link->index == params->link_index) - snd_hdac_ext_link_set_stream_id(link, - hstream->stream_tag); + stream_tag = hstream->stream_tag; + if (stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) { + list_for_each_entry(link, &bus->hlink_list, list) { + if (link->index == params->link_index) + snd_hdac_ext_link_set_stream_id(link, + stream_tag); + } } stream->link_prepared = 1; @@ -645,6 +649,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream, struct hdac_ext_stream *link_dev = snd_soc_dai_get_dma_data(dai, substream); struct hdac_ext_link *link; + unsigned char stream_tag; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -654,7 +659,11 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream, if (!link) return -EINVAL; - snd_hdac_ext_link_clear_stream_id(link, hdac_stream(link_dev)->stream_tag); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + stream_tag = hdac_stream(link_dev)->stream_tag; + snd_hdac_ext_link_clear_stream_id(link, stream_tag); + } + snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); return 0; } From c50dd5817ed7ddeffe36b623575a8db5b07cf0a6 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Wed, 6 Mar 2019 20:47:54 +0800 Subject: [PATCH 1117/1995] ASoC: SOF: free scontrol when components are unload scontrol is allocated by sof_control_load() which will be called when a kcontrol or a widget with kcontrol is created. We have to free it in both sof_control_unload() and sof_widget_unload(). Signed-off-by: Bard liao --- sound/soc/sof/topology.c | 42 ++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index cc4a08f2d4f968..a9323dccb6c5c4 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -904,6 +904,9 @@ static int sof_control_unload(struct snd_soc_component *scomp, fcomp.hdr.size = sizeof(fcomp); fcomp.id = scontrol->comp_id; + kfree(scontrol->control_data); + list_del(&scontrol->list); + kfree(scontrol); /* send IPC to the DSP */ return sof_ipc_tx_message(sdev->ipc, fcomp.hdr.cmd, &fcomp, sizeof(fcomp), @@ -1925,8 +1928,11 @@ static int sof_widget_unload(struct snd_soc_component *scomp, struct snd_sof_control *scontrol; struct snd_sof_widget *swidget; struct soc_mixer_control *sm; + struct soc_bytes_ext *sbe; struct snd_sof_dai *dai; + struct soc_enum *se; int ret = 0; + int i; swidget = dobj->private; if (!swidget) @@ -1957,21 +1963,37 @@ static int sof_widget_unload(struct snd_soc_component *scomp, /* update enabled cores mask */ sdev->enabled_cores_mask &= ~(1 << pipeline->core); - break; - case snd_soc_dapm_pga: - - /* get volume kcontrol */ - kc = &widget->kcontrol_news[0]; - sm = (struct soc_mixer_control *)kc->private_value; - scontrol = sm->dobj.private; - - /* free volume table */ - kfree(scontrol->volume_table); break; default: break; } + for (i = 0; i < widget->num_kcontrols; i++) { + kc = &widget->kcontrol_news[i]; + switch (dobj->widget.kcontrol_type) { + case SND_SOC_TPLG_TYPE_MIXER: + sm = (struct soc_mixer_control *)kc->private_value; + scontrol = sm->dobj.private; + if (sm->max > 1) + kfree(scontrol->volume_table); + break; + case SND_SOC_TPLG_TYPE_ENUM: + se = (struct soc_enum *)kc->private_value; + scontrol = se->dobj.private; + break; + case SND_SOC_TPLG_TYPE_BYTES: + sbe = (struct soc_bytes_ext *)kc->private_value; + scontrol = sbe->dobj.private; + break; + default: + dev_warn(sdev->dev, "unsupported kcontrol_type\n"); + goto out; + } + kfree(scontrol->control_data); + list_del(&scontrol->list); + kfree(scontrol); + } +out: /* free private value */ kfree(swidget->private); From 07702c11318b055c18af9f6e1dd98a21ce114464 Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Tue, 26 Feb 2019 17:18:39 -0800 Subject: [PATCH 1118/1995] ASoC: SOF: remove unused properties in tokens Some properties are not populated from the topologies and not being used by DSP either. Need to clean up token data structures. These are identified as unused. comp_tokens: preload_count dai_tokens: dmac_config Signed-off-by: Fred Oh --- include/sound/sof/topology.h | 6 +++--- include/uapi/sound/sof/abi.h | 2 +- sound/soc/sof/topology.c | 9 ++------- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h index 155758598ed532..27966998251db1 100644 --- a/include/sound/sof/topology.h +++ b/include/sound/sof/topology.h @@ -80,7 +80,7 @@ struct sof_ipc_comp_config { struct sof_ipc_cmd_hdr hdr; uint32_t periods_sink; /**< 0 means variable */ uint32_t periods_source; /**< 0 means variable */ - uint32_t preload_count; /**< how many periods to preload */ + uint32_t reserved1; /**< reserved */ uint32_t frame_fmt; /**< SOF_IPC_FRAME_ */ uint32_t xrun_action; @@ -102,9 +102,9 @@ struct sof_ipc_comp_dai { struct sof_ipc_comp comp; struct sof_ipc_comp_config config; uint32_t direction; /**< SOF_IPC_STREAM_ */ - uint32_t dai_index; /**< index of this type dai */ + uint32_t dai_index; /**< index of this type dai */ uint32_t type; /**< DAI type - SOF_DAI_ */ - uint32_t dmac_config; /**< DMA engine specific */ + uint32_t reserved; /**< reserved */ } __packed; /* generic mixer component */ diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index 65ce9ee51835f4..6861b12a958e39 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 1 +#define SOF_ABI_MINOR 2 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index a9323dccb6c5c4..a6d18ba21121b3 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -454,8 +454,6 @@ static const struct sof_topology_token buffer_tokens[] = { /* DAI */ static const struct sof_topology_token dai_tokens[] = { - {SOF_TKN_DAI_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_comp_dai, dmac_config), 0}, {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, offsetof(struct sof_ipc_comp_dai, type), 0}, {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -533,9 +531,6 @@ static const struct sof_topology_token comp_tokens[] = { {SOF_TKN_COMP_FORMAT, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format, offsetof(struct sof_ipc_comp_config, frame_fmt), 0}, - {SOF_TKN_COMP_PRELOAD_COUNT, - SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_comp_config, preload_count), 0}, }; /* SSP */ @@ -2221,12 +2216,12 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, config->ssp.rx_slots = le32_to_cpu(hw_config->rx_slots); config->ssp.tx_slots = le32_to_cpu(hw_config->tx_slots); - dev_dbg(sdev->dev, "tplg: config SSP%d fmt 0x%x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d\n", + dev_dbg(sdev->dev, "tplg: config SSP%d fmt 0x%x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d quirks %d\n", config->dai_index, config->format, config->ssp.mclk_rate, config->ssp.bclk_rate, config->ssp.fsync_rate, config->ssp.sample_valid_bits, config->ssp.tdm_slot_width, config->ssp.tdm_slots, - config->ssp.mclk_id); + config->ssp.mclk_id, config->ssp.quirks); /* validate SSP fsync rate and channel count */ if (config->ssp.fsync_rate < 8000 || config->ssp.fsync_rate > 192000) { From 7ff9d7fee84765d3b53da41f1bf608a7865fc9c4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 7 Mar 2019 16:02:22 -0600 Subject: [PATCH 1119/1995] ASoC: SOF: scontrol: remove unused mutex we initialize a mutex but never use it. Remove. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-priv.h | 1 - sound/soc/sof/topology.c | 1 - 2 files changed, 2 deletions(-) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 926053e50e0aa8..59bd510d678205 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -294,7 +294,6 @@ struct snd_sof_control { enum sof_ipc_ctrl_cmd cmd; u32 *volume_table; /* volume table computed from tlv data*/ - struct mutex mutex; /* access mutex */ struct list_head list; /* list in sdev control list */ }; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index a6d18ba21121b3..1059beed9761f4 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -846,7 +846,6 @@ static int sof_control_load(struct snd_soc_component *scomp, int index, return -ENOMEM; scontrol->sdev = sdev; - mutex_init(&scontrol->mutex); switch (le32_to_cpu(hdr->ops.info)) { case SND_SOC_TPLG_CTL_VOLSW: From 6ea2a63eab78afca8f32b0947addcc03dd2686c7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 7 Mar 2019 16:04:48 -0600 Subject: [PATCH 1120/1995] ASoC: SOF: swidget: remove unused mutex We initialize a mutex and never use it. Remove Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-priv.h | 1 - sound/soc/sof/topology.c | 1 - 2 files changed, 2 deletions(-) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 59bd510d678205..876f59a4f8adf7 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -306,7 +306,6 @@ struct snd_sof_widget { int id; struct snd_soc_dapm_widget *widget; - struct mutex mutex; /* access mutex */ struct list_head list; /* list in sdev widget list */ void *private; /* core does not touch this */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 1059beed9761f4..9ca8d39df08dca 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1890,7 +1890,6 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, } w->dobj.private = swidget; - mutex_init(&swidget->mutex); list_add(&swidget->list, &sdev->widget_list); return ret; } From facd448b4a4e91ec5b0c8b7de52b7bd6c86a2517 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 7 Mar 2019 16:07:40 -0600 Subject: [PATCH 1121/1995] ASoC: SOF: spcm: remove mutex We use a mutex without knowing what it protects. Remove. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/compressed.c | 4 ---- sound/soc/sof/pcm.c | 6 ------ sound/soc/sof/pm.c | 2 -- sound/soc/sof/sof-priv.h | 1 - sound/soc/sof/topology.c | 1 - 5 files changed, 14 deletions(-) diff --git a/sound/soc/sof/compressed.c b/sound/soc/sof/compressed.c index 701d204cabf708..69db228cdf1063 100644 --- a/sound/soc/sof/compressed.c +++ b/sound/soc/sof/compressed.c @@ -27,12 +27,10 @@ static int sof_compressed_open(struct snd_compr_stream *cstream) struct snd_sof_pcm *spcm = rtd->private; int ret; - mutex_lock(&spcm->mutex); ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) dev_err(sdev->dev, "error: comp open failed to resume %d\n", ret); - mutex_unlock(&spcm->mutex); return ret; } @@ -46,12 +44,10 @@ static int sof_compressed_free(struct snd_compr_stream *cstream) struct snd_sof_pcm *spcm = rtd->private; int err; - mutex_lock(&spcm->mutex); err = pm_runtime_put(sdev->dev); if (err < 0) dev_err(sdev->dev, "error: comp close failed to idle %d\n", err); - mutex_unlock(&spcm->mutex); return err; } diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 8f9743b3a955fe..489db97e180ade 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -404,13 +404,10 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) caps = &spcm->pcm.caps[substream->stream]; - mutex_lock(&spcm->mutex); - ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { dev_err(sdev->dev, "error: pcm open failed to resume %d\n", ret); - mutex_unlock(&spcm->mutex); return ret; } @@ -465,7 +462,6 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) err); } - mutex_unlock(&spcm->mutex); return ret; } @@ -500,7 +496,6 @@ static int sof_pcm_close(struct snd_pcm_substream *substream) */ } - mutex_lock(&spcm->mutex); pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); @@ -508,7 +503,6 @@ static int sof_pcm_close(struct snd_pcm_substream *substream) dev_err(sdev->dev, "error: pcm close failed to idle %d\n", err); - mutex_unlock(&spcm->mutex); return 0; } diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 225336b9cd5e91..15daad65f18064 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -210,12 +210,10 @@ static void sof_set_restore_stream(struct snd_sof_dev *sdev) /* suspend all running streams */ list_for_each_entry(spcm, &sdev->pcm_list, list) { - mutex_lock(&spcm->mutex); spcm->restore_stream[0] = 1; spcm->restore_stream[1] = 1; - mutex_unlock(&spcm->mutex); } } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 876f59a4f8adf7..7af3f4db8a2510 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -277,7 +277,6 @@ struct snd_sof_pcm { struct snd_soc_tplg_pcm pcm; struct snd_sof_pcm_stream stream[2]; u32 posn_offset[2]; - struct mutex mutex; /* access mutex */ struct list_head list; /* list in sdev pcm list */ struct snd_pcm_hw_params params[2]; int restore_stream[2]; /* restore hw_params for paused stream */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 9ca8d39df08dca..953c750bd0ace8 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2029,7 +2029,6 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, dev_dbg(sdev->dev, "tplg: load pcm %s\n", pcm->dai_name); } dai_drv->dobj.private = spcm; - mutex_init(&spcm->mutex); list_add(&spcm->list, &sdev->pcm_list); /* do we need to allocate playback PCM DMA pages */ From f7e3555f4b954fef76e1cf473024339819bc88ca Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sun, 3 Mar 2019 16:53:15 +0100 Subject: [PATCH 1122/1995] ASoC: SOF: create audio buffer page tables in a hardware-safe way The SOF packs 20-bit page frame numbers into memory back-to-back, which produces both unaligned access and endianness problems. Use unaligned memory accessors to guarantee correct packing on all platforms. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/core.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 70cb1a06529ea3..a81fc6d0d28e1b 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include "sof-priv.h" @@ -215,16 +216,31 @@ int snd_sof_create_page_table(struct snd_sof_dev *sdev, */ u32 idx = (5 * i) >> 1; u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT; - u32 *pg_table; + u8 *pg_table; dev_vdbg(sdev->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); - pg_table = (u32 *)(page_table + idx); + pg_table = (u8 *)(page_table + idx); + /* + * pagetable compression: + * byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 + * ___________pfn 0__________ __________pfn 1___________ _pfn 2... + * .... .... .... .... .... .... .... .... .... .... .... + * It is created by: + * 1. set current location to 0, PFN index i to 0 + * 2. put pfn[i] at current location in Little Endian byte order + * 3. calculate an intermediate value as + * x = (pfn[i+1] << 4) | (pfn[i] & 0xf) + * 4. put x at offset (current location + 2) in LE byte order + * 5. increment current location by 5 bytes, increment i by 2 + * 6. continue to (1) + */ if (i & 1) - *pg_table |= (pfn << 4); + put_unaligned_le32((pg_table[0] & 0xf) | pfn << 4, + pg_table); else - *pg_table |= pfn; + put_unaligned_le32(pfn, pg_table); } return pages; From 6645423a618af0f944fbeddbed799818a875f657 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Mon, 11 Mar 2019 18:52:33 +0200 Subject: [PATCH 1123/1995] ASoC: SOF: Update EQ ABI header This patch updates the kernel header to match the firmware equalizers ABI. Signed-off-by: Seppo Ingalsuo --- include/uapi/sound/sof/eq.h | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/include/uapi/sound/sof/eq.h b/include/uapi/sound/sof/eq.h index 71a159502d069d..cd748204a5a19c 100644 --- a/include/uapi/sound/sof/eq.h +++ b/include/uapi/sound/sof/eq.h @@ -71,10 +71,12 @@ struct sof_eq_fir_coef_data { int16_t coef[]; /* FIR coefficients */ } __packed; -/* In the struct above there's two words (length, shift) before the actual - * FIR coefficients. This information is used in parsing of the config blob. +/* In the struct above there's two 16 bit words (length, shift) and four + * reserved 32 bit words before the actual FIR coefficients. This information + * is used in parsing of the configuration blob. */ -#define SOF_EQ_FIR_COEF_NHEADER 2 +#define SOF_EQ_FIR_COEF_NHEADER \ + (sizeof(struct sof_eq_fir_coef_data) / sizeof(int16_t)) /* IIR EQ type */ @@ -155,10 +157,16 @@ struct sof_eq_iir_biquad_df2t { */ #define SOF_EQ_IIR_DF2T_BIQUADS_MAX 11 -/* The number of int32_t words in sof_eq_iir_header_df2t */ -#define SOF_EQ_IIR_NHEADER_DF2T 2 +/* The number of int32_t words in sof_eq_iir_header_df2t: + * num_sections, num_sections_in_series, reserved[4] + */ +#define SOF_EQ_IIR_NHEADER_DF2T \ + (sizeof(struct sof_eq_iir_header_df2t) / sizeof(int32_t)) -/* The number of int32_t words in sof_eq_iir_biquad_df2t */ -#define SOF_EQ_IIR_NBIQUAD_DF2T 7 +/* The number of int32_t words in sof_eq_iir_biquad_df2t: + * a2, a1, b2, b1, b0, output_shift, output_gain + */ +#define SOF_EQ_IIR_NBIQUAD_DF2T \ + (sizeof(struct sof_eq_iir_biquad_df2t) / sizeof(int32_t)) #endif From b735636d14d72b338677a5dd39e935a9b5d74dbd Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 7 Mar 2019 22:45:19 -0800 Subject: [PATCH 1124/1995] ASoC: SOF: make ROM init timeout platform specific Change the ROM init timeout value to be platform specific and set the recommended values for APL/CNL/SKL platforms. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/apl.c | 1 + sound/soc/sof/intel/cnl.c | 1 + sound/soc/sof/intel/hda-loader.c | 2 +- sound/soc/sof/intel/hda.h | 1 - sound/soc/sof/intel/shim.h | 1 + sound/soc/sof/intel/skl.c | 1 + 6 files changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 692f0e06652f2f..3baedbb48d10e1 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -108,5 +108,6 @@ const struct sof_intel_dsp_desc apl_chip_info = { .ipc_ack = HDA_DSP_REG_HIPCIE, .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, .ipc_ctl = HDA_DSP_REG_HIPCCTL, + .rom_init_timeout = 150, }; EXPORT_SYMBOL(apl_chip_info); diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 5ec0246b9400d4..3db59228db6e1a 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -266,5 +266,6 @@ const struct sof_intel_dsp_desc cnl_chip_info = { .ipc_ack = CNL_DSP_REG_HIPCIDA, .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .rom_init_timeout = 300, }; EXPORT_SYMBOL(cnl_chip_info); diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 9362771ee0d0a9..4f182e6326f2e1 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -131,7 +131,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_ROM_STATUS, HDA_DSP_ROM_STS_MASK, HDA_DSP_ROM_INIT, - HDA_ROM_INIT_TIMEOUT, + chip->rom_init_timeout, HDA_DSP_REG_POLL_INTERVAL_US); if (!ret) return 0; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index ca6e8fc947f4ab..baf1785442bbd2 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -198,7 +198,6 @@ #define HDA_DSP_RESET_TIMEOUT 50 #define HDA_DSP_BASEFW_TIMEOUT 3000 #define HDA_DSP_INIT_TIMEOUT 500 -#define HDA_ROM_INIT_TIMEOUT 70 #define HDA_DSP_CTRL_RESET_TIMEOUT 100 #define HDA_DSP_WAIT_TIMEOUT 500 /* 500 msec */ #define HDA_DSP_REG_POLL_INTERVAL_US 500 /* 0.5 msec */ diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 63fc9b7499a09b..617da2dda17270 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -161,6 +161,7 @@ struct sof_intel_dsp_desc { int ipc_ack; int ipc_ack_mask; int ipc_ctl; + int rom_init_timeout; }; extern const struct snd_sof_dsp_ops sof_tng_ops; diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index fd3d187f9face5..69816deb3c358c 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -101,5 +101,6 @@ const struct sof_intel_dsp_desc skl_chip_info = { .ipc_ack = HDA_DSP_REG_HIPCIE, .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, .ipc_ctl = HDA_DSP_REG_HIPCCTL, + .rom_init_timeout = 150, }; EXPORT_SYMBOL(skl_chip_info); From 16609bca17ab95a4de7cdefb262c05a9de1ca4c5 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 8 Mar 2019 05:13:57 +0800 Subject: [PATCH 1125/1995] ASoC: topology: create tlv before soc_tplg_init_kcontrol Component driver may want to use tlv data. Create tlv before soc_tplg_init_kcontrol so component driver can use the tlv data in the control_load ops. Signed-off-by: Bard liao --- sound/soc/soc-topology.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index e3506b056358e1..472f7705da9368 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -896,19 +896,20 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, continue; } + /* create any TLV data */ + soc_tplg_create_tlv(tplg, &kc, &mc->hdr); + /* pass control to driver for optional further init */ err = soc_tplg_init_kcontrol(tplg, &kc, (struct snd_soc_tplg_ctl_hdr *) mc); if (err < 0) { dev_err(tplg->dev, "ASoC: failed to init %s\n", mc->hdr.name); + soc_tplg_free_tlv(tplg, &kc); kfree(sm); continue; } - /* create any TLV data */ - soc_tplg_create_tlv(tplg, &kc, &mc->hdr); - /* register control here */ err = soc_tplg_add_kcontrol(tplg, &kc, &sm->dobj.control.kcontrol); @@ -1327,18 +1328,19 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( continue; } + /* create any TLV data */ + soc_tplg_create_tlv(tplg, &kc[i], &mc->hdr); + /* pass control to driver for optional further init */ err = soc_tplg_init_kcontrol(tplg, &kc[i], (struct snd_soc_tplg_ctl_hdr *)mc); if (err < 0) { dev_err(tplg->dev, "ASoC: failed to init %s\n", mc->hdr.name); + soc_tplg_free_tlv(tplg, &kc[i]); kfree(sm); continue; } - - /* create any TLV data */ - soc_tplg_create_tlv(tplg, &kc[i], &mc->hdr); } return kc; From 91f32d810d06f3923b49a87301f0f58c6a7a5e83 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Mon, 11 Mar 2019 06:42:18 +0800 Subject: [PATCH 1126/1995] ASoC: SOF: topology: create volume table in control_load volume table is a part of kcontrol instead of widget. Currently, we set up volume table only for pga type widget. However, we should set up volume table for all volume kcontrols including stand alone volume kcontrol. Signed-off-by: Bard liao --- sound/soc/sof/topology.c | 73 +++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 42 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 953c750bd0ace8..b695b039136ced 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -269,6 +269,10 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_mixer_control *mc = (struct snd_soc_tplg_mixer_control *)hdr; + struct sof_ipc_ctrl_data *cdata; + int tlv[TLV_ITEMS]; + unsigned int i; + int ret; /* validate topology data */ if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN) @@ -286,11 +290,34 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, scontrol->num_channels = le32_to_cpu(mc->num_channels); /* set cmd for mixer control */ - if (mc->max > 1) - scontrol->cmd = SOF_CTRL_CMD_VOLUME; - else + if (mc->max == 1) { scontrol->cmd = SOF_CTRL_CMD_SWITCH; + goto out; + } + + scontrol->cmd = SOF_CTRL_CMD_VOLUME; + + /* extract tlv data */ + if (get_tlv_data(kc->tlv.p, tlv) < 0) { + dev_err(sdev->dev, "error: invalid TLV data\n"); + return -EINVAL; + } + + /* set up volume table */ + ret = set_up_volume_table(scontrol, tlv, mc->max + 1); + if (ret < 0) { + dev_err(sdev->dev, "error: setting up volume table\n"); + return ret; + } + + /* set default volume values to 0dB in control */ + cdata = scontrol->control_data; + for (i = 0; i < scontrol->num_channels; i++) { + cdata->chanv[i].channel = i; + cdata->chanv[i].value = VOL_ZERO_DB; + } +out: dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", scontrol->comp_id, scontrol->num_channels); @@ -1359,14 +1386,7 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &tw->priv; struct sof_ipc_comp_volume *volume; - struct snd_soc_dapm_widget *widget = swidget->widget; - const struct snd_kcontrol_new *kc = NULL; - struct soc_mixer_control *sm; - struct snd_sof_control *scontrol; - struct sof_ipc_ctrl_data *cdata; - const unsigned int *p; - int ret, tlv[TLV_ITEMS]; - unsigned int i; + int ret; volume = kzalloc(sizeof(*volume), GFP_KERNEL); if (!volume) @@ -1379,30 +1399,6 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, goto err; } - /* set up volume gain tables for kcontrol */ - kc = &widget->kcontrol_news[0]; - sm = (struct soc_mixer_control *)kc->private_value; - - /* get volume control */ - scontrol = sm->dobj.private; - - /* get topology tlv data */ - p = kc->tlv.p; - - /* extract tlv data */ - if (get_tlv_data(p, tlv) < 0) { - dev_err(sdev->dev, "error: invalid TLV data\n"); - ret = -EINVAL; - goto err; - } - - /* set up volume table */ - ret = set_up_volume_table(scontrol, tlv, sm->max + 1); - if (ret < 0) { - dev_err(sdev->dev, "error: setting up volume table\n"); - goto err; - } - /* configure dai IPC message */ volume->comp.hdr.size = sizeof(*volume); volume->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; @@ -1428,13 +1424,6 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, goto err; } - /* set default volume values to 0dB in control */ - cdata = scontrol->control_data; - for (i = 0; i < scontrol->num_channels; i++) { - cdata->chanv[i].channel = i; - cdata->chanv[i].value = VOL_ZERO_DB; - } - sof_dbg_comp_config(scomp, &volume->config); swidget->private = (void *)volume; From dca70eb3612ec375427551e54614c77bc543c8c3 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 8 Mar 2019 13:17:23 +0800 Subject: [PATCH 1127/1995] ASoC:sof:hda: fix hda preload issue This issue could be reproduced by multiplex_pipeline-test.sh with two pipelines. The hda preload would be in unexpected status sometimes and this results ipc timeout. The recommended hardware programming sequence for HDAudio DMA format is: 1. Put DMA into coupled mode by clearing PPCTL.PROCEN bit for corresponding stream index before the time of writing format to SDxFMT register. 2. Write SDxFMT 3. Set PPCTL.PROCEN bit for corresponding stream index to enable decoupled mode I reproduced this issue on Apollolake UP2 a few times and validated the fix a few times. I can't reproduce it on Icelake because this platform is not stable with multiple threads test for other reasons, but this patch didn't make any negative effect with single thread test of playback or capture. Signed-off-by: Keyon Jie Signed-off-by: Rander Wang --- sound/soc/sof/intel/hda-stream.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index c70046f20eece1..5b8e589b1bd9b0 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -363,12 +363,31 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, hstream->bufsize); + /* + * Recommended hardware programming sequence for HDAudio DMA format + * + * 1. Put DMA into coupled mode by clearing PPCTL.PROCEN bit + * for corresponding stream index before the time of writing + * format to SDxFMT register. + * 2. Write SDxFMT + * 3. Set PPCTL.PROCEN bit for corresponding stream index to + * enable decoupled mode + */ + + /* couple host and link DMA, disable DSP features */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + mask, 0); + /* program stream format */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_FORMAT, 0xffff, hstream->format_val); + /* decouple host and link DMA, enable DSP features */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + mask, mask); + /* program last valid index */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, From 98caf8480b97efce0092b3d0d7325c044c734c8f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 1 Mar 2019 16:27:55 +0100 Subject: [PATCH 1128/1995] ASoC: SOF: (cosmetic) reduce nesting depth Invert a condition and use an early return from a function to reduce its nesting depth. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/ipc.c | 49 ++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index bcd56f5a5fa907..c77358332cf8d6 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -293,33 +293,32 @@ static void ipc_tx_next_msg(struct work_struct *work) spin_lock_irq(&sdev->ipc_lock); /* send message if HW ready and message in TX list */ - if (!list_empty(&ipc->tx_list) && snd_sof_dsp_is_ipc_ready(sdev)) { - /* send first message in TX list */ - msg = list_first_entry(&ipc->tx_list, struct snd_sof_ipc_msg, - list); - ret = snd_sof_dsp_send_msg(sdev, msg); - if (ret < 0) { - - /* - * if ipc tx fails, the msg will be retained in the - * msg_list, so that it can be re-tried until it - * succeeds or times-out. The ipc re-try mechanism in - * SOF currently relies upon tx_kwork being - * rescheduled, which is not guaranteed. This needs - * to be enhanced with a better mechanism. - */ - dev_err_ratelimited(sdev->dev, - "error: ipc tx failed with error %d\n", - ret); - } else { - - /* message sent. move it to the reply list */ - list_move(&msg->list, &ipc->reply_list); - - ipc_log_header(sdev->dev, "ipc tx", msg->header); - } + if (list_empty(&ipc->tx_list) || !snd_sof_dsp_is_ipc_ready(sdev)) + goto unlock; + + /* send first message in TX list */ + msg = list_first_entry(&ipc->tx_list, struct snd_sof_ipc_msg, list); + + ret = snd_sof_dsp_send_msg(sdev, msg); + if (ret < 0) { + /* + * if ipc tx fails, the msg will be retained in the msg_list, so + * that it can be re-tried until it succeeds or times-out. The + * ipc re-try mechanism in SOF currently relies upon tx_kwork + * being rescheduled, which is not guaranteed. This needs to be + * enhanced with a better mechanism. + */ + dev_err_ratelimited(sdev->dev, + "error: ipc tx failed with error %d\n", + ret); + } else { + /* message sent. move it to the reply list */ + list_move(&msg->list, &ipc->reply_list); + + ipc_log_header(sdev->dev, "ipc tx", msg->header); } +unlock: spin_unlock_irq(&sdev->ipc_lock); } From 9fd59c941aab0df7ff71752748a2c04e61b94da7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sun, 3 Mar 2019 17:05:10 +0100 Subject: [PATCH 1129/1995] ASoC: SOF: remove the RX work Using the RX work isn't required since also without it the serialisation is guaranteed by proocessing received messages directly in the IRQ thread. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/ipc.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index c77358332cf8d6..b7c90e4f808d97 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -37,9 +37,6 @@ struct snd_sof_ipc { struct work_struct tx_kwork; u32 msg_pending; - /* Rx Message work and status */ - struct work_struct rx_kwork; - /* lists */ struct list_head tx_list; struct list_head reply_list; @@ -391,11 +388,8 @@ int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) EXPORT_SYMBOL(snd_sof_ipc_reply); /* DSP firmware has sent host a message */ -static void ipc_msgs_rx(struct work_struct *work) +void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) { - struct snd_sof_ipc *ipc = - container_of(work, struct snd_sof_ipc, rx_kwork); - struct snd_sof_dev *sdev = ipc->sdev; struct sof_ipc_cmd_hdr hdr; u32 cmd, type; int err = 0; @@ -454,6 +448,7 @@ static void ipc_msgs_rx(struct work_struct *work) /* tell DSP we are done */ snd_sof_dsp_cmd_done(sdev, SOF_IPC_HOST_REPLY); } +EXPORT_SYMBOL(snd_sof_ipc_msgs_rx); /* schedule work to transmit any IPC in queue */ void snd_sof_ipc_msgs_tx(struct snd_sof_dev *sdev) @@ -463,14 +458,6 @@ void snd_sof_ipc_msgs_tx(struct snd_sof_dev *sdev) } EXPORT_SYMBOL(snd_sof_ipc_msgs_tx); -/* schedule work to handle IPC from DSP */ -void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) -{ - if (!sdev->disable_ipc_queue) - schedule_work(&sdev->ipc->rx_kwork); -} -EXPORT_SYMBOL(snd_sof_ipc_msgs_rx); - /* * IPC trace mechanism. */ @@ -799,7 +786,6 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) INIT_LIST_HEAD(&ipc->empty_list); init_waitqueue_head(&ipc->wait_txq); INIT_WORK(&ipc->tx_kwork, ipc_tx_next_msg); - INIT_WORK(&ipc->rx_kwork, ipc_msgs_rx); ipc->sdev = sdev; /* pre-allocate messages */ @@ -836,6 +822,5 @@ void snd_sof_ipc_free(struct snd_sof_dev *sdev) sdev->disable_ipc_queue = true; cancel_work_sync(&sdev->ipc->tx_kwork); - cancel_work_sync(&sdev->ipc->rx_kwork); } EXPORT_SYMBOL(snd_sof_ipc_free); From 4edf18d7f4ed56c4dfe8de4aa4596c2336f4bbc3 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sun, 3 Mar 2019 17:10:00 +0100 Subject: [PATCH 1130/1995] ASoC: SOF: removed the unused .wait_txq field The .wait_txq wait queue head is initialised but never used. Remove it. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/ipc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index b7c90e4f808d97..0dfa4d8a48dac4 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -33,7 +33,6 @@ struct snd_sof_ipc { struct snd_sof_dev *sdev; /* TX message work and status */ - wait_queue_head_t wait_txq; struct work_struct tx_kwork; u32 msg_pending; @@ -784,7 +783,6 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) INIT_LIST_HEAD(&ipc->tx_list); INIT_LIST_HEAD(&ipc->reply_list); INIT_LIST_HEAD(&ipc->empty_list); - init_waitqueue_head(&ipc->wait_txq); INIT_WORK(&ipc->tx_kwork, ipc_tx_next_msg); ipc->sdev = sdev; From b982949aac023be9e60561e27a39f135a3650021 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 4 Mar 2019 11:00:20 +0100 Subject: [PATCH 1131/1995] ASoC: SOF: use a mutex for IPC TX serialisation IPC TX is currently fully synchronous, the only entry point to send an IPC message is sof_ipc_tx_message() and it unconditionally waits for a reply to the message being sent. Enclosing the complete function into a mutex lock-unlock block ensures, that IPC registers and structs aren't accessed from multiple contexts. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/ipc.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 0dfa4d8a48dac4..c0a9b901244d04 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -11,6 +11,8 @@ // by platform driver code. // +#include + #include "sof-priv.h" #include "ops.h" @@ -32,6 +34,9 @@ static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd); struct snd_sof_ipc { struct snd_sof_dev *sdev; + /* protects messages and the disable flag */ + struct mutex tx_mutex; + /* TX message work and status */ struct work_struct tx_kwork; u32 msg_pending; @@ -244,14 +249,23 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, { struct snd_sof_dev *sdev = ipc->sdev; struct snd_sof_ipc_msg *msg; + int ret; + /* Serialise IPC TX */ + mutex_lock(&ipc->tx_mutex); + + /* + * The spin-lock is also still needed to protect message objects against + * other atomic contexts. + */ spin_lock_irq(&sdev->ipc_lock); /* get an empty message */ msg = msg_get_empty(ipc); if (!msg) { spin_unlock_irq(&sdev->ipc_lock); - return -EBUSY; + ret = -EBUSY; + goto unlock; } msg->header = header; @@ -273,7 +287,12 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, snd_sof_ipc_msgs_tx(sdev); /* now wait for completion */ - return tx_wait_done(ipc, msg, reply_data); + ret = tx_wait_done(ipc, msg, reply_data); + +unlock: + mutex_unlock(&ipc->tx_mutex); + + return ret; } EXPORT_SYMBOL(sof_ipc_tx_message); @@ -784,6 +803,7 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) INIT_LIST_HEAD(&ipc->reply_list); INIT_LIST_HEAD(&ipc->empty_list); INIT_WORK(&ipc->tx_kwork, ipc_tx_next_msg); + mutex_init(&ipc->tx_mutex); ipc->sdev = sdev; /* pre-allocate messages */ From 71b493911274c321d6082bcb79e870bf1cd8e7de Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 8 Mar 2019 10:49:47 +0100 Subject: [PATCH 1132/1995] ASoC: SOF: fix a theoretical race If snd_sof_ipc_reply() is called from an IPC ISR for a DSP response, i.e. after snd_sof_dsp_send_msg() has sent a message out, but before the message is moved to the .reply_list in ipc_tx_next_msg(), it won't find the message to which the received response is related. This race is almost certainly only theoretical, since ipc_tx_next_msg() is holding a spin-lock and has local interrupts disabled while sending the message out. Still, it has to be closed. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/ipc.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index c0a9b901244d04..854cd99a219d07 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -391,9 +391,20 @@ EXPORT_SYMBOL(sof_ipc_drop_all); int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) { struct snd_sof_ipc_msg *msg; + unsigned long flags; + + /* + * Protect against a theoretical race with ipc_tx_next_msg(): if the DSP + * is fast enough to receive an IPC message, reply to it, and the host + * interrupt processing calls this function on a different core from the + * one, where the sending is taking place, the message might not yet be + * on the .reply_list and sof_ipc_reply_find_msg() will return 0. + */ + spin_lock_irqsave(&sdev->ipc_lock, flags); msg = sof_ipc_reply_find_msg(sdev->ipc, msg_id); if (!msg) { + spin_unlock_irqrestore(&sdev->ipc_lock, flags); dev_err(sdev->dev, "error: can't find message header 0x%x", msg_id); return -EINVAL; @@ -401,6 +412,9 @@ int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) /* wake up and return the error if we have waiters on this message ? */ sof_ipc_tx_msg_reply_complete(sdev->ipc, msg); + + spin_unlock_irqrestore(&sdev->ipc_lock, flags); + return 0; } EXPORT_SYMBOL(snd_sof_ipc_reply); From ae5dfe243f62fc126e143bb1022654ce85908549 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 7 Mar 2019 13:02:33 +0100 Subject: [PATCH 1133/1995] ASoC: SOF: remove IPC TX scheduling An IPC TX work was used to serialise IPC message transmission. Now that a mutex is used for this, scheduling isn't needed any more. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/ipc.c | 113 +++++++++++++++++---------------------- sound/soc/sof/sof-priv.h | 2 - 2 files changed, 49 insertions(+), 66 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 854cd99a219d07..273b700934b9ce 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -12,6 +12,7 @@ // #include +#include #include "sof-priv.h" #include "ops.h" @@ -36,10 +37,8 @@ struct snd_sof_ipc { /* protects messages and the disable flag */ struct mutex tx_mutex; - - /* TX message work and status */ - struct work_struct tx_kwork; - u32 msg_pending; + /* disables further sending of ipc's */ + bool disable_ipc_tx; /* lists */ struct list_head tx_list; @@ -236,8 +235,34 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, snd_sof_dsp_cmd_done(sdev, SOF_IPC_DSP_REPLY); - /* continue to schedule any remaining messages... */ - snd_sof_ipc_msgs_tx(sdev); + return ret; +} + +/* send next IPC message in list */ +static int ipc_tx_next_msg(struct snd_sof_ipc *ipc) +{ + struct snd_sof_dev *sdev = ipc->sdev; + struct snd_sof_ipc_msg *msg; + int ret; + + /* send first message in TX list */ + msg = list_first_entry(&ipc->tx_list, struct snd_sof_ipc_msg, list); + + ret = snd_sof_dsp_send_msg(sdev, msg); + if (ret < 0) { + /* + * if ipc tx fails, the msg will be retained in the msg_list, so + * that it can be re-tried until it succeeds or times-out. + */ + dev_err_ratelimited(sdev->dev, + "error: ipc tx failed with error %d\n", + ret); + } else { + /* message sent. move it to the reply list */ + list_move(&msg->list, &ipc->reply_list); + + ipc_log_header(sdev->dev, "ipc tx", msg->header); + } return ret; } @@ -254,6 +279,11 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, /* Serialise IPC TX */ mutex_lock(&ipc->tx_mutex); + if (ipc->disable_ipc_tx) { + ret = -ENODEV; + goto unlock; + } + /* * The spin-lock is also still needed to protect message objects against * other atomic contexts. @@ -280,14 +310,17 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, /* add message to transmit list */ list_add_tail(&msg->list, &ipc->tx_list); - spin_unlock_irq(&sdev->ipc_lock); - - /* schedule the message if not busy */ + /* send the message if not busy */ if (snd_sof_dsp_is_ipc_ready(sdev)) - snd_sof_ipc_msgs_tx(sdev); + ret = ipc_tx_next_msg(sdev->ipc); + else + ret = -EAGAIN; + + spin_unlock_irq(&sdev->ipc_lock); /* now wait for completion */ - ret = tx_wait_done(ipc, msg, reply_data); + if (!ret) + ret = tx_wait_done(ipc, msg, reply_data); unlock: mutex_unlock(&ipc->tx_mutex); @@ -296,47 +329,6 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, } EXPORT_SYMBOL(sof_ipc_tx_message); -/* send next IPC message in list */ -static void ipc_tx_next_msg(struct work_struct *work) -{ - struct snd_sof_ipc *ipc = - container_of(work, struct snd_sof_ipc, tx_kwork); - struct snd_sof_dev *sdev = ipc->sdev; - struct snd_sof_ipc_msg *msg; - int ret; - - spin_lock_irq(&sdev->ipc_lock); - - /* send message if HW ready and message in TX list */ - if (list_empty(&ipc->tx_list) || !snd_sof_dsp_is_ipc_ready(sdev)) - goto unlock; - - /* send first message in TX list */ - msg = list_first_entry(&ipc->tx_list, struct snd_sof_ipc_msg, list); - - ret = snd_sof_dsp_send_msg(sdev, msg); - if (ret < 0) { - /* - * if ipc tx fails, the msg will be retained in the msg_list, so - * that it can be re-tried until it succeeds or times-out. The - * ipc re-try mechanism in SOF currently relies upon tx_kwork - * being rescheduled, which is not guaranteed. This needs to be - * enhanced with a better mechanism. - */ - dev_err_ratelimited(sdev->dev, - "error: ipc tx failed with error %d\n", - ret); - } else { - /* message sent. move it to the reply list */ - list_move(&msg->list, &ipc->reply_list); - - ipc_log_header(sdev->dev, "ipc tx", msg->header); - } - -unlock: - spin_unlock_irq(&sdev->ipc_lock); -} - /* find original TX message from DSP reply */ static struct snd_sof_ipc_msg *sof_ipc_reply_find_msg(struct snd_sof_ipc *ipc, u32 header) @@ -482,14 +474,6 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) } EXPORT_SYMBOL(snd_sof_ipc_msgs_rx); -/* schedule work to transmit any IPC in queue */ -void snd_sof_ipc_msgs_tx(struct snd_sof_dev *sdev) -{ - if (!sdev->disable_ipc_queue) - schedule_work(&sdev->ipc->tx_kwork); -} -EXPORT_SYMBOL(snd_sof_ipc_msgs_tx); - /* * IPC trace mechanism. */ @@ -816,7 +800,6 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) INIT_LIST_HEAD(&ipc->tx_list); INIT_LIST_HEAD(&ipc->reply_list); INIT_LIST_HEAD(&ipc->empty_list); - INIT_WORK(&ipc->tx_kwork, ipc_tx_next_msg); mutex_init(&ipc->tx_mutex); ipc->sdev = sdev; @@ -850,9 +833,11 @@ EXPORT_SYMBOL(snd_sof_ipc_init); void snd_sof_ipc_free(struct snd_sof_dev *sdev) { - /* disable queueing of ipc's */ - sdev->disable_ipc_queue = true; + struct snd_sof_ipc *ipc = sdev->ipc; - cancel_work_sync(&sdev->ipc->tx_kwork); + /* disable sending of ipc's */ + mutex_lock(&ipc->tx_mutex); + ipc->disable_ipc_tx = true; + mutex_unlock(&ipc->tx_mutex); } EXPORT_SYMBOL(snd_sof_ipc_free); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 7af3f4db8a2510..09134fa1b2b71b 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -363,7 +363,6 @@ struct snd_sof_dev { u64 irq_status; int ipc_irq; u32 next_comp_id; /* monotonic - reset during S3 */ - u32 disable_ipc_queue; /* disables further queueing of ipc's */ /* memory bases for mmaped DSPs - set by dsp_init() */ void __iomem *bar[SND_SOF_BARS]; /* DSP base address */ @@ -453,7 +452,6 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev); void snd_sof_ipc_free(struct snd_sof_dev *sdev); int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id); void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev); -void snd_sof_ipc_msgs_tx(struct snd_sof_dev *sdev); int snd_sof_ipc_stream_pcm_params(struct snd_sof_dev *sdev, struct sof_ipc_pcm_params *params); int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox, From b4f490d2752ad1f944032142d2557572ab6fbc15 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 8 Mar 2019 13:41:31 +0100 Subject: [PATCH 1134/1995] ASoC: SOF: remove IPC message lists IPC message lists are currently unused. Only one message is ever used. Remove lists and use just one message. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/ipc.c | 163 +++++++-------------------------------- sound/soc/sof/pm.c | 3 - sound/soc/sof/sof-priv.h | 5 +- 3 files changed, 31 insertions(+), 140 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 273b700934b9ce..ae3be4124cb862 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -22,7 +22,6 @@ * TODO: allow platforms to set size and timeout. */ #define IPC_TIMEOUT_MS 300 -#define IPC_EMPTY_LIST_SIZE 8 static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id); static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd); @@ -40,27 +39,9 @@ struct snd_sof_ipc { /* disables further sending of ipc's */ bool disable_ipc_tx; - /* lists */ - struct list_head tx_list; - struct list_head reply_list; - struct list_head empty_list; + struct snd_sof_ipc_msg msg; }; -/* locks held by caller */ -static struct snd_sof_ipc_msg *msg_get_empty(struct snd_sof_ipc *ipc) -{ - struct snd_sof_ipc_msg *msg = NULL; - - /* get first empty message in the list */ - if (!list_empty(&ipc->empty_list)) { - msg = list_first_entry(&ipc->empty_list, struct snd_sof_ipc_msg, - list); - list_del(&msg->list); - } - - return msg; -} - #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC) static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) { @@ -203,13 +184,6 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, ret = wait_event_timeout(msg->waitq, msg->ipc_complete, msecs_to_jiffies(IPC_TIMEOUT_MS)); - /* - * ipc_lock is used to protect ipc message list shared by user - * contexts and a workqueue. There is no need to save interrupt - * status with spin_lock_irqsave. - */ - spin_lock_irq(&sdev->ipc_lock); - if (ret == 0) { dev_err(sdev->dev, "error: ipc timed out for 0x%x size 0x%x\n", hdr->cmd, hdr->size); @@ -228,11 +202,6 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, ipc_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd); } - /* return message body to empty list */ - list_move(&msg->list, &ipc->empty_list); - - spin_unlock_irq(&sdev->ipc_lock); - snd_sof_dsp_cmd_done(sdev, SOF_IPC_DSP_REPLY); return ret; @@ -242,27 +211,16 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, static int ipc_tx_next_msg(struct snd_sof_ipc *ipc) { struct snd_sof_dev *sdev = ipc->sdev; - struct snd_sof_ipc_msg *msg; - int ret; - - /* send first message in TX list */ - msg = list_first_entry(&ipc->tx_list, struct snd_sof_ipc_msg, list); + struct snd_sof_ipc_msg *msg = &ipc->msg; + int ret = snd_sof_dsp_send_msg(sdev, msg); - ret = snd_sof_dsp_send_msg(sdev, msg); - if (ret < 0) { - /* - * if ipc tx fails, the msg will be retained in the msg_list, so - * that it can be re-tried until it succeeds or times-out. - */ + if (ret < 0) + /* So far IPC TX never fails, consider making the above void */ dev_err_ratelimited(sdev->dev, "error: ipc tx failed with error %d\n", ret); - } else { - /* message sent. move it to the reply list */ - list_move(&msg->list, &ipc->reply_list); - + else ipc_log_header(sdev->dev, "ipc tx", msg->header); - } return ret; } @@ -290,31 +248,26 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, */ spin_lock_irq(&sdev->ipc_lock); - /* get an empty message */ - msg = msg_get_empty(ipc); - if (!msg) { - spin_unlock_irq(&sdev->ipc_lock); - ret = -EBUSY; - goto unlock; - } + /* initialise the message */ + msg = &ipc->msg; msg->header = header; msg->msg_size = msg_bytes; msg->reply_size = reply_bytes; - msg->ipc_complete = false; /* attach any data */ if (msg_bytes) memcpy(msg->msg_data, msg_data, msg_bytes); - /* add message to transmit list */ - list_add_tail(&msg->list, &ipc->tx_list); - /* send the message if not busy */ - if (snd_sof_dsp_is_ipc_ready(sdev)) + if (snd_sof_dsp_is_ipc_ready(sdev)) { ret = ipc_tx_next_msg(sdev->ipc); - else + /* Next reply that we receive will be related to this message */ + if (!ret) + msg->ipc_complete = false; + } else { ret = -EAGAIN; + } spin_unlock_irq(&sdev->ipc_lock); @@ -329,25 +282,6 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, } EXPORT_SYMBOL(sof_ipc_tx_message); -/* find original TX message from DSP reply */ -static struct snd_sof_ipc_msg *sof_ipc_reply_find_msg(struct snd_sof_ipc *ipc, - u32 header) -{ - struct snd_sof_dev *sdev = ipc->sdev; - struct snd_sof_ipc_msg *msg; - - header = SOF_IPC_MESSAGE_ID(header); - - list_for_each_entry(msg, &ipc->reply_list, list) { - if (SOF_IPC_MESSAGE_ID(msg->header) == header) - return msg; - } - - dev_err(sdev->dev, "error: rx list empty but received 0x%x\n", - header); - return NULL; -} - /* mark IPC message as complete - locks held by caller */ static void sof_ipc_tx_msg_reply_complete(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg) @@ -356,33 +290,10 @@ static void sof_ipc_tx_msg_reply_complete(struct snd_sof_ipc *ipc, wake_up(&msg->waitq); } -/* drop all IPC messages in preparation for DSP stall/reset */ -void sof_ipc_drop_all(struct snd_sof_ipc *ipc) -{ - struct snd_sof_dev *sdev = ipc->sdev; - struct snd_sof_ipc_msg *msg, *tmp; - - /* drop all TX and Rx messages before we stall + reset DSP */ - spin_lock_irq(&sdev->ipc_lock); - - list_for_each_entry_safe(msg, tmp, &ipc->tx_list, list) { - list_move(&msg->list, &ipc->empty_list); - dev_err(sdev->dev, "error: dropped msg %d\n", msg->header); - } - - list_for_each_entry_safe(msg, tmp, &ipc->reply_list, list) { - list_move(&msg->list, &ipc->empty_list); - dev_err(sdev->dev, "error: dropped reply %d\n", msg->header); - } - - spin_unlock_irq(&sdev->ipc_lock); -} -EXPORT_SYMBOL(sof_ipc_drop_all); - /* handle reply message from DSP */ int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) { - struct snd_sof_ipc_msg *msg; + struct snd_sof_ipc_msg *msg = &sdev->ipc->msg; unsigned long flags; /* @@ -390,14 +301,13 @@ int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) * is fast enough to receive an IPC message, reply to it, and the host * interrupt processing calls this function on a different core from the * one, where the sending is taking place, the message might not yet be - * on the .reply_list and sof_ipc_reply_find_msg() will return 0. + * marked as expecting a reply. */ spin_lock_irqsave(&sdev->ipc_lock, flags); - msg = sof_ipc_reply_find_msg(sdev->ipc, msg_id); - if (!msg) { + if (msg->ipc_complete) { spin_unlock_irqrestore(&sdev->ipc_lock, flags); - dev_err(sdev->dev, "error: can't find message header 0x%x", + dev_err(sdev->dev, "error: no reply expected, received 0x%x", msg_id); return -EINVAL; } @@ -785,7 +695,6 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) { struct snd_sof_ipc *ipc; struct snd_sof_ipc_msg *msg; - int i; /* check if mandatory ops required for ipc are defined */ if (!sof_ops(sdev)->is_ipc_ready || !sof_ops(sdev)->fw_ready) { @@ -797,35 +706,23 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) if (!ipc) return NULL; - INIT_LIST_HEAD(&ipc->tx_list); - INIT_LIST_HEAD(&ipc->reply_list); - INIT_LIST_HEAD(&ipc->empty_list); mutex_init(&ipc->tx_mutex); ipc->sdev = sdev; + msg = &ipc->msg; - /* pre-allocate messages */ - dev_dbg(sdev->dev, "pre-allocate %d IPC messages\n", - IPC_EMPTY_LIST_SIZE); - msg = devm_kzalloc(sdev->dev, sizeof(struct snd_sof_ipc_msg) * - IPC_EMPTY_LIST_SIZE, GFP_KERNEL); - if (!msg) - return NULL; + /* Indicate, that we aren't sending a message ATM */ + msg->ipc_complete = true; /* pre-allocate message data */ - for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { - msg->msg_data = devm_kzalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL); - if (!msg->msg_data) - return NULL; - - msg->reply_data = devm_kzalloc(sdev->dev, PAGE_SIZE, - GFP_KERNEL); - if (!msg->reply_data) - return NULL; - - init_waitqueue_head(&msg->waitq); - list_add(&msg->list, &ipc->empty_list); - msg++; - } + msg->msg_data = devm_kzalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL); + if (!msg->msg_data) + return NULL; + + msg->reply_data = devm_kzalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL); + if (!msg->reply_data) + return NULL; + + init_waitqueue_head(&msg->waitq); return ipc; } diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 15daad65f18064..75a4e20c16d8a4 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -342,9 +342,6 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) ret); } - /* drop all ipc */ - sof_ipc_drop_all(sdev->ipc); - /* power down all DSP cores */ if (runtime_suspend) ret = snd_sof_dsp_runtime_suspend(sdev, 0); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 09134fa1b2b71b..5497534ae0136f 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -250,8 +250,6 @@ struct snd_sof_mailbox { /* IPC message descriptor for host <-> DSP IO */ struct snd_sof_ipc_msg { - struct list_head list; - /* message data */ u32 header; void *msg_data; @@ -260,7 +258,7 @@ struct snd_sof_ipc_msg { size_t reply_size; wait_queue_head_t waitq; - u32 ipc_complete; + bool ipc_complete; }; /* PCM stream, mapped to FW component */ @@ -489,7 +487,6 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev, int *direction); struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev, unsigned int pcm_id); -void sof_ipc_drop_all(struct snd_sof_ipc *ipc); /* * Stream IPC From 02c906f30e16163f023f66e8c10f109aa990118a Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 8 Mar 2019 15:24:10 +0100 Subject: [PATCH 1135/1995] ASoC: SOF: protect against buffer overflow The sof_ipc_tx_message() function is called from multiple locations in SOF to transmit IPC messages. It copies data from the supplied location to an internal fixed-size buffer without verifying the size and prepares a response buffer for data from the DSP, if any, also without checking the size of requested response data. This can lead to buffer overflows. Add a check to avoid it. When allocating those buffers only allocate the maximum IPC message size. Also remove type-casting of those buffers, since they are of the "void *" type. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/hda-ipc.c | 2 +- sound/soc/sof/ipc.c | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 589264524f08c5..766281f3a55c6e 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -90,7 +90,7 @@ int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev, int ret = 0; u32 size; - hdr = (struct sof_ipc_cmd_hdr *)msg->msg_data; + hdr = msg->msg_data; if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) { /* * memory windows are powered off before sending IPC reply, diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index ae3be4124cb862..04d64ef8a3ec28 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -177,7 +177,7 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, void *reply_data) { struct snd_sof_dev *sdev = ipc->sdev; - struct sof_ipc_cmd_hdr *hdr = (struct sof_ipc_cmd_hdr *)msg->msg_data; + struct sof_ipc_cmd_hdr *hdr = msg->msg_data; int ret; /* wait for DSP IPC completion */ @@ -234,6 +234,10 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, struct snd_sof_ipc_msg *msg; int ret; + if (msg_bytes > SOF_IPC_MSG_MAX_SIZE || + reply_bytes > SOF_IPC_MSG_MAX_SIZE) + return -ENOBUFS; + /* Serialise IPC TX */ mutex_lock(&ipc->tx_mutex); @@ -714,11 +718,13 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) msg->ipc_complete = true; /* pre-allocate message data */ - msg->msg_data = devm_kzalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL); + msg->msg_data = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, + GFP_KERNEL); if (!msg->msg_data) return NULL; - msg->reply_data = devm_kzalloc(sdev->dev, PAGE_SIZE, GFP_KERNEL); + msg->reply_data = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, + GFP_KERNEL); if (!msg->reply_data) return NULL; From b280317462e647a1f004b68a7620324b9b1543d4 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 7 Mar 2019 11:45:54 +0100 Subject: [PATCH 1136/1995] ASoC: SOF: remove the "is_ipc_ready" API .is_ipc_ready() is a platform-provided method, that checks whether an IPC transmission operation is currently in progress. It is used by sof_ipc_tx_message() itself to avoid races. However, now the complete sof_ipc_tx_message() function is protected by a mutex, therefore it cannot be re-entered. This allows us to remove .is_ipc_ready() by implicitly replacing its return code with a "true" value. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/hw-spi.c | 9 ------ sound/soc/sof/intel/apl.c | 1 - sound/soc/sof/intel/bdw.c | 12 -------- sound/soc/sof/intel/byt.c | 14 --------- sound/soc/sof/intel/cnl.c | 14 --------- sound/soc/sof/intel/hda-ipc.c | 14 --------- sound/soc/sof/intel/hda.h | 1 - sound/soc/sof/intel/hsw.c | 12 -------- sound/soc/sof/intel/skl.c | 1 - sound/soc/sof/ipc.c | 53 +++++++++++++---------------------- sound/soc/sof/ops.h | 9 ------ sound/soc/sof/sof-priv.h | 1 - 12 files changed, 20 insertions(+), 121 deletions(-) diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index 426f276d2c232c..58815c65c9c8e3 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -181,14 +181,6 @@ static irqreturn_t spi_irq_thread(int irq __maybe_unused, void *context __maybe_ return IRQ_HANDLED; } -static int spi_is_ipc_ready(struct snd_sof_dev *sdev __maybe_unused) -{ - // use local variable to store DSP command state. either DSP is ready - // for new cmd or still processing current cmd. - - return 1; -} - static int spi_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { /* send the message */ @@ -300,7 +292,6 @@ const struct snd_sof_dsp_ops snd_sof_spi_ops = { .send_msg = spi_send_msg, .get_reply = spi_get_reply, .fw_ready = spi_fw_ready, - .is_ipc_ready = spi_is_ipc_ready, .cmd_done = spi_cmd_done, /* debug */ diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 3baedbb48d10e1..5b53b149c26301 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -52,7 +52,6 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .send_msg = hda_dsp_ipc_send_msg, .get_reply = hda_dsp_ipc_get_reply, .fw_ready = hda_dsp_ipc_fw_ready, - .is_ipc_ready = hda_dsp_is_ipc_ready, .cmd_done = hda_dsp_ipc_cmd_done, /* debug */ diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 1340ccf6fba845..cc7fc1d4c513ba 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -465,17 +465,6 @@ static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) * IPC Mailbox IO */ -static int bdw_is_ipc_ready(struct snd_sof_dev *sdev) -{ - u32 val; - - val = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCX); - if ((val & SHIM_IPCX_BUSY) || (val & SHIM_IPCX_DONE)) - return 0; - - return 1; -} - static int bdw_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { /* send the message */ @@ -677,7 +666,6 @@ const struct snd_sof_dsp_ops sof_bdw_ops = { .send_msg = bdw_send_msg, .get_reply = bdw_get_reply, .fw_ready = bdw_fw_ready, - .is_ipc_ready = bdw_is_ipc_ready, .cmd_done = bdw_cmd_done, /* debug */ diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 74a618c095df56..72eb2a886a2990 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -360,17 +360,6 @@ static irqreturn_t byt_irq_thread(int irq, void *context) return IRQ_HANDLED; } -static int byt_is_ipc_ready(struct snd_sof_dev *sdev) -{ - u64 ipcx; - - ipcx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCX); - if ((ipcx & SHIM_BYT_IPCX_BUSY) || (ipcx & SHIM_BYT_IPCX_DONE)) - return 0; - - return 1; -} - static int byt_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { u64 cmd = msg->header; @@ -616,7 +605,6 @@ const struct snd_sof_dsp_ops sof_tng_ops = { .send_msg = byt_send_msg, .get_reply = byt_get_reply, .fw_ready = byt_fw_ready, - .is_ipc_ready = byt_is_ipc_ready, .cmd_done = byt_cmd_done, /* debug */ @@ -778,7 +766,6 @@ const struct snd_sof_dsp_ops sof_byt_ops = { .send_msg = byt_send_msg, .get_reply = byt_get_reply, .fw_ready = byt_fw_ready, - .is_ipc_ready = byt_is_ipc_ready, .cmd_done = byt_cmd_done, /* debug */ @@ -835,7 +822,6 @@ const struct snd_sof_dsp_ops sof_cht_ops = { .send_msg = byt_send_msg, .get_reply = byt_get_reply, .fw_ready = byt_fw_ready, - .is_ipc_ready = byt_is_ipc_ready, .cmd_done = byt_cmd_done, /* debug */ diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 3db59228db6e1a..3fb17f42e22bb7 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -153,19 +153,6 @@ static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev, int dir) return 0; } -static int cnl_is_ipc_ready(struct snd_sof_dev *sdev) -{ - u32 busy, done; - - busy = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR); - done = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); - if ((busy & CNL_DSP_REG_HIPCIDR_BUSY) || - (done & CNL_DSP_REG_HIPCIDA_DONE)) - return 0; - - return 1; -} - static int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { @@ -208,7 +195,6 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .send_msg = cnl_ipc_send_msg, .get_reply = hda_dsp_ipc_get_reply, .fw_ready = hda_dsp_ipc_fw_ready, - .is_ipc_ready = cnl_is_ipc_ready, .cmd_done = cnl_ipc_cmd_done, /* debug */ diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 766281f3a55c6e..4d978666db5ac6 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -55,20 +55,6 @@ int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir) return 0; } -int hda_dsp_is_ipc_ready(struct snd_sof_dev *sdev) -{ - u32 busy, done; - - /* is DSP ready for next IPC command */ - busy = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI); - done = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE); - if ((busy & HDA_DSP_REG_HIPCI_BUSY) || - (done & HDA_DSP_REG_HIPCIE_DONE)) - return 0; - - return 1; -} - int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { u32 cmd = msg->header; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index baf1785442bbd2..6e1caf8331ae45 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -465,7 +465,6 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, /* * DSP IPC Operations. */ -int hda_dsp_is_ipc_ready(struct snd_sof_dev *sdev); int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 09c9ab8e0f67bd..b7193d21cebb48 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -466,17 +466,6 @@ static int hsw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) * IPC Mailbox IO */ -static int hsw_is_ipc_ready(struct snd_sof_dev *sdev) -{ - u32 val; - - val = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_IPCX); - if ((val & SHIM_IPCX_BUSY) || (val & SHIM_IPCX_DONE)) - return 0; - - return 1; -} - static int hsw_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { /* send the message */ @@ -677,7 +666,6 @@ const struct snd_sof_dsp_ops sof_hsw_ops = { .send_msg = hsw_send_msg, .get_reply = hsw_get_reply, .fw_ready = hsw_fw_ready, - .is_ipc_ready = hsw_is_ipc_ready, .cmd_done = hsw_cmd_done, /* debug */ diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 69816deb3c358c..1918297bae420b 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -52,7 +52,6 @@ const struct snd_sof_dsp_ops sof_skl_ops = { .send_msg = hda_dsp_ipc_send_msg, .get_reply = hda_dsp_ipc_get_reply, .fw_ready = hda_dsp_ipc_fw_ready, - .is_ipc_ready = hda_dsp_is_ipc_ready, .cmd_done = hda_dsp_ipc_cmd_done, /* debug */ diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 04d64ef8a3ec28..e27cdd8702f93e 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -207,24 +207,6 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, return ret; } -/* send next IPC message in list */ -static int ipc_tx_next_msg(struct snd_sof_ipc *ipc) -{ - struct snd_sof_dev *sdev = ipc->sdev; - struct snd_sof_ipc_msg *msg = &ipc->msg; - int ret = snd_sof_dsp_send_msg(sdev, msg); - - if (ret < 0) - /* So far IPC TX never fails, consider making the above void */ - dev_err_ratelimited(sdev->dev, - "error: ipc tx failed with error %d\n", - ret); - else - ipc_log_header(sdev->dev, "ipc tx", msg->header); - - return ret; -} - /* send IPC message from host to DSP */ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, void *msg_data, size_t msg_bytes, void *reply_data, @@ -263,18 +245,23 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, if (msg_bytes) memcpy(msg->msg_data, msg_data, msg_bytes); - /* send the message if not busy */ - if (snd_sof_dsp_is_ipc_ready(sdev)) { - ret = ipc_tx_next_msg(sdev->ipc); - /* Next reply that we receive will be related to this message */ - if (!ret) - msg->ipc_complete = false; - } else { - ret = -EAGAIN; - } + ret = snd_sof_dsp_send_msg(sdev, msg); + /* Next reply that we receive will be related to this message */ + if (!ret) + msg->ipc_complete = false; spin_unlock_irq(&sdev->ipc_lock); + if (ret < 0) { + /* So far IPC TX never fails, consider making the above void */ + dev_err_ratelimited(sdev->dev, + "error: ipc tx failed with error %d\n", + ret); + goto unlock; + } + + ipc_log_header(sdev->dev, "ipc tx", msg->header); + /* now wait for completion */ if (!ret) ret = tx_wait_done(ipc, msg, reply_data); @@ -301,11 +288,11 @@ int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) unsigned long flags; /* - * Protect against a theoretical race with ipc_tx_next_msg(): if the DSP - * is fast enough to receive an IPC message, reply to it, and the host - * interrupt processing calls this function on a different core from the - * one, where the sending is taking place, the message might not yet be - * marked as expecting a reply. + * Protect against a theoretical race with sof_ipc_tx_message(): if the + * DSP is fast enough to receive an IPC message, reply to it, and the + * host interrupt processing calls this function on a different core + * from the one, where the sending is taking place, the message might + * not yet be marked as expecting a reply. */ spin_lock_irqsave(&sdev->ipc_lock, flags); @@ -701,7 +688,7 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) struct snd_sof_ipc_msg *msg; /* check if mandatory ops required for ipc are defined */ - if (!sof_ops(sdev)->is_ipc_ready || !sof_ops(sdev)->fw_ready) { + if (!sof_ops(sdev)->fw_ready) { dev_err(sdev->dev, "error: ipc mandatory ops not defined\n"); return NULL; } diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index e5a00f573c0608..23b57884c19984 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -267,15 +267,6 @@ static inline int snd_sof_dsp_get_reply(struct snd_sof_dev *sdev, return -ENOTSUPP; } -static inline int snd_sof_dsp_is_ipc_ready(struct snd_sof_dev *sdev) -{ - if (sof_ops(sdev)->is_ipc_ready) - return sof_ops(sdev)->is_ipc_ready(sdev); - - dev_err(sdev->dev, "error: %s not defined\n", __func__); - return -ENOTSUPP; -} - static inline int snd_sof_dsp_cmd_done(struct snd_sof_dev *sdev, int dir) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 5497534ae0136f..f5fc283d478f88 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -114,7 +114,6 @@ struct snd_sof_dsp_ops { struct snd_sof_ipc_msg *msg); /* mandatory */ int (*get_reply)(struct snd_sof_dev *sof_dev, struct snd_sof_ipc_msg *msg); /* mandatory */ - int (*is_ipc_ready)(struct snd_sof_dev *sof_dev); /* mandatory */ int (*cmd_done)(struct snd_sof_dev *sof_dev, int dir); /* mandatory */ /* FW loading */ From 41e4680a035ec574a170947b79a93c6db3a85749 Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Thu, 14 Mar 2019 16:59:37 -0700 Subject: [PATCH 1137/1995] ASoC: SOF: fix cppcheck warnings with pointer arithmetic Reported by cppcheck [debug.c:76]: (portability) 'dfse->buf' is of type 'void *' [trace.c:88]: (portability) 'dfse->buf' is of type 'void *' [loader.c:56]: (portability) 'ext_data' is of type 'void *' [loader.c:148]: (portability) '(void*)block' is of type 'void *' [loader.c:154]: (portability) '(void*)block' is of type 'void *' [loader.c:154]: (portability) '(void*)block+sizeof(*block)' is of type 'void *' [loader.c:203]: (portability) '(void*)fw->data' is of type 'void *' [loader.c:220]: (portability) '(void*)module' is of type 'void *' [loader.c:220]: (portability) '(void*)module+sizeof(*module)' is of type 'void *' [topology.c:405]: (portability) 'object' is of type 'void *' [topology.c:414]: (portability) 'object' is of type 'void *' [topology.c:423]: (portability) 'object' is of type 'void *' [topology.c:432]: (portability) 'object' is of type 'void *' [topology.c:441]: (portability) 'object' is of type 'void *' [topology.c:818]: (portability) '(void*)array' is of type 'void *' Signed-off-by: Fred Oh --- sound/soc/sof/debug.c | 2 +- sound/soc/sof/loader.c | 16 +++++++++------- sound/soc/sof/topology.c | 13 +++++++------ sound/soc/sof/trace.c | 2 +- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 76628952775cb4..a71d1aa78ffe31 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -73,7 +73,7 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, memcpy_fromio(buf, dfse->io_mem + pos, size); #endif } else { - memcpy(buf, dfse->buf + pos, size); + memcpy(buf, (void *)((u8 *)(dfse->buf) + pos), size); } /* copy to userspace */ diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 60802a1fca7644..657c0dd5c01348 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -53,8 +53,8 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) /* read in ext structure */ offset += sizeof(*ext_hdr); snd_sof_dsp_block_read(sdev, bar, offset, - ext_data + sizeof(*ext_hdr), - ext_hdr->hdr.size - sizeof(*ext_hdr)); + (void *)((u8 *)ext_data + sizeof(*ext_hdr)), + ext_hdr->hdr.size - sizeof(*ext_hdr)); dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n", ext_hdr->type, ext_hdr->hdr.size); @@ -100,7 +100,7 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, dev_dbg(sdev->dev, "new module size 0x%x blocks 0x%x type 0x%x\n", module->size, module->num_blocks, module->type); - block = (void *)module + sizeof(*module); + block = (struct snd_sof_blk_hdr *)((u8 *)module + sizeof(*module)); /* module->size doesn't include header size */ remaining = module->size; @@ -145,13 +145,14 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, return -EINVAL; } snd_sof_dsp_block_write(sdev, sdev->mmio_bar, offset, - (void *)block + sizeof(*block), + (void *)((u8 *)block + sizeof(*block)), block->size); /* minus body size of block */ remaining -= block->size; /* next block */ - block = (void *)block + sizeof(*block) + block->size; + block = (struct snd_sof_blk_hdr *)((u8 *)block + sizeof(*block) + + block->size); } return 0; @@ -200,7 +201,7 @@ static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw) return -EINVAL; /* parse each module */ - module = (void *)fw->data + sizeof(*header); + module = (struct snd_sof_mod_hdr *)((u8 *)(fw->data) + sizeof(*header)); remaining = fw->size - sizeof(*header); for (count = 0; count < header->num_modules; count++) { /* minus header size of module */ @@ -217,7 +218,8 @@ static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw) } /* minus body size of module */ remaining -= module->size; - module = (void *)module + sizeof(*module) + module->size; + module = (struct snd_sof_mod_hdr *)((u8 *)module + + sizeof(*module) + module->size); } return 0; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index b695b039136ced..d0d1236646c47b 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -429,7 +429,7 @@ struct sof_topology_token { static int get_token_u32(void *elem, void *object, u32 offset, u32 size) { struct snd_soc_tplg_vendor_value_elem *velem = elem; - u32 *val = object + offset; + u32 *val = (u32 *)((u8 *)object + offset); *val = le32_to_cpu(velem->value); return 0; @@ -438,7 +438,7 @@ static int get_token_u32(void *elem, void *object, u32 offset, u32 size) static int get_token_u16(void *elem, void *object, u32 offset, u32 size) { struct snd_soc_tplg_vendor_value_elem *velem = elem; - u16 *val = object + offset; + u16 *val = (u16 *)((u8 *)object + offset); *val = (u16)le32_to_cpu(velem->value); return 0; @@ -447,7 +447,7 @@ static int get_token_u16(void *elem, void *object, u32 offset, u32 size) static int get_token_comp_format(void *elem, void *object, u32 offset, u32 size) { struct snd_soc_tplg_vendor_string_elem *velem = elem; - u32 *val = object + offset; + u32 *val = (u32 *)((u8 *)object + offset); *val = find_format(velem->string); return 0; @@ -456,7 +456,7 @@ static int get_token_comp_format(void *elem, void *object, u32 offset, u32 size) static int get_token_dai_type(void *elem, void *object, u32 offset, u32 size) { struct snd_soc_tplg_vendor_string_elem *velem = elem; - u32 *val = object + offset; + u32 *val = (u32 *)((u8 *)object + offset); *val = find_dai(velem->string); return 0; @@ -465,7 +465,7 @@ static int get_token_dai_type(void *elem, void *object, u32 offset, u32 size) static int get_token_effect_type(void *elem, void *object, u32 offset, u32 size) { struct snd_soc_tplg_vendor_string_elem *velem = elem; - u32 *val = object + offset; + u32 *val = (u32 *)((u8 *)object + offset); *val = find_effect(velem->string); return 0; @@ -837,7 +837,8 @@ static int sof_parse_tokens(struct snd_soc_component *scomp, } /* next array */ - array = (void *)array + asize; + array = (struct snd_soc_tplg_vendor_array *)((u8 *)array + + asize); } return 0; } diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 0b5c6a18328bb8..8c95e3453b6fb3 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -85,7 +85,7 @@ static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer, count = avail > count ? count : avail; /* copy available trace data to debugfs */ - rem = copy_to_user(buffer, dfse->buf + lpos, count); + rem = copy_to_user(buffer, (void *)((u8 *)(dfse->buf) + lpos), count); if (rem) return -EFAULT; From 54b12897d5451ffe642bb1a5a4ea4b21e471e649 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 18 Mar 2019 15:17:42 +0800 Subject: [PATCH 1138/1995] ASoC: rt5682: recording has no sound after booting If ASRC turns on, HW will use clk_dac as the reference clock whether recording or playback. Both of clk_dac and clk_adc should set proper clock while using ASRC. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 9d5acd2d04abd4..c5de3a47c2eab1 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -1198,7 +1198,7 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); - int ref, val, reg, sft, mask, idx = -EINVAL; + int ref, val, reg, idx = -EINVAL; static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48}; static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48}; @@ -1212,15 +1212,10 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w, idx = rt5682_div_sel(rt5682, ref, div_f, ARRAY_SIZE(div_f)); - if (w->shift == RT5682_PWR_ADC_S1F_BIT) { + if (w->shift == RT5682_PWR_ADC_S1F_BIT) reg = RT5682_PLL_TRACK_3; - sft = RT5682_ADC_OSR_SFT; - mask = RT5682_ADC_OSR_MASK; - } else { + else reg = RT5682_PLL_TRACK_2; - sft = RT5682_DAC_OSR_SFT; - mask = RT5682_DAC_OSR_MASK; - } snd_soc_component_update_bits(component, reg, RT5682_FILTER_CLK_DIV_MASK, idx << RT5682_FILTER_CLK_DIV_SFT); @@ -1232,7 +1227,8 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w, } snd_soc_component_update_bits(component, RT5682_ADDA_CLK_1, - mask, idx << sft); + RT5682_ADC_OSR_MASK | RT5682_DAC_OSR_MASK, + (idx << RT5682_ADC_OSR_SFT) | (idx << RT5682_DAC_OSR_SFT)); return 0; } From 95b2fab5625be0495a627b92c41b0e9dc629cc80 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Tue, 19 Mar 2019 04:32:03 +0800 Subject: [PATCH 1139/1995] ASoC: intel: sof_rt5682: enable adc asrc We should enable asrc on both dac and adc, otherwise, we will get a choppy recording file. Signed-off-by: Bard liao --- sound/soc/intel/boards/sof_rt5682.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index eab6eaaedd6c9e..99735cc247c02f 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -117,7 +117,8 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) /* need to enable ASRC function for 24MHz mclk rate */ if ((sof_rt5682_quirk & SOF_RT5682_MCLK_EN) && (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ)) { - rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER, + rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER | + RT5682_AD_STEREO1_FILTER, RT5682_CLK_SEL_I2S1_ASRC); } From 9d5436250cb3e1f99c7f14741dbf6b646a69efb6 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 9 Jan 2019 16:20:50 +0800 Subject: [PATCH 1140/1995] ALSA: hda: Fix mismatches for register mask and value in hdac controller E.g. for azx_int_enable(), we should set both mask and value to be "AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN"(the mask was 0) to enable controller CIE and GIE. We have similar issues on setting AZX_GCTL_RESET and AZX_GCTL_UNSOL, here try to correct all of them. Signed-off-by: Keyon Jie Signed-off-by: Takashi Iwai (cherry picked from commit 081e01f059ba03b25499cb4616ec58db0979406d) --- sound/hda/hdac_controller.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index 74244d8e290909..b2e9454f5816a0 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -376,7 +376,7 @@ void snd_hdac_bus_exit_link_reset(struct hdac_bus *bus) { unsigned long timeout; - snd_hdac_chip_updateb(bus, GCTL, 0, AZX_GCTL_RESET); + snd_hdac_chip_updateb(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET); timeout = jiffies + msecs_to_jiffies(100); while (!snd_hdac_chip_readb(bus, GCTL) && time_before(jiffies, timeout)) @@ -415,7 +415,7 @@ int snd_hdac_bus_reset_link(struct hdac_bus *bus, bool full_reset) } /* Accept unsolicited responses */ - snd_hdac_chip_updatel(bus, GCTL, 0, AZX_GCTL_UNSOL); + snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL); /* detect codecs */ if (!bus->codec_mask) { @@ -431,7 +431,9 @@ EXPORT_SYMBOL_GPL(snd_hdac_bus_reset_link); static void azx_int_enable(struct hdac_bus *bus) { /* enable controller CIE and GIE */ - snd_hdac_chip_updatel(bus, INTCTL, 0, AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN); + snd_hdac_chip_updatel(bus, INTCTL, + AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN, + AZX_INT_CTRL_EN | AZX_INT_GLOBAL_EN); } /* disable interrupts */ From f28774136aade9c770e16c643165466143653e89 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 14 Jan 2019 23:51:08 +0530 Subject: [PATCH 1141/1995] ALSA: hda: add verbs for stripe control Controllers can support multiple Serial Data Out(SDO) lines, for extended outbound bandwidth, to pump data to all codecs on the link. Codecs can sample data present on SDO. Add verbs AC_VERB_GET_STRIPE_CONTROL and AC_VERB_SET_STRIPE_CONTROL These can be used to program usage of SDO lines for codec. Signed-off-by: Sameer Pujar Reviewed-by: Mohan Kumar D Reviewed-by: Ravindra Lokhande Reviewed-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai (cherry picked from commit e6ce7943231fcba95a3c8842ab65f257cb5ab124) --- include/sound/hda_verbs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sound/hda_verbs.h b/include/sound/hda_verbs.h index 2a8573a00ea60d..e36b77531c5c38 100644 --- a/include/sound/hda_verbs.h +++ b/include/sound/hda_verbs.h @@ -66,6 +66,7 @@ enum { #define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c /* f20: AFG/MFG */ #define AC_VERB_GET_SUBSYSTEM_ID 0x0f20 +#define AC_VERB_GET_STRIPE_CONTROL 0x0f24 #define AC_VERB_GET_CVT_CHAN_COUNT 0x0f2d #define AC_VERB_GET_HDMI_DIP_SIZE 0x0f2e #define AC_VERB_GET_HDMI_ELDD 0x0f2f @@ -110,6 +111,7 @@ enum { #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 0x71f #define AC_VERB_SET_EAPD 0x788 #define AC_VERB_SET_CODEC_RESET 0x7ff +#define AC_VERB_SET_STRIPE_CONTROL 0x724 #define AC_VERB_SET_CVT_CHAN_COUNT 0x72d #define AC_VERB_SET_HDMI_DIP_INDEX 0x730 #define AC_VERB_SET_HDMI_DIP_DATA 0x731 From be84321a3c7369bc4838eee1655d7302ef5ad95b Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 14 Jan 2019 23:51:09 +0530 Subject: [PATCH 1142/1995] ALSA: hda: Add api to program stripe control bits Controllers and codecs can support striping of audio out across multiple SDO lines. The number of supported SDO lines can be specific to chip. GCAP register can be read to know the maximum supported SDO lines. snd_hdac_get_stream_stripe_ctl() is exposed to program stripe bits on controller and codec side. stripe value: 0 for 1SDO, 1 for 2SDO, 2 for 4SDO lines, etc., Signed-off-by: Sameer Pujar Reviewed-by: Mohan Kumar D Reviewed-by: Ravindra Lokhande Reviewed-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai (cherry picked from commit 5dd3d271320d888bb708ca6252b8a9e416a7fe64) --- include/sound/hdaudio.h | 3 +++ sound/hda/hdac_stream.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index b4fa1c7752510b..45f944d5798280 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -539,6 +539,9 @@ void snd_hdac_stream_sync(struct hdac_stream *azx_dev, bool start, unsigned int streams); void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev, unsigned int streams); +int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus, + struct snd_pcm_substream *substream); + /* * macros for easy use */ diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index ba73a33480b66f..820694a2061e95 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -12,6 +12,40 @@ #include #include "trace.h" +/** + * snd_hdac_get_stream_stripe_ctl - get stripe control value + * @bus: HD-audio core bus + * @substream: PCM substream + */ +int snd_hdac_get_stream_stripe_ctl(struct hdac_bus *bus, + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int channels = runtime->channels, + rate = runtime->rate, + bits_per_sample = runtime->sample_bits, + max_sdo_lines, value, sdo_line; + + /* T_AZA_GCAP_NSDO is 1:2 bitfields in GCAP */ + max_sdo_lines = snd_hdac_chip_readl(bus, GCAP) & AZX_GCAP_NSDO; + + /* following is from HD audio spec */ + for (sdo_line = max_sdo_lines; sdo_line > 0; sdo_line >>= 1) { + if (rate > 48000) + value = (channels * bits_per_sample * + (rate / 48000)) / sdo_line; + else + value = (channels * bits_per_sample) / sdo_line; + + if (value >= 8) + break; + } + + /* stripe value: 0 for 1SDO, 1 for 2SDO, 2 for 4SDO lines */ + return sdo_line >> 1; +} +EXPORT_SYMBOL_GPL(snd_hdac_get_stream_stripe_ctl); + /** * snd_hdac_stream_init - initialize each stream (aka device) * @bus: HD-audio core bus From 7a5ca203c928340cae790766fe5990ed2e8f687e Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 14 Jan 2019 23:51:10 +0530 Subject: [PATCH 1143/1995] ALSA: hda: add register offset for stripe control bits 16:17 in SD_CTL register refer to stripe control. Added an offset register(AZX_REG_SD_CTL_3B) to have exclusive read/write of corresponding register byte. This helps to avoid unnecessary 32-bit read/write of SD_CTL whenever only stripe or other bits of corresponding byte need to be updated. Also HD audio spec defines SD_CTL as 3 byte register. SD_CTL_STRIPE_MASK(0x3) can be used for stripe control programming and when updating AZX_REG_SD_CTL_3B. Signed-off-by: Sameer Pujar Reviewed-by: Mohan Kumar D Reviewed-by: Ravindra Lokhande Reviewed-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai (cherry picked from commit b59c8e7a73160b11f99b9008a5f215dd54b9d581) --- include/sound/hda_register.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h index 2ab39fb52d7a12..0fd39295b426b0 100644 --- a/include/sound/hda_register.h +++ b/include/sound/hda_register.h @@ -79,6 +79,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; /* stream register offsets from stream base */ #define AZX_REG_SD_CTL 0x00 +#define AZX_REG_SD_CTL_3B 0x02 /* 3rd byte of SD_CTL register */ #define AZX_REG_SD_STS 0x03 #define AZX_REG_SD_LPIB 0x04 #define AZX_REG_SD_CBL 0x08 @@ -165,6 +166,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define SD_INT_COMPLETE 0x04 /* completion interrupt */ #define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\ SD_INT_COMPLETE) +#define SD_CTL_STRIPE_MASK 0x3 /* stripe control mask */ /* SD_STS */ #define SD_STS_FIFO_READY 0x20 /* FIFO ready */ From a434f4d163ea1b69fdf6836410b22bbf274dc511 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Mon, 14 Jan 2019 23:51:11 +0530 Subject: [PATCH 1144/1995] ALSA: hda: program stripe bits for controller Platforms having multiple SORs and hdmi/dp sinks require higher bandwidth to support simultaneous playbacks of higher resolution. If hda controller supports multiple SDO lines, STRIPE can be used to indicate how many of the SDO lines the stream should be striped across. During stream start stripe control bits are programmed to use given number of sdo lines and the same is cleared during stream stop. Signed-off-by: Sameer Pujar Reviewed-by: Mohan Kumar D Reviewed-by: Ravindra Lokhande Reviewed-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai (cherry picked from commit 9b6f7e7a296e17990aae298c809b001e99ddd151) --- sound/hda/hdac_stream.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index 820694a2061e95..f5dd288d1a7a39 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -82,6 +82,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_stream_init); void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start) { struct hdac_bus *bus = azx_dev->bus; + int stripe_ctl; trace_snd_hdac_stream_start(bus, azx_dev); @@ -93,6 +94,10 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start) snd_hdac_chip_updatel(bus, INTCTL, 1 << azx_dev->index, 1 << azx_dev->index); + /* set stripe control */ + stripe_ctl = snd_hdac_get_stream_stripe_ctl(bus, azx_dev->substream); + snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, + stripe_ctl); /* set DMA start and interrupt mask */ snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_DMA_START | SD_INT_MASK); @@ -109,6 +114,7 @@ void snd_hdac_stream_clear(struct hdac_stream *azx_dev) snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_CTL_DMA_START | SD_INT_MASK, 0); snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ + snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0); azx_dev->running = false; } EXPORT_SYMBOL_GPL(snd_hdac_stream_clear); From da6027defa37b2be3dcc09f090c2ea81d60128a1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 11 Jan 2019 15:58:39 +0100 Subject: [PATCH 1145/1995] ALSA: pcm: Suspend streams globally via device type PM ops Until now we rely on each driver calling snd_pcm_suspend*() explicitly at its own PM handling. However, this can be done far more easily by setting the PM ops to each actual snd_pcm device object. This patch adds the device_type object for PCM stream and assigns to each PCM stream object. The type contains only the PM ops for system suspend; we don't need to deal with the resume in general. The suspend hook simply calls snd_pcm_suspend_all() for the given PCM streams. This implies that the PM order is correctly put, i.e. PCM is suspended before the main (or codec) driver, which should be true in general. If a special ordering is needed, you'd need to adjust the device PM order manually later. This patch introduces a new flag, snd_pcm.no_device_suspend, too. With this flag set, the PCM device object won't invoke snd_pcm_suspend_all() by itself. This is needed for ASoC who wants to manage the PM call orders in its serialized way, and the flag is set in soc_new_pcm() as default. For the non-ASoC world, we can get rid of the manual snd_pcm_suspend calls. This will be done in the later patches. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai (cherry picked from commit 3d21ef0b49f84d3341984caafc5c658739674927) --- include/sound/pcm.h | 1 + sound/core/pcm.c | 26 ++++++++++++++++++++++++++ sound/soc/soc-pcm.c | 1 + 3 files changed, 28 insertions(+) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index d6bd3caf687874..04e97564949c19 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -538,6 +538,7 @@ struct snd_pcm { void (*private_free) (struct snd_pcm *pcm); bool internal; /* pcm is for internal use only */ bool nonatomic; /* whole PCM operations are in non-atomic context */ + bool no_device_suspend; /* don't invoke device PM suspend */ #if IS_ENABLED(CONFIG_SND_PCM_OSS) struct snd_pcm_oss oss; #endif diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 01b9d62eef14db..ca1ea3cf93508e 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -683,6 +683,31 @@ static inline int snd_pcm_substream_proc_done(struct snd_pcm_substream *substrea static const struct attribute_group *pcm_dev_attr_groups[]; +/* + * PM callbacks: we need to deal only with suspend here, as the resume is + * triggered either from user-space or the driver's resume callback + */ +#ifdef CONFIG_PM_SLEEP +static int do_pcm_suspend(struct device *dev) +{ + struct snd_pcm_str *pstr = container_of(dev, struct snd_pcm_str, dev); + + if (!pstr->pcm->no_device_suspend) + snd_pcm_suspend_all(pstr->pcm); + return 0; +} +#endif + +static const struct dev_pm_ops pcm_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(do_pcm_suspend, NULL) +}; + +/* device type for PCM -- basically only for passing PM callbacks */ +static const struct device_type pcm_dev_type = { + .name = "pcm", + .pm = &pcm_dev_pm_ops, +}; + /** * snd_pcm_new_stream - create a new PCM stream * @pcm: the pcm instance @@ -713,6 +738,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) snd_device_initialize(&pstr->dev, pcm->card); pstr->dev.groups = pcm_dev_attr_groups; + pstr->dev.type = &pcm_dev_type; dev_set_name(&pstr->dev, "pcmC%iD%i%c", pcm->card->number, pcm->device, stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c'); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index a5b40e82dea4ac..0d5ec68a1e5086 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -3159,6 +3159,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) } pcm->private_free = soc_pcm_private_free; + pcm->no_device_suspend = true; out: dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name, From 9902a30c01f80b122f055da97ce78205d9e5beb9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 15 Jan 2019 10:54:02 +0100 Subject: [PATCH 1146/1995] ALSA: pcm: Make snd_pcm_suspend() local static snd_pcm_suspend() is no longer called from outside, so let's make it local static. Also drop a superfluous NULL check there. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai (cherry picked from commit ce7f93e2bd6f649980846914e4a04ad6ba141fa6) --- include/sound/pcm.h | 5 ----- sound/core/pcm_native.c | 11 +++-------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 04e97564949c19..2c30c1ad1b0dca 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -582,13 +582,8 @@ int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t status); int snd_pcm_drain_done(struct snd_pcm_substream *substream); int snd_pcm_stop_xrun(struct snd_pcm_substream *substream); #ifdef CONFIG_PM -int snd_pcm_suspend(struct snd_pcm_substream *substream); int snd_pcm_suspend_all(struct snd_pcm *pcm); #else -static inline int snd_pcm_suspend(struct snd_pcm_substream *substream) -{ - return 0; -} static inline int snd_pcm_suspend_all(struct snd_pcm *pcm) { return 0; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index b6e158ce6650de..17d02374f6b809 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1460,29 +1460,24 @@ static const struct action_ops snd_pcm_action_suspend = { .post_action = snd_pcm_post_suspend }; -/** +/* * snd_pcm_suspend - trigger SUSPEND to all linked streams * @substream: the PCM substream * * After this call, all streams are changed to SUSPENDED state. * - * Return: Zero if successful (or @substream is %NULL), or a negative error - * code. + * Return: Zero if successful, or a negative error code. */ -int snd_pcm_suspend(struct snd_pcm_substream *substream) +static int snd_pcm_suspend(struct snd_pcm_substream *substream) { int err; unsigned long flags; - if (! substream) - return 0; - snd_pcm_stream_lock_irqsave(substream, flags); err = snd_pcm_action(&snd_pcm_action_suspend, substream, 0); snd_pcm_stream_unlock_irqrestore(substream, flags); return err; } -EXPORT_SYMBOL(snd_pcm_suspend); /** * snd_pcm_suspend_all - trigger SUSPEND to all substreams in the given pcm From a0236ef08214e25bce9beb299553f295818a95bf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 13 Jan 2019 09:25:42 +0100 Subject: [PATCH 1147/1995] ALSA: pcm: Call snd_card_unref() inside in_pcm_file() The snd_card_unref() call in snd_pcm_link() looks suspicious through a quick glance, but it's a correct usage; this is needed just because the file descriptor check in is_pcm_file() calls the helper snd_lookup_minor_data() that keeps the card refcount. Despite of the correctness, the code still looks confusing. Basically, keeping the card ref for the whole code isn't needed as fdget() blocks the release of the opened file. Hence it's more understandable if snd_card_unref() is moved into is_pcm_file(), then the caller doesn't have to take care after the call. Signed-off-by: Takashi Iwai (cherry picked from commit d819fb21eecc70972c4a3681f2542e1ddcc1ca13) --- sound/core/pcm_native.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 17d02374f6b809..bf2c40722d9455 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1938,13 +1938,19 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream) static bool is_pcm_file(struct file *file) { struct inode *inode = file_inode(file); + struct snd_pcm *pcm; unsigned int minor; if (!S_ISCHR(inode->i_mode) || imajor(inode) != snd_major) return false; minor = iminor(inode); - return snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) || - snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE); + pcm = snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK); + if (!pcm) + pcm = snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE); + if (!pcm) + return false; + snd_card_unref(pcm->card); + return true; } /* @@ -1999,7 +2005,6 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) write_unlock_irq(&snd_pcm_link_rwlock); up_write(&snd_pcm_link_rwsem); _nolock: - snd_card_unref(substream1->pcm->card); kfree(group); _badf: fdput(f); From 17c4df5f691726c6e38fbdefbc709a1f3fa09728 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 13 Jan 2019 09:35:17 +0100 Subject: [PATCH 1148/1995] ALSA: pcm: Unify snd_pcm_group initialization There are multiple open codes that initialize the same object. Create a common helper function instead. Also, use kzalloc() to be safer at creating a group object, and move the initialization out of the critical section. Signed-off-by: Takashi Iwai (cherry picked from commit 73365cb10b280e539bad14e129e0d8434418bb79) --- sound/core/pcm.c | 4 +--- sound/core/pcm_local.h | 1 + sound/core/pcm_native.c | 13 +++++++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index ca1ea3cf93508e..01b583bda82a9d 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -779,9 +779,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) } } substream->group = &substream->self_group; - spin_lock_init(&substream->self_group.lock); - mutex_init(&substream->self_group.mutex); - INIT_LIST_HEAD(&substream->self_group.substreams); + snd_pcm_group_init(&substream->self_group); list_add_tail(&substream->link_list, &substream->self_group.substreams); atomic_set(&substream->mmap_count, 0); prev = substream; diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h index c515612969a474..0b4b5dfaec1819 100644 --- a/sound/core/pcm_local.h +++ b/sound/core/pcm_local.h @@ -66,5 +66,6 @@ static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {} #endif void __snd_pcm_xrun(struct snd_pcm_substream *substream); +void snd_pcm_group_init(struct snd_pcm_group *group); #endif /* __SOUND_CORE_PCM_LOCAL_H */ diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index bf2c40722d9455..19658f73ca9bb4 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -100,6 +100,13 @@ static inline void down_write_nonfifo(struct rw_semaphore *lock) msleep(1); } +void snd_pcm_group_init(struct snd_pcm_group *group) +{ + spin_lock_init(&group->lock); + mutex_init(&group->mutex); + INIT_LIST_HEAD(&group->substreams); +} + #define PCM_LOCK_DEFAULT 0 #define PCM_LOCK_IRQ 1 #define PCM_LOCK_IRQSAVE 2 @@ -1972,11 +1979,12 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) } pcm_file = f.file->private_data; substream1 = pcm_file->substream; - group = kmalloc(sizeof(*group), GFP_KERNEL); + group = kzalloc(sizeof(*group), GFP_KERNEL); if (!group) { res = -ENOMEM; goto _nolock; } + snd_pcm_group_init(group); down_write_nonfifo(&snd_pcm_link_rwsem); write_lock_irq(&snd_pcm_link_rwlock); if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || @@ -1992,9 +2000,6 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) if (!snd_pcm_stream_linked(substream)) { substream->group = group; group = NULL; - spin_lock_init(&substream->group->lock); - mutex_init(&substream->group->mutex); - INIT_LIST_HEAD(&substream->group->substreams); list_add_tail(&substream->link_list, &substream->group->substreams); substream->group->count = 1; } From f7f29b6be888072fc9f80e8847b226bf5d24eae2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 13 Jan 2019 09:40:21 +0100 Subject: [PATCH 1149/1995] ALSA: pcm: Make PCM linked list consistent while re-grouping Make a common helper to re-assign the PCM link using list_move() instead of open code with manual list_del() and list_add_tail(). This assures the consistency and we can get rid of snd_pcm_group.count field -- its purpose is only to check whether the list is singular, and we can know it by list_is_singular() call now. Signed-off-by: Takashi Iwai (cherry picked from commit a41c4cb913b53bf74f1ec66a4b96057626c87009) --- include/sound/pcm.h | 1 - sound/core/pcm_native.c | 34 ++++++++++++++++++++-------------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 2c30c1ad1b0dca..bb2f2871c05219 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -439,7 +439,6 @@ struct snd_pcm_group { /* keep linked substreams */ spinlock_t lock; struct mutex mutex; struct list_head substreams; - int count; }; struct pid; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 19658f73ca9bb4..9945e9c04e9849 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1131,6 +1131,13 @@ static int snd_pcm_action_single(const struct action_ops *ops, return res; } +static void snd_pcm_group_assign(struct snd_pcm_substream *substream, + struct snd_pcm_group *new_group) +{ + substream->group = new_group; + list_move(&substream->link_list, &new_group->substreams); +} + /* * Note: call with stream lock */ @@ -1998,14 +2005,10 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) goto _end; } if (!snd_pcm_stream_linked(substream)) { - substream->group = group; + snd_pcm_group_assign(substream, group); group = NULL; - list_add_tail(&substream->link_list, &substream->group->substreams); - substream->group->count = 1; } - list_add_tail(&substream1->link_list, &substream->group->substreams); - substream->group->count++; - substream1->group = substream->group; + snd_pcm_group_assign(substream1, substream->group); _end: write_unlock_irq(&snd_pcm_link_rwlock); up_write(&snd_pcm_link_rwsem); @@ -2018,14 +2021,13 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) static void relink_to_local(struct snd_pcm_substream *substream) { - substream->group = &substream->self_group; - INIT_LIST_HEAD(&substream->self_group.substreams); - list_add_tail(&substream->link_list, &substream->self_group.substreams); + snd_pcm_group_assign(substream, &substream->self_group); } static int snd_pcm_unlink(struct snd_pcm_substream *substream) { struct snd_pcm_substream *s; + struct snd_pcm_group *group; int res = 0; down_write_nonfifo(&snd_pcm_link_rwsem); @@ -2034,16 +2036,20 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream) res = -EALREADY; goto _end; } - list_del(&substream->link_list); - substream->group->count--; - if (substream->group->count == 1) { /* detach the last stream, too */ + + group = substream->group; + + relink_to_local(substream); + + /* detach the last stream, too */ + if (list_is_singular(&group->substreams)) { snd_pcm_group_for_each_entry(s, substream) { relink_to_local(s); break; } - kfree(substream->group); + kfree(group); } - relink_to_local(substream); + _end: write_unlock_irq(&snd_pcm_link_rwlock); up_write(&snd_pcm_link_rwsem); From 3032a9fc3e0f67d7add4dfb2debfc0078868e004 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 13 Jan 2019 10:19:32 +0100 Subject: [PATCH 1150/1995] ALSA: pcm: Avoid confusing loop in snd_pcm_unlink() The snd_pcm_group_for_each_entry() loop found in snd_pcm_unlink() is only for taking the first list entry. Use list_first_entry() to make clearer. Signed-off-by: Takashi Iwai (cherry picked from commit 7df5a5f66b8fc2cd51649b3f1b0b88dc59c49d2d) --- sound/core/pcm_native.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 9945e9c04e9849..bd752326e13ab3 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2026,7 +2026,6 @@ static void relink_to_local(struct snd_pcm_substream *substream) static int snd_pcm_unlink(struct snd_pcm_substream *substream) { - struct snd_pcm_substream *s; struct snd_pcm_group *group; int res = 0; @@ -2043,10 +2042,9 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream) /* detach the last stream, too */ if (list_is_singular(&group->substreams)) { - snd_pcm_group_for_each_entry(s, substream) { - relink_to_local(s); - break; - } + relink_to_local(list_first_entry(&group->substreams, + struct snd_pcm_substream, + link_list)); kfree(group); } From 2db9aed485c6d3421300020c05e3b86b91b6a8bb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 13 Jan 2019 09:50:33 +0100 Subject: [PATCH 1151/1995] ALSA: pcm: More fine-grained PCM link locking We have currently two global locks, a rwlock and a rwsem, that are used for managing linking the PCM streams. Due to these global locks, once when a linked stream is used, the lock granularity suffers a lot. This patch attempts to eliminate the former global lock for atomic ops. The latter rwsem needs remaining because of the loosy way of the loop calls in snd_pcm_action_nonatomic(), as well as for avoiding the deadlock at linking. However, these are used far rarely, actually only by two actions (prepare and reset), where both are no timing critical ones. So this can be still seen as a good improvement. The basic strategy to eliminate the rwlock is to assure group->lock at adding or removing a stream to / from the group. Since we already takes the group lock whenever taking the all substream locks under the group, this shouldn't be a big problem. The reference to group pointer in snd_pcm_substream object is protected by the stream lock itself. However, there are still pitfalls: a race window at re-locking and the lifecycle of group object. The former is a small race window for dereferencing the substream group object opened while snd_pcm_action() performs re-locking to avoid ABBA deadlocks. This includes the unlink of group during that window, too. And the latter is the kfree performed after all streams are removed from the group while it's still dereferenced. For addressing these corner cases, two new tricks are introduced: - After re-locking, the group assigned to the stream is checked again; if the group is changed, we retry the whole procedure. - Introduce a refcount to snd_pcm_group object, so that it's freed only when it's empty and really no one refers to it. (Some readers might wonder why not RCU for the latter. RCU in this case would cost more than refcounting, unfortunately. We take the group lock sooner or later, hence the performance improvement by RCU would be negligible. Meanwhile, because we need to deal with schedulable context depending on the pcm->nonatomic flag, it'll become dynamic RCU/SRCU switch, and the grace period may become too long.) Along with these changes, there are a significant amount of code refactoring. The complex group re-lock & ref code is factored out to snd_pcm_stream_group_ref() function, for example. Signed-off-by: Takashi Iwai (cherry picked from commit f57f3df03a8e6010e321fa0258d3e054713c3cb7) --- include/sound/pcm.h | 2 + sound/core/pcm_native.c | 166 +++++++++++++++++++++++++++++----------- 2 files changed, 124 insertions(+), 44 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index bb2f2871c05219..d03132d8c00da4 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -30,6 +30,7 @@ #include #include #include +#include #define snd_pcm_substream_chip(substream) ((substream)->private_data) #define snd_pcm_chip(pcm) ((pcm)->private_data) @@ -439,6 +440,7 @@ struct snd_pcm_group { /* keep linked substreams */ spinlock_t lock; struct mutex mutex; struct list_head substreams; + refcount_t refs; }; struct pid; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index bd752326e13ab3..ef77109c0ad1e9 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -85,7 +85,6 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream); * */ -static DEFINE_RWLOCK(snd_pcm_link_rwlock); static DECLARE_RWSEM(snd_pcm_link_rwsem); /* Writer in rwsem may block readers even during its waiting in queue, @@ -105,8 +104,24 @@ void snd_pcm_group_init(struct snd_pcm_group *group) spin_lock_init(&group->lock); mutex_init(&group->mutex); INIT_LIST_HEAD(&group->substreams); + refcount_set(&group->refs, 0); } +/* define group lock helpers */ +#define DEFINE_PCM_GROUP_LOCK(action, mutex_action) \ +static void snd_pcm_group_ ## action(struct snd_pcm_group *group, bool nonatomic) \ +{ \ + if (nonatomic) \ + mutex_ ## mutex_action(&group->mutex); \ + else \ + spin_ ## action(&group->lock); \ +} + +DEFINE_PCM_GROUP_LOCK(lock, lock); +DEFINE_PCM_GROUP_LOCK(unlock, unlock); +DEFINE_PCM_GROUP_LOCK(lock_irq, lock); +DEFINE_PCM_GROUP_LOCK(unlock_irq, unlock); + #define PCM_LOCK_DEFAULT 0 #define PCM_LOCK_IRQ 1 #define PCM_LOCK_IRQSAVE 2 @@ -116,21 +131,19 @@ static unsigned long __snd_pcm_stream_lock_mode(struct snd_pcm_substream *substr { unsigned long flags = 0; if (substream->pcm->nonatomic) { - down_read_nested(&snd_pcm_link_rwsem, SINGLE_DEPTH_NESTING); mutex_lock(&substream->self_group.mutex); } else { switch (mode) { case PCM_LOCK_DEFAULT: - read_lock(&snd_pcm_link_rwlock); + spin_lock(&substream->self_group.lock); break; case PCM_LOCK_IRQ: - read_lock_irq(&snd_pcm_link_rwlock); + spin_lock_irq(&substream->self_group.lock); break; case PCM_LOCK_IRQSAVE: - read_lock_irqsave(&snd_pcm_link_rwlock, flags); + spin_lock_irqsave(&substream->self_group.lock, flags); break; } - spin_lock(&substream->self_group.lock); } return flags; } @@ -140,19 +153,16 @@ static void __snd_pcm_stream_unlock_mode(struct snd_pcm_substream *substream, { if (substream->pcm->nonatomic) { mutex_unlock(&substream->self_group.mutex); - up_read(&snd_pcm_link_rwsem); } else { - spin_unlock(&substream->self_group.lock); - switch (mode) { case PCM_LOCK_DEFAULT: - read_unlock(&snd_pcm_link_rwlock); + spin_unlock(&substream->self_group.lock); break; case PCM_LOCK_IRQ: - read_unlock_irq(&snd_pcm_link_rwlock); + spin_unlock_irq(&substream->self_group.lock); break; case PCM_LOCK_IRQSAVE: - read_unlock_irqrestore(&snd_pcm_link_rwlock, flags); + spin_unlock_irqrestore(&substream->self_group.lock, flags); break; } } @@ -1138,6 +1148,61 @@ static void snd_pcm_group_assign(struct snd_pcm_substream *substream, list_move(&substream->link_list, &new_group->substreams); } +/* + * Unref and unlock the group, but keep the stream lock; + * when the group becomes empty and no longer referred, destroy itself + */ +static void snd_pcm_group_unref(struct snd_pcm_group *group, + struct snd_pcm_substream *substream) +{ + bool do_free; + + if (!group) + return; + do_free = refcount_dec_and_test(&group->refs) && + list_empty(&group->substreams); + snd_pcm_group_unlock(group, substream->pcm->nonatomic); + if (do_free) + kfree(group); +} + +/* + * Lock the group inside a stream lock and reference it; + * return the locked group object, or NULL if not linked + */ +static struct snd_pcm_group * +snd_pcm_stream_group_ref(struct snd_pcm_substream *substream) +{ + bool nonatomic = substream->pcm->nonatomic; + struct snd_pcm_group *group; + bool trylock; + + for (;;) { + if (!snd_pcm_stream_linked(substream)) + return NULL; + group = substream->group; + /* block freeing the group object */ + refcount_inc(&group->refs); + + trylock = nonatomic ? mutex_trylock(&group->mutex) : + spin_trylock(&group->lock); + if (trylock) + break; /* OK */ + + /* re-lock for avoiding ABBA deadlock */ + snd_pcm_stream_unlock(substream); + snd_pcm_group_lock(group, nonatomic); + snd_pcm_stream_lock(substream); + + /* check the group again; the above opens a small race window */ + if (substream->group == group) + break; /* OK */ + /* group changed, try again */ + snd_pcm_group_unref(group, substream); + } + return group; +} + /* * Note: call with stream lock */ @@ -1145,28 +1210,15 @@ static int snd_pcm_action(const struct action_ops *ops, struct snd_pcm_substream *substream, int state) { + struct snd_pcm_group *group; int res; - if (!snd_pcm_stream_linked(substream)) - return snd_pcm_action_single(ops, substream, state); - - if (substream->pcm->nonatomic) { - if (!mutex_trylock(&substream->group->mutex)) { - mutex_unlock(&substream->self_group.mutex); - mutex_lock(&substream->group->mutex); - mutex_lock(&substream->self_group.mutex); - } + group = snd_pcm_stream_group_ref(substream); + if (group) res = snd_pcm_action_group(ops, substream, state, 1); - mutex_unlock(&substream->group->mutex); - } else { - if (!spin_trylock(&substream->group->lock)) { - spin_unlock(&substream->self_group.lock); - spin_lock(&substream->group->lock); - spin_lock(&substream->self_group.lock); - } - res = snd_pcm_action_group(ops, substream, state, 1); - spin_unlock(&substream->group->lock); - } + else + res = snd_pcm_action_single(ops, substream, state); + snd_pcm_group_unref(group, substream); return res; } @@ -1193,6 +1245,7 @@ static int snd_pcm_action_nonatomic(const struct action_ops *ops, { int res; + /* Guarantee the group members won't change during non-atomic action */ down_read(&snd_pcm_link_rwsem); if (snd_pcm_stream_linked(substream)) res = snd_pcm_action_group(ops, substream, state, 0); @@ -1824,6 +1877,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, struct snd_card *card; struct snd_pcm_runtime *runtime; struct snd_pcm_substream *s; + struct snd_pcm_group *group; wait_queue_entry_t wait; int result = 0; int nonblock = 0; @@ -1840,7 +1894,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, } else if (substream->f_flags & O_NONBLOCK) nonblock = 1; - down_read(&snd_pcm_link_rwsem); snd_pcm_stream_lock_irq(substream); /* resume pause */ if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) @@ -1865,6 +1918,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, } /* find a substream to drain */ to_check = NULL; + group = snd_pcm_stream_group_ref(substream); snd_pcm_group_for_each_entry(s, substream) { if (s->stream != SNDRV_PCM_STREAM_PLAYBACK) continue; @@ -1874,12 +1928,12 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, break; } } + snd_pcm_group_unref(group, substream); if (!to_check) break; /* all drained */ init_waitqueue_entry(&wait, current); add_wait_queue(&to_check->sleep, &wait); snd_pcm_stream_unlock_irq(substream); - up_read(&snd_pcm_link_rwsem); if (runtime->no_period_wakeup) tout = MAX_SCHEDULE_TIMEOUT; else { @@ -1891,9 +1945,17 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, tout = msecs_to_jiffies(tout * 1000); } tout = schedule_timeout_interruptible(tout); - down_read(&snd_pcm_link_rwsem); + snd_pcm_stream_lock_irq(substream); - remove_wait_queue(&to_check->sleep, &wait); + group = snd_pcm_stream_group_ref(substream); + snd_pcm_group_for_each_entry(s, substream) { + if (s->runtime == to_check) { + remove_wait_queue(&to_check->sleep, &wait); + break; + } + } + snd_pcm_group_unref(group, substream); + if (card->shutdown) { result = -ENODEV; break; @@ -1913,7 +1975,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream, unlock: snd_pcm_stream_unlock_irq(substream); - up_read(&snd_pcm_link_rwsem); return result; } @@ -1975,7 +2036,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) int res = 0; struct snd_pcm_file *pcm_file; struct snd_pcm_substream *substream1; - struct snd_pcm_group *group; + struct snd_pcm_group *group, *target_group; + bool nonatomic = substream->pcm->nonatomic; struct fd f = fdget(fd); if (!f.file) @@ -1992,8 +2054,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) goto _nolock; } snd_pcm_group_init(group); + down_write_nonfifo(&snd_pcm_link_rwsem); - write_lock_irq(&snd_pcm_link_rwlock); if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || substream->runtime->status->state != substream1->runtime->status->state || substream->pcm->nonatomic != substream1->pcm->nonatomic) { @@ -2004,13 +2066,21 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) res = -EALREADY; goto _end; } + + snd_pcm_stream_lock_irq(substream); if (!snd_pcm_stream_linked(substream)) { snd_pcm_group_assign(substream, group); - group = NULL; + group = NULL; /* assigned, don't free this one below */ } - snd_pcm_group_assign(substream1, substream->group); + target_group = substream->group; + snd_pcm_stream_unlock_irq(substream); + + snd_pcm_group_lock_irq(target_group, nonatomic); + snd_pcm_stream_lock(substream1); + snd_pcm_group_assign(substream1, target_group); + snd_pcm_stream_unlock(substream1); + snd_pcm_group_unlock_irq(target_group, nonatomic); _end: - write_unlock_irq(&snd_pcm_link_rwlock); up_write(&snd_pcm_link_rwsem); _nolock: kfree(group); @@ -2021,22 +2091,27 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) static void relink_to_local(struct snd_pcm_substream *substream) { + snd_pcm_stream_lock(substream); snd_pcm_group_assign(substream, &substream->self_group); + snd_pcm_stream_unlock(substream); } static int snd_pcm_unlink(struct snd_pcm_substream *substream) { struct snd_pcm_group *group; + bool nonatomic = substream->pcm->nonatomic; + bool do_free = false; int res = 0; down_write_nonfifo(&snd_pcm_link_rwsem); - write_lock_irq(&snd_pcm_link_rwlock); + if (!snd_pcm_stream_linked(substream)) { res = -EALREADY; goto _end; } group = substream->group; + snd_pcm_group_lock_irq(group, nonatomic); relink_to_local(substream); @@ -2045,11 +2120,14 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream) relink_to_local(list_first_entry(&group->substreams, struct snd_pcm_substream, link_list)); - kfree(group); + do_free = !refcount_read(&group->refs); } + snd_pcm_group_unlock_irq(group, nonatomic); + if (do_free) + kfree(group); + _end: - write_unlock_irq(&snd_pcm_link_rwlock); up_write(&snd_pcm_link_rwsem); return res; } From 30f35c9d7fa7fc421c8cbfc4acae9ea84ace1677 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 22 Jan 2019 14:29:51 +0100 Subject: [PATCH 1152/1995] ALSA: pcm: Remove down_write() hack for snd_pcm_link_rwsem Remove the hackish down_write_nonfifo() that was introduced as a workaround of rwsem deadlock. It used to be a problem for non-atomic PCM streams that take the rwsem for the locking and hit the high lock contention. Since the current PCM locking refactoring, we'll no longer hit it as the hot code-paths don't take global locks. Signed-off-by: Takashi Iwai (cherry picked from commit ecb41f0f44cadfa90ef9acff3ffe95563274ec1c) --- sound/core/pcm_native.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index ef77109c0ad1e9..026ab05dff5953 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -87,18 +87,6 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream); static DECLARE_RWSEM(snd_pcm_link_rwsem); -/* Writer in rwsem may block readers even during its waiting in queue, - * and this may lead to a deadlock when the code path takes read sem - * twice (e.g. one in snd_pcm_action_nonatomic() and another in - * snd_pcm_stream_lock()). As a (suboptimal) workaround, let writer to - * sleep until all the readers are completed without blocking by writer. - */ -static inline void down_write_nonfifo(struct rw_semaphore *lock) -{ - while (!down_write_trylock(lock)) - msleep(1); -} - void snd_pcm_group_init(struct snd_pcm_group *group) { spin_lock_init(&group->lock); @@ -2055,7 +2043,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) } snd_pcm_group_init(group); - down_write_nonfifo(&snd_pcm_link_rwsem); + down_write(&snd_pcm_link_rwsem); if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || substream->runtime->status->state != substream1->runtime->status->state || substream->pcm->nonatomic != substream1->pcm->nonatomic) { @@ -2103,7 +2091,7 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream) bool do_free = false; int res = 0; - down_write_nonfifo(&snd_pcm_link_rwsem); + down_write(&snd_pcm_link_rwsem); if (!snd_pcm_stream_linked(substream)) { res = -EALREADY; From d55d6d826602993df1c7d2be58eb3864f815ec51 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sun, 13 Jan 2019 10:15:03 +0100 Subject: [PATCH 1153/1995] ALSA: pcm: Cleanup snd_pcm_stream_lock() & co After the previous code refactoring, the PCM stream locking code became nothing but the PCM group lock with self_group object. Use the existing helper function for simplifying the code. Signed-off-by: Takashi Iwai (cherry picked from commit ef2056b8f3945c78cc5a3a3ba7592e18a757ffd9) --- sound/core/pcm_native.c | 68 ++++++++++------------------------------- 1 file changed, 16 insertions(+), 52 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 026ab05dff5953..7fd84520af0a9e 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -110,52 +110,6 @@ DEFINE_PCM_GROUP_LOCK(unlock, unlock); DEFINE_PCM_GROUP_LOCK(lock_irq, lock); DEFINE_PCM_GROUP_LOCK(unlock_irq, unlock); -#define PCM_LOCK_DEFAULT 0 -#define PCM_LOCK_IRQ 1 -#define PCM_LOCK_IRQSAVE 2 - -static unsigned long __snd_pcm_stream_lock_mode(struct snd_pcm_substream *substream, - unsigned int mode) -{ - unsigned long flags = 0; - if (substream->pcm->nonatomic) { - mutex_lock(&substream->self_group.mutex); - } else { - switch (mode) { - case PCM_LOCK_DEFAULT: - spin_lock(&substream->self_group.lock); - break; - case PCM_LOCK_IRQ: - spin_lock_irq(&substream->self_group.lock); - break; - case PCM_LOCK_IRQSAVE: - spin_lock_irqsave(&substream->self_group.lock, flags); - break; - } - } - return flags; -} - -static void __snd_pcm_stream_unlock_mode(struct snd_pcm_substream *substream, - unsigned int mode, unsigned long flags) -{ - if (substream->pcm->nonatomic) { - mutex_unlock(&substream->self_group.mutex); - } else { - switch (mode) { - case PCM_LOCK_DEFAULT: - spin_unlock(&substream->self_group.lock); - break; - case PCM_LOCK_IRQ: - spin_unlock_irq(&substream->self_group.lock); - break; - case PCM_LOCK_IRQSAVE: - spin_unlock_irqrestore(&substream->self_group.lock, flags); - break; - } - } -} - /** * snd_pcm_stream_lock - Lock the PCM stream * @substream: PCM substream @@ -166,7 +120,7 @@ static void __snd_pcm_stream_unlock_mode(struct snd_pcm_substream *substream, */ void snd_pcm_stream_lock(struct snd_pcm_substream *substream) { - __snd_pcm_stream_lock_mode(substream, PCM_LOCK_DEFAULT); + snd_pcm_group_lock(&substream->self_group, substream->pcm->nonatomic); } EXPORT_SYMBOL_GPL(snd_pcm_stream_lock); @@ -178,7 +132,7 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_lock); */ void snd_pcm_stream_unlock(struct snd_pcm_substream *substream) { - __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_DEFAULT, 0); + snd_pcm_group_unlock(&substream->self_group, substream->pcm->nonatomic); } EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock); @@ -192,7 +146,8 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock); */ void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream) { - __snd_pcm_stream_lock_mode(substream, PCM_LOCK_IRQ); + snd_pcm_group_lock_irq(&substream->self_group, + substream->pcm->nonatomic); } EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq); @@ -204,13 +159,19 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq); */ void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream) { - __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_IRQ, 0); + snd_pcm_group_unlock_irq(&substream->self_group, + substream->pcm->nonatomic); } EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irq); unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream) { - return __snd_pcm_stream_lock_mode(substream, PCM_LOCK_IRQSAVE); + unsigned long flags = 0; + if (substream->pcm->nonatomic) + mutex_lock(&substream->self_group.mutex); + else + spin_lock_irqsave(&substream->self_group.lock, flags); + return flags; } EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave); @@ -224,7 +185,10 @@ EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave); void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, unsigned long flags) { - __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_IRQSAVE, flags); + if (substream->pcm->nonatomic) + mutex_unlock(&substream->self_group.mutex); + else + spin_unlock_irqrestore(&substream->self_group.lock, flags); } EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); From a361e77c07ccd0739849f2f520965bf170230dbe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 23 Jan 2019 12:47:34 +0100 Subject: [PATCH 1154/1995] ALSA: pcm: Drop unused snd_pcm_substream.file field It's assigned but nowhere used. Let's remove it. Signed-off-by: Takashi Iwai (cherry picked from commit de89750c56f4bf2f04492c6ce298911381a7597a) --- include/sound/pcm.h | 1 - sound/core/oss/pcm_oss.c | 1 - sound/core/pcm_native.c | 4 +--- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index d03132d8c00da4..17c30e70bfb0a1 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -471,7 +471,6 @@ struct snd_pcm_substream { struct snd_pcm_group self_group; /* fake group for non linked substream (with substream lock inside) */ struct snd_pcm_group *group; /* pointer to current group */ /* -- assigned files -- */ - void *file; int ref_count; atomic_t mmap_count; unsigned int f_flags; diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 467039b342b511..d5b0d7ba83c420 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -2427,7 +2427,6 @@ static int snd_pcm_oss_open_file(struct file *file, } pcm_oss_file->streams[idx] = substream; - substream->file = pcm_oss_file; snd_pcm_oss_init_substream(substream, &setup[idx], minor); } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 7fd84520af0a9e..0c2816a555bf58 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2504,10 +2504,8 @@ static int snd_pcm_open_file(struct file *file, return -ENOMEM; } pcm_file->substream = substream; - if (substream->ref_count == 1) { - substream->file = pcm_file; + if (substream->ref_count == 1) substream->pcm_release = pcm_release_private; - } file->private_data = pcm_file; return 0; From b0c07a8a65627514b58de3592f43a6af2be00b3a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 23 Jan 2019 16:44:38 +0100 Subject: [PATCH 1155/1995] ALSA: pcm: Simplify proc file destruction The proc files are recursively freed by calling with the root snd_info_entry object, so we don't have to keep each object for releasing one by one. Move the release of the PCM stream proc root at the beginning, so that we can remove the redundant code and resource. Signed-off-by: Takashi Iwai (cherry picked from commit 480e32ebd524ffdf3d50cc5cac179fb9e44a552d) --- include/sound/pcm.h | 11 ------- sound/core/pcm.c | 66 +++++++---------------------------------- sound/core/pcm_memory.c | 16 ++-------- 3 files changed, 13 insertions(+), 80 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 17c30e70bfb0a1..ca20f80f8976aa 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -482,15 +482,6 @@ struct snd_pcm_substream { #endif #ifdef CONFIG_SND_VERBOSE_PROCFS struct snd_info_entry *proc_root; - struct snd_info_entry *proc_info_entry; - struct snd_info_entry *proc_hw_params_entry; - struct snd_info_entry *proc_sw_params_entry; - struct snd_info_entry *proc_status_entry; - struct snd_info_entry *proc_prealloc_entry; - struct snd_info_entry *proc_prealloc_max_entry; -#ifdef CONFIG_SND_PCM_XRUN_DEBUG - struct snd_info_entry *proc_xrun_injection_entry; -#endif #endif /* CONFIG_SND_VERBOSE_PROCFS */ /* misc flags */ unsigned int hw_opened: 1; @@ -512,10 +503,8 @@ struct snd_pcm_str { #endif #ifdef CONFIG_SND_VERBOSE_PROCFS struct snd_info_entry *proc_root; - struct snd_info_entry *proc_info_entry; #ifdef CONFIG_SND_PCM_XRUN_DEBUG unsigned int xrun_debug; /* 0 = disabled, 1 = verbose, 2 = stacktrace */ - struct snd_info_entry *proc_xrun_debug_entry; #endif #endif struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */ diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 01b583bda82a9d..4f45b30003472f 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -536,12 +536,9 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root); if (entry) { snd_info_set_text_ops(entry, pstr, snd_pcm_stream_proc_info_read); - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - pstr->proc_info_entry = entry; #ifdef CONFIG_SND_PCM_XRUN_DEBUG entry = snd_info_create_card_entry(pcm->card, "xrun_debug", @@ -551,24 +548,15 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) entry->c.text.write = snd_pcm_xrun_debug_write; entry->mode |= 0200; entry->private_data = pstr; - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - pstr->proc_xrun_debug_entry = entry; #endif return 0; } static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) { -#ifdef CONFIG_SND_PCM_XRUN_DEBUG - snd_info_free_entry(pstr->proc_xrun_debug_entry); - pstr->proc_xrun_debug_entry = NULL; -#endif - snd_info_free_entry(pstr->proc_info_entry); - pstr->proc_info_entry = NULL; snd_info_free_entry(pstr->proc_root); pstr->proc_root = NULL; return 0; @@ -597,45 +585,33 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) if (entry) { snd_info_set_text_ops(entry, substream, snd_pcm_substream_proc_info_read); - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - substream->proc_info_entry = entry; entry = snd_info_create_card_entry(card, "hw_params", substream->proc_root); if (entry) { snd_info_set_text_ops(entry, substream, snd_pcm_substream_proc_hw_params_read); - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - substream->proc_hw_params_entry = entry; entry = snd_info_create_card_entry(card, "sw_params", substream->proc_root); if (entry) { snd_info_set_text_ops(entry, substream, snd_pcm_substream_proc_sw_params_read); - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - substream->proc_sw_params_entry = entry; entry = snd_info_create_card_entry(card, "status", substream->proc_root); if (entry) { snd_info_set_text_ops(entry, substream, snd_pcm_substream_proc_status_read); - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - substream->proc_status_entry = entry; #ifdef CONFIG_SND_PCM_XRUN_DEBUG entry = snd_info_create_card_entry(card, "xrun_injection", @@ -645,40 +621,18 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) entry->c.text.read = NULL; entry->c.text.write = snd_pcm_xrun_injection_write; entry->mode = S_IFREG | 0200; - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - substream->proc_xrun_injection_entry = entry; #endif /* CONFIG_SND_PCM_XRUN_DEBUG */ return 0; } -static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) -{ - snd_info_free_entry(substream->proc_info_entry); - substream->proc_info_entry = NULL; - snd_info_free_entry(substream->proc_hw_params_entry); - substream->proc_hw_params_entry = NULL; - snd_info_free_entry(substream->proc_sw_params_entry); - substream->proc_sw_params_entry = NULL; - snd_info_free_entry(substream->proc_status_entry); - substream->proc_status_entry = NULL; -#ifdef CONFIG_SND_PCM_XRUN_DEBUG - snd_info_free_entry(substream->proc_xrun_injection_entry); - substream->proc_xrun_injection_entry = NULL; -#endif - snd_info_free_entry(substream->proc_root); - substream->proc_root = NULL; - return 0; -} #else /* !CONFIG_SND_VERBOSE_PROCFS */ static inline int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) { return 0; } static inline int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) { return 0; } static inline int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) { return 0; } -static inline int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) { return 0; } #endif /* CONFIG_SND_VERBOSE_PROCFS */ static const struct attribute_group *pcm_dev_attr_groups[]; @@ -909,15 +863,17 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr) #if IS_ENABLED(CONFIG_SND_PCM_OSS) struct snd_pcm_oss_setup *setup, *setupn; #endif + + /* free all proc files under the stream */ + snd_pcm_stream_proc_done(pstr); + substream = pstr->substream; while (substream) { substream_next = substream->next; snd_pcm_timer_done(substream); - snd_pcm_substream_proc_done(substream); kfree(substream); substream = substream_next; } - snd_pcm_stream_proc_done(pstr); #if IS_ENABLED(CONFIG_SND_PCM_OSS) for (setup = pstr->oss.setup_list; setup; setup = setupn) { setupn = setup->next; diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 4b5356a1031599..9a98bc61461fe4 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -93,12 +93,6 @@ static void snd_pcm_lib_preallocate_dma_free(struct snd_pcm_substream *substream int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream) { snd_pcm_lib_preallocate_dma_free(substream); -#ifdef CONFIG_SND_VERBOSE_PROCFS - snd_info_free_entry(substream->proc_prealloc_max_entry); - substream->proc_prealloc_max_entry = NULL; - snd_info_free_entry(substream->proc_prealloc_entry); - substream->proc_prealloc_entry = NULL; -#endif return 0; } @@ -203,21 +197,15 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream) entry->c.text.write = snd_pcm_lib_preallocate_proc_write; entry->mode |= 0200; entry->private_data = substream; - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - substream->proc_prealloc_entry = entry; if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max", substream->proc_root)) != NULL) { entry->c.text.read = snd_pcm_lib_preallocate_max_proc_read; entry->private_data = substream; - if (snd_info_register(entry) < 0) { + if (snd_info_register(entry) < 0) snd_info_free_entry(entry); - entry = NULL; - } } - substream->proc_prealloc_max_entry = entry; } #else /* !CONFIG_SND_VERBOSE_PROCFS */ From 65099dbb6158f066c8723467a2796cae02fa6de0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 23 Jan 2019 17:59:40 +0100 Subject: [PATCH 1156/1995] ALSA: proc: Avoid possible leaks of snd_info_entry objects This patch changes the parent pointer assignment of snd_info_entry object to be always non-NULL. More specifically,check the parent argument in snd_info_create_module_entry() & co, and assign snd_proc_root if NULL is passed there. This assures that the proc object is always freed when the root is freed, so avoid possible memory leaks. For example, some error paths (e.g. snd_info_register() error at snd_minor_info_init()) may leave snd_info_entry object although the proc file itself is freed. Signed-off-by: Takashi Iwai (cherry picked from commit 3a55437141a1d287dead685b37fe240185144f15) --- sound/core/info.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sound/core/info.c b/sound/core/info.c index fe502bc5e6d20e..2dfb6389c084eb 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -741,7 +741,11 @@ struct snd_info_entry *snd_info_create_module_entry(struct module * module, const char *name, struct snd_info_entry *parent) { - struct snd_info_entry *entry = snd_info_create_entry(name, parent); + struct snd_info_entry *entry; + + if (!parent) + parent = snd_proc_root; + entry = snd_info_create_entry(name, parent); if (entry) entry->module = module; return entry; @@ -762,7 +766,11 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, const char *name, struct snd_info_entry * parent) { - struct snd_info_entry *entry = snd_info_create_entry(name, parent); + struct snd_info_entry *entry; + + if (!parent) + parent = card->proc_root; + entry = snd_info_create_entry(name, parent); if (entry) { entry->module = card->module; entry->card = card; From 4550dc5d4889d7d58cdc689299bc6b3f41195c6a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 25 Jan 2019 17:31:59 +0100 Subject: [PATCH 1157/1995] ALSA: pcm: Use the common error path in __snd_pcm_lib_xfer() An open-coded error path in __snd_pcm_lib_xfer() can be replaced with the simple goto to the common error path. This also makes the error handling more consistent, i.e. when some samples have been already processed, return that size instead of the error code. Signed-off-by: Takashi Iwai (cherry picked from commit 315d9f1bee40b20d399176acb1e27036abbd4384) --- sound/core/pcm_lib.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 6c0b30391ba99c..bcb06bd3d81d17 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2214,9 +2214,8 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, if (frames > cont) frames = cont; if (snd_BUG_ON(!frames)) { - runtime->twake = 0; - snd_pcm_stream_unlock_irq(substream); - return -EINVAL; + err = -EINVAL; + goto _end_unlock; } snd_pcm_stream_unlock_irq(substream); err = writer(substream, appl_ofs, data, offset, frames, From 96ecf9c43e47397b61589dbda6191e5c0a61b699 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 30 Jan 2019 17:22:39 +0100 Subject: [PATCH 1158/1995] ALSA: pcm: remove a superfluous function declaration Declaration of snd_pcm_drop() in sound/core/pcm_native.c is superfluous since the function isn't called before being defined. Remove the declaration. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Takashi Iwai (cherry picked from commit 515548fdd8a3c579535fe05e3c39558f75158bc5) --- sound/core/pcm_native.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 0c2816a555bf58..f731f904e8ccb4 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1814,8 +1814,6 @@ static const struct action_ops snd_pcm_action_drain_init = { .post_action = snd_pcm_post_drain_init }; -static int snd_pcm_drop(struct snd_pcm_substream *substream); - /* * Drain the stream(s). * When the substream is linked, sync until the draining of all playback streams From 7545d04124ce1532ff71e87151f36a38dc919c86 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 1 Feb 2019 12:14:53 +0100 Subject: [PATCH 1159/1995] ALSA: isa: Avoid passing NULL to memory allocators We used to pass NULL to memory allocators for ISA devices due to historical reasons. But we prefer rather a proper device object to be assigned, so let's fix it by replacing snd_dma_isa_data() call with card->dev reference, and kill snd_dma_isa_data() definition. Reviewed-by: Christoph Hellwig Signed-off-by: Takashi Iwai (cherry picked from commit 0b6a2c9cf4a00f54a0916499ece8a5cf3cced385) --- .../sound/kernel-api/writing-an-alsa-driver.rst | 10 +++++----- include/sound/memalloc.h | 1 - sound/isa/ad1816a/ad1816a_lib.c | 2 +- sound/isa/cmi8330.c | 2 +- sound/isa/es1688/es1688_lib.c | 2 +- sound/isa/es18xx.c | 2 +- sound/isa/gus/gus_pcm.c | 4 ++-- sound/isa/sb/sb16_main.c | 2 +- sound/isa/sb/sb8_main.c | 2 +- sound/isa/sscape.c | 7 ++++--- sound/isa/wss/wss_lib.c | 2 +- 11 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst index b37234afdfa1cd..288fcf9bcca1fb 100644 --- a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst +++ b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst @@ -3520,14 +3520,14 @@ allocator will try to get an area as large as possible within the given size. The second argument (type) and the third argument (device pointer) are -dependent on the bus. In the case of the ISA bus, pass -:c:func:`snd_dma_isa_data()` as the third argument with +dependent on the bus. For normal devices, pass the device pointer +(typically identical as ``card->dev``) to the third argument with ``SNDRV_DMA_TYPE_DEV`` type. For the continuous buffer unrelated to the bus can be pre-allocated with ``SNDRV_DMA_TYPE_CONTINUOUS`` type and the ``snd_dma_continuous_data(GFP_KERNEL)`` device pointer, where -``GFP_KERNEL`` is the kernel allocation flag to use. For the PCI -scatter-gather buffers, use ``SNDRV_DMA_TYPE_DEV_SG`` with -``snd_dma_pci_data(pci)`` (see the `Non-Contiguous Buffers`_ +``GFP_KERNEL`` is the kernel allocation flag to use. For the +scatter-gather buffers, use ``SNDRV_DMA_TYPE_DEV_SG`` with the device +pointer (see the `Non-Contiguous Buffers`_ section). Once the buffer is pre-allocated, you can use the allocator in the diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h index af3fa577fa066a..1ac0dd82a91638 100644 --- a/include/sound/memalloc.h +++ b/include/sound/memalloc.h @@ -37,7 +37,6 @@ struct snd_dma_device { }; #define snd_dma_pci_data(pci) (&(pci)->dev) -#define snd_dma_isa_data() NULL #define snd_dma_continuous_data(x) ((struct device *)(__force unsigned long)(x)) diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index fba6d22f7f4bdf..9bba81c9910136 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -694,7 +694,7 @@ int snd_ad1816a_pcm(struct snd_ad1816a *chip, int device) snd_ad1816a_init(chip); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + chip->card->dev, 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); chip->pcm = pcm; diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index 6b8c46942efb4b..328241d5edc998 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -470,7 +470,7 @@ static int snd_cmi8330_pcm(struct snd_card *card, struct snd_cmi8330 *chip) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &chip->streams[SNDRV_PCM_STREAM_CAPTURE].ops); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + card->dev, 64*1024, 128*1024); chip->pcm = pcm; diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index 50cdce0e894686..da341969e65083 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -746,7 +746,7 @@ int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip, int device) chip->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + card->dev, 64*1024, 64*1024); return 0; } diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 0d103d6f805e32..64548040cb8f30 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -1717,7 +1717,7 @@ static int snd_es18xx_pcm(struct snd_card *card, int device) chip->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + card->dev, 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); return 0; diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index 131b28997e1d1e..b9efc6dff45dcd 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -891,7 +891,7 @@ int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index) for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + card->dev, 64*1024, gus->gf1.dma1 > 3 ? 128*1024 : 64*1024); pcm->info_flags = 0; @@ -901,7 +901,7 @@ int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index) if (gus->gf1.dma2 == gus->gf1.dma1) pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX; snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, - SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), + SNDRV_DMA_TYPE_DEV, card->dev, 64*1024, gus->gf1.dma2 > 3 ? 128*1024 : 64*1024); } strcpy(pcm->name, pcm->id); diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c index 37e6ce7b0b13a2..cb9ec92e831f87 100644 --- a/sound/isa/sb/sb16_main.c +++ b/sound/isa/sb/sb16_main.c @@ -885,7 +885,7 @@ int snd_sb16dsp_pcm(struct snd_sb *chip, int device) pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + card->dev, 64*1024, 128*1024); return 0; } diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index 8288fae90085c8..97645a732a7104 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c @@ -610,7 +610,7 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device) if (chip->dma8 > 3 || chip->dma16 >= 0) max_prealloc = 128 * 1024; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + card->dev, 64*1024, max_prealloc); return 0; diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 733adee5afbf94..8181db4db019d0 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -167,12 +167,13 @@ static inline struct soundscape *get_card_soundscape(struct snd_card *c) * I think this means that the memory has to map to * contiguous pages of physical memory. */ -static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf, +static struct snd_dma_buffer *get_dmabuf(struct soundscape *s, + struct snd_dma_buffer *buf, unsigned long size) { if (buf) { if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + s->chip->card->dev, size, buf) < 0) { snd_printk(KERN_ERR "sscape: Failed to allocate " "%lu bytes for DMA\n", @@ -443,7 +444,7 @@ static int upload_dma_data(struct soundscape *s, const unsigned char *data, int ret; unsigned char val; - if (!get_dmabuf(&dma, PAGE_ALIGN(32 * 1024))) + if (!get_dmabuf(s, &dma, PAGE_ALIGN(32 * 1024))) return -ENOMEM; spin_lock_irqsave(&s->lock, flags); diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 3a500883757603..dd4982271e51db 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -1943,7 +1943,7 @@ int snd_wss_pcm(struct snd_wss *chip, int device) strcpy(pcm->name, snd_wss_chip_id(chip)); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_isa_data(), + chip->card->dev, 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); chip->pcm = pcm; From c50ea1944a20d7cdda51e7fa6197caeeb0e95aaf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 14:34:00 +0100 Subject: [PATCH 1160/1995] ALSA: core: Don't allow NULL device for memory allocation Since we covered all callers with NULL device pointer, let's catch the remaining calls with NULL and warn explicitly. Acked-by: Christoph Hellwig Signed-off-by: Takashi Iwai (cherry picked from commit 6ce1d63ed7210e7120070297976460f868c36314) --- sound/core/memalloc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 59a4adc286ed77..eb974235c92bdf 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -182,6 +182,8 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size, return -ENXIO; if (WARN_ON(!dmab)) return -ENXIO; + if (WARN_ON(!device)) + return -EINVAL; dmab->dev.type = type; dmab->dev.dev = device; From 806e8cf18cb1cac3589e84eca930793eda3734d0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Feb 2019 12:31:42 +0100 Subject: [PATCH 1161/1995] ALSA: info: Always register entries recursively Make sure that all children entries are registered by a single call of snd_info_register(). OTOH, don't register if a parent isn't registered yet. This allows us to create the whole procfs tree in a shot at the last stage of card registration phase in a later patch. Signed-off-by: Takashi Iwai (cherry picked from commit 348c5ad5d69cc0a3fb1f6e3f22787a9721e2a420) --- sound/core/info.c | 65 +++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/sound/core/info.c b/sound/core/info.c index 2dfb6389c084eb..5cd00629c0f550 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -523,27 +523,6 @@ int snd_info_card_create(struct snd_card *card) return 0; } -/* register all pending info entries */ -static int snd_info_register_recursive(struct snd_info_entry *entry) -{ - struct snd_info_entry *p; - int err; - - if (!entry->p) { - err = snd_info_register(entry); - if (err < 0) - return err; - } - - list_for_each_entry(p, &entry->children, list) { - err = snd_info_register_recursive(p); - if (err < 0) - return err; - } - - return 0; -} - /* * register the card proc file * called from init.c @@ -557,7 +536,7 @@ int snd_info_card_register(struct snd_card *card) if (snd_BUG_ON(!card)) return -ENXIO; - err = snd_info_register_recursive(card->proc_root); + err = snd_info_register(card->proc_root); if (err < 0) return err; @@ -821,15 +800,7 @@ void snd_info_free_entry(struct snd_info_entry * entry) } EXPORT_SYMBOL(snd_info_free_entry); -/** - * snd_info_register - register the info entry - * @entry: the info entry - * - * Registers the proc info entry. - * - * Return: Zero if successful, or a negative error code on failure. - */ -int snd_info_register(struct snd_info_entry * entry) +static int __snd_info_register(struct snd_info_entry *entry) { struct proc_dir_entry *root, *p = NULL; @@ -837,6 +808,8 @@ int snd_info_register(struct snd_info_entry * entry) return -ENXIO; root = entry->parent == NULL ? snd_proc_root->p : entry->parent->p; mutex_lock(&info_mutex); + if (entry->p || !root) + goto unlock; if (S_ISDIR(entry->mode)) { p = proc_mkdir_mode(entry->name, entry->mode, root); if (!p) { @@ -858,9 +831,39 @@ int snd_info_register(struct snd_info_entry * entry) proc_set_size(p, entry->size); } entry->p = p; + unlock: mutex_unlock(&info_mutex); return 0; } + +/** + * snd_info_register - register the info entry + * @entry: the info entry + * + * Registers the proc info entry. + * The all children entries are registered recursively. + * + * Return: Zero if successful, or a negative error code on failure. + */ +int snd_info_register(struct snd_info_entry *entry) +{ + struct snd_info_entry *p; + int err; + + if (!entry->p) { + err = __snd_info_register(entry); + if (err < 0) + return err; + } + + list_for_each_entry(p, &entry->children, list) { + err = snd_info_register(p); + if (err < 0) + return err; + } + + return 0; +} EXPORT_SYMBOL(snd_info_register); /* From d581461eb7c336bbd3a25fc5505b41e4137ea58b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 15:02:11 +0100 Subject: [PATCH 1162/1995] ALSA: pcm: Remove superfluous snd_info_register() calls The calls of snd_info_register() are superfluous and should be avoided at the procfs creation time. They are called at the end of the whole initialization via snd_card_register(). This patch drops such superfluous calls, as well as cleaning up the calls of substream proc entries with a common helper. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai (cherry picked from commit a8d149813b4456b689effb1f10accdc937566703) --- sound/core/pcm.c | 81 ++++++++++++++--------------------------- sound/core/pcm_memory.c | 21 +++++------ 2 files changed, 37 insertions(+), 65 deletions(-) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 4f45b30003472f..7b63aee124af3e 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -528,28 +528,17 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) if (!entry) return -ENOMEM; entry->mode = S_IFDIR | 0555; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - return -ENOMEM; - } pstr->proc_root = entry; entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root); - if (entry) { + if (entry) snd_info_set_text_ops(entry, pstr, snd_pcm_stream_proc_info_read); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); - } - #ifdef CONFIG_SND_PCM_XRUN_DEBUG entry = snd_info_create_card_entry(pcm->card, "xrun_debug", pstr->proc_root); if (entry) { - entry->c.text.read = snd_pcm_xrun_debug_read; + snd_info_set_text_ops(entry, pstr, snd_pcm_xrun_debug_read); entry->c.text.write = snd_pcm_xrun_debug_write; entry->mode |= 0200; - entry->private_data = pstr; - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); } #endif return 0; @@ -562,6 +551,21 @@ static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) return 0; } +static struct snd_info_entry * +create_substream_info_entry(struct snd_pcm_substream *substream, + const char *name, + void (*read)(struct snd_info_entry *, + struct snd_info_buffer *)) +{ + struct snd_info_entry *entry; + + entry = snd_info_create_card_entry(substream->pcm->card, name, + substream->proc_root); + if (entry) + snd_info_set_text_ops(entry, substream, read); + return entry; +} + static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) { struct snd_info_entry *entry; @@ -576,53 +580,22 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) if (!entry) return -ENOMEM; entry->mode = S_IFDIR | 0555; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - return -ENOMEM; - } substream->proc_root = entry; - entry = snd_info_create_card_entry(card, "info", substream->proc_root); - if (entry) { - snd_info_set_text_ops(entry, substream, - snd_pcm_substream_proc_info_read); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); - } - entry = snd_info_create_card_entry(card, "hw_params", - substream->proc_root); - if (entry) { - snd_info_set_text_ops(entry, substream, - snd_pcm_substream_proc_hw_params_read); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); - } - entry = snd_info_create_card_entry(card, "sw_params", - substream->proc_root); - if (entry) { - snd_info_set_text_ops(entry, substream, - snd_pcm_substream_proc_sw_params_read); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); - } - entry = snd_info_create_card_entry(card, "status", - substream->proc_root); - if (entry) { - snd_info_set_text_ops(entry, substream, - snd_pcm_substream_proc_status_read); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); - } + + create_substream_info_entry(substream, "info", + snd_pcm_substream_proc_info_read); + create_substream_info_entry(substream, "hw_params", + snd_pcm_substream_proc_hw_params_read); + create_substream_info_entry(substream, "sw_params", + snd_pcm_substream_proc_sw_params_read); + create_substream_info_entry(substream, "status", + snd_pcm_substream_proc_status_read); #ifdef CONFIG_SND_PCM_XRUN_DEBUG - entry = snd_info_create_card_entry(card, "xrun_injection", - substream->proc_root); + entry = create_substream_info_entry(substream, "xrun_injection", NULL); if (entry) { - entry->private_data = substream; - entry->c.text.read = NULL; entry->c.text.write = snd_pcm_xrun_injection_write; entry->mode = S_IFREG | 0200; - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); } #endif /* CONFIG_SND_PCM_XRUN_DEBUG */ diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 9a98bc61461fe4..4012a3a01de1a1 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -192,20 +192,19 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream) { struct snd_info_entry *entry; - if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc", substream->proc_root)) != NULL) { - entry->c.text.read = snd_pcm_lib_preallocate_proc_read; + entry = snd_info_create_card_entry(substream->pcm->card, "prealloc", + substream->proc_root); + if (entry) { + snd_info_set_text_ops(entry, substream, + snd_pcm_lib_preallocate_proc_read); entry->c.text.write = snd_pcm_lib_preallocate_proc_write; entry->mode |= 0200; - entry->private_data = substream; - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); - } - if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max", substream->proc_root)) != NULL) { - entry->c.text.read = snd_pcm_lib_preallocate_max_proc_read; - entry->private_data = substream; - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); } + entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max", + substream->proc_root); + if (entry) + snd_info_set_text_ops(entry, substream, + snd_pcm_lib_preallocate_max_proc_read); } #else /* !CONFIG_SND_VERBOSE_PROCFS */ From 7328eb8b37e65119e1cc543f115f080f7567249e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 14:55:19 +0100 Subject: [PATCH 1163/1995] ALSA: compress: Remove superfluous snd_info_register() calls The calls of snd_info_register() are superfluous and should be avoided at the procfs creation time. They are called at the end of the whole initialization via snd_card_register(). This patch drops such superfluous calls. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai (cherry picked from commit 4a471d7cc99d6a2f7c58d11c3f1a9665ca60dcd6) --- sound/core/compress_offload.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index f7d2b373da0aae..a1a6fd75cfe500 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -1015,22 +1015,13 @@ static int snd_compress_proc_init(struct snd_compr *compr) if (!entry) return -ENOMEM; entry->mode = S_IFDIR | 0555; - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - return -ENOMEM; - } compr->proc_root = entry; entry = snd_info_create_card_entry(compr->card, "info", compr->proc_root); - if (entry) { + if (entry) snd_info_set_text_ops(entry, compr, snd_compress_proc_info_read); - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - entry = NULL; - } - } compr->proc_info_entry = entry; return 0; From a94604f5ca5ef3c24aa9c9f994526a200842ff3b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 14:53:04 +0100 Subject: [PATCH 1164/1995] ALSA: info: Add standard helpers for card proc file entries Two new helper functions are added here for cleaning up the existing lengthy calls. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai (cherry picked from commit 7453e1dafdec076f87384c8647d2960affd57ecc) --- include/sound/info.h | 35 +++++++++++++++++++++++++++++++++++ sound/core/info.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/include/sound/info.h b/include/sound/info.h index becdf66d2825e9..96530f7599e1bf 100644 --- a/include/sound/info.h +++ b/include/sound/info.h @@ -160,6 +160,13 @@ static inline void snd_info_set_text_ops(struct snd_info_entry *entry, entry->c.text.read = read; } +int snd_card_rw_proc_new(struct snd_card *card, const char *name, + void *private_data, + void (*read)(struct snd_info_entry *, + struct snd_info_buffer *), + void (*write)(struct snd_info_entry *entry, + struct snd_info_buffer *buffer)); + int snd_info_check_reserved_words(const char *str); #else @@ -189,10 +196,38 @@ static inline int snd_card_proc_new(struct snd_card *card, const char *name, static inline void snd_info_set_text_ops(struct snd_info_entry *entry __attribute__((unused)), void *private_data, void (*read)(struct snd_info_entry *, struct snd_info_buffer *)) {} +static inline int snd_card_rw_proc_new(struct snd_card *card, const char *name, + void *private_data, + void (*read)(struct snd_info_entry *, + struct snd_info_buffer *), + void (*write)(struct snd_info_entry *entry, + struct snd_info_buffer *buffer)) +{ + return 0; +} static inline int snd_info_check_reserved_words(const char *str) { return 1; } #endif +/** + * snd_card_ro_proc_new - Create a read-only text proc file entry for the card + * @card: the card instance + * @name: the file name + * @private_data: the arbitrary private data + * @read: the read callback + * + * This proc file entry will be registered via snd_card_register() call, and + * it will be removed automatically at the card removal, too. + */ +static inline int +snd_card_ro_proc_new(struct snd_card *card, const char *name, + void *private_data, + void (*read)(struct snd_info_entry *, + struct snd_info_buffer *)) +{ + return snd_card_rw_proc_new(card, name, private_data, read, NULL); +} + /* * OSS info part */ diff --git a/sound/core/info.c b/sound/core/info.c index 5cd00629c0f550..6c149fa54d2dc1 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -866,6 +866,38 @@ int snd_info_register(struct snd_info_entry *entry) } EXPORT_SYMBOL(snd_info_register); +/** + * snd_card_rw_proc_new - Create a read/write text proc file entry for the card + * @card: the card instance + * @name: the file name + * @private_data: the arbitrary private data + * @read: the read callback + * @write: the write callback, NULL for read-only + * + * This proc file entry will be registered via snd_card_register() call, and + * it will be removed automatically at the card removal, too. + */ +int snd_card_rw_proc_new(struct snd_card *card, const char *name, + void *private_data, + void (*read)(struct snd_info_entry *, + struct snd_info_buffer *), + void (*write)(struct snd_info_entry *entry, + struct snd_info_buffer *buffer)) +{ + struct snd_info_entry *entry; + + entry = snd_info_create_card_entry(card, name, card->proc_root); + if (!entry) + return -ENOMEM; + snd_info_set_text_ops(entry, private_data, read); + if (write) { + entry->mode |= 0200; + entry->c.text.write = write; + } + return 0; +} +EXPORT_SYMBOL_GPL(snd_card_rw_proc_new); + /* */ From 358717abf0701e9c86847cf98df1f2bb2f80d37f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Feb 2019 16:10:00 +0100 Subject: [PATCH 1165/1995] ALSA: info: Drop unused snd_info_entry.card field It's referred only in snd_card_id_read() which can receive the card object via private_data. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai (cherry picked from commit 9725752867cb158e076bcb6bc4bdb35d9710b1bd) --- include/sound/info.h | 1 - sound/core/info.c | 4 +--- sound/core/init.c | 6 ++++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/sound/info.h b/include/sound/info.h index 96530f7599e1bf..97fdda41e0763a 100644 --- a/include/sound/info.h +++ b/include/sound/info.h @@ -82,7 +82,6 @@ struct snd_info_entry { struct snd_info_entry_ops *ops; } c; struct snd_info_entry *parent; - struct snd_card *card; struct module *module; void *private_data; void (*private_free)(struct snd_info_entry *entry); diff --git a/sound/core/info.c b/sound/core/info.c index 6c149fa54d2dc1..4d23069e7928e9 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -750,10 +750,8 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, if (!parent) parent = card->proc_root; entry = snd_info_create_entry(name, parent); - if (entry) { + if (entry) entry->module = card->module; - entry->card = card; - } return entry; } EXPORT_SYMBOL(snd_info_create_card_entry); diff --git a/sound/core/init.c b/sound/core/init.c index 4849c611c0fe3a..5252a9ce13dc77 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -104,7 +104,9 @@ EXPORT_SYMBOL(snd_mixer_oss_notify_callback); static void snd_card_id_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - snd_iprintf(buffer, "%s\n", entry->card->id); + struct snd_card *card = entry->private_data; + + snd_iprintf(buffer, "%s\n", card->id); } static int init_info_for_card(struct snd_card *card) @@ -116,7 +118,7 @@ static int init_info_for_card(struct snd_card *card) dev_dbg(card->dev, "unable to create card entry\n"); return -ENOMEM; } - entry->c.text.read = snd_card_id_read; + snd_info_set_text_ops(entry, card, snd_card_id_read); card->proc_id = entry; return snd_info_card_register(card); From d7035384e2a9d10a9df22f61f07375876774c5d0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Feb 2019 16:17:48 +0100 Subject: [PATCH 1166/1995] ALSA: info: Minor optimization Just a minor code optimization to reduce the source code size slightly. No functional changes. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai (cherry picked from commit a858ee6655ca2f0fc6e2e5d426446bd898c92272) --- sound/core/info.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/sound/core/info.c b/sound/core/info.c index 4d23069e7928e9..7a4e733172eed0 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -463,11 +463,12 @@ static struct snd_info_entry *create_subdir(struct module *mod, } static struct snd_info_entry * -snd_info_create_entry(const char *name, struct snd_info_entry *parent); +snd_info_create_entry(const char *name, struct snd_info_entry *parent, + struct module *module); int __init snd_info_init(void) { - snd_proc_root = snd_info_create_entry("asound", NULL); + snd_proc_root = snd_info_create_entry("asound", NULL, THIS_MODULE); if (!snd_proc_root) return -ENOMEM; snd_proc_root->mode = S_IFDIR | 0555; @@ -684,7 +685,8 @@ EXPORT_SYMBOL(snd_info_get_str); * Return: The pointer of the new instance, or %NULL on failure. */ static struct snd_info_entry * -snd_info_create_entry(const char *name, struct snd_info_entry *parent) +snd_info_create_entry(const char *name, struct snd_info_entry *parent, + struct module *module) { struct snd_info_entry *entry; entry = kzalloc(sizeof(*entry), GFP_KERNEL); @@ -701,6 +703,7 @@ snd_info_create_entry(const char *name, struct snd_info_entry *parent) INIT_LIST_HEAD(&entry->children); INIT_LIST_HEAD(&entry->list); entry->parent = parent; + entry->module = module; if (parent) list_add_tail(&entry->list, &parent->children); return entry; @@ -720,14 +723,9 @@ struct snd_info_entry *snd_info_create_module_entry(struct module * module, const char *name, struct snd_info_entry *parent) { - struct snd_info_entry *entry; - if (!parent) parent = snd_proc_root; - entry = snd_info_create_entry(name, parent); - if (entry) - entry->module = module; - return entry; + return snd_info_create_entry(name, parent, module); } EXPORT_SYMBOL(snd_info_create_module_entry); @@ -745,14 +743,9 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, const char *name, struct snd_info_entry * parent) { - struct snd_info_entry *entry; - if (!parent) parent = card->proc_root; - entry = snd_info_create_entry(name, parent); - if (entry) - entry->module = card->module; - return entry; + return snd_info_create_entry(name, parent, card->module); } EXPORT_SYMBOL(snd_info_create_card_entry); From dcd47dfb25f598fb1d2bbb7aa4ed1e4e042de06b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Feb 2019 16:26:06 +0100 Subject: [PATCH 1167/1995] ALSA: info: Move card id proc creation into info.c The creation of card's id proc file can be moved gracefully into info.c. Also, the assignment of card->proc_id is superfluous and can be dropped. So let's do it. Basically this is no functional change but code refactoring, but one potential behavior change is that now it returns properly the error code from snd_info_card_register(), which is a good thing (tm). Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai (cherry picked from commit 29b2625ff605394ecd0b078e0cb67a151bb4d80c) --- include/sound/core.h | 1 - sound/core/info.c | 11 ++++++++++- sound/core/init.c | 33 ++++----------------------------- 3 files changed, 14 insertions(+), 31 deletions(-) diff --git a/include/sound/core.h b/include/sound/core.h index 36a5934cf4b10f..e923c23e05dd77 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -120,7 +120,6 @@ struct snd_card { struct list_head ctl_files; /* active control files */ struct snd_info_entry *proc_root; /* root for soundcard specific files */ - struct snd_info_entry *proc_id; /* the card id */ struct proc_dir_entry *proc_root_link; /* number link to real id */ struct list_head files_list; /* all files associated to this card */ diff --git a/sound/core/info.c b/sound/core/info.c index 7a4e733172eed0..96a074019c33c2 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -504,6 +504,14 @@ int __exit snd_info_done(void) return 0; } +static void snd_card_id_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct snd_card *card = entry->private_data; + + snd_iprintf(buffer, "%s\n", card->id); +} + /* * create a card proc file * called from init.c @@ -521,7 +529,8 @@ int snd_info_card_create(struct snd_card *card) if (!entry) return -ENOMEM; card->proc_root = entry; - return 0; + + return snd_card_ro_proc_new(card, "id", card, snd_card_id_read); } /* diff --git a/sound/core/init.c b/sound/core/init.c index 5252a9ce13dc77..0c4dc40376a709 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -100,33 +100,6 @@ int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag); EXPORT_SYMBOL(snd_mixer_oss_notify_callback); #endif -#ifdef CONFIG_SND_PROC_FS -static void snd_card_id_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - struct snd_card *card = entry->private_data; - - snd_iprintf(buffer, "%s\n", card->id); -} - -static int init_info_for_card(struct snd_card *card) -{ - struct snd_info_entry *entry; - - entry = snd_info_create_card_entry(card, "id", card->proc_root); - if (!entry) { - dev_dbg(card->dev, "unable to create card entry\n"); - return -ENOMEM; - } - snd_info_set_text_ops(entry, card, snd_card_id_read); - card->proc_id = entry; - - return snd_info_card_register(card); -} -#else /* !CONFIG_SND_PROC_FS */ -#define init_info_for_card(card) -#endif - static int check_empty_slot(struct module *module, int slot) { return !slots[slot] || !*slots[slot]; @@ -493,7 +466,6 @@ static int snd_card_do_free(struct snd_card *card) snd_device_free_all(card); if (card->private_free) card->private_free(card); - snd_info_free_entry(card->proc_id); if (snd_info_card_free(card) < 0) { dev_warn(card->dev, "unable to free card info\n"); /* Not fatal error */ @@ -797,7 +769,10 @@ int snd_card_register(struct snd_card *card) } snd_cards[card->number] = card; mutex_unlock(&snd_card_mutex); - init_info_for_card(card); + err = snd_info_card_register(card); + if (err < 0) + return err; + #if IS_ENABLED(CONFIG_SND_MIXER_OSS) if (snd_mixer_oss_notify_callback) snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER); From 6afcd0e7f8d2dd43a601600803e577e02e47fb06 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:38:42 +0100 Subject: [PATCH 1168/1995] ASoC: intel: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Acked-by: Mark Brown Signed-off-by: Takashi Iwai (cherry picked from commit 62961dd5f609b202080e7d9053de1a8967c9d4d8) --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 9 ++------- sound/soc/intel/baytrail/sst-baytrail-pcm.c | 15 ++++----------- sound/soc/intel/haswell/sst-haswell-pcm.c | 10 ++-------- sound/soc/intel/skylake/skl-pcm.c | 9 ++------- 4 files changed, 10 insertions(+), 33 deletions(-) diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index b0873fea23ab4e..08cea5b5cda9fa 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -687,20 +687,15 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *dai = rtd->cpu_dai; struct snd_pcm *pcm = rtd->pcm; - int retval = 0; if (dai->driver->playback.channels_min || dai->driver->capture.channels_min) { - retval = snd_pcm_lib_preallocate_pages_for_all(pcm, + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_DMA), SST_MIN_BUFFER, SST_MAX_BUFFER); - if (retval) { - dev_err(rtd->dev, "dma buffer allocation failure\n"); - return retval; - } } - return retval; + return 0; } static int sst_soc_probe(struct snd_soc_component *component) diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c index 498fb5346f1a81..5373605de0af7e 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-pcm.c +++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c @@ -327,23 +327,16 @@ static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd) size_t size; struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct sst_pdata *pdata = dev_get_platdata(component->dev); - int ret = 0; if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { size = sst_byt_pcm_hardware.buffer_bytes_max; - ret = snd_pcm_lib_preallocate_pages_for_all(pcm, - SNDRV_DMA_TYPE_DEV, - pdata->dma_dev, - size, size); - if (ret) { - dev_err(rtd->dev, "dma buffer allocation failed %d\n", - ret); - return ret; - } + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + pdata->dma_dev, + size, size); } - return ret; + return 0; } static struct snd_soc_dai_driver byt_dais[] = { diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index 2debcc2ed99a1f..e023c4c3e5a941 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c @@ -946,27 +946,21 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) struct sst_pdata *pdata = dev_get_platdata(component->dev); struct hsw_priv_data *priv_data = dev_get_drvdata(component->dev); struct device *dev = pdata->dma_dev; - int ret = 0; if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { - ret = snd_pcm_lib_preallocate_pages_for_all(pcm, + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, dev, hsw_pcm_hardware.buffer_bytes_max, hsw_pcm_hardware.buffer_bytes_max); - if (ret) { - dev_err(rtd->dev, "dma buffer allocation failed %d\n", - ret); - return ret; - } } if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_PLAYBACK].hsw_pcm = pcm; if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_CAPTURE].hsw_pcm = pcm; - return ret; + return 0; } #define HSW_FORMATS \ diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index a4284778f117d6..1ae83f4ccc3615 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1289,7 +1289,6 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) struct hdac_bus *bus = dev_get_drvdata(dai->dev); struct snd_pcm *pcm = rtd->pcm; unsigned int size; - int retval = 0; struct skl *skl = bus_to_skl(bus); if (dai->driver->playback.channels_min || @@ -1298,17 +1297,13 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; if (size > MAX_PREALLOC_SIZE) size = MAX_PREALLOC_SIZE; - retval = snd_pcm_lib_preallocate_pages_for_all(pcm, + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(skl->pci), size, MAX_PREALLOC_SIZE); - if (retval) { - dev_err(dai->dev, "dma buffer allocation fail\n"); - return retval; - } } - return retval; + return 0; } static int skl_get_module_info(struct skl *skl, struct skl_module_cfg *mconfig) From c43aca1f9a901de4ba4e9d1e80c7e01ff6529011 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:41:43 +0100 Subject: [PATCH 1169/1995] ASoC: dmaengine: Drop superfluous PCM preallocation error checks snd_pcm_lib_preallocate_pages() and co always succeed, so the error check is simply redundant. Drop it. Reviewed-by: Jaroslav Kysela Acked-by: Mark Brown Signed-off-by: Takashi Iwai (cherry picked from commit 6c422436638af9f8240df71c53275c3d255c2170) --- sound/soc/soc-generic-dmaengine-pcm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index f1ab6285a08510..748f5f641002e9 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -269,7 +269,6 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) size_t prealloc_buffer_size; size_t max_buffer_size; unsigned int i; - int ret; if (config && config->prealloc_buffer_size) { prealloc_buffer_size = config->prealloc_buffer_size; @@ -299,13 +298,11 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) return -EINVAL; } - ret = snd_pcm_lib_preallocate_pages(substream, + snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_IRAM, dmaengine_dma_dev(pcm, substream), prealloc_buffer_size, max_buffer_size); - if (ret) - return ret; if (!dmaengine_pcm_can_report_residue(dev, pcm->chan[i])) pcm->flags |= SND_DMAENGINE_PCM_FLAG_NO_RESIDUE; From c087fe6aa6d706aa19c668bc3454e22ca6c662bc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Feb 2019 16:42:24 +0100 Subject: [PATCH 1170/1995] ALSA: pcm: Define snd_pcm_lib_preallocate_*() as returning void Now all callers no longer check the return value from snd_pcm_lib_preallocate_pages() and co, let's make them to return void, so that any new code won't fall into the same pitfall. Reviewed-by: Jaroslav Kysela Signed-off-by: Takashi Iwai (cherry picked from commit bb580602f3924976d8bc36c171266de73e92cbf7) --- include/sound/pcm.h | 8 ++++---- sound/core/pcm_memory.c | 29 ++++++++--------------------- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index ca20f80f8976aa..465d7d033c4c61 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -1185,12 +1185,12 @@ static inline void snd_pcm_gettime(struct snd_pcm_runtime *runtime, * Memory */ -int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream); -int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm); -int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, +void snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream); +void snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm); +void snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, int type, struct device *data, size_t size, size_t max); -int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, +void snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, int type, void *data, size_t size, size_t max); int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size); diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 4012a3a01de1a1..ed73be80bd2971 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -87,13 +87,10 @@ static void snd_pcm_lib_preallocate_dma_free(struct snd_pcm_substream *substream * @substream: the pcm substream instance * * Releases the pre-allocated buffer of the given substream. - * - * Return: Zero if successful, or a negative error code on failure. */ -int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream) +void snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream) { snd_pcm_lib_preallocate_dma_free(substream); - return 0; } /** @@ -101,10 +98,8 @@ int snd_pcm_lib_preallocate_free(struct snd_pcm_substream *substream) * @pcm: the pcm instance * * Releases all the pre-allocated buffers on the given pcm. - * - * Return: Zero if successful, or a negative error code on failure. */ -int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm) +void snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm) { struct snd_pcm_substream *substream; int stream; @@ -112,7 +107,6 @@ int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm) for (stream = 0; stream < 2; stream++) for (substream = pcm->streams[stream].substream; substream; substream = substream->next) snd_pcm_lib_preallocate_free(substream); - return 0; } EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all); @@ -214,7 +208,7 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream) /* * pre-allocate the buffer and create a proc file for the substream */ -static int snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream, +static void snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream, size_t size, size_t max) { @@ -225,7 +219,6 @@ static int snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream, substream->buffer_bytes_max = substream->dma_buffer.bytes; substream->dma_max = max; preallocate_info_init(substream); - return 0; } @@ -238,16 +231,14 @@ static int snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream, * @max: the max. allowed pre-allocation size * * Do pre-allocation for the given DMA buffer type. - * - * Return: Zero if successful, or a negative error code on failure. */ -int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, +void snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, int type, struct device *data, size_t size, size_t max) { substream->dma_buffer.dev.type = type; substream->dma_buffer.dev.dev = data; - return snd_pcm_lib_preallocate_pages1(substream, size, max); + snd_pcm_lib_preallocate_pages1(substream, size, max); } EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); @@ -261,21 +252,17 @@ EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); * * Do pre-allocation to all substreams of the given pcm for the * specified DMA type. - * - * Return: Zero if successful, or a negative error code on failure. */ -int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, +void snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, int type, void *data, size_t size, size_t max) { struct snd_pcm_substream *substream; - int stream, err; + int stream; for (stream = 0; stream < 2; stream++) for (substream = pcm->streams[stream].substream; substream; substream = substream->next) - if ((err = snd_pcm_lib_preallocate_pages(substream, type, data, size, max)) < 0) - return err; - return 0; + snd_pcm_lib_preallocate_pages(substream, type, data, size, max); } EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); From 85c1529d0df3ed343cd9317acd3b69d17949e950 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 8 Feb 2019 00:27:56 +0100 Subject: [PATCH 1171/1995] component: Add documentation While typing these I think doing an s/component_master/aggregate/ would be useful: - it's shorter :-) - I think component/aggregate is much more meaningful naming than component/puppetmaster or something like that. At least to my English ear "aggregate" emphasizes much more the "assemble a pile of things into something bigger" aspect, and there's not really much of a control hierarchy between aggregate and constituing components. But that's way more than a quick doc typing exercise ... Thanks to Ram for commenting on an initial draft of these docs. v2: Review from Rafael: - git add Documenation/driver-api/component.rst - lots of polish to the wording + spelling fixes. v3: Review from Russell: - s/framework/helper - clarify the documentation for component_match_add functions. v4: Remove a few superflous "This". Reviewed-by: Rafael J. Wysocki Cc: "C, Ramalingam" Cc: Greg Kroah-Hartman Cc: Russell King Cc: Rafael J. Wysocki Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: Rodrigo Vivi Cc: Jani Nikula Reviewed-by: Greg Kroah-Hartman Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20190207232759.14553-1-daniel.vetter@ffwll.ch (cherry picked from commit 4d69c80e0d0fd8cf12d985841eb0fce5c29819ad) --- Documentation/driver-api/component.rst | 17 ++++ Documentation/driver-api/device_link.rst | 3 + Documentation/driver-api/index.rst | 1 + drivers/base/component.c | 106 ++++++++++++++++++++++- include/linux/component.h | 70 +++++++++++++++ 5 files changed, 194 insertions(+), 3 deletions(-) create mode 100644 Documentation/driver-api/component.rst diff --git a/Documentation/driver-api/component.rst b/Documentation/driver-api/component.rst new file mode 100644 index 00000000000000..2da4a8f2060765 --- /dev/null +++ b/Documentation/driver-api/component.rst @@ -0,0 +1,17 @@ +====================================== +Component Helper for Aggregate Drivers +====================================== + +.. kernel-doc:: drivers/base/component.c + :doc: overview + + +API +=== + +.. kernel-doc:: include/linux/component.h + :internal: + +.. kernel-doc:: drivers/base/component.c + :export: + diff --git a/Documentation/driver-api/device_link.rst b/Documentation/driver-api/device_link.rst index d6763272e747c8..2d5919b2b337fa 100644 --- a/Documentation/driver-api/device_link.rst +++ b/Documentation/driver-api/device_link.rst @@ -1,6 +1,9 @@ .. |struct dev_pm_domain| replace:: :c:type:`struct dev_pm_domain ` .. |struct generic_pm_domain| replace:: :c:type:`struct generic_pm_domain ` + +.. _device_link: + ============ Device links ============ diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst index ab38ced66a4424..c0b600ed99613e 100644 --- a/Documentation/driver-api/index.rst +++ b/Documentation/driver-api/index.rst @@ -22,6 +22,7 @@ available subsections can be seen below. device_connection dma-buf device_link + component message-based sound frame-buffer diff --git a/drivers/base/component.c b/drivers/base/component.c index ddcea8739c1240..1624c2a892a551 100644 --- a/drivers/base/component.c +++ b/drivers/base/component.c @@ -16,6 +16,32 @@ #include #include +/** + * DOC: overview + * + * The component helper allows drivers to collect a pile of sub-devices, + * including their bound drivers, into an aggregate driver. Various subsystems + * already provide functions to get hold of such components, e.g. + * of_clk_get_by_name(). The component helper can be used when such a + * subsystem-specific way to find a device is not available: The component + * helper fills the niche of aggregate drivers for specific hardware, where + * further standardization into a subsystem would not be practical. The common + * example is when a logical device (e.g. a DRM display driver) is spread around + * the SoC on various component (scanout engines, blending blocks, transcoders + * for various outputs and so on). + * + * The component helper also doesn't solve runtime dependencies, e.g. for system + * suspend and resume operations. See also :ref:`device links`. + * + * Components are registered using component_add() and unregistered with + * component_del(), usually from the driver's probe and disconnect functions. + * + * Aggregate drivers first assemble a component match list of what they need + * using component_match_add(). This is then registered as an aggregate driver + * using component_master_add_with_match(), and unregistered using + * component_master_del(). + */ + struct component; struct component_match_array { @@ -301,10 +327,24 @@ static int component_match_realloc(struct device *dev, return 0; } -/* - * Add a component to be matched, with a release function. +/** + * component_match_add_release - add a component match with release callback + * @master: device with the aggregate driver + * @matchptr: pointer to the list of component matches + * @release: release function for @compare_data + * @compare: compare function to match against all components + * @compare_data: opaque pointer passed to the @compare function + * + * Adds a new component match to the list stored in @matchptr, which the @master + * aggregate driver needs to function. The list of component matches pointed to + * by @matchptr must be initialized to NULL before adding the first match. + * + * The allocated match list in @matchptr is automatically released using devm + * actions, where upon @release will be called to free any references held by + * @compare_data, e.g. when @compare_data is a &device_node that must be + * released with of_node_put(). * - * The match array is first created or extended if necessary. + * See also component_match_add(). */ void component_match_add_release(struct device *master, struct component_match **matchptr, @@ -367,6 +407,18 @@ static void free_master(struct master *master) kfree(master); } +/** + * component_master_add_with_match - register an aggregate driver + * @dev: device with the aggregate driver + * @ops: callbacks for the aggregate driver + * @match: component match list for the aggregate driver + * + * Registers a new aggregate driver consisting of the components added to @match + * by calling one of the component_match_add() functions. Once all components in + * @match are available, it will be assembled by calling + * &component_master_ops.bind from @ops. Must be unregistered by calling + * component_master_del(). + */ int component_master_add_with_match(struct device *dev, const struct component_master_ops *ops, struct component_match *match) @@ -403,6 +455,15 @@ int component_master_add_with_match(struct device *dev, } EXPORT_SYMBOL_GPL(component_master_add_with_match); +/** + * component_master_del - unregister an aggregate driver + * @dev: device with the aggregate driver + * @ops: callbacks for the aggregate driver + * + * Unregisters an aggregate driver registered with + * component_master_add_with_match(). If necessary the aggregate driver is first + * disassembled by calling &component_master_ops.unbind from @ops. + */ void component_master_del(struct device *dev, const struct component_master_ops *ops) { @@ -430,6 +491,15 @@ static void component_unbind(struct component *component, devres_release_group(component->dev, component); } +/** + * component_unbind_all - unbind all component to an aggregate driver + * @master_dev: device with the aggregate driver + * @data: opaque pointer, passed to all components + * + * Unbinds all components to the aggregate @dev by passing @data to their + * &component_ops.unbind functions. Should be called from + * &component_master_ops.unbind. + */ void component_unbind_all(struct device *master_dev, void *data) { struct master *master; @@ -503,6 +573,15 @@ static int component_bind(struct component *component, struct master *master, return ret; } +/** + * component_bind_all - bind all component to an aggregate driver + * @master_dev: device with the aggregate driver + * @data: opaque pointer, passed to all components + * + * Binds all components to the aggregate @dev by passing @data to their + * &component_ops.bind functions. Should be called from + * &component_master_ops.bind. + */ int component_bind_all(struct device *master_dev, void *data) { struct master *master; @@ -537,6 +616,18 @@ int component_bind_all(struct device *master_dev, void *data) } EXPORT_SYMBOL_GPL(component_bind_all); +/** + * component_add - register a component + * @dev: component device + * @ops: component callbacks + * + * Register a new component for @dev. Functions in @ops will be called when the + * aggregate driver is ready to bind the overall driver by calling + * component_bind_all(). See also &struct component_ops. + * + * The component needs to be unregistered at driver unload/disconnect by calling + * component_del(). + */ int component_add(struct device *dev, const struct component_ops *ops) { struct component *component; @@ -568,6 +659,15 @@ int component_add(struct device *dev, const struct component_ops *ops) } EXPORT_SYMBOL_GPL(component_add); +/** + * component_del - unregister a component + * @dev: component device + * @ops: component callbacks + * + * Unregister a component added with component_add(). If the component is bound + * into an aggregate driver, this will force the entire aggregate driver, including + * all its components, to be unbound. + */ void component_del(struct device *dev, const struct component_ops *ops) { struct component *c, *component = NULL; diff --git a/include/linux/component.h b/include/linux/component.h index e71fbbbc74e2b4..83da25bdf59ca2 100644 --- a/include/linux/component.h +++ b/include/linux/component.h @@ -4,11 +4,31 @@ #include + struct device; +/** + * struct component_ops - callbacks for component drivers + * + * Components are registered with component_add() and unregistered with + * component_del(). + */ struct component_ops { + /** + * @bind: + * + * Called through component_bind_all() when the aggregate driver is + * ready to bind the overall driver. + */ int (*bind)(struct device *comp, struct device *master, void *master_data); + /** + * @unbind: + * + * Called through component_unbind_all() when the aggregate driver is + * ready to bind the overall driver, or when component_bind_all() fails + * part-ways through and needs to unbind some already bound components. + */ void (*unbind)(struct device *comp, struct device *master, void *master_data); }; @@ -21,8 +41,42 @@ void component_unbind_all(struct device *master, void *master_data); struct master; +/** + * struct component_master_ops - callback for the aggregate driver + * + * Aggregate drivers are registered with component_master_add_with_match() and + * unregistered with component_master_del(). + */ struct component_master_ops { + /** + * @bind: + * + * Called when all components or the aggregate driver, as specified in + * the match list passed to component_master_add_with_match(), are + * ready. Usually there are 3 steps to bind an aggregate driver: + * + * 1. Allocate a structure for the aggregate driver. + * + * 2. Bind all components to the aggregate driver by calling + * component_bind_all() with the aggregate driver structure as opaque + * pointer data. + * + * 3. Register the aggregate driver with the subsystem to publish its + * interfaces. + * + * Note that the lifetime of the aggregate driver does not align with + * any of the underlying &struct device instances. Therefore devm cannot + * be used and all resources acquired or allocated in this callback must + * be explicitly released in the @unbind callback. + */ int (*bind)(struct device *master); + /** + * @unbind: + * + * Called when either the aggregate driver, using + * component_master_del(), or one of its components, using + * component_del(), is unregistered. + */ void (*unbind)(struct device *master); }; @@ -38,6 +92,22 @@ void component_match_add_release(struct device *master, void (*release)(struct device *, void *), int (*compare)(struct device *, void *), void *compare_data); +/** + * component_match_add - add a compent match + * @master: device with the aggregate driver + * @matchptr: pointer to the list of component matches + * @compare: compare function to match against all components + * @compare_data: opaque pointer passed to the @compare function + * + * Adds a new component match to the list stored in @matchptr, which the @master + * aggregate driver needs to function. The list of component matches pointed to + * by @matchptr must be initialized to NULL before adding the first match. + * + * The allocated match list in @matchptr is automatically released using devm + * actions. + * + * See also component_match_add_release(). + */ static inline void component_match_add(struct device *master, struct component_match **matchptr, int (*compare)(struct device *, void *), void *compare_data) From cb7fa69e0a2b15fea9333f8f742d48ab33c0e82f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 8 Feb 2019 00:27:57 +0100 Subject: [PATCH 1172/1995] components: multiple components for a device Component framework is extended to support multiple components for a struct device. These will be matched with different masters based on its sub component value. We are introducing this, as I915 needs two different components with different subcomponent value, which will be matched to two different component masters(Audio and HDCP) based on the subcomponent values. v2: Add documenation. v3: Rebase on top of updated documenation. v4: Review from Rafael: - Remove redundant "This" from kerneldoc (also in the previous patch) - Streamline the logic in find_component() a bit. Signed-off-by: Daniel Vetter (v1 code) Signed-off-by: Ramalingam C (v1 commit message) Cc: Ramalingam C Cc: Greg Kroah-Hartman Cc: Russell King Cc: Rafael J. Wysocki Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: Rodrigo Vivi Cc: Jani Nikula Reviewed-by: Greg Kroah-Hartman Reviewed-by: Rafael J. Wysocki Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20190207232759.14553-2-daniel.vetter@ffwll.ch (cherry picked from commit 3521ee994bca90c57b539e106ff7e12a839aa8ea) --- drivers/base/component.c | 158 +++++++++++++++++++++++++++++--------- include/linux/component.h | 10 ++- 2 files changed, 129 insertions(+), 39 deletions(-) diff --git a/drivers/base/component.c b/drivers/base/component.c index 1624c2a892a551..7dbc41cccd5811 100644 --- a/drivers/base/component.c +++ b/drivers/base/component.c @@ -47,6 +47,7 @@ struct component; struct component_match_array { void *data; int (*compare)(struct device *, void *); + int (*compare_typed)(struct device *, int, void *); void (*release)(struct device *, void *); struct component *component; bool duplicate; @@ -74,6 +75,7 @@ struct component { bool bound; const struct component_ops *ops; + int subcomponent; struct device *dev; }; @@ -158,7 +160,7 @@ static struct master *__master_find(struct device *dev, } static struct component *find_component(struct master *master, - int (*compare)(struct device *, void *), void *compare_data) + struct component_match_array *mc) { struct component *c; @@ -166,7 +168,11 @@ static struct component *find_component(struct master *master, if (c->master && c->master != master) continue; - if (compare(c->dev, compare_data)) + if (mc->compare && mc->compare(c->dev, mc->data)) + return c; + + if (mc->compare_typed && + mc->compare_typed(c->dev, c->subcomponent, mc->data)) return c; } @@ -192,7 +198,7 @@ static int find_components(struct master *master) if (match->compare[i].component) continue; - c = find_component(master, mc->compare, mc->data); + c = find_component(master, mc); if (!c) { ret = -ENXIO; break; @@ -327,29 +333,12 @@ static int component_match_realloc(struct device *dev, return 0; } -/** - * component_match_add_release - add a component match with release callback - * @master: device with the aggregate driver - * @matchptr: pointer to the list of component matches - * @release: release function for @compare_data - * @compare: compare function to match against all components - * @compare_data: opaque pointer passed to the @compare function - * - * Adds a new component match to the list stored in @matchptr, which the @master - * aggregate driver needs to function. The list of component matches pointed to - * by @matchptr must be initialized to NULL before adding the first match. - * - * The allocated match list in @matchptr is automatically released using devm - * actions, where upon @release will be called to free any references held by - * @compare_data, e.g. when @compare_data is a &device_node that must be - * released with of_node_put(). - * - * See also component_match_add(). - */ -void component_match_add_release(struct device *master, +static void __component_match_add(struct device *master, struct component_match **matchptr, void (*release)(struct device *, void *), - int (*compare)(struct device *, void *), void *compare_data) + int (*compare)(struct device *, void *), + int (*compare_typed)(struct device *, int, void *), + void *compare_data) { struct component_match *match = *matchptr; @@ -381,13 +370,69 @@ void component_match_add_release(struct device *master, } match->compare[match->num].compare = compare; + match->compare[match->num].compare_typed = compare_typed; match->compare[match->num].release = release; match->compare[match->num].data = compare_data; match->compare[match->num].component = NULL; match->num++; } + +/** + * component_match_add_release - add a component match with release callback + * @master: device with the aggregate driver + * @matchptr: pointer to the list of component matches + * @release: release function for @compare_data + * @compare: compare function to match against all components + * @compare_data: opaque pointer passed to the @compare function + * + * Adds a new component match to the list stored in @matchptr, which the @master + * aggregate driver needs to function. The list of component matches pointed to + * by @matchptr must be initialized to NULL before adding the first match. This + * only matches against components added with component_add(). + * + * The allocated match list in @matchptr is automatically released using devm + * actions, where upon @release will be called to free any references held by + * @compare_data, e.g. when @compare_data is a &device_node that must be + * released with of_node_put(). + * + * See also component_match_add() and component_match_add_typed(). + */ +void component_match_add_release(struct device *master, + struct component_match **matchptr, + void (*release)(struct device *, void *), + int (*compare)(struct device *, void *), void *compare_data) +{ + __component_match_add(master, matchptr, release, compare, NULL, + compare_data); +} EXPORT_SYMBOL(component_match_add_release); +/** + * component_match_add_typed - add a compent match for a typed component + * @master: device with the aggregate driver + * @matchptr: pointer to the list of component matches + * @compare_typed: compare function to match against all typed components + * @compare_data: opaque pointer passed to the @compare function + * + * Adds a new component match to the list stored in @matchptr, which the @master + * aggregate driver needs to function. The list of component matches pointed to + * by @matchptr must be initialized to NULL before adding the first match. This + * only matches against components added with component_add_typed(). + * + * The allocated match list in @matchptr is automatically released using devm + * actions. + * + * See also component_match_add_release() and component_match_add_typed(). + */ +void component_match_add_typed(struct device *master, + struct component_match **matchptr, + int (*compare_typed)(struct device *, int, void *), void *compare_data) +{ + __component_match_add(master, matchptr, NULL, NULL, compare_typed, + compare_data); +} +EXPORT_SYMBOL(component_match_add_typed); + static void free_master(struct master *master) { struct component_match *match = master->match; @@ -616,19 +661,8 @@ int component_bind_all(struct device *master_dev, void *data) } EXPORT_SYMBOL_GPL(component_bind_all); -/** - * component_add - register a component - * @dev: component device - * @ops: component callbacks - * - * Register a new component for @dev. Functions in @ops will be called when the - * aggregate driver is ready to bind the overall driver by calling - * component_bind_all(). See also &struct component_ops. - * - * The component needs to be unregistered at driver unload/disconnect by calling - * component_del(). - */ -int component_add(struct device *dev, const struct component_ops *ops) +static int __component_add(struct device *dev, const struct component_ops *ops, + int subcomponent) { struct component *component; int ret; @@ -639,6 +673,7 @@ int component_add(struct device *dev, const struct component_ops *ops) component->ops = ops; component->dev = dev; + component->subcomponent = subcomponent; dev_dbg(dev, "adding component (ops %ps)\n", ops); @@ -657,6 +692,55 @@ int component_add(struct device *dev, const struct component_ops *ops) return ret < 0 ? ret : 0; } + +/** + * component_add_typed - register a component + * @dev: component device + * @ops: component callbacks + * @subcomponent: nonzero identifier for subcomponents + * + * Register a new component for @dev. Functions in @ops will be call when the + * aggregate driver is ready to bind the overall driver by calling + * component_bind_all(). See also &struct component_ops. + * + * @subcomponent must be nonzero and is used to differentiate between multiple + * components registerd on the same device @dev. These components are match + * using component_match_add_typed(). + * + * The component needs to be unregistered at driver unload/disconnect by + * calling component_del(). + * + * See also component_add(). + */ +int component_add_typed(struct device *dev, const struct component_ops *ops, + int subcomponent) +{ + if (WARN_ON(subcomponent == 0)) + return -EINVAL; + + return __component_add(dev, ops, subcomponent); +} +EXPORT_SYMBOL_GPL(component_add_typed); + +/** + * component_add - register a component + * @dev: component device + * @ops: component callbacks + * + * Register a new component for @dev. Functions in @ops will be called when the + * aggregate driver is ready to bind the overall driver by calling + * component_bind_all(). See also &struct component_ops. + * + * The component needs to be unregistered at driver unload/disconnect by + * calling component_del(). + * + * See also component_add_typed() for a variant that allows multipled different + * components on the same device. + */ +int component_add(struct device *dev, const struct component_ops *ops) +{ + return __component_add(dev, ops, 0); +} EXPORT_SYMBOL_GPL(component_add); /** diff --git a/include/linux/component.h b/include/linux/component.h index 83da25bdf59ca2..30bcc7e590eb4e 100644 --- a/include/linux/component.h +++ b/include/linux/component.h @@ -34,6 +34,8 @@ struct component_ops { }; int component_add(struct device *, const struct component_ops *); +int component_add_typed(struct device *dev, const struct component_ops *ops, + int subcomponent); void component_del(struct device *, const struct component_ops *); int component_bind_all(struct device *master, void *master_data); @@ -91,6 +93,9 @@ void component_match_add_release(struct device *master, struct component_match **matchptr, void (*release)(struct device *, void *), int (*compare)(struct device *, void *), void *compare_data); +void component_match_add_typed(struct device *master, + struct component_match **matchptr, + int (*compare_typed)(struct device *, int, void *), void *compare_data); /** * component_match_add - add a compent match @@ -101,12 +106,13 @@ void component_match_add_release(struct device *master, * * Adds a new component match to the list stored in @matchptr, which the @master * aggregate driver needs to function. The list of component matches pointed to - * by @matchptr must be initialized to NULL before adding the first match. + * by @matchptr must be initialized to NULL before adding the first match. This + * only matches against components added with component_add(). * * The allocated match list in @matchptr is automatically released using devm * actions. * - * See also component_match_add_release(). + * See also component_match_add_release() and component_match_add_typed(). */ static inline void component_match_add(struct device *master, struct component_match **matchptr, From ee46eceaf0cba56dafd6163ce6e56f62f3fe6b40 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 8 Feb 2019 00:27:59 +0100 Subject: [PATCH 1173/1995] i915/snd_hdac: I915 subcomponent for the snd_hdac Since we need multiple components for I915 for different purposes (Audio & Mei_hdcp), we adopt the subcomponents methodology introduced by the previous patch (mentioned below). Author: Daniel Vetter Date: Mon Jan 28 17:08:20 2019 +0530 components: multiple components for a device Reviewed-by: Takashi Iwai Signed-off-by-by: Ramalingam C (commit message) Signed-off-by: Daniel Vetter (code) cc: Greg Kroah-Hartman cc: Russell King cc: Rafael J. Wysocki cc: Jaroslav Kysela cc: Takashi Iwai cc: Rodrigo Vivi cc: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20190207232759.14553-4-daniel.vetter@ffwll.ch (cherry picked from commit 8857c7d065e900a0b3829c97634c99501b606541) --- drivers/gpu/drm/i915/intel_audio.c | 4 +++- include/drm/i915_component.h | 4 ++++ include/sound/hda_component.h | 5 +++-- sound/hda/hdac_component.c | 4 ++-- sound/hda/hdac_i915.c | 6 ++++-- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index ae55a6865d5cca..b32681632f3009 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -984,7 +984,9 @@ void i915_audio_component_init(struct drm_i915_private *dev_priv) { int ret; - ret = component_add(dev_priv->drm.dev, &i915_audio_component_bind_ops); + ret = component_add_typed(dev_priv->drm.dev, + &i915_audio_component_bind_ops, + I915_COMPONENT_AUDIO); if (ret < 0) { DRM_ERROR("failed to add audio component (%d)\n", ret); /* continue with reduced functionality */ diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h index fca22d463e1bf7..72fbb037f9b301 100644 --- a/include/drm/i915_component.h +++ b/include/drm/i915_component.h @@ -26,6 +26,10 @@ #include "drm_audio_component.h" +enum i915_component_type { + I915_COMPONENT_AUDIO = 1, +}; + /* MAX_PORT is the number of port * It must be sync with I915_MAX_PORTS defined i915_drv.h */ diff --git a/include/sound/hda_component.h b/include/sound/hda_component.h index 2ec31b35895045..d4804c72d959e3 100644 --- a/include/sound/hda_component.h +++ b/include/sound/hda_component.h @@ -20,7 +20,7 @@ int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id, bool *audio_enabled, char *buffer, int max_bytes); int snd_hdac_acomp_init(struct hdac_bus *bus, const struct drm_audio_component_audio_ops *aops, - int (*match_master)(struct device *, void *), + int (*match_master)(struct device *, int, void *), size_t extra_size); int snd_hdac_acomp_exit(struct hdac_bus *bus); int snd_hdac_acomp_register_notifier(struct hdac_bus *bus, @@ -47,7 +47,8 @@ static inline int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t ni } static inline int snd_hdac_acomp_init(struct hdac_bus *bus, const struct drm_audio_component_audio_ops *aops, - int (*match_master)(struct device *, void *), + int (*match_master)(struct device *, + int, void *), size_t extra_size) { return -ENODEV; diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c index a6d37b9d6413f5..5c95933e739a43 100644 --- a/sound/hda/hdac_component.c +++ b/sound/hda/hdac_component.c @@ -269,7 +269,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_acomp_register_notifier); */ int snd_hdac_acomp_init(struct hdac_bus *bus, const struct drm_audio_component_audio_ops *aops, - int (*match_master)(struct device *, void *), + int (*match_master)(struct device *, int, void *), size_t extra_size) { struct component_match *match = NULL; @@ -288,7 +288,7 @@ int snd_hdac_acomp_init(struct hdac_bus *bus, bus->audio_component = acomp; devres_add(dev, acomp); - component_match_add(dev, &match, match_master, bus); + component_match_add_typed(dev, &match, match_master, bus); ret = component_master_add_with_match(dev, &hdac_component_master_ops, match); if (ret < 0) diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index 617ff1aa818f99..7aee090e3d2758 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c @@ -82,9 +82,11 @@ void snd_hdac_i915_set_bclk(struct hdac_bus *bus) } EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk); -static int i915_component_master_match(struct device *dev, void *data) +static int i915_component_master_match(struct device *dev, int subcomponent, + void *data) { - return !strcmp(dev->driver->name, "i915"); + return !strcmp(dev->driver->name, "i915") && + subcomponent == I915_COMPONENT_AUDIO; } /* check whether intel graphics is present */ From 7f8dd9ead58c4db6d9247a6fac6afecceadadc4a Mon Sep 17 00:00:00 2001 From: Ricardo Biehl Pasquali Date: Wed, 13 Feb 2019 00:57:51 -0200 Subject: [PATCH 1174/1995] ALSA: pcm: Comment why read blocks when PCM is not running This avoids bringing back the problem introduced by 62ba568f7aef ("ALSA: pcm: Return 0 when size < start_threshold in capture") and fixed in 00a399cad1a0 ("ALSA: pcm: Revert capture stream behavior change in blocking mode"), which prevented the user from starting capture from another thread. Signed-off-by: Ricardo Biehl Pasquali Signed-off-by: Takashi Iwai (cherry picked from commit 932a81519572156a88dbc2349d183c603446f9c4) --- sound/core/pcm_lib.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index bcb06bd3d81d17..345ab1ab2cac49 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -2176,6 +2176,10 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) snd_pcm_update_hw_ptr(substream); + /* + * If size < start_threshold, wait indefinitely. Another + * thread may start capture + */ if (!is_playback && runtime->status->state == SNDRV_PCM_STATE_PREPARED && size >= runtime->start_threshold) { From 451431aa7ea253214779fac78b7873b4f2dcd1b7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 25 Feb 2019 16:49:27 +0100 Subject: [PATCH 1175/1995] ALSA: hda: Extend i915 component bind timeout I set 10 seconds for the timeout of the i915 audio component binding with a hope that recent machines are fast enough to handle all probe tasks in that period, but I was too optimistic. The binding may take longer than that, and this caused a problem on the machine with both audio and graphics driver modules loaded in parallel, as Paul Menzel experienced. This problem haven't hit so often just because the KMS driver is loaded in initrd on most machines. As a simple workaround, extend the timeout to 60 seconds. Fixes: f9b54e1961c7 ("ALSA: hda/i915: Allow delayed i915 audio component binding") Reported-by: Paul Menzel Cc: Signed-off-by: Takashi Iwai (cherry picked from commit cfc35f9c128cea8fce6a5513b1de50d36f3b209f) --- sound/hda/hdac_i915.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index 7aee090e3d2758..575198bd3cd00f 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c @@ -146,9 +146,9 @@ int snd_hdac_i915_init(struct hdac_bus *bus) return -ENODEV; if (!acomp->ops) { request_module("i915"); - /* 10s timeout */ + /* 60s timeout */ wait_for_completion_timeout(&bind_complete, - msecs_to_jiffies(10 * 1000)); + msecs_to_jiffies(60 * 1000)); } if (!acomp->ops) { dev_info(bus->dev, "couldn't bind with audio component\n"); From e2b72d40a2889c874debc5aa28e0dfad1b8f5fd1 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 8 Mar 2019 16:38:57 +0800 Subject: [PATCH 1176/1995] ASoC:soc-pcm:fix a codec fixup issue in TDM case On HDaudio platforms, if playback is started when capture is working, there is no audible output. This can be root-caused to the use of the rx|tx_mask to store an HDaudio stream tag. If capture is stared before playback, rx_mask would be non-zero on HDaudio platform, then the channel number of playback, which is in the same codec dai with the capture, would be changed by soc_pcm_codec_params_fixup based on the tx_mask at first, then overwritten by this function based on rx_mask at last. According to the author of tx|rx_mask, tx_mask is for playback and rx_mask is for capture. And stream direction is checked at all other references of tx|rx_mask in ASoC, so here should be an error. This patch checks stream direction for tx|rx_mask for fixup function. This issue would affect not only HDaudio+ASoC, but also I2S codecs if the channel number based on rx_mask is not equal to the one for tx_mask. It could be rarely reproduecd because most drivers in kernel set the same channel number to tx|rx_mask or rx_mask is zero. Tested on all platforms using stream_tag & HDaudio and intel I2S platforms. Signed-off-by: Rander Wang Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 570f18b6a8d1f0e60e8caf30e66161b6438dcc91) --- sound/soc/soc-pcm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 0d5ec68a1e5086..f60a9f58acf563 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -954,10 +954,13 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, codec_params = *params; /* fixup params based on TDM slot masks */ - if (codec_dai->tx_mask) + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + codec_dai->tx_mask) soc_pcm_codec_params_fixup(&codec_params, codec_dai->tx_mask); - if (codec_dai->rx_mask) + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && + codec_dai->rx_mask) soc_pcm_codec_params_fixup(&codec_params, codec_dai->rx_mask); From e55f2ed10b63b32896e1be274ea33734f9b1142a Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 8 Mar 2019 16:38:58 +0800 Subject: [PATCH 1177/1995] ASoC:hdac_hda:use correct format to setup hda codec The current implementation of the hdac_hda codec results in zero-valued samples on capture and noise with headset playback when SOF is used on platforms with an on-board HDaudio codec. This is root-caused to SOF using be_hw_params_fixup, and the prepare() call using invalid runtime fields to determine the format. This patch moves the format handling to the hw_params() callback, as done already for hdac_hdmi, to make sure the fixed-up information is taken into account but keeps the codec initialization in prepare() as the stream_tag is only available at that time. Moving everything in the prepare() callback is possible but the code is less elegant so this two-step solution was chosen. The solution was tested with the SST driver with no regressions, and all the issues with SOF playback and capture are solved. Signed-off-by: Rander Wang Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 03d0aa4d4fddce4a5d865d819a4d98bfc3d451e6) --- sound/soc/codecs/hdac_hda.c | 53 +++++++++++++++++++++++++++---------- sound/soc/codecs/hdac_hda.h | 1 + 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index ffecdaaa8cf2bb..f889d94c8e3cf7 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -38,6 +38,9 @@ static void hdac_hda_dai_close(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); +static int hdac_hda_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, @@ -50,6 +53,7 @@ static const struct snd_soc_dai_ops hdac_hda_dai_ops = { .startup = hdac_hda_dai_open, .shutdown = hdac_hda_dai_close, .prepare = hdac_hda_dai_prepare, + .hw_params = hdac_hda_dai_hw_params, .hw_free = hdac_hda_dai_hw_free, .set_tdm_slot = hdac_hda_dai_set_tdm_slot, }; @@ -139,6 +143,39 @@ static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, return 0; } +static int hdac_hda_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct hdac_hda_priv *hda_pvt; + unsigned int format_val; + unsigned int maxbps; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + maxbps = dai->driver->playback.sig_bits; + else + maxbps = dai->driver->capture.sig_bits; + + hda_pvt = snd_soc_component_get_drvdata(component); + format_val = snd_hdac_calc_stream_format(params_rate(params), + params_channels(params), + params_format(params), + maxbps, + 0); + if (!format_val) { + dev_err(dai->dev, + "invalid format_val, rate=%d, ch=%d, format=%d, maxbps=%d\n", + params_rate(params), params_channels(params), + params_format(params), maxbps); + + return -EINVAL; + } + + hda_pvt->pcm[dai->id].format_val[substream->stream] = format_val; + return 0; +} + static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -162,10 +199,9 @@ static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; + struct hda_pcm_stream *hda_stream; struct hdac_hda_priv *hda_pvt; - struct snd_pcm_runtime *runtime = substream->runtime; struct hdac_device *hdev; - struct hda_pcm_stream *hda_stream; unsigned int format_val; struct hda_pcm *pcm; unsigned int stream; @@ -179,19 +215,8 @@ static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, hda_stream = &pcm->stream[substream->stream]; - format_val = snd_hdac_calc_stream_format(runtime->rate, - runtime->channels, - runtime->format, - hda_stream->maxbps, - 0); - if (!format_val) { - dev_err(&hdev->dev, - "invalid format_val, rate=%d, ch=%d, format=%d\n", - runtime->rate, runtime->channels, runtime->format); - return -EINVAL; - } - stream = hda_pvt->pcm[dai->id].stream_tag[substream->stream]; + format_val = hda_pvt->pcm[dai->id].format_val[substream->stream]; ret = snd_hda_codec_prepare(&hda_pvt->codec, hda_stream, stream, format_val, substream); diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h index e444ef5933606c..6b1bd4f428e70e 100644 --- a/sound/soc/codecs/hdac_hda.h +++ b/sound/soc/codecs/hdac_hda.h @@ -8,6 +8,7 @@ struct hdac_hda_pcm { int stream_tag[2]; + unsigned int format_val[2]; }; struct hdac_hda_priv { From f81ad0196643d763016348d30f027c21638d4d08 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 8 Mar 2019 16:38:59 +0800 Subject: [PATCH 1178/1995] ASoC:intel:skl:fix a simultaneous playback & capture issue on hda platform If playback and capture are enabled concurrently, when the capture stops the output becomes inaudile. The playback application will become stuck and underrun after a timeout. This is caused by mistaken use of the stream_id, which should only be set for playback and not for capture Tested on Apollolake and Kabylake with SST driver. Signed-off-by: Rander Wang Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit c899df3e9b0bf7b76e642aed1a214582ea7012d5) --- sound/soc/intel/skylake/skl-pcm.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 1ae83f4ccc3615..56099db8f86ddf 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -181,6 +181,7 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) struct hdac_stream *hstream; struct hdac_ext_stream *stream; struct hdac_ext_link *link; + unsigned char stream_tag; hstream = snd_hdac_get_stream(bus, params->stream, params->link_dma_id + 1); @@ -199,10 +200,13 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) snd_hdac_ext_link_stream_setup(stream, format_val); - list_for_each_entry(link, &bus->hlink_list, list) { - if (link->index == params->link_index) - snd_hdac_ext_link_set_stream_id(link, - hstream->stream_tag); + stream_tag = hstream->stream_tag; + if (stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) { + list_for_each_entry(link, &bus->hlink_list, list) { + if (link->index == params->link_index) + snd_hdac_ext_link_set_stream_id(link, + stream_tag); + } } stream->link_prepared = 1; @@ -645,6 +649,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream, struct hdac_ext_stream *link_dev = snd_soc_dai_get_dma_data(dai, substream); struct hdac_ext_link *link; + unsigned char stream_tag; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -654,7 +659,11 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream, if (!link) return -EINVAL; - snd_hdac_ext_link_clear_stream_id(link, hdac_stream(link_dev)->stream_tag); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + stream_tag = hdac_stream(link_dev)->stream_tag; + snd_hdac_ext_link_clear_stream_id(link, stream_tag); + } + snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); return 0; } From a75be5200dccfbc31eeba47f466f4827b89e04d9 Mon Sep 17 00:00:00 2001 From: KaiChieh Chuang Date: Fri, 8 Mar 2019 13:05:53 +0800 Subject: [PATCH 1179/1995] ASoC: dpcm: prevent snd_soc_dpcm use after free The dpcm get from fe_clients/be_clients may be free before use Add a spin lock at snd_soc_card level, to protect the dpcm instance. The lock may be used in atomic context, so use spin lock. Use irq spin lock version, since the lock may be used in interrupts. possible race condition between void dpcm_be_disconnect( ... list_del(&dpcm->list_be); list_del(&dpcm->list_fe); kfree(dpcm); ... and for_each_dpcm_fe() for_each_dpcm_be*() race condition example Thread 1: snd_soc_dapm_mixer_update_power() -> soc_dpcm_runtime_update() -> dpcm_be_disconnect() -> kfree(dpcm); Thread 2: dpcm_fe_dai_trigger() -> dpcm_be_dai_trigger() -> snd_soc_dpcm_can_be_free_stop() -> if (dpcm->fe == fe) Excpetion Scenario: two FE link to same BE FE1 -> BE FE2 -> Thread 1: switch of mixer between FE2 -> BE Thread 2: pcm_stop FE1 Exception: Unable to handle kernel paging request at virtual address dead0000000000e0 pc=<> [] dpcm_be_dai_trigger+0x29c/0x47c sound/soc/soc-pcm.c:3226 if (dpcm->fe == fe) lr=<> [] dpcm_fe_dai_do_trigger+0x94/0x26c Backtrace: [] notify_die+0x68/0xb8 [] die+0x118/0x2a8 [] __do_kernel_fault+0x13c/0x14c [] do_translation_fault+0x64/0xa0 [] do_mem_abort+0x4c/0xd0 [] el1_da+0x24/0x40 [] dpcm_be_dai_trigger+0x29c/0x47c [] dpcm_fe_dai_do_trigger+0x94/0x26c [] dpcm_fe_dai_trigger+0x3c/0x44 [] snd_pcm_do_stop+0x50/0x5c [] snd_pcm_action+0xb4/0x13c [] snd_pcm_drop+0xa0/0x128 [] snd_pcm_common_ioctl+0x9d8/0x30f0 [] snd_pcm_ioctl_compat+0x29c/0x2f14 [] compat_SyS_ioctl+0x128/0x244 [] el0_svc_naked+0x34/0x38 [] 0xffffffffffffffff Signed-off-by: KaiChieh Chuang Signed-off-by: Mark Brown (cherry picked from commit a9764869779081e8bf24da07ac040e8f3efcf13a) --- include/sound/soc.h | 2 ++ sound/soc/soc-core.c | 1 + sound/soc/soc-pcm.c | 40 +++++++++++++++++++++++++++++++++------- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index eb7db605955b85..1e2be35ed36f2b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1083,6 +1083,8 @@ struct snd_soc_card { struct mutex mutex; struct mutex dapm_mutex; + spinlock_t dpcm_lock; + bool instantiated; bool topology_shortname_created; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 5a5764dba1479c..d887576597290d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2820,6 +2820,7 @@ int snd_soc_register_card(struct snd_soc_card *card) card->instantiated = 0; mutex_init(&card->mutex); mutex_init(&card->dapm_mutex); + spin_lock_init(&card->dpcm_lock); return snd_soc_bind_card(card); } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index f60a9f58acf563..7fe5321000e877 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1216,6 +1216,7 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, struct snd_soc_pcm_runtime *be, int stream) { struct snd_soc_dpcm *dpcm; + unsigned long flags; /* only add new dpcms */ for_each_dpcm_be(fe, stream, dpcm) { @@ -1231,8 +1232,10 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, dpcm->fe = fe; be->dpcm[stream].runtime = fe->dpcm[stream].runtime; dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW; + spin_lock_irqsave(&fe->card->dpcm_lock, flags); list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients); list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients); + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n", stream ? "capture" : "playback", fe->dai_link->name, @@ -1278,6 +1281,7 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe, void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm, *d; + unsigned long flags; for_each_dpcm_be_safe(fe, stream, dpcm, d) { dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n", @@ -1297,8 +1301,10 @@ void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) #ifdef CONFIG_DEBUG_FS debugfs_remove(dpcm->debugfs_state); #endif + spin_lock_irqsave(&fe->card->dpcm_lock, flags); list_del(&dpcm->list_be); list_del(&dpcm->list_fe); + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); kfree(dpcm); } } @@ -1550,10 +1556,13 @@ int dpcm_process_paths(struct snd_soc_pcm_runtime *fe, void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm; + unsigned long flags; + spin_lock_irqsave(&fe->card->dpcm_lock, flags); for_each_dpcm_be(fe, stream, dpcm) dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); } static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, @@ -2574,6 +2583,7 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) struct snd_soc_dpcm *dpcm; enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; int ret; + unsigned long flags; dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n", stream ? "capture" : "playback", fe->dai_link->name); @@ -2643,11 +2653,13 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) dpcm_be_dai_shutdown(fe, stream); disconnect: /* disconnect any non started BEs */ + spin_lock_irqsave(&fe->card->dpcm_lock, flags); for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; } + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); return ret; } @@ -3224,7 +3236,10 @@ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, { struct snd_soc_dpcm *dpcm; int state; + int ret = 1; + unsigned long flags; + spin_lock_irqsave(&fe->card->dpcm_lock, flags); for_each_dpcm_fe(be, stream, dpcm) { if (dpcm->fe == fe) @@ -3233,12 +3248,15 @@ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, state = dpcm->fe->dpcm[stream].state; if (state == SND_SOC_DPCM_STATE_START || state == SND_SOC_DPCM_STATE_PAUSED || - state == SND_SOC_DPCM_STATE_SUSPEND) - return 0; + state == SND_SOC_DPCM_STATE_SUSPEND) { + ret = 0; + break; + } } + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); /* it's safe to free/stop this BE DAI */ - return 1; + return ret; } EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop); @@ -3251,7 +3269,10 @@ int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe, { struct snd_soc_dpcm *dpcm; int state; + int ret = 1; + unsigned long flags; + spin_lock_irqsave(&fe->card->dpcm_lock, flags); for_each_dpcm_fe(be, stream, dpcm) { if (dpcm->fe == fe) @@ -3261,12 +3282,15 @@ int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe, if (state == SND_SOC_DPCM_STATE_START || state == SND_SOC_DPCM_STATE_PAUSED || state == SND_SOC_DPCM_STATE_SUSPEND || - state == SND_SOC_DPCM_STATE_PREPARE) - return 0; + state == SND_SOC_DPCM_STATE_PREPARE) { + ret = 0; + break; + } } + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); /* it's safe to change hw_params */ - return 1; + return ret; } EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params); @@ -3305,6 +3329,7 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params; struct snd_soc_dpcm *dpcm; ssize_t offset = 0; + unsigned long flags; /* FE state */ offset += snprintf(buf + offset, size - offset, @@ -3332,6 +3357,7 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, goto out; } + spin_lock_irqsave(&fe->card->dpcm_lock, flags); for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; params = &dpcm->hw_params; @@ -3352,7 +3378,7 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, params_channels(params), params_rate(params)); } - + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); out: return offset; } From b0543efa7b202241de387ba790499228070316d5 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Mon, 11 Mar 2019 09:36:45 +0800 Subject: [PATCH 1180/1995] ASoC: nau8824: fix the issue of the widget with prefix name The driver has two issues when machine add prefix name for codec. (1)The stream name of DAI can't find the AIF widgets. (2)The drivr can enable/disalbe the MICBIAS and SAR widgets. The patch will fix these issues caused by prefixed name added. Signed-off-by: John Hsu Signed-off-by: Mark Brown (cherry picked from commit 844a4a362dbec166b44d6b9b3dd45b08cb273703) --- sound/soc/codecs/nau8824.c | 46 +++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index 87ed3dc496dc2d..5ab05e75edeac6 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -681,8 +681,8 @@ static const struct snd_soc_dapm_widget nau8824_dapm_widgets[] = { SND_SOC_DAPM_ADC("ADCR", NULL, NAU8824_REG_ANALOG_ADC_2, NAU8824_ADCR_EN_SFT, 0), - SND_SOC_DAPM_AIF_OUT("AIFTX", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("AIFRX", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIFTX", "Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIFRX", "Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_DAC("DACL", NULL, NAU8824_REG_RDAC, NAU8824_DACL_EN_SFT, 0), @@ -831,6 +831,36 @@ static void nau8824_int_status_clear_all(struct regmap *regmap) } } +static void nau8824_dapm_disable_pin(struct nau8824 *nau8824, const char *pin) +{ + struct snd_soc_dapm_context *dapm = nau8824->dapm; + const char *prefix = dapm->component->name_prefix; + char prefixed_pin[80]; + + if (prefix) { + snprintf(prefixed_pin, sizeof(prefixed_pin), "%s %s", + prefix, pin); + snd_soc_dapm_disable_pin(dapm, prefixed_pin); + } else { + snd_soc_dapm_disable_pin(dapm, pin); + } +} + +static void nau8824_dapm_enable_pin(struct nau8824 *nau8824, const char *pin) +{ + struct snd_soc_dapm_context *dapm = nau8824->dapm; + const char *prefix = dapm->component->name_prefix; + char prefixed_pin[80]; + + if (prefix) { + snprintf(prefixed_pin, sizeof(prefixed_pin), "%s %s", + prefix, pin); + snd_soc_dapm_force_enable_pin(dapm, prefixed_pin); + } else { + snd_soc_dapm_force_enable_pin(dapm, pin); + } +} + static void nau8824_eject_jack(struct nau8824 *nau8824) { struct snd_soc_dapm_context *dapm = nau8824->dapm; @@ -839,8 +869,8 @@ static void nau8824_eject_jack(struct nau8824 *nau8824) /* Clear all interruption status */ nau8824_int_status_clear_all(regmap); - snd_soc_dapm_disable_pin(dapm, "SAR"); - snd_soc_dapm_disable_pin(dapm, "MICBIAS"); + nau8824_dapm_disable_pin(nau8824, "SAR"); + nau8824_dapm_disable_pin(nau8824, "MICBIAS"); snd_soc_dapm_sync(dapm); /* Enable the insertion interruption, disable the ejection @@ -870,8 +900,8 @@ static void nau8824_jdet_work(struct work_struct *work) struct regmap *regmap = nau8824->regmap; int adc_value, event = 0, event_mask = 0; - snd_soc_dapm_force_enable_pin(dapm, "MICBIAS"); - snd_soc_dapm_force_enable_pin(dapm, "SAR"); + nau8824_dapm_enable_pin(nau8824, "MICBIAS"); + nau8824_dapm_enable_pin(nau8824, "SAR"); snd_soc_dapm_sync(dapm); msleep(100); @@ -882,8 +912,8 @@ static void nau8824_jdet_work(struct work_struct *work) if (adc_value < HEADSET_SARADC_THD) { event |= SND_JACK_HEADPHONE; - snd_soc_dapm_disable_pin(dapm, "SAR"); - snd_soc_dapm_disable_pin(dapm, "MICBIAS"); + nau8824_dapm_disable_pin(nau8824, "SAR"); + nau8824_dapm_disable_pin(nau8824, "MICBIAS"); snd_soc_dapm_sync(dapm); } else { event |= SND_JACK_HEADSET; From fc68a4a0e50eaf03034f0590140ea08374dd8d94 Mon Sep 17 00:00:00 2001 From: Mariusz Ceier Date: Mon, 11 Mar 2019 21:53:57 +0100 Subject: [PATCH 1181/1995] ALSA: hda: Avoid NULL pointer dereference at snd_hdac_stream_start() For ca0132 codec, azx_dev->stream is NULL during firmware loading. Calling snd_hdac_get_stream_stripe_ctl unconditionally causes NULL pointer dereference in that function. Fixes: 9b6f7e7a296e ("ALSA: hda: program stripe bits for controller") Signed-off-by: Mariusz Ceier Signed-off-by: Takashi Iwai (cherry picked from commit d344e07940f3a3a93dec38f36593cca1591a7a5e) --- sound/hda/hdac_stream.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index f5dd288d1a7a39..76e9b41fcea2cb 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -95,7 +95,10 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start) 1 << azx_dev->index, 1 << azx_dev->index); /* set stripe control */ - stripe_ctl = snd_hdac_get_stream_stripe_ctl(bus, azx_dev->substream); + if (azx_dev->substream) + stripe_ctl = snd_hdac_get_stream_stripe_ctl(bus, azx_dev->substream); + else + stripe_ctl = 0; snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, stripe_ctl); /* set DMA start and interrupt mask */ From 2ca603d45be4b99129bd773141fd545712def4b4 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Wed, 13 Mar 2019 16:23:44 +0800 Subject: [PATCH 1182/1995] ASoC: nau8810: fix the issue of widget with prefixed name The driver changes the stream name of DAC and ADC to avoid the issue of widget with prefixed name. When the machine adds prefixed name for codec, the stream name of DAI may not find the widgets. Signed-off-by: John Hsu Signed-off-by: Mark Brown (cherry picked from commit 54d1cf78b0f4ba348a7c7fb8b7d0708d71b6cc8a) --- sound/soc/codecs/nau8810.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c index bfd74b86c9d2f4..645aa07941237d 100644 --- a/sound/soc/codecs/nau8810.c +++ b/sound/soc/codecs/nau8810.c @@ -411,9 +411,9 @@ static const struct snd_soc_dapm_widget nau8810_dapm_widgets[] = { SND_SOC_DAPM_MIXER("Mono Mixer", NAU8810_REG_POWER3, NAU8810_MOUTMX_EN_SFT, 0, &nau8810_mono_mixer_controls[0], ARRAY_SIZE(nau8810_mono_mixer_controls)), - SND_SOC_DAPM_DAC("DAC", "HiFi Playback", NAU8810_REG_POWER3, + SND_SOC_DAPM_DAC("DAC", "Playback", NAU8810_REG_POWER3, NAU8810_DAC_EN_SFT, 0), - SND_SOC_DAPM_ADC("ADC", "HiFi Capture", NAU8810_REG_POWER2, + SND_SOC_DAPM_ADC("ADC", "Capture", NAU8810_REG_POWER2, NAU8810_ADC_EN_SFT, 0), SND_SOC_DAPM_PGA("SpkN Out", NAU8810_REG_POWER3, NAU8810_NSPK_EN_SFT, 0, NULL, 0), From 8db1b5eb98cff5bb3ad938e2ae30a4d4ec2bac17 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Wed, 13 Mar 2019 14:47:18 +0800 Subject: [PATCH 1183/1995] ASoC: nau8810: use 64-bit arithmetic instead of 32-bit Add suffix ULL to constant 256 in order to give the compiler complete information about the proper arithmetic to use. Signed-off-by: John Hsu Signed-off-by: Mark Brown (cherry picked from commit b517229ca2f7836125be58997808f2803f9ebc86) --- sound/soc/codecs/nau8810.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c index 645aa07941237d..d6f35615ce1ba3 100644 --- a/sound/soc/codecs/nau8810.c +++ b/sound/soc/codecs/nau8810.c @@ -505,7 +505,7 @@ static int nau88l0_calc_pll(unsigned int pll_in, f2_max = 0; scal_sel = ARRAY_SIZE(nau8810_mclk_scaler); for (i = 0; i < ARRAY_SIZE(nau8810_mclk_scaler); i++) { - f2 = 256 * fs * 4 * nau8810_mclk_scaler[i] / 10; + f2 = 256ULL * fs * 4 * nau8810_mclk_scaler[i] / 10; if (f2 > NAU_PLL_FREQ_MIN && f2 < NAU_PLL_FREQ_MAX && f2_max < f2) { f2_max = f2; From 51b56257685cf3efe32978ad76f770b7a7f26b83 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Wed, 13 Mar 2019 15:04:16 +0800 Subject: [PATCH 1184/1995] ASoC: nau8810: fix the typo of function name Correct the typo at the function name. Signed-off-by: John Hsu Signed-off-by: Mark Brown (cherry picked from commit 709a9b8a1f4ff6c34c0a6e6fefb31cfb23b19bf5) --- sound/soc/codecs/nau8810.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c index d6f35615ce1ba3..832657720a5ff1 100644 --- a/sound/soc/codecs/nau8810.c +++ b/sound/soc/codecs/nau8810.c @@ -493,7 +493,7 @@ static int nau8810_set_sysclk(struct snd_soc_dai *dai, return 0; } -static int nau88l0_calc_pll(unsigned int pll_in, +static int nau8810_calc_pll(unsigned int pll_in, unsigned int fs, struct nau8810_pll *pll_param) { u64 f2, f2_max, pll_ratio; @@ -542,7 +542,7 @@ static int nau8810_set_pll(struct snd_soc_dai *codec_dai, int pll_id, int ret, fs; fs = freq_out / 256; - ret = nau88l0_calc_pll(freq_in, fs, pll_param); + ret = nau8810_calc_pll(freq_in, fs, pll_param); if (ret < 0) { dev_err(nau8810->dev, "Unsupported input clock %d\n", freq_in); return ret; From 19a781c96d16dca2fa5845212d3a8edc2d0aed04 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Wed, 13 Mar 2019 16:52:01 +0800 Subject: [PATCH 1185/1995] ASoC: nau8810: automatic selecting BCLK in I2S master mode The driver will select correct BCLK automatically according to BCLK and FS information in I2S master mode. Signed-off-by: John Hsu Signed-off-by: Mark Brown (cherry picked from commit 20b83421e8eea43e28cb7aeea3e3f865f86aa69d) --- sound/soc/codecs/nau8810.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c index 832657720a5ff1..125e205e668715 100644 --- a/sound/soc/codecs/nau8810.c +++ b/sound/soc/codecs/nau8810.c @@ -667,6 +667,24 @@ static int nau8810_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct nau8810 *nau8810 = snd_soc_component_get_drvdata(component); int val_len = 0, val_rate = 0, ret = 0; + unsigned int ctrl_val, bclk_fs, bclk_div; + + /* Select BCLK configuration if the codec as master. */ + regmap_read(nau8810->regmap, NAU8810_REG_CLOCK, &ctrl_val); + if (ctrl_val & NAU8810_CLKIO_MASTER) { + /* get the bclk and fs ratio */ + bclk_fs = snd_soc_params_to_bclk(params) / params_rate(params); + if (bclk_fs <= 32) + bclk_div = NAU8810_BCLKDIV_8; + else if (bclk_fs <= 64) + bclk_div = NAU8810_BCLKDIV_4; + else if (bclk_fs <= 128) + bclk_div = NAU8810_BCLKDIV_2; + else + return -EINVAL; + regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK, + NAU8810_BCLKSEL_MASK, bclk_div); + } switch (params_width(params)) { case 16: From 415c85e5d479a60ef49c43bb522c0fa45888098b Mon Sep 17 00:00:00 2001 From: Bard liao Date: Wed, 13 Mar 2019 21:49:43 +0800 Subject: [PATCH 1186/1995] ASoC: topology: create tlv before soc_tplg_init_kcontrol Component driver may want to use tlv data. Create tlv before soc_tplg_init_kcontrol so component driver can use the tlv data in the control_load ops. Signed-off-by: Bard liao Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 3789debfc379ac84b90e2db32d7a6b66d28a2c7c) --- sound/soc/soc-topology.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 25fca7055464a8..fbee4720b8346b 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -894,19 +894,20 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, continue; } + /* create any TLV data */ + soc_tplg_create_tlv(tplg, &kc, &mc->hdr); + /* pass control to driver for optional further init */ err = soc_tplg_init_kcontrol(tplg, &kc, (struct snd_soc_tplg_ctl_hdr *) mc); if (err < 0) { dev_err(tplg->dev, "ASoC: failed to init %s\n", mc->hdr.name); + soc_tplg_free_tlv(tplg, &kc); kfree(sm); continue; } - /* create any TLV data */ - soc_tplg_create_tlv(tplg, &kc, &mc->hdr); - /* register control here */ err = soc_tplg_add_kcontrol(tplg, &kc, &sm->dobj.control.kcontrol); @@ -1324,18 +1325,19 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( continue; } + /* create any TLV data */ + soc_tplg_create_tlv(tplg, &kc[i], &mc->hdr); + /* pass control to driver for optional further init */ err = soc_tplg_init_kcontrol(tplg, &kc[i], (struct snd_soc_tplg_ctl_hdr *)mc); if (err < 0) { dev_err(tplg->dev, "ASoC: failed to init %s\n", mc->hdr.name); + soc_tplg_free_tlv(tplg, &kc[i]); kfree(sm); continue; } - - /* create any TLV data */ - soc_tplg_create_tlv(tplg, &kc[i], &mc->hdr); } return kc; From 2fab6ea5053a7f86df02ca99f1ee24a0e161dee9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 5 Mar 2019 12:38:59 +0100 Subject: [PATCH 1187/1995] ASoC: rt5651: Add support for active-high jack detect Some boards use a jack-receptacle with a switch which reports the jack-inserted status as active-high, rather then the standard active-low reporting most jacks use. This commit adds support for it. This is activated by a boolean "realtek,jack-detect-not-inverted" device-property. The not-inverted in the device-property name, rather then active-high, was chosen to keep the device-property naming consistent with the rt5640 codec driver. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit 8a68a509ae6b5d7d18c6bfc88553ca7761029ada) --- .../devicetree/bindings/sound/rt5651.txt | 5 ++ sound/soc/codecs/rt5651.c | 47 ++++++++++++++++--- sound/soc/codecs/rt5651.h | 1 + 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/rt5651.txt b/Documentation/devicetree/bindings/sound/rt5651.txt index a41199a5cd79b5..56e736a1cba974 100644 --- a/Documentation/devicetree/bindings/sound/rt5651.txt +++ b/Documentation/devicetree/bindings/sound/rt5651.txt @@ -22,6 +22,11 @@ Optional properties: 2: Use JD1_2 pin for jack-detect 3: Use JD2 pin for jack-detect +- realtek,jack-detect-not-inverted + bool. Normal jack-detect switches give an inverted (active-low) signal, + set this bool in the rare case you've a jack-detect switch which is not + inverted. + - realtek,over-current-threshold-microamp u32, micbias over-current detection threshold in µA, valid values are 600, 1500 and 2000µA. diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 29b2d60076b022..cb8252ff31cb86 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -1645,7 +1645,10 @@ static bool rt5651_jack_inserted(struct snd_soc_component *component) break; } - return val == 0; + if (rt5651->jd_active_high) + return val != 0; + else + return val == 0; } /* Jack detect and button-press timings */ @@ -1868,20 +1871,47 @@ static void rt5651_enable_jack_detect(struct snd_soc_component *component, case RT5651_JD1_1: snd_soc_component_update_bits(component, RT5651_JD_CTRL2, RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_1); - snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1, - RT5651_JD1_1_IRQ_EN, RT5651_JD1_1_IRQ_EN); + /* active-low is normal, set inv flag for active-high */ + if (rt5651->jd_active_high) + snd_soc_component_update_bits(component, + RT5651_IRQ_CTRL1, + RT5651_JD1_1_IRQ_EN | RT5651_JD1_1_INV, + RT5651_JD1_1_IRQ_EN | RT5651_JD1_1_INV); + else + snd_soc_component_update_bits(component, + RT5651_IRQ_CTRL1, + RT5651_JD1_1_IRQ_EN | RT5651_JD1_1_INV, + RT5651_JD1_1_IRQ_EN); break; case RT5651_JD1_2: snd_soc_component_update_bits(component, RT5651_JD_CTRL2, RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_2); - snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1, - RT5651_JD1_2_IRQ_EN, RT5651_JD1_2_IRQ_EN); + /* active-low is normal, set inv flag for active-high */ + if (rt5651->jd_active_high) + snd_soc_component_update_bits(component, + RT5651_IRQ_CTRL1, + RT5651_JD1_2_IRQ_EN | RT5651_JD1_2_INV, + RT5651_JD1_2_IRQ_EN | RT5651_JD1_2_INV); + else + snd_soc_component_update_bits(component, + RT5651_IRQ_CTRL1, + RT5651_JD1_2_IRQ_EN | RT5651_JD1_2_INV, + RT5651_JD1_2_IRQ_EN); break; case RT5651_JD2: snd_soc_component_update_bits(component, RT5651_JD_CTRL2, RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD2); - snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1, - RT5651_JD2_IRQ_EN, RT5651_JD2_IRQ_EN); + /* active-low is normal, set inv flag for active-high */ + if (rt5651->jd_active_high) + snd_soc_component_update_bits(component, + RT5651_IRQ_CTRL1, + RT5651_JD2_IRQ_EN | RT5651_JD2_INV, + RT5651_JD2_IRQ_EN | RT5651_JD2_INV); + else + snd_soc_component_update_bits(component, + RT5651_IRQ_CTRL1, + RT5651_JD2_IRQ_EN | RT5651_JD2_INV, + RT5651_JD2_IRQ_EN); break; default: dev_err(component->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n"); @@ -1986,6 +2016,9 @@ static void rt5651_apply_properties(struct snd_soc_component *component) "realtek,jack-detect-source", &val) == 0) rt5651->jd_src = val; + if (device_property_read_bool(component->dev, "realtek,jack-detect-not-inverted")) + rt5651->jd_active_high = true; + /* * Testing on various boards has shown that good defaults for the OVCD * threshold and scale-factor are 2000µA and 0.75. For an effective diff --git a/sound/soc/codecs/rt5651.h b/sound/soc/codecs/rt5651.h index 41fcb8b5eb4072..05b0f6f8b95d38 100644 --- a/sound/soc/codecs/rt5651.h +++ b/sound/soc/codecs/rt5651.h @@ -2083,6 +2083,7 @@ struct rt5651_priv { int release_count; int poll_count; unsigned int jd_src; + bool jd_active_high; unsigned int ovcd_th; unsigned int ovcd_sf; From 78e14767d2db16ad5e8e7ba5eb13d505ce5c2edc Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 5 Mar 2019 12:39:00 +0100 Subject: [PATCH 1188/1995] ASoC: Intel: bytcr_rt5651: Add BYT_RT5651_JD_NOT_INV quirk Add BYT_RT5651_JD_NOT_INV quirk for devices with an inverted (active-high instead of the normal active-low) jack-detect switch. And add a quirk for the Complet Electro Serv MY8307 tablet which has an inverted jack-detect switch (and a mono-speaker). Signed-off-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit a0cb2d4357e483b7bca3c06f790d8f5d4cc20d84) --- sound/soc/intel/boards/bytcr_rt5651.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index b0a4d297176e02..4ed59f41ee8357 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -79,14 +79,15 @@ enum { #define BYT_RT5651_SSP0_AIF2 BIT(21) #define BYT_RT5651_HP_LR_SWAPPED BIT(22) #define BYT_RT5651_MONO_SPEAKER BIT(23) +#define BYT_RT5651_JD_NOT_INV BIT(24) #define BYT_RT5651_DEFAULT_QUIRKS (BYT_RT5651_MCLK_EN | \ BYT_RT5651_JD1_1 | \ BYT_RT5651_OVCD_TH_2000UA | \ BYT_RT5651_OVCD_SF_0P75) -/* jack-detect-source + dmic-en + ovcd-th + -sf + terminating empty entry */ -#define MAX_NO_PROPS 5 +/* jack-detect-source + inv + dmic-en + ovcd-th + -sf + terminating entry */ +#define MAX_NO_PROPS 6 struct byt_rt5651_private { struct clk *mclk; @@ -137,6 +138,8 @@ static void log_quirks(struct device *dev) dev_info(dev, "quirk SSP0_AIF2 enabled\n"); if (byt_rt5651_quirk & BYT_RT5651_MONO_SPEAKER) dev_info(dev, "quirk MONO_SPEAKER enabled\n"); + if (byt_rt5651_quirk & BYT_RT5651_JD_NOT_INV) + dev_info(dev, "quirk JD_NOT_INV enabled\n"); } #define BYT_CODEC_DAI1 "rt5651-aif1" @@ -414,6 +417,18 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = { BYT_RT5651_HP_LR_SWAPPED | BYT_RT5651_MONO_SPEAKER), }, + { + /* Complet Electro Serv MY8307 */ + .callback = byt_rt5651_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Complet Electro Serv"), + DMI_MATCH(DMI_PRODUCT_NAME, "MY8307"), + }, + .driver_data = (void *)(BYT_RT5651_DEFAULT_QUIRKS | + BYT_RT5651_IN2_MAP | + BYT_RT5651_MONO_SPEAKER | + BYT_RT5651_JD_NOT_INV), + }, { /* I.T.Works TW701, Ployer Momo7w and Trekstor ST70416-6 * (these all use the same mainboard) */ @@ -525,6 +540,9 @@ static int byt_rt5651_add_codec_device_props(struct device *i2c_dev) if (byt_rt5651_quirk & BYT_RT5651_DMIC_EN) props[cnt++] = PROPERTY_ENTRY_BOOL("realtek,dmic-en"); + if (byt_rt5651_quirk & BYT_RT5651_JD_NOT_INV) + props[cnt++] = PROPERTY_ENTRY_BOOL("realtek,jack-detect-not-inverted"); + return device_add_properties(i2c_dev, props); } From 848b6fa4189206a6a9dcda69fb8a86b393f2daf3 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Fri, 8 Mar 2019 11:36:08 +0800 Subject: [PATCH 1189/1995] ASoC: rt5682: Check JD status when system resume The IRQ function may not work when system suspend. We remove snd_soc_dapm_force_enable_pin function call to make sure the bias off when idle and run into suspend/resume function. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown (cherry picked from commit 4834d7070c85a5fb69637265dbbb05d13043280c) --- sound/soc/codecs/rt5682.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 9d5acd2d04abd4..b7e2e9937e6d45 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -910,13 +910,20 @@ static int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert) { struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); unsigned int val, count; if (jack_insert) { - snd_soc_dapm_force_enable_pin(dapm, "CBJ Power"); - snd_soc_dapm_sync(dapm); + + snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1, + RT5682_PWR_VREF2, RT5682_PWR_VREF2); + snd_soc_component_update_bits(component, + RT5682_PWR_ANLG_1, RT5682_PWR_FV2, 0); + usleep_range(15000, 20000); + snd_soc_component_update_bits(component, + RT5682_PWR_ANLG_1, RT5682_PWR_FV2, RT5682_PWR_FV2); + snd_soc_component_update_bits(component, RT5682_PWR_ANLG_3, + RT5682_PWR_CBJ, RT5682_PWR_CBJ); + snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1, RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_HIGH); @@ -944,8 +951,10 @@ static int rt5682_headset_detect(struct snd_soc_component *component, rt5682_enable_push_button_irq(component, false); snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1, RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_LOW); - snd_soc_dapm_disable_pin(dapm, "CBJ Power"); - snd_soc_dapm_sync(dapm); + snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1, + RT5682_PWR_VREF2, 0); + snd_soc_component_update_bits(component, RT5682_PWR_ANLG_3, + RT5682_PWR_CBJ, 0); rt5682->jack_type = 0; } @@ -1591,8 +1600,6 @@ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = { 0, NULL, 0), SND_SOC_DAPM_SUPPLY("Vref1", RT5682_PWR_ANLG_1, RT5682_PWR_VREF1_BIT, 0, rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), - SND_SOC_DAPM_SUPPLY("Vref2", RT5682_PWR_ANLG_1, RT5682_PWR_VREF2_BIT, 0, - rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), /* ASRC */ SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5682_PLL_TRACK_1, @@ -1627,9 +1634,6 @@ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = { SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("CBJ Power", RT5682_PWR_ANLG_3, - RT5682_PWR_CBJ_BIT, 0, NULL, 0), - /* REC Mixer */ SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5682_rec1_l_mix, ARRAY_SIZE(rt5682_rec1_l_mix)), @@ -1792,17 +1796,13 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = { /*Vref*/ {"MICBIAS1", NULL, "Vref1"}, - {"MICBIAS1", NULL, "Vref2"}, {"MICBIAS2", NULL, "Vref1"}, - {"MICBIAS2", NULL, "Vref2"}, {"CLKDET SYS", NULL, "CLKDET"}, {"IN1P", NULL, "LDO2"}, {"BST1 CBJ", NULL, "IN1P"}, - {"BST1 CBJ", NULL, "CBJ Power"}, - {"CBJ Power", NULL, "Vref2"}, {"RECMIX1L", "CBJ Switch", "BST1 CBJ"}, {"RECMIX1L", NULL, "RECMIX1L Power"}, @@ -1912,9 +1912,7 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = { {"HP Amp", NULL, "Capless"}, {"HP Amp", NULL, "Charge Pump"}, {"HP Amp", NULL, "CLKDET SYS"}, - {"HP Amp", NULL, "CBJ Power"}, {"HP Amp", NULL, "Vref1"}, - {"HP Amp", NULL, "Vref2"}, {"HPOL Playback", "Switch", "HP Amp"}, {"HPOR Playback", "Switch", "HP Amp"}, {"HPOL", NULL, "HPOL Playback"}, @@ -2363,6 +2361,8 @@ static int rt5682_resume(struct snd_soc_component *component) regcache_cache_only(rt5682->regmap, false); regcache_sync(rt5682->regmap); + rt5682_irq(0, rt5682); + return 0; } #else From 128aa79d7fce94ccd57714c65591a80193202fb0 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 18 Mar 2019 15:17:13 +0800 Subject: [PATCH 1190/1995] ASoC: rt5682: fix jack type detection issue The jack type detection needs the main bias power of analog. The modification makes sure the main bias power on/off while jack plug/unplug. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown (cherry picked from commit 675212bfb23394514b7f68ebf3954ba936281ccc) --- sound/soc/codecs/rt5682.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index b7e2e9937e6d45..b98974edf6ad18 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -915,7 +915,8 @@ static int rt5682_headset_detect(struct snd_soc_component *component, if (jack_insert) { snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1, - RT5682_PWR_VREF2, RT5682_PWR_VREF2); + RT5682_PWR_VREF2 | RT5682_PWR_MB, + RT5682_PWR_VREF2 | RT5682_PWR_MB); snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1, RT5682_PWR_FV2, 0); usleep_range(15000, 20000); @@ -952,7 +953,7 @@ static int rt5682_headset_detect(struct snd_soc_component *component, snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1, RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_LOW); snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1, - RT5682_PWR_VREF2, 0); + RT5682_PWR_VREF2 | RT5682_PWR_MB, 0); snd_soc_component_update_bits(component, RT5682_PWR_ANLG_3, RT5682_PWR_CBJ, 0); @@ -2301,16 +2302,13 @@ static int rt5682_set_bias_level(struct snd_soc_component *component, switch (level) { case SND_SOC_BIAS_PREPARE: regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1, - RT5682_PWR_MB | RT5682_PWR_BG, - RT5682_PWR_MB | RT5682_PWR_BG); + RT5682_PWR_BG, RT5682_PWR_BG); regmap_update_bits(rt5682->regmap, RT5682_PWR_DIG_1, RT5682_DIG_GATE_CTRL | RT5682_PWR_LDO, RT5682_DIG_GATE_CTRL | RT5682_PWR_LDO); break; case SND_SOC_BIAS_STANDBY: - regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1, - RT5682_PWR_MB, RT5682_PWR_MB); regmap_update_bits(rt5682->regmap, RT5682_PWR_DIG_1, RT5682_DIG_GATE_CTRL, RT5682_DIG_GATE_CTRL); break; @@ -2318,7 +2316,7 @@ static int rt5682_set_bias_level(struct snd_soc_component *component, regmap_update_bits(rt5682->regmap, RT5682_PWR_DIG_1, RT5682_DIG_GATE_CTRL | RT5682_PWR_LDO, 0); regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1, - RT5682_PWR_MB | RT5682_PWR_BG, 0); + RT5682_PWR_BG, 0); break; default: From 759a670580a0310f252ceb56fe4baaec77cb210d Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 18 Mar 2019 15:17:42 +0800 Subject: [PATCH 1191/1995] ASoC: rt5682: recording has no sound after booting If ASRC turns on, HW will use clk_dac as the reference clock whether recording or playback. Both of clk_dac and clk_adc should set proper clock while using ASRC. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown (cherry picked from commit 1c5b6a27e432e4fe170a924c8b41012271496a4c) --- sound/soc/codecs/rt5682.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index b98974edf6ad18..86a7fa31c294b2 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -1208,7 +1208,7 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); - int ref, val, reg, sft, mask, idx = -EINVAL; + int ref, val, reg, idx = -EINVAL; static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48}; static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48}; @@ -1222,15 +1222,10 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w, idx = rt5682_div_sel(rt5682, ref, div_f, ARRAY_SIZE(div_f)); - if (w->shift == RT5682_PWR_ADC_S1F_BIT) { + if (w->shift == RT5682_PWR_ADC_S1F_BIT) reg = RT5682_PLL_TRACK_3; - sft = RT5682_ADC_OSR_SFT; - mask = RT5682_ADC_OSR_MASK; - } else { + else reg = RT5682_PLL_TRACK_2; - sft = RT5682_DAC_OSR_SFT; - mask = RT5682_DAC_OSR_MASK; - } snd_soc_component_update_bits(component, reg, RT5682_FILTER_CLK_DIV_MASK, idx << RT5682_FILTER_CLK_DIV_SFT); @@ -1242,7 +1237,8 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w, } snd_soc_component_update_bits(component, RT5682_ADDA_CLK_1, - mask, idx << sft); + RT5682_ADC_OSR_MASK | RT5682_DAC_OSR_MASK, + (idx << RT5682_ADC_OSR_SFT) | (idx << RT5682_DAC_OSR_SFT)); return 0; } From 5110eae1705f5833113d239b0f760988285985ca Mon Sep 17 00:00:00 2001 From: Bard liao Date: Tue, 5 Mar 2019 23:57:52 +0800 Subject: [PATCH 1192/1995] ASoC: topology: free stream_name of dai_drv The stream_name is allocated by kstrdup. We have to free it when the dai is removed or return from error. Signed-off-by: Bard liao Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 7b6f68a4df4df3a58e854d24da991640bd4d9590) --- sound/soc/soc-topology.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index fbee4720b8346b..1be60cea2bf541 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -535,6 +535,8 @@ static void remove_dai(struct snd_soc_component *comp, if (dai->driver == dai_drv) dai->driver = NULL; + kfree(dai_drv->playback.stream_name); + kfree(dai_drv->capture.stream_name); kfree(dai_drv->name); list_del(&dobj->list); kfree(dai_drv); @@ -1808,6 +1810,9 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL); if (ret < 0) { dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n"); + kfree(dai_drv->playback.stream_name); + kfree(dai_drv->capture.stream_name); + kfree(dai_drv->name); kfree(dai_drv); return ret; } From 864a07b60213864c491d3071ad364da8c989e05c Mon Sep 17 00:00:00 2001 From: Bard liao Date: Tue, 5 Mar 2019 23:57:53 +0800 Subject: [PATCH 1193/1995] ASoC: topology: free link string in error Some strings are allocated by kstrdup, but not freed when error happened. Signed-off-by: Bard liao Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit b3718b8f7e9b4afdfd281d35233b078585aef2e9) --- sound/soc/soc-topology.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 1be60cea2bf541..c6a30d000f59fe 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1883,6 +1883,9 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, ret = soc_tplg_dai_link_load(tplg, link, NULL); if (ret < 0) { dev_err(tplg->comp->dev, "ASoC: FE link loading failed\n"); + kfree(link->name); + kfree(link->stream_name); + kfree(link->cpu_dai_name); kfree(link); return ret; } From 785832ee57bd7a1fdf367a932234258efbb32e7e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 19 Mar 2019 14:59:27 -0500 Subject: [PATCH 1194/1995] ASoC: SOF: Intel: fix Kconfig spelling s/enble/enable/g Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 267b5606c6baa1..4d2c5b93c39cf7 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -220,7 +220,7 @@ config SND_SOC_SOF_HDA_LINK help This adds support for HDA links(HDA/HDMI) with Sound Open Firmware for Intel(R) platforms. - Say Y if you want to enble HDA links with SOF. + Say Y if you want to enable HDA links with SOF. If unsure select "N". config SND_SOC_SOF_HDA_AUDIO_CODEC @@ -229,7 +229,7 @@ config SND_SOC_SOF_HDA_AUDIO_CODEC help This adds support for HDAudio codecs with Sound Open Firmware for Intel(R) platforms. - Say Y if you want to enble HDAudio codecs with SOF. + Say Y if you want to enable HDAudio codecs with SOF. If unsure select "N". endif ## SND_SOC_SOF_HDA_COMMON From 9a60e9301f8b9c33d54e4c3318e8ea70f9f7669f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 19 Mar 2019 15:01:39 -0500 Subject: [PATCH 1195/1995] ASoC: SOF: ops: remove spurious line make checkpatch happy Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/ops.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index bd3aca388aebd4..ba0b7a66f39521 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -86,7 +86,6 @@ bool snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar, } EXPORT_SYMBOL(snd_sof_dsp_update_bits64_unlocked); - /* This is for registers bits with attribute RWC */ bool snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 mask, u32 value) From 68bbdacf6c9e40289ceabb3a91695ae00514a8e1 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 18 Mar 2019 21:36:15 -0700 Subject: [PATCH 1196/1995] ASoC: SOF: ACPI: detach platform dev from pm_domain on Minnowboard A recent change in the SOF driver to power off all DAPM widgets in the audio pipeline when not active causes the DSP on the Minnowboard to be powered off. This is despite the fact that PM is not implemented for the Baytrail platform and we explicitly keep the device usage count > 0 to prevent the system from being runtime suspended. In ACPI platforms (such as BYT), the platform device is attached to a pm_domain. The pm_domain provider is responsible for powering on/off all the devices that are attached it. So when all the DAPM widgets in the card get powered down, the pm_domain provider powers off the DSP as well. Additionally, Minnowboard has a known issue with the BIOS that prevents the DSP from resuming back to D0 when the system resumes from S3 to S0. So, given the above limitations, it is recommended to detach the platform device from the pm_domain to prevent the DSP from being powered off on the Minnowboard. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/sof-acpi-dev.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 53d2ade525b57f..2f0082edcd4460 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include #ifdef CONFIG_X86 @@ -166,6 +168,26 @@ static const struct sof_dev_desc sof_acpi_cherrytrail_desc = { #endif +/* BYT Minnowboard quirk table */ +static const struct dmi_system_id byt_quirk_table[] = { + { + /* Minnowboard Max B3 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), + DMI_MATCH(DMI_PRODUCT_NAME, + "Minnowboard Max B3 PLATFORM"), + }, + }, + { + /* Minnowboard Turbot */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ADI"), + DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Turbot"), + }, + }, + {} +}; + static const struct dev_pm_ops sof_acpi_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, @@ -191,6 +213,18 @@ static int sof_acpi_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "ACPI DSP detected"); + /* + * Minnowboard has a known issue with the BIOS that prevents the DSP + * from resuming back to D0 when the system resumes from S3 to S0. + * So, detach the platform device from the pm_domain to prevent + * the DSP from entering D3. The @power_off argument to the + * dev_pm_domain_detach() call indicates that the DSP should be + * left powered on. + */ + if (dmi_check_system(byt_quirk_table)) + if (dev->pm_domain) + dev_pm_domain_detach(dev, false); + sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); if (!sof_pdata) return -ENOMEM; From b96840cc2fba09a1f458076d865293d98ca3fa50 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 19 Mar 2019 19:26:33 -0700 Subject: [PATCH 1197/1995] ASoC: SOF: remove stale comment and fix return value for PM ipc We have recently fixed the CTX_SAVE ipc to not read the memory window when the DSP sends a reply. With this, the ipc should technically not fail. So remove the workaround we had earlier to power off the DSP even when CTX_SAVE fails. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pm.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 75a4e20c16d8a4..fd0cf10bf742b7 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -329,17 +329,10 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) /* notify DSP of upcoming power down */ ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_SAVE); if (ret < 0) { - - /* - * FIXME: CTX_SAVE ipc should not time-out. - * But if it happens, just report the error - * and continue powering off the DSP for now. - * This will allow the DSP to power up - * normally upon system resume. - */ dev_err(sdev->dev, "error: ctx_save ipc error during suspend %d\n", ret); + return ret; } /* power down all DSP cores */ From b57c32aaca8d1c1645f86595b763bc3bc6483e09 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 19 Mar 2019 21:31:50 -0700 Subject: [PATCH 1198/1995] ASoC: SOF: PM: decrement dev usage count if pm_runtime_get_sync() fails This is based on Andy's feedback that the device usage count should be decremented if pm_runtime_get_sync() returns an error. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/compressed.c | 4 +++- sound/soc/sof/control.c | 10 ++++++++++ sound/soc/sof/pcm.c | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/compressed.c b/sound/soc/sof/compressed.c index 69db228cdf1063..6703db3920b270 100644 --- a/sound/soc/sof/compressed.c +++ b/sound/soc/sof/compressed.c @@ -28,9 +28,11 @@ static int sof_compressed_open(struct snd_compr_stream *cstream) int ret; ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) + if (ret < 0) { dev_err(sdev->dev, "error: comp open failed to resume %d\n", ret); + pm_runtime_put_noidle(sdev->dev); + } return ret; } diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 945b01a2612967..6b8b47157dfb8f 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -48,6 +48,7 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, if (ret < 0) { dev_err_ratelimited(sdev->dev, "error: volume get failed to resume %d\n", ret); + pm_runtime_put_noidle(sdev->dev); return ret; } @@ -85,6 +86,7 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, if (ret < 0) { dev_err_ratelimited(sdev->dev, "error: volume put failed to resume %d\n", ret); + pm_runtime_put_noidle(sdev->dev); return ret; } @@ -124,6 +126,7 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol, if (ret < 0) { dev_err_ratelimited(sdev->dev, "error: switch get failed to resume %d\n", ret); + pm_runtime_put_noidle(sdev->dev); return ret; } @@ -159,6 +162,7 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, if (ret < 0) { dev_err_ratelimited(sdev->dev, "error: switch put failed to resume %d\n", ret); + pm_runtime_put_noidle(sdev->dev); return ret; } @@ -196,6 +200,7 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, if (ret < 0) { dev_err_ratelimited(sdev->dev, "error: enum get failed to resume %d\n", ret); + pm_runtime_put_noidle(sdev->dev); return ret; } @@ -231,6 +236,7 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, if (ret < 0) { dev_err_ratelimited(sdev->dev, "error: enum put failed to resume %d\n", ret); + pm_runtime_put_noidle(sdev->dev); return ret; } @@ -275,6 +281,7 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, if (ret < 0) { dev_err_ratelimited(sdev->dev, "error: bytes get failed to resume %d\n", ret); + pm_runtime_put_noidle(sdev->dev); return ret; } @@ -328,6 +335,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, if (ret < 0) { dev_err_ratelimited(sdev->dev, "error: bytes put failed to resume %d\n", ret); + pm_runtime_put_noidle(sdev->dev); return ret; } @@ -414,6 +422,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, if (ret < 0) { dev_err_ratelimited(sdev->dev, "error: bytes_ext put failed to resume %d\n", ret); + pm_runtime_put_noidle(sdev->dev); return ret; } @@ -452,6 +461,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, if (ret < 0) { dev_err_ratelimited(sdev->dev, "error: bytes_ext get failed to resume %d\n", ret); + pm_runtime_put_noidle(sdev->dev); return ret; } diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 489db97e180ade..17889fb8389b2a 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -408,6 +408,7 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) if (ret < 0) { dev_err(sdev->dev, "error: pcm open failed to resume %d\n", ret); + pm_runtime_put_noidle(sdev->dev); return ret; } From 1238f6740cccf293674d37090ed17b17ca8b55dc Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 19 Mar 2019 20:22:26 -0700 Subject: [PATCH 1199/1995] Revert "ASoC: SOF: ACPI: detach platform dev from pm_domain on Minnowboard" This reverts commit 68bbdacf6c9e40289ceabb3a91695ae00514a8e1. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/sof-acpi-dev.c | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 2f0082edcd4460..53d2ade525b57f 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -13,8 +13,6 @@ #include #include #include -#include -#include #include #include #ifdef CONFIG_X86 @@ -168,26 +166,6 @@ static const struct sof_dev_desc sof_acpi_cherrytrail_desc = { #endif -/* BYT Minnowboard quirk table */ -static const struct dmi_system_id byt_quirk_table[] = { - { - /* Minnowboard Max B3 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), - DMI_MATCH(DMI_PRODUCT_NAME, - "Minnowboard Max B3 PLATFORM"), - }, - }, - { - /* Minnowboard Turbot */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ADI"), - DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Turbot"), - }, - }, - {} -}; - static const struct dev_pm_ops sof_acpi_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, @@ -213,18 +191,6 @@ static int sof_acpi_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "ACPI DSP detected"); - /* - * Minnowboard has a known issue with the BIOS that prevents the DSP - * from resuming back to D0 when the system resumes from S3 to S0. - * So, detach the platform device from the pm_domain to prevent - * the DSP from entering D3. The @power_off argument to the - * dev_pm_domain_detach() call indicates that the DSP should be - * left powered on. - */ - if (dmi_check_system(byt_quirk_table)) - if (dev->pm_domain) - dev_pm_domain_detach(dev, false); - sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); if (!sof_pdata) return -ENOMEM; From 95dea6e3add13044a599cf0d57efec4844deb6b5 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 19 Mar 2019 20:23:02 -0700 Subject: [PATCH 1200/1995] ASoC: SOF: PM: increment device usage count if PM callbacks are not set Previously, the call to pm_runtime_put_noidle() in pcm_probe() was needed due to the fact that when the card was registered, the SOF device usage count was incremented but never decremented. This prevented the SOF device from getting runtime suspended. In fact, what was causing this problem was the fact that not all the DAPM widgets attached to the card were powered off. This was recently fixed in the SOF driver. This makes the call to pm_runtime_put_noidle() in pcm_probe() incorrect. So this patch removes it. Secondly, for platforms such as BYT where PM has not been implemented, there is a need for explicitly incrementing the usage count to prevent the device from getting runtime suspended. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pcm.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 17889fb8389b2a..e1b7373eb0ca65 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -695,17 +695,11 @@ static int sof_pcm_probe(struct snd_soc_component *component) /* * Some platforms in SOF, ex: BYT, may not have their platform PM - * callbacks set. Skip decrementing the usage count so as to - * prevent their runtime PM callbacks from being invoked. + * callbacks set. Increment the usage count so as to + * prevent the device entering runtime suspend. */ if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume) - return ret; - - /* - * Decrement the usage count to enable the device to enter - * runtime suspend after probe() completes. - */ - pm_runtime_put_noidle(sdev->dev); + pm_runtime_get_noresume(sdev->dev); return ret; } From 53bb8dd2674739fec99c97b6f6f31d549e0afaea Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 20 Mar 2019 11:07:39 -0500 Subject: [PATCH 1201/1995] ASoC: SOF: core.c: address comments from Andy Shevchenko No new functionality, style only Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 61 +++++++++++++++++----------------------- sound/soc/sof/sof-priv.h | 16 ++++++----- 2 files changed, 35 insertions(+), 42 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index a81fc6d0d28e1b..04a6716e9762a2 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -50,8 +50,7 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm = NULL; list_for_each_entry(spcm, &sdev->pcm_list, list) { - if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id == - comp_id) { + if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id == comp_id) { *direction = SNDRV_PCM_STREAM_PLAYBACK; return spcm; } @@ -103,8 +102,7 @@ struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev, type = snd_soc_dapm_aif_out; list_for_each_entry(swidget, &sdev->widget_list, list) { - if (!strcmp(pcm_name, swidget->widget->sname) && - swidget->id == type) + if (!strcmp(pcm_name, swidget->widget->sname) && swidget->id == type) return swidget; } @@ -163,8 +161,7 @@ int snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, return 0; /* no fault ? */ } - code = panic_code & - (SOF_IPC_PANIC_MAGIC_MASK | SOF_IPC_PANIC_CODE_MASK); + code = panic_code & (SOF_IPC_PANIC_MAGIC_MASK | SOF_IPC_PANIC_CODE_MASK); for (i = 0; i < ARRAY_SIZE(panic_msg); i++) { if (panic_msg[i].id == code) { @@ -252,30 +249,30 @@ int snd_sof_create_page_table(struct snd_sof_dev *sdev, static int sof_machine_check(struct snd_sof_dev *sdev) { struct snd_sof_pdata *plat_data = sdev->pdata; + struct snd_soc_acpi_mach *machine; + int ret; - if (!plat_data->machine) { -#if IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) - struct snd_soc_acpi_mach *machine; - int ret; - - /* fallback to nocodec mode */ - dev_warn(sdev->dev, "No ASoC machine driver found - using nocodec\n"); - machine = devm_kzalloc(sdev->dev, sizeof(*machine), GFP_KERNEL); - if (!machine) - return -ENOMEM; - - ret = sof_nocodec_setup(sdev->dev, plat_data, machine, - plat_data->desc, plat_data->desc->ops); - if (ret < 0) - return ret; + if (plat_data->machine) + return 0; - plat_data->machine = machine; -#else + if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) { dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); return -ENODEV; -#endif } + /* fallback to nocodec mode */ + dev_warn(sdev->dev, "No ASoC machine driver found - using nocodec\n"); + machine = devm_kzalloc(sdev->dev, sizeof(*machine), GFP_KERNEL); + if (!machine) + return -ENOMEM; + + ret = sof_nocodec_setup(sdev->dev, plat_data, machine, + plat_data->desc, plat_data->desc->ops); + if (ret < 0) + return ret; + + plat_data->machine = machine; + return 0; } @@ -309,9 +306,9 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) ret = snd_sof_dbg_init(sdev); if (ret < 0) { /* - * errors can only happen due to memory allocation. - * we cannot rely on debugfs so debugfs issues are only - * logged and we don't stop execution + * debugfs issues are suppressed in snd_sof_dbg_init() since + * we cannot rely on debugfs + * here we trap errors due to memory allocation only. */ dev_err(sdev->dev, "error: failed to init DSP trace/debug %d\n", ret); @@ -398,21 +395,18 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) return ret; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) static void sof_probe_work(struct work_struct *work) { struct snd_sof_dev *sdev = container_of(work, struct snd_sof_dev, probe_work); int ret; - dev_dbg(sdev->dev, "%s entry\n", __func__); ret = sof_probe_continue(sdev); if (ret < 0) { /* errors cannot be propagated, log */ dev_err(sdev->dev, "error: %s failed err: %d\n", __func__, ret); } } -#endif int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) { @@ -422,8 +416,6 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) if (!sdev) return -ENOMEM; - dev_dbg(dev, "probing SOF DSP device....\n"); - /* initialize sof device */ sdev->dev = dev; @@ -439,9 +431,8 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) spin_lock_init(&sdev->ipc_lock); spin_lock_init(&sdev->hw_lock); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) - INIT_WORK(&sdev->probe_work, sof_probe_work); -#endif + if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) + INIT_WORK(&sdev->probe_work, sof_probe_work); /* set default timeouts if none provided */ if (plat_data->desc->ipc_timeout == 0) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index f5fc283d478f88..f7fa0d19efd49c 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -12,16 +12,19 @@ #define __SOUND_SOC_SOF_PRIV_H #include -#include + #include -#include +#include + +#include +#include /* needs to be included before control.h */ #include #include -#include -#include #include #include -#include +#include +#include + #include /* debug flags */ @@ -187,8 +190,7 @@ struct sof_arch_ops { u32 *stack, u32 stack_words); }; -#define sof_arch_ops(sdev) \ - ((sdev)->pdata->desc->arch_ops) +#define sof_arch_ops(sdev) ((sdev)->pdata->desc->arch_ops) /* DSP device HW descriptor mapping between bus ID and ops */ struct sof_ops_table { From fc18610255339e776b338dcca62d0cf68f55eb39 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 20 Mar 2019 11:18:23 -0500 Subject: [PATCH 1202/1995] ASoC: SOF: control.c: use consistent style for dev_err Try to fit error message in 80 characters for consistency. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/control.c | 87 +++++++++++++++++++++++++++-------------- 1 file changed, 58 insertions(+), 29 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 6b8b47157dfb8f..189cdc6459391c 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -46,7 +46,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err_ratelimited(sdev->dev, "error: volume get failed to resume %d\n", + dev_err_ratelimited(sdev->dev, + "error: volume get failed to resume %d\n", ret); pm_runtime_put_noidle(sdev->dev); return ret; @@ -66,7 +67,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err_ratelimited(sdev->dev, "error: volume get failed to idle %d\n", + dev_err_ratelimited(sdev->dev, + "error: volume get failed to idle %d\n", err); return 0; } @@ -84,7 +86,8 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err_ratelimited(sdev->dev, "error: volume put failed to resume %d\n", + dev_err_ratelimited(sdev->dev, + "error: volume put failed to resume %d\n", ret); pm_runtime_put_noidle(sdev->dev); return ret; @@ -106,7 +109,8 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err_ratelimited(sdev->dev, "error: volume put failed to idle %d\n", + dev_err_ratelimited(sdev->dev, + "error: volume put failed to idle %d\n", err); return 0; } @@ -124,7 +128,8 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol, ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err_ratelimited(sdev->dev, "error: switch get failed to resume %d\n", + dev_err_ratelimited(sdev->dev, + "error: switch get failed to resume %d\n", ret); pm_runtime_put_noidle(sdev->dev); return ret; @@ -142,7 +147,8 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err_ratelimited(sdev->dev, "error: switch get failed to idle %d\n", + dev_err_ratelimited(sdev->dev, + "error: switch get failed to idle %d\n", err); return 0; } @@ -160,7 +166,8 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err_ratelimited(sdev->dev, "error: switch put failed to resume %d\n", + dev_err_ratelimited(sdev->dev, + "error: switch put failed to resume %d\n", ret); pm_runtime_put_noidle(sdev->dev); return ret; @@ -180,7 +187,8 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err_ratelimited(sdev->dev, "error: switch put failed to idle %d\n", + dev_err_ratelimited(sdev->dev, + "error: switch put failed to idle %d\n", err); return 0; } @@ -198,7 +206,8 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err_ratelimited(sdev->dev, "error: enum get failed to resume %d\n", + dev_err_ratelimited(sdev->dev, + "error: enum get failed to resume %d\n", ret); pm_runtime_put_noidle(sdev->dev); return ret; @@ -216,7 +225,8 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err_ratelimited(sdev->dev, "error: enum get failed to idle %d\n", + dev_err_ratelimited(sdev->dev, + "error: enum get failed to idle %d\n", err); return 0; } @@ -234,7 +244,8 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err_ratelimited(sdev->dev, "error: enum put failed to resume %d\n", + dev_err_ratelimited(sdev->dev, + "error: enum put failed to resume %d\n", ret); pm_runtime_put_noidle(sdev->dev); return ret; @@ -254,7 +265,8 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err_ratelimited(sdev->dev, "error: enum put failed to idle %d\n", + dev_err_ratelimited(sdev->dev, + "error: enum put failed to idle %d\n", err); return 0; } @@ -272,14 +284,16 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, int ret, err; if (be->max > sizeof(ucontrol->value.bytes.data)) { - dev_err_ratelimited(sdev->dev, "error: data max %d exceeds ucontrol data array size\n", + dev_err_ratelimited(sdev->dev, + "error: data max %d exceeds ucontrol data array size\n", be->max); return -EINVAL; } ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err_ratelimited(sdev->dev, "error: bytes get failed to resume %d\n", + dev_err_ratelimited(sdev->dev, + "error: bytes get failed to resume %d\n", ret); pm_runtime_put_noidle(sdev->dev); return ret; @@ -290,7 +304,8 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, SOF_CTRL_TYPE_DATA_GET, scontrol->cmd); size = data->size + sizeof(*data); if (size > be->max) { - dev_err_ratelimited(sdev->dev, "error: DSP sent %zu bytes max is %d\n", + dev_err_ratelimited(sdev->dev, + "error: DSP sent %zu bytes max is %d\n", size, be->max); ret = -EINVAL; goto out; @@ -303,7 +318,8 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err_ratelimited(sdev->dev, "error: bytes get failed to idle %d\n", + dev_err_ratelimited(sdev->dev, + "error: bytes get failed to idle %d\n", err); return ret; } @@ -320,20 +336,23 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, int ret, err; if (be->max > sizeof(ucontrol->value.bytes.data)) { - dev_err_ratelimited(sdev->dev, "error: data max %d exceeds ucontrol data array size\n", + dev_err_ratelimited(sdev->dev, + "error: data max %d exceeds ucontrol data array size\n", be->max); return -EINVAL; } if (data->size > be->max) { - dev_err_ratelimited(sdev->dev, "error: size too big %d bytes max is %d\n", + dev_err_ratelimited(sdev->dev, + "error: size too big %d bytes max is %d\n", data->size, be->max); return -EINVAL; } ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err_ratelimited(sdev->dev, "error: bytes put failed to resume %d\n", + dev_err_ratelimited(sdev->dev, + "error: bytes put failed to resume %d\n", ret); pm_runtime_put_noidle(sdev->dev); return ret; @@ -349,7 +368,8 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err_ratelimited(sdev->dev, "error: bytes put failed to idle %d\n", + dev_err_ratelimited(sdev->dev, + "error: bytes put failed to idle %d\n", err); return ret; } @@ -386,14 +406,16 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, if (be->max < max_size) /* min() not used to avoid sparse warnings */ max_size = be->max; if (header.length > max_size) { - dev_err_ratelimited(sdev->dev, "error: Bytes data size %d exceeds max %d.\n", + dev_err_ratelimited(sdev->dev, + "error: Bytes data size %d exceeds max %d.\n", header.length, max_size); return -EINVAL; } /* Check that header id matches the command */ if (header.numid != scontrol->cmd) { - dev_err_ratelimited(sdev->dev, "error: incorrect numid %d\n", + dev_err_ratelimited(sdev->dev, + "error: incorrect numid %d\n", header.numid); return -EINVAL; } @@ -402,7 +424,8 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, return -EFAULT; if (cdata->data->magic != SOF_ABI_MAGIC) { - dev_err_ratelimited(sdev->dev, "error: Wrong ABI magic 0x%08x.\n", + dev_err_ratelimited(sdev->dev, + "error: Wrong ABI magic 0x%08x.\n", cdata->data->magic); return -EINVAL; } @@ -414,13 +437,15 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, } if (cdata->data->size + sizeof(const struct sof_abi_hdr) > max_size) { - dev_err_ratelimited(sdev->dev, "error: Mismatch in ABI data size (truncated?).\n"); + dev_err_ratelimited(sdev->dev, + "error: Mismatch in ABI data size (truncated?).\n"); return -EINVAL; } ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err_ratelimited(sdev->dev, "error: bytes_ext put failed to resume %d\n", + dev_err_ratelimited(sdev->dev, + "error: bytes_ext put failed to resume %d\n", ret); pm_runtime_put_noidle(sdev->dev); return ret; @@ -433,7 +458,8 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err_ratelimited(sdev->dev, "error: bytes_ext put failed to idle %d\n", + dev_err_ratelimited(sdev->dev, + "error: bytes_ext put failed to idle %d\n", err); return ret; @@ -459,7 +485,8 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, ret = pm_runtime_get_sync(sdev->dev); if (ret < 0) { - dev_err_ratelimited(sdev->dev, "error: bytes_ext get failed to resume %d\n", + dev_err_ratelimited(sdev->dev, + "error: bytes_ext get failed to resume %d\n", ret); pm_runtime_put_noidle(sdev->dev); return ret; @@ -489,7 +516,8 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, if (be->max < max_size) max_size = be->max; if (data_size > max_size) { - dev_err_ratelimited(sdev->dev, "error: user data size %d exceeds max size %d.\n", + dev_err_ratelimited(sdev->dev, + "error: user data size %d exceeds max size %d.\n", data_size, max_size); ret = -EINVAL; goto out; @@ -509,7 +537,8 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); if (err < 0) - dev_err_ratelimited(sdev->dev, "error: bytes_ext get failed to idle %d\n", + dev_err_ratelimited(sdev->dev, + "error: bytes_ext get failed to idle %d\n", err); return ret; } From 05a0f0de198ae1fc2df47ac3ec625aadf1cdd559 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 20 Mar 2019 11:35:04 -0500 Subject: [PATCH 1203/1995] ASoC: SOF: debug.c: address Andy Shevchenko's comments style only, no new functionality Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/debug.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index a71d1aa78ffe31..5876269aa776db 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -39,7 +39,8 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, count = size - pos; /* intermediate buffer size must be u32 multiple */ - size = round_up(count, 4); + size = ALIGN(count, 4); + buf = kzalloc(size, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -73,7 +74,7 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, memcpy_fromio(buf, dfse->io_mem + pos, size); #endif } else { - memcpy(buf, (void *)((u8 *)(dfse->buf) + pos), size); + memcpy(buf, ((u8 *)(dfse->buf) + pos), size); } /* copy to userspace */ From b32680f1a7519c8b5ddb19e2a7ea95c2bcc117c3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 20 Mar 2019 12:13:01 -0500 Subject: [PATCH 1204/1995] ASoC: SOF: ipc.c: address Andy Shevchenko's comments Reduce memory footprint by using 2 strings Change size to decimal instead of hex in IPC log messages Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/ipc.c | 93 +++++++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 42 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index e27cdd8702f93e..02910d82923f5f 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -46,6 +46,7 @@ struct snd_sof_ipc { static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) { u8 *str; + u8 *str2 = NULL; u32 glb; u32 type; @@ -58,103 +59,108 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) case SOF_IPC_GLB_COMPOUND: str = "GLB_COMPOUND"; break; case SOF_IPC_GLB_TPLG_MSG: + str = "GLB_TPLG_MSG"; switch (type) { case SOF_IPC_TPLG_COMP_NEW: - str = "GLB_TPLG_MSG: COMP_NEW"; break; + str2 = "COMP_NEW"; break; case SOF_IPC_TPLG_COMP_FREE: - str = "GLB_TPLG_MSG: COMP_FREE"; break; + str2 = "COMP_FREE"; break; case SOF_IPC_TPLG_COMP_CONNECT: - str = "GLB_TPLG_MSG: COMP_CONNECT"; break; + str2 = "COMP_CONNECT"; break; case SOF_IPC_TPLG_PIPE_NEW: - str = "GLB_TPLG_MSG: PIPE_NEW"; break; + str2 = "PIPE_NEW"; break; case SOF_IPC_TPLG_PIPE_FREE: - str = "GLB_TPLG_MSG: PIPE_FREE"; break; + str2 = "PIPE_FREE"; break; case SOF_IPC_TPLG_PIPE_CONNECT: - str = "GLB_TPLG_MSG: PIPE_CONNECT"; break; + str2 = "PIPE_CONNECT"; break; case SOF_IPC_TPLG_PIPE_COMPLETE: - str = "GLB_TPLG_MSG: PIPE_COMPLETE"; break; + str2 = "PIPE_COMPLETE"; break; case SOF_IPC_TPLG_BUFFER_NEW: - str = "GLB_TPLG_MSG: BUFFER_NEW"; break; + str2 = "BUFFER_NEW"; break; case SOF_IPC_TPLG_BUFFER_FREE: - str = "GLB_TPLG_MSG: BUFFER_FREE"; break; + str2 = "BUFFER_FREE"; break; default: - str = "GLB_TPLG_MSG: unknown type"; break; + str2 = "unknown type"; break; } break; case SOF_IPC_GLB_PM_MSG: + str = "GLB_PM_MSG"; switch (type) { case SOF_IPC_PM_CTX_SAVE: - str = "GLB_PM_MSG: CTX_SAVE"; break; + str2 = "CTX_SAVE"; break; case SOF_IPC_PM_CTX_RESTORE: - str = "GLB_PM_MSG: CTX_RESTORE"; break; + str2 = "CTX_RESTORE"; break; case SOF_IPC_PM_CTX_SIZE: - str = "GLB_PM_MSG: CTX_SIZE"; break; + str2 = "CTX_SIZE"; break; case SOF_IPC_PM_CLK_SET: - str = "GLB_PM_MSG: CLK_SET"; break; + str2 = "CLK_SET"; break; case SOF_IPC_PM_CLK_GET: - str = "GLB_PM_MSG: CLK_GET"; break; + str2 = "CLK_GET"; break; case SOF_IPC_PM_CLK_REQ: - str = "GLB_PM_MSG: CLK_REQ"; break; + str2 = "CLK_REQ"; break; case SOF_IPC_PM_CORE_ENABLE: - str = "GLB_PM_MSG: CORE_ENABLE"; break; + str2 = "CORE_ENABLE"; break; default: - str = "GLB_PM_MSG: unknown type"; break; + str2 = "unknown type"; break; } break; case SOF_IPC_GLB_COMP_MSG: + str = "GLB_COMP_MSG: SET_VALUE"; switch (type) { case SOF_IPC_COMP_SET_VALUE: - str = "GLB_COMP_MSG: SET_VALUE"; break; + str2 = "SET_VALUE"; break; case SOF_IPC_COMP_GET_VALUE: - str = "GLB_COMP_MSG: GET_VALUE"; break; + str2 = "GET_VALUE"; break; case SOF_IPC_COMP_SET_DATA: - str = "GLB_COMP_MSG: SET_DATA"; break; + str2 = "SET_DATA"; break; case SOF_IPC_COMP_GET_DATA: - str = "GLB_COMP_MSG: GET_DATA"; break; + str2 = "GET_DATA"; break; default: - str = "GLB_COMP_MSG: unknown type"; break; + str2 = "unknown type"; break; } break; case SOF_IPC_GLB_STREAM_MSG: + str = "GLB_STREAM_MSG"; switch (type) { case SOF_IPC_STREAM_PCM_PARAMS: - str = "GLB_STREAM_MSG: PCM_PARAMS"; break; + str2 = "PCM_PARAMS"; break; case SOF_IPC_STREAM_PCM_PARAMS_REPLY: - str = "GLB_STREAM_MSG: PCM_REPLY"; break; + str2 = "PCM_REPLY"; break; case SOF_IPC_STREAM_PCM_FREE: - str = "GLB_STREAM_MSG: PCM_FREE"; break; + str2 = "PCM_FREE"; break; case SOF_IPC_STREAM_TRIG_START: - str = "GLB_STREAM_MSG: TRIG_START"; break; + str2 = "TRIG_START"; break; case SOF_IPC_STREAM_TRIG_STOP: - str = "GLB_STREAM_MSG: TRIG_STOP"; break; + str2 = "TRIG_STOP"; break; case SOF_IPC_STREAM_TRIG_PAUSE: - str = "GLB_STREAM_MSG: TRIG_PAUSE"; break; + str2 = "TRIG_PAUSE"; break; case SOF_IPC_STREAM_TRIG_RELEASE: - str = "GLB_STREAM_MSG: TRIG_RELEASE"; break; + str2 = "TRIG_RELEASE"; break; case SOF_IPC_STREAM_TRIG_DRAIN: - str = "GLB_STREAM_MSG: TRIG_DRAIN"; break; + str2 = "TRIG_DRAIN"; break; case SOF_IPC_STREAM_TRIG_XRUN: - str = "GLB_STREAM_MSG: TRIG_XRUN"; break; + str2 = "TRIG_XRUN"; break; case SOF_IPC_STREAM_POSITION: - str = "GLB_STREAM_MSG: POSITION"; break; + str2 = "POSITION"; break; case SOF_IPC_STREAM_VORBIS_PARAMS: - str = "GLB_STREAM_MSG: VORBIS_PARAMS"; break; + str2 = "VORBIS_PARAMS"; break; case SOF_IPC_STREAM_VORBIS_FREE: - str = "GLB_STREAM_MSG: VORBIS_FREE"; break; + str2 = "VORBIS_FREE"; break; default: - str = "GLB_STREAM_MSG: unknown type"; break; + str2 = "unknown type"; break; } break; case SOF_IPC_FW_READY: str = "FW_READY"; break; case SOF_IPC_GLB_DAI_MSG: + str = "GLB_DAI_MSG"; switch (type) { case SOF_IPC_DAI_CONFIG: - str = "GLB_DAI_MSG: CONFIG"; break; + str2 = "CONFIG"; break; case SOF_IPC_DAI_LOOPBACK: - str = "GLB_DAI_MSG: LOOPBACK"; break; + str2 = "LOOPBACK"; break; default: - str = "GLB_DAI_MSG: unknown type"; break; + str2 = "unknown type"; break; } break; case SOF_IPC_GLB_TRACE_MSG: @@ -163,7 +169,10 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) str = "unknown GLB command"; break; } - dev_dbg(dev, "%s: 0x%x: %s\n", text, cmd, str); + if (str2) + dev_dbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2); + else + dev_dbg(dev, "%s: 0x%x: %s\n", text, cmd, str); } #else static inline void ipc_log_header(struct device *dev, u8 *text, u32 cmd) @@ -185,7 +194,7 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, msecs_to_jiffies(IPC_TIMEOUT_MS)); if (ret == 0) { - dev_err(sdev->dev, "error: ipc timed out for 0x%x size 0x%x\n", + dev_err(sdev->dev, "error: ipc timed out for 0x%x size %d\n", hdr->cmd, hdr->size); snd_sof_dsp_dbg_dump(ipc->sdev, SOF_DBG_REGS | SOF_DBG_MBOX); snd_sof_trace_notify_for_error(ipc->sdev); @@ -196,7 +205,7 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, if (msg->reply_size) memcpy(reply_data, msg->reply_data, msg->reply_size); if (ret < 0) - dev_err(sdev->dev, "error: ipc error for 0x%x size 0x%zx\n", + dev_err(sdev->dev, "error: ipc error for 0x%x size %zu\n", hdr->cmd, msg->reply_size); else ipc_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd); From 0ba314f4e709d0c61d4d83eb0b5865fa8daec4ff Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 20 Mar 2019 12:14:11 -0500 Subject: [PATCH 1205/1995] ASoC: SOF: pcm.c: Address Andy Shevchenko's comments Use PFN_UP() remove useless assignments use one line when possible Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pcm.c | 44 ++++++++++++++++---------------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index e1b7373eb0ca65..6dd94c00f7afbe 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -25,8 +25,7 @@ static int create_page_table(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream); int stream = substream->stream; @@ -47,8 +46,7 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; struct sof_ipc_pcm_params pcm; struct sof_ipc_pcm_params_reply ipc_params_reply; @@ -83,7 +81,7 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, return ret; /* number of pages should be rounded up */ - pcm.params.buffer.pages = DIV_ROUND_UP(runtime->dma_bytes, PAGE_SIZE); + pcm.params.buffer.pages = PFN_UP(runtime->dma_bytes); /* set IPC PCM parameters */ pcm.hdr.size = sizeof(pcm); @@ -181,8 +179,7 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; struct sof_ipc_stream stream; struct sof_ipc_reply reply; @@ -215,9 +212,9 @@ static int sof_restore_hw_params(struct snd_pcm_substream *substream, struct snd_sof_pcm *spcm, struct snd_sof_dev *sdev) { - snd_pcm_uframes_t host = 0; + snd_pcm_uframes_t host; u64 host_posn; - int ret = 0; + int ret; /* resume stream */ host_posn = spcm->stream[substream->stream].posn.host_posn; @@ -247,12 +244,11 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; struct sof_ipc_stream stream; struct sof_ipc_reply reply; - int ret = 0; + int ret; /* nothing todo for BE */ if (rtd->dai_link->no_pcm) @@ -338,10 +334,8 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) snd_sof_pcm_platform_trigger(sdev, substream, cmd); /* send IPC to the DSP */ - ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, - sizeof(stream), &reply, sizeof(reply)); - - return ret; + return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, + sizeof(stream), &reply, sizeof(reply)); } static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) @@ -349,8 +343,7 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; snd_pcm_uframes_t host = 0, dai = 0; @@ -384,8 +377,7 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; struct snd_soc_tplg_stream_caps *caps; int ret; @@ -471,8 +463,7 @@ static int sof_pcm_close(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; int err; @@ -527,8 +518,7 @@ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; struct snd_pcm *pcm = rtd->pcm; struct snd_soc_tplg_stream_caps *caps; @@ -590,8 +580,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_dai *dai = snd_sof_find_dai(sdev, (char *)rtd->dai_link->name); @@ -670,8 +659,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, static int sof_pcm_probe(struct snd_soc_component *component) { - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(component); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pdata *plat_data = sdev->pdata; const char *tplg_filename; int ret; From eeb9475ff80b89a5678c14e21a8cd76a33beaf17 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 20 Mar 2019 14:26:23 -0500 Subject: [PATCH 1206/1995] ASoC: SOF: align ABI files with firmware Missing comments, edits and definitions that are part of the firmware files, reflect changes. Signed-off-by: Pierre-Louis Bossart --- include/sound/sof/control.h | 30 ++++++++++++++++++++++++++++++ include/uapi/sound/sof/eq.h | 4 ++-- include/uapi/sound/sof/tokens.h | 8 ++++++-- include/uapi/sound/sof/trace.h | 4 ++++ 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/include/sound/sof/control.h b/include/sound/sof/control.h index 7d7d2eba7d7639..858e48be3abb96 100644 --- a/include/sound/sof/control.h +++ b/include/sound/sof/control.h @@ -122,4 +122,34 @@ struct sof_ipc_ctrl_data { }; } __packed; +/** Event type */ +enum sof_ipc_ctrl_event_type { + SOF_CTRL_EVENT_GENERIC = 0, /**< generic event */ + SOF_CTRL_EVENT_GENERIC_METADATA, /**< generic event with metadata */ + SOF_CTRL_EVENT_KD, /**< keyword detection event */ + SOF_CTRL_EVENT_VAD, /**< voice activity detection event */ +}; + +/** + * Generic notification data. + */ +struct sof_ipc_comp_event { + struct sof_ipc_reply rhdr; + uint16_t src_comp_type; /**< COMP_TYPE_ */ + uint32_t src_comp_id; /**< source component id */ + uint32_t event_type; /**< event type - SOF_CTRL_EVENT_* */ + uint32_t num_elems; /**< in array elems or bytes for data type */ + + /* reserved for future use */ + uint32_t reserved[8]; + + /* control data - add new types if needed */ + union { + /* data can be used by binary controls */ + struct sof_abi_hdr data[0]; + /* event specific values */ + uint32_t event_value; + }; +} __packed; + #endif diff --git a/include/uapi/sound/sof/eq.h b/include/uapi/sound/sof/eq.h index cd748204a5a19c..666c2b6a3229d1 100644 --- a/include/uapi/sound/sof/eq.h +++ b/include/uapi/sound/sof/eq.h @@ -158,13 +158,13 @@ struct sof_eq_iir_biquad_df2t { #define SOF_EQ_IIR_DF2T_BIQUADS_MAX 11 /* The number of int32_t words in sof_eq_iir_header_df2t: - * num_sections, num_sections_in_series, reserved[4] + * num_sections, num_sections_in_series, reserved[4] */ #define SOF_EQ_IIR_NHEADER_DF2T \ (sizeof(struct sof_eq_iir_header_df2t) / sizeof(int32_t)) /* The number of int32_t words in sof_eq_iir_biquad_df2t: - * a2, a1, b2, b1, b0, output_shift, output_gain + * a2, a1, b2, b1, b0, output_shift, output_gain */ #define SOF_EQ_IIR_NBIQUAD_DF2T \ (sizeof(struct sof_eq_iir_biquad_df2t) / sizeof(int32_t)) diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index ebf7ab5a00a773..649c31acce240f 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -34,7 +34,9 @@ #define SOF_TKN_BUF_CAPS 101 /* DAI */ -#define SOF_TKN_DAI_DMAC_CONFIG 153 +/* Token retired with ABI 3.2, do not use for new capabilities + * #define SOF_TKN_DAI_DMAC_CONFIG 153 + */ #define SOF_TKN_DAI_TYPE 154 #define SOF_TKN_DAI_INDEX 155 #define SOF_TKN_DAI_DIRECTION 156 @@ -62,7 +64,9 @@ #define SOF_TKN_COMP_PERIOD_SINK_COUNT 400 #define SOF_TKN_COMP_PERIOD_SOURCE_COUNT 401 #define SOF_TKN_COMP_FORMAT 402 -#define SOF_TKN_COMP_PRELOAD_COUNT 403 +/* Token retired with ABI 3.2, do not use for new capabilities + * #define SOF_TKN_COMP_PRELOAD_COUNT 403 + */ /* SSP */ #define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500 diff --git a/include/uapi/sound/sof/trace.h b/include/uapi/sound/sof/trace.h index dadedd199a68aa..69c6e0845fad7c 100644 --- a/include/uapi/sound/sof/trace.h +++ b/include/uapi/sound/sof/trace.h @@ -50,6 +50,10 @@ struct system_time { #define TRACE_CLASS_POWER (23 << 24) #define TRACE_CLASS_IDC (24 << 24) #define TRACE_CLASS_CPU (25 << 24) +#define TRACE_CLASS_EDF (27 << 24) +#define TRACE_CLASS_KPB (28 << 24) +#define TRACE_CLASS_SELECTOR (29 << 24) +#define TRACE_CLASS_SCHEDULE (30 << 24) #define LOG_ENABLE 1 /* Enable logging */ #define LOG_DISABLE 0 /* Disable logging */ From f4aed560e342e1c62289c4a5b0a7d8ecb082ceff Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Wed, 20 Mar 2019 16:08:06 +0200 Subject: [PATCH 1207/1995] ASoC: SOF: add new members to ctrl data and bump abi Add msg_id and elems_remaining to ctrl data to enable large messaging and bumb abi minor version. Signed-off-by: Jaska Uimonen --- include/sound/sof/control.h | 5 ++++- include/uapi/sound/sof/abi.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/sound/sof/control.h b/include/sound/sof/control.h index 858e48be3abb96..0604acbfdb9383 100644 --- a/include/sound/sof/control.h +++ b/include/sound/sof/control.h @@ -107,9 +107,12 @@ struct sof_ipc_ctrl_data { /* control data - can either be appended or DMAed from host */ struct sof_ipc_host_buffer buffer; uint32_t num_elems; /**< in array elems or bytes for data type */ + uint32_t elems_remaining; /**< elems remaining if sent in parts */ + + uint32_t msg_index; /**< for large messages sent in parts */ /* reserved for future use */ - uint32_t reserved[8]; + uint32_t reserved[6]; /* control data - add new types if needed */ union { diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index 6861b12a958e39..98da1236cd66b3 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 2 +#define SOF_ABI_MINOR 3 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ From 6ecefe312ac2062056011e66d9971d383187c021 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 20 Mar 2019 14:56:16 -0500 Subject: [PATCH 1208/1995] ASoC: SOF: pci: add support for CoffeeLake Add PCI ID and reuse CannonLake information for now. We may at some point change the firmware and topology default names if relevant Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-pci-dev.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 27d43bcca8de4e..556c718df1a324 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -111,6 +111,24 @@ static const struct sof_dev_desc cnl_desc = { }; #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) +static const struct sof_dev_desc cfl_desc = { + .machines = snd_soc_acpi_intel_cnl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &cnl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-cnl.ri", + .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", + .ops = &sof_cnl_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) static const struct sof_dev_desc icl_desc = { .machines = snd_soc_acpi_intel_icl_machines, @@ -320,6 +338,10 @@ static const struct pci_device_id sof_pci_ids[] = { { PCI_DEVICE(0x8086, 0x9dc8), .driver_data = (unsigned long)&cnl_desc}, #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) + { PCI_DEVICE(0x8086, 0xa348), + .driver_data = (unsigned long)&cfl_desc}, +#endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) { PCI_DEVICE(0x8086, 0x9d71), .driver_data = (unsigned long)&kbl_desc}, From 919fbc11ed5477b8bbb5d3b4351011d4646fc5dd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 20 Mar 2019 14:53:49 -0500 Subject: [PATCH 1209/1995] ASoC: SOF: Intel: add build support for CoffeeLake update Kconfig following Cannonlake example Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/Kconfig | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 4d2c5b93c39cf7..7eb6d37911c862 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -23,6 +23,7 @@ config SND_SOC_SOF_INTEL_PCI select SND_SOC_SOF_APOLLOLAKE if SND_SOC_SOF_APOLLOLAKE_SUPPORT select SND_SOC_SOF_GEMINILAKE if SND_SOC_SOF_GEMINILAKE_SUPPORT select SND_SOC_SOF_CANNONLAKE if SND_SOC_SOF_CANNONLAKE_SUPPORT + select SND_SOC_SOF_COFFEELAKE if SND_SOC_SOF_COFFEELAKE_SUPPORT select SND_SOC_SOF_KABYLAKE if SND_SOC_SOF_KABYLAKE_SUPPORT select SND_SOC_SOF_SKYLAKE if SND_SOC_SOF_SKYLAKE_SUPPORT select SND_SOC_SOF_ICELAKE if SND_SOC_SOF_ICELAKE_SUPPORT @@ -158,6 +159,21 @@ config SND_SOC_SOF_CANNONLAKE This option is not user-selectable but automagically handled by 'select' statements at a higher level +config SND_SOC_SOF_COFFEELAKE_SUPPORT + bool "SOF support for CoffeeLake" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Coffeelake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_COFFEELAKE + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + config SND_SOC_SOF_KABYLAKE_SUPPORT bool "SOF support for Kabylake" help From 2893fad670dc521335a9628aa2aa458e0b8d643e Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Wed, 13 Feb 2019 19:11:41 +0200 Subject: [PATCH 1210/1995] ASoC: SOF: ipc: refactor control set and get ipc Merge control set and get ipc functions as they are almost identical pieces of code. Signed-off-by: Jaska Uimonen --- sound/soc/sof/control.c | 78 +++++++++++++++++---------- sound/soc/sof/ipc.c | 114 +++++++++++++++------------------------ sound/soc/sof/pm.c | 15 +++--- sound/soc/sof/sof-priv.h | 13 ++--- 4 files changed, 107 insertions(+), 113 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 189cdc6459391c..b1ff41d3db02d1 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -54,9 +54,11 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, } /* get all the mixer data from DSP */ - snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_VOLUME); + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_GET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_VOLUME, + false); /* read back each channel */ for (i = 0; i < channels; i++) @@ -102,9 +104,11 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, } /* notify DSP of mixer updates */ - snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_VOLUME); + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_VOLUME, + true); pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); @@ -136,9 +140,11 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol, } /* get all the mixer data from DSP */ - snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_SWITCH); + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_GET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_SWITCH, + false); /* read back each channel */ for (i = 0; i < channels; i++) @@ -180,9 +186,11 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, } /* notify DSP of mixer updates */ - snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_SWITCH); + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_SWITCH, + true); pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); @@ -214,9 +222,11 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, } /* get all the mixer data from DSP */ - snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_ENUM); + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_GET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_ENUM, + false); /* read back each channel */ for (i = 0; i < channels; i++) @@ -258,9 +268,11 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, } /* notify DSP of mixer updates */ - snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_ENUM); + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_ENUM, + true); pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); @@ -300,8 +312,12 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, } /* get all the mixer data from DSP */ - snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_DATA, - SOF_CTRL_TYPE_DATA_GET, scontrol->cmd); + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_GET_DATA, + SOF_CTRL_TYPE_DATA_GET, + scontrol->cmd, + false); + size = data->size + sizeof(*data); if (size > be->max) { dev_err_ratelimited(sdev->dev, @@ -362,8 +378,11 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, memcpy(data, ucontrol->value.bytes.data, data->size); /* notify DSP of mixer updates */ - snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_DATA, - SOF_CTRL_TYPE_DATA_SET, scontrol->cmd); + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_DATA, + SOF_CTRL_TYPE_DATA_SET, + scontrol->cmd, + true); pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); @@ -452,8 +471,11 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, } /* notify DSP of mixer updates */ - snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_DATA, - SOF_CTRL_TYPE_DATA_SET, scontrol->cmd); + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_DATA, + SOF_CTRL_TYPE_DATA_SET, + scontrol->cmd, + true); pm_runtime_mark_last_busy(sdev->dev); err = pm_runtime_put_autosuspend(sdev->dev); @@ -503,9 +525,11 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, cdata->data->abi = SOF_ABI_VERSION; /* get all the component data from DSP */ - ret = snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_GET_DATA, - SOF_CTRL_TYPE_DATA_GET, scontrol->cmd); + ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_GET_DATA, + SOF_CTRL_TYPE_DATA_GET, + scontrol->cmd, + false); /* Prevent read of other kernel data or possibly corrupt response */ data_size = cdata->data->size + sizeof(const struct sof_abi_hdr); diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 02910d82923f5f..6880cdda405ba0 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -551,90 +551,60 @@ EXPORT_SYMBOL(snd_sof_ipc_stream_posn); /* * IPC get()/set() for kcontrols. */ - -int snd_sof_ipc_set_comp_data(struct snd_sof_ipc *ipc, - struct snd_sof_control *scontrol, u32 ipc_cmd, - enum sof_ipc_ctrl_type ctrl_type, - enum sof_ipc_ctrl_cmd ctrl_cmd) +int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc, + struct snd_sof_control *scontrol, + u32 ipc_cmd, + enum sof_ipc_ctrl_type ctrl_type, + enum sof_ipc_ctrl_cmd ctrl_cmd, + bool send) { struct snd_sof_dev *sdev = ipc->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; - int err; + size_t send_bytes; + int err = 0; - /* read firmware volume */ + /* read or write firmware volume */ if (scontrol->readback_offset != 0) { - /* we can read value header via mmaped region */ - snd_sof_dsp_block_write(sdev, sdev->mmio_bar, - scontrol->readback_offset, cdata->chanv, - sizeof(struct sof_ipc_ctrl_value_chan) * - cdata->num_elems); + /* write/read value header via mmaped region */ + send_bytes = sizeof(struct sof_ipc_ctrl_value_chan) * + cdata->num_elems; + if (send) + snd_sof_dsp_block_write(sdev, sdev->mmio_bar, + scontrol->readback_offset, + cdata->chanv, send_bytes); - } else { - /* write value via slower IPC */ - cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd; - cdata->cmd = ctrl_cmd; - cdata->type = ctrl_type; - cdata->rhdr.hdr.size = scontrol->size; - cdata->comp_id = scontrol->comp_id; - cdata->num_elems = scontrol->num_channels; - - /* send IPC to the DSP */ - err = sof_ipc_tx_message(sdev->ipc, - cdata->rhdr.hdr.cmd, cdata, - cdata->rhdr.hdr.size, - cdata, cdata->rhdr.hdr.size); - if (err < 0) { - dev_err(sdev->dev, "error: failed to set control %d values\n", - cdata->comp_id); - return err; - } + else + snd_sof_dsp_block_read(sdev, sdev->mmio_bar, + scontrol->readback_offset, + cdata->chanv, send_bytes); + return 0; } - return 0; -} -EXPORT_SYMBOL(snd_sof_ipc_set_comp_data); - -int snd_sof_ipc_get_comp_data(struct snd_sof_ipc *ipc, - struct snd_sof_control *scontrol, u32 ipc_cmd, - enum sof_ipc_ctrl_type ctrl_type, - enum sof_ipc_ctrl_cmd ctrl_cmd) -{ - struct snd_sof_dev *sdev = ipc->sdev; - struct sof_ipc_ctrl_data *cdata = scontrol->control_data; - int err; + cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd; + cdata->cmd = ctrl_cmd; + cdata->type = ctrl_type; + cdata->rhdr.hdr.size = scontrol->size; + cdata->comp_id = scontrol->comp_id; + cdata->num_elems = scontrol->num_channels; + + /* write value via slower IPC */ + if (cdata->rhdr.hdr.size > SOF_IPC_MSG_MAX_SIZE) { + dev_err(sdev->dev, "error: set/get size %d too big comp %d\n", + cdata->rhdr.hdr.size, cdata->comp_id); + return -EINVAL; + } - /* read firmware byte counters */ - if (scontrol->readback_offset != 0) { - /* we can read values via mmaped region */ - snd_sof_dsp_block_read(sdev, sdev->mmio_bar, - scontrol->readback_offset, cdata->chanv, - sizeof(struct sof_ipc_ctrl_value_chan) * - cdata->num_elems); + err = sof_ipc_tx_message(sdev->ipc, cdata->rhdr.hdr.cmd, cdata, + cdata->rhdr.hdr.size, cdata, + cdata->rhdr.hdr.size); - } else { - /* read position via slower IPC */ - cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd; - cdata->cmd = ctrl_cmd; - cdata->type = ctrl_type; - cdata->rhdr.hdr.size = scontrol->size; - cdata->comp_id = scontrol->comp_id; - cdata->num_elems = scontrol->num_channels; - - /* send IPC to the DSP */ - err = sof_ipc_tx_message(sdev->ipc, - cdata->rhdr.hdr.cmd, cdata, - cdata->rhdr.hdr.size, - cdata, cdata->rhdr.hdr.size); - if (err < 0) { - dev_err(sdev->dev, "error: failed to get control %d values\n", - cdata->comp_id); - return err; - } - } + if (err < 0) + dev_err(sdev->dev, "error: set/get control ipc comp %d\n", + cdata->comp_id); - return 0; + return err; } -EXPORT_SYMBOL(snd_sof_ipc_get_comp_data); +EXPORT_SYMBOL(snd_sof_ipc_set_get_comp_data); /* * IPC layer enumeration. diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index fd0cf10bf742b7..8d1cdba92706d6 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -31,21 +31,24 @@ static int sof_restore_kcontrols(struct snd_sof_dev *sdev) case SOF_CTRL_CMD_SWITCH: ipc_cmd = SOF_IPC_COMP_SET_VALUE; ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET; - ret = snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, - ipc_cmd, ctrl_type, - scontrol->cmd); + ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + ipc_cmd, ctrl_type, + scontrol->cmd, + true); break; case SOF_CTRL_CMD_BINARY: ipc_cmd = SOF_IPC_COMP_SET_DATA; ctrl_type = SOF_CTRL_TYPE_DATA_SET; - ret = snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, - ipc_cmd, ctrl_type, - scontrol->cmd); + ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + ipc_cmd, ctrl_type, + scontrol->cmd, + true); break; default: break; } + if (ret < 0) { dev_err(sdev->dev, "error: failed kcontrol value set for widget: %d\n", diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index f7fa0d19efd49c..42936799f7b828 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -499,14 +499,11 @@ int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev, /* * Mixer IPC */ -int snd_sof_ipc_set_comp_data(struct snd_sof_ipc *ipc, - struct snd_sof_control *scontrol, u32 ipc_cmd, - enum sof_ipc_ctrl_type ctrl_type, - enum sof_ipc_ctrl_cmd ctrl_cmd); -int snd_sof_ipc_get_comp_data(struct snd_sof_ipc *ipc, - struct snd_sof_control *scontrol, u32 ipc_cmd, - enum sof_ipc_ctrl_type ctrl_type, - enum sof_ipc_ctrl_cmd ctrl_cmd); +int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc, + struct snd_sof_control *scontrol, u32 ipc_cmd, + enum sof_ipc_ctrl_type ctrl_type, + enum sof_ipc_ctrl_cmd ctrl_cmd, + bool send); /* * Topology. From ca113134fff6ff5ca5acd5958ef14c3fdbd79808 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Fri, 15 Mar 2019 08:56:35 +0200 Subject: [PATCH 1211/1995] ASoC: SOF: ipc: add unlocked version of send messages Large messages are sent in a loop so we need a unlocked mutex free version of send so we can use the mutex outside the loop. Signed-off-by: Jaska Uimonen --- sound/soc/sof/ipc.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 6880cdda405ba0..ec360958313c8d 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -217,25 +217,16 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, } /* send IPC message from host to DSP */ -int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, - void *msg_data, size_t msg_bytes, void *reply_data, - size_t reply_bytes) +static int sof_ipc_tx_message_unlocked(struct snd_sof_ipc *ipc, u32 header, + void *msg_data, size_t msg_bytes, + void *reply_data, size_t reply_bytes) { struct snd_sof_dev *sdev = ipc->sdev; struct snd_sof_ipc_msg *msg; int ret; - if (msg_bytes > SOF_IPC_MSG_MAX_SIZE || - reply_bytes > SOF_IPC_MSG_MAX_SIZE) - return -ENOBUFS; - - /* Serialise IPC TX */ - mutex_lock(&ipc->tx_mutex); - - if (ipc->disable_ipc_tx) { - ret = -ENODEV; - goto unlock; - } + if (ipc->disable_ipc_tx) + return -ENODEV; /* * The spin-lock is also still needed to protect message objects against @@ -266,7 +257,7 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, dev_err_ratelimited(sdev->dev, "error: ipc tx failed with error %d\n", ret); - goto unlock; + return ret; } ipc_log_header(sdev->dev, "ipc tx", msg->header); @@ -275,7 +266,26 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, if (!ret) ret = tx_wait_done(ipc, msg, reply_data); -unlock: + return ret; +} + +/* send IPC message from host to DSP */ +int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, + void *msg_data, size_t msg_bytes, void *reply_data, + size_t reply_bytes) +{ + int ret; + + if (msg_bytes > SOF_IPC_MSG_MAX_SIZE || + reply_bytes > SOF_IPC_MSG_MAX_SIZE) + return -ENOBUFS; + + /* Serialise IPC TX */ + mutex_lock(&ipc->tx_mutex); + + ret = sof_ipc_tx_message_unlocked(ipc, header, msg_data, msg_bytes, + reply_data, reply_bytes); + mutex_unlock(&ipc->tx_mutex); return ret; From 7614e0216f3f4d524bff99adc4d20d1bacb61e9f Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Wed, 20 Mar 2019 16:09:06 +0200 Subject: [PATCH 1212/1995] ASoC: SOF: ipc: large messages for set and get control data Enable cutting big control messages into parts and sending them in a loop as dma max size chunks to DSP. Signed-off-by: Jaska Uimonen --- sound/soc/sof/ipc.c | 176 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 165 insertions(+), 11 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index ec360958313c8d..ce42376489178b 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -42,6 +42,16 @@ struct snd_sof_ipc { struct snd_sof_ipc_msg msg; }; +struct sof_ipc_ctrl_data_params { + size_t msg_bytes; + size_t hdr_bytes; + size_t pl_size; + size_t elems; + u32 num_msg; + u8 *src; + u8 *dst; +}; + #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC) static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) { @@ -558,6 +568,103 @@ int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev, } EXPORT_SYMBOL(snd_sof_ipc_stream_posn); +static int sof_get_ctrl_copy_params(enum sof_ipc_ctrl_type ctrl_type, + struct sof_ipc_ctrl_data *src, + struct sof_ipc_ctrl_data *dst, + struct sof_ipc_ctrl_data_params *sparams) +{ + switch (ctrl_type) { + case SOF_CTRL_TYPE_VALUE_CHAN_GET: + case SOF_CTRL_TYPE_VALUE_CHAN_SET: + sparams->src = (u8 *)src->chanv; + sparams->dst = (u8 *)dst->chanv; + break; + case SOF_CTRL_TYPE_VALUE_COMP_GET: + case SOF_CTRL_TYPE_VALUE_COMP_SET: + sparams->src = (u8 *)src->compv; + sparams->dst = (u8 *)dst->compv; + break; + case SOF_CTRL_TYPE_DATA_GET: + case SOF_CTRL_TYPE_DATA_SET: + sparams->src = (u8 *)src->data->data; + sparams->dst = (u8 *)dst->data->data; + break; + default: + return -EINVAL; + } + + /* calculate payload size and number of messages */ + sparams->pl_size = SOF_IPC_MSG_MAX_SIZE - sparams->hdr_bytes; + sparams->num_msg = DIV_ROUND_UP(sparams->msg_bytes, sparams->pl_size); + + return 0; +} + +static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev, + struct sof_ipc_ctrl_data *cdata, + struct sof_ipc_ctrl_data_params *sparams, + bool send) +{ + struct sof_ipc_ctrl_data *partdata; + size_t send_bytes; + size_t offset = 0; + size_t msg_bytes; + size_t pl_size; + int err = 0; + int i; + + /* allocate max ipc size because we have at least one */ + partdata = kzalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); + if (!partdata) + return -ENOMEM; + + if (send) + sof_get_ctrl_copy_params(cdata->type, cdata, partdata, sparams); + else + sof_get_ctrl_copy_params(cdata->type, partdata, cdata, sparams); + + msg_bytes = sparams->msg_bytes; + pl_size = sparams->pl_size; + + /* copy the header data */ + memcpy(partdata, cdata, sparams->hdr_bytes); + + /* Serialise IPC TX */ + mutex_lock(&sdev->ipc->tx_mutex); + + /* copy the payload data in a loop */ + for (i = 0; i < sparams->num_msg; i++) { + send_bytes = min(msg_bytes, pl_size); + partdata->num_elems = send_bytes; + partdata->rhdr.hdr.size = sparams->hdr_bytes + send_bytes; + partdata->msg_index = i; + msg_bytes -= send_bytes; + partdata->elems_remaining = msg_bytes; + + if (send) + memcpy(sparams->dst, sparams->src + offset, send_bytes); + + err = sof_ipc_tx_message_unlocked(sdev->ipc, + partdata->rhdr.hdr.cmd, + partdata, + partdata->rhdr.hdr.size, + partdata, + partdata->rhdr.hdr.size); + if (err < 0) + break; + + if (!send) + memcpy(sparams->dst + offset, sparams->src, send_bytes); + + offset += pl_size; + } + + mutex_unlock(&sdev->ipc->tx_mutex); + + kfree(partdata); + return err; +} + /* * IPC get()/set() for kcontrols. */ @@ -568,8 +675,11 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc, enum sof_ipc_ctrl_cmd ctrl_cmd, bool send) { - struct snd_sof_dev *sdev = ipc->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct snd_sof_dev *sdev = ipc->sdev; + struct sof_ipc_fw_ready *ready = &sdev->fw_ready; + struct sof_ipc_fw_version *v = &ready->version; + struct sof_ipc_ctrl_data_params sparams; size_t send_bytes; int err = 0; @@ -593,23 +703,67 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc, cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd; cdata->cmd = ctrl_cmd; cdata->type = ctrl_type; - cdata->rhdr.hdr.size = scontrol->size; cdata->comp_id = scontrol->comp_id; - cdata->num_elems = scontrol->num_channels; + cdata->msg_index = 0; + + /* calculate header and data size */ + switch (cdata->type) { + case SOF_CTRL_TYPE_VALUE_CHAN_GET: + case SOF_CTRL_TYPE_VALUE_CHAN_SET: + sparams.msg_bytes = scontrol->num_channels * + sizeof(struct sof_ipc_ctrl_value_chan); + sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data); + sparams.elems = scontrol->num_channels; + break; + case SOF_CTRL_TYPE_VALUE_COMP_GET: + case SOF_CTRL_TYPE_VALUE_COMP_SET: + sparams.msg_bytes = scontrol->num_channels * + sizeof(struct sof_ipc_ctrl_value_comp); + sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data); + sparams.elems = scontrol->num_channels; + break; + case SOF_CTRL_TYPE_DATA_GET: + case SOF_CTRL_TYPE_DATA_SET: + sparams.msg_bytes = cdata->data->size; + sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data) + + sizeof(struct sof_abi_hdr); + sparams.elems = cdata->data->size; + break; + default: + return -EINVAL; + } + + cdata->rhdr.hdr.size = sparams.msg_bytes + sparams.hdr_bytes; + cdata->num_elems = sparams.elems; + cdata->elems_remaining = 0; + + /* send normal size ipc in one part */ + if (cdata->rhdr.hdr.size <= SOF_IPC_MSG_MAX_SIZE) { + err = sof_ipc_tx_message(sdev->ipc, cdata->rhdr.hdr.cmd, cdata, + cdata->rhdr.hdr.size, cdata, + cdata->rhdr.hdr.size); - /* write value via slower IPC */ - if (cdata->rhdr.hdr.size > SOF_IPC_MSG_MAX_SIZE) { - dev_err(sdev->dev, "error: set/get size %d too big comp %d\n", - cdata->rhdr.hdr.size, cdata->comp_id); + if (err < 0) + dev_err(sdev->dev, "error: set/get ctrl ipc comp %d\n", + cdata->comp_id); + + return err; + } + + /* data is bigger than max ipc size, chop to smaller pieces */ + dev_dbg(sdev->dev, "large ipc size %u, control size %u\n", + cdata->rhdr.hdr.size, scontrol->size); + + /* large messages is only supported from abi 3.3.0 onwards */ + if (v->abi_version < SOF_ABI_VER(3, 3, 0)) { + dev_err(sdev->dev, "error: incompatible FW ABI version\n"); return -EINVAL; } - err = sof_ipc_tx_message(sdev->ipc, cdata->rhdr.hdr.cmd, cdata, - cdata->rhdr.hdr.size, cdata, - cdata->rhdr.hdr.size); + err = sof_set_get_large_ctrl_data(sdev, cdata, &sparams, send); if (err < 0) - dev_err(sdev->dev, "error: set/get control ipc comp %d\n", + dev_err(sdev->dev, "error: set/get large ctrl ipc comp %d\n", cdata->comp_id); return err; From 2293bc78b0a1f875e9d835cfa372cff07c165108 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Wed, 13 Feb 2019 20:16:15 +0200 Subject: [PATCH 1213/1995] ASoC: SOF: control: remove ipc size restrictions Remove the max ipc size restriction when creating controls. The max size is coming from topology after this change. Signed-off-by: Jaska Uimonen --- sound/soc/sof/control.c | 36 ++++++++++-------------------------- sound/soc/sof/topology.c | 21 +++++++++++---------- 2 files changed, 21 insertions(+), 36 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index b1ff41d3db02d1..750663b974eb64 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -407,8 +407,6 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, (const struct snd_ctl_tlv __user *)binary_data; int ret; int err; - int max_size = SOF_IPC_MSG_MAX_SIZE - - sizeof(const struct sof_ipc_ctrl_data); /* * The beginning of bytes data contains a header from where @@ -418,16 +416,10 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, if (copy_from_user(&header, tlvd, sizeof(const struct snd_ctl_tlv))) return -EFAULT; - /* - * The maximum length that can be copied is limited by IPC max - * length and topology defined length for ext bytes control. - */ - if (be->max < max_size) /* min() not used to avoid sparse warnings */ - max_size = be->max; - if (header.length > max_size) { - dev_err_ratelimited(sdev->dev, - "error: Bytes data size %d exceeds max %d.\n", - header.length, max_size); + /* be->max is coming from topology */ + if (header.length > be->max) { + dev_err_ratelimited(sdev->dev, "error: Bytes data size %d exceeds max %d.\n", + header.length, be->max); return -EINVAL; } @@ -455,9 +447,8 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, return -EINVAL; } - if (cdata->data->size + sizeof(const struct sof_abi_hdr) > max_size) { - dev_err_ratelimited(sdev->dev, - "error: Mismatch in ABI data size (truncated?).\n"); + if (cdata->data->size + sizeof(const struct sof_abi_hdr) > be->max) { + dev_err_ratelimited(sdev->dev, "error: Mismatch in ABI data size (truncated?).\n"); return -EINVAL; } @@ -499,8 +490,6 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, struct snd_ctl_tlv header; struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data; - int max_size = SOF_IPC_MSG_MAX_SIZE - - sizeof(const struct sof_ipc_ctrl_data); int data_size; int err; int ret; @@ -534,15 +523,10 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, /* Prevent read of other kernel data or possibly corrupt response */ data_size = cdata->data->size + sizeof(const struct sof_abi_hdr); - /* check size. min3() is not used to avoid sparse warnings */ - if (size < max_size) - max_size = size; - if (be->max < max_size) - max_size = be->max; - if (data_size > max_size) { - dev_err_ratelimited(sdev->dev, - "error: user data size %d exceeds max size %d.\n", - data_size, max_size); + /* check data size doesn't exceed max coming from topology */ + if (data_size > be->max) { + dev_err_ratelimited(sdev->dev, "error: user data size %d exceeds max size %d.\n", + data_size, be->max); ret = -EINVAL; goto out; } diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index d0d1236646c47b..e5c3bfa65bcfa8 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -365,12 +365,19 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, struct sof_ipc_ctrl_data *cdata; struct snd_soc_tplg_bytes_control *control = (struct snd_soc_tplg_bytes_control *)hdr; - const int max_size = SOF_IPC_MSG_MAX_SIZE - - sizeof(const struct sof_ipc_ctrl_data); + struct soc_bytes_ext *sbe = (struct soc_bytes_ext *)kc->private_value; + int max_size = sbe->max; + + if (le32_to_cpu(control->priv.size) > max_size) { + dev_err(sdev->dev, "err: bytes data size %d exceeds max %d.\n", + control->priv.size, max_size); + return -EINVAL; + } /* init the get/put bytes data */ - scontrol->size = SOF_IPC_MSG_MAX_SIZE; - scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); + scontrol->size = sizeof(struct sof_ipc_ctrl_data) + + le32_to_cpu(control->priv.size); + scontrol->control_data = kzalloc(max_size, GFP_KERNEL); cdata = scontrol->control_data; if (!scontrol->control_data) return -ENOMEM; @@ -381,12 +388,6 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", scontrol->comp_id, scontrol->num_channels); - if (le32_to_cpu(control->priv.size) > max_size) { - dev_err(sdev->dev, "error: bytes priv data size %d exceeds max %d.\n", - control->priv.size, max_size); - return -EINVAL; - } - if (le32_to_cpu(control->priv.size) > 0) { memcpy(cdata->data, control->priv.data, le32_to_cpu(control->priv.size)); From e077463a1a08ad55813929dc6915fe86f09e2120 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 22 Mar 2019 10:24:32 +0800 Subject: [PATCH 1214/1995] ASoC: SOF: check mach before using it mach could be null. So we must check it before assigning something to it. Signed-off-by: Bard liao --- sound/soc/sof/sof-acpi-dev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 53d2ade525b57f..ae8df9988c5fc2 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -231,8 +231,10 @@ static int sof_acpi_probe(struct platform_device *pdev) } #endif - mach->mach_params.platform = dev_name(dev); - mach->mach_params.acpi_ipc_irq_index = desc->irqindex_host_ipc; + if (mach) { + mach->mach_params.platform = dev_name(dev); + mach->mach_params.acpi_ipc_irq_index = desc->irqindex_host_ipc; + } sof_pdata->machine = mach; sof_pdata->desc = desc; From 0adc726c4bf2490e51c116136fb2331a25331988 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 22 Mar 2019 10:44:24 +0800 Subject: [PATCH 1215/1995] ASoC: SOF: debug: free buf before return in error buf is allocated by kzalloc and we must free it when we don't need it. Signed-off-by: Bard liao --- sound/soc/sof/debug.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 5876269aa776db..b5ba606d2ac6e1 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -68,6 +68,7 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, dev_err(sdev->dev, "error: debugfs entry %s cannot be read in DSP D3\n", dfse->dfsentry->d_name.name); + kfree(buf); return -EINVAL; } From a45a6b6cd7030193f175b5d15a3a606c7da0bb23 Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Fri, 22 Mar 2019 14:00:02 -0700 Subject: [PATCH 1216/1995] ASoC: SOF: typo in control.h our structs are so strong they are struct structs Signed-off-by: Curtis Malainey --- include/sound/sof/control.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/sof/control.h b/include/sound/sof/control.h index 0604acbfdb9383..bded69e696d4a2 100644 --- a/include/sound/sof/control.h +++ b/include/sound/sof/control.h @@ -66,7 +66,7 @@ enum sof_ipc_ctrl_type { /* component data - uses struct sof_ipc_ctrl_value_comp */ SOF_CTRL_TYPE_VALUE_COMP_GET, SOF_CTRL_TYPE_VALUE_COMP_SET, - /* bespoke data - struct struct sof_abi_hdr */ + /* bespoke data - uses struct sof_abi_hdr */ SOF_CTRL_TYPE_DATA_GET, SOF_CTRL_TYPE_DATA_SET, }; From e127788a610c8a726addf16b7beab5313c943c0b Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Wed, 20 Mar 2019 10:59:01 +0800 Subject: [PATCH 1217/1995] ASoC: SOF: regenerate the page table only needed snd_pcm_lib_malloc_pages() may return 0 directly. This means there is no new memory allocated and so there is no need to regenerate the table. Signed-off-by: Libin Yang --- sound/soc/sof/pcm.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 6dd94c00f7afbe..545eed461849cb 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -73,12 +73,18 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, params_buffer_bytes(params), spcm->pcm.pcm_id); return ret; } - - /* create compressed page table for audio firmware */ - ret = create_page_table(substream, runtime->dma_area, - runtime->dma_bytes); - if (ret < 0) - return ret; + if (ret) { + /* + * ret == 1 means the buffer is changed + * create compressed page table for audio firmware + * ret == 0 means the buffer is not changed + * so no need to regenerate the page table + */ + ret = create_page_table(substream, runtime->dma_area, + runtime->dma_bytes); + if (ret < 0) + return ret; + } /* number of pages should be rounded up */ pcm.params.buffer.pages = PFN_UP(runtime->dma_bytes); From 156237f783948a84ee4b5d07a78c6f9bded86781 Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Wed, 27 Mar 2019 09:39:11 +0100 Subject: [PATCH 1218/1995] ASoC: SOF: update sof_ipc_pipe_new Updates sof_ipc_pipe_new struct to align with changes on FW side. Only field names are changing. Signed-off-by: Tomasz Lauda --- include/sound/sof/topology.h | 12 ++++++++---- include/uapi/sound/sof/tokens.h | 4 ++-- sound/soc/sof/topology.c | 12 ++++++------ 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h index 27966998251db1..b60a6026df3aac 100644 --- a/include/sound/sof/topology.h +++ b/include/sound/sof/topology.h @@ -218,6 +218,12 @@ struct sof_ipc_comp_reply { * Pipeline */ +/** \brief Types of pipeline scheduling time domains */ +enum sof_ipc_pipe_sched_time_domain { + SOF_TIME_DOMAIN_DMA = 0, /**< DMA interrupt */ + SOF_TIME_DOMAIN_TIMER, /**< Timer interrupt */ +}; + /* new pipeline - SOF_IPC_TPLG_PIPE_NEW */ struct sof_ipc_pipe_new { struct sof_ipc_cmd_hdr hdr; @@ -225,14 +231,12 @@ struct sof_ipc_pipe_new { uint32_t pipeline_id; /**< pipeline id */ uint32_t sched_id; /**< Scheduling component id */ uint32_t core; /**< core we run on */ - uint32_t deadline; /**< execution completion deadline in us*/ + uint32_t period; /**< execution period in us*/ uint32_t priority; /**< priority level 0 (low) to 10 (max) */ uint32_t period_mips; /**< worst case instruction count per period */ uint32_t frames_per_sched;/**< output frames of pipeline, 0 is variable */ uint32_t xrun_limit_usecs; /**< report xruns greater than limit */ - - /* non zero if timer scheduled, otherwise DAI DMA irq scheduled */ - uint32_t timer_delay; + uint32_t time_domain; /**< scheduling time domain */ } __packed; /* pipeline construction complete - SOF_IPC_TPLG_PIPE_COMPLETE */ diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 649c31acce240f..8c39da56d89140 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -42,12 +42,12 @@ #define SOF_TKN_DAI_DIRECTION 156 /* scheduling */ -#define SOF_TKN_SCHED_DEADLINE 200 +#define SOF_TKN_SCHED_PERIOD 200 #define SOF_TKN_SCHED_PRIORITY 201 #define SOF_TKN_SCHED_MIPS 202 #define SOF_TKN_SCHED_CORE 203 #define SOF_TKN_SCHED_FRAMES 204 -#define SOF_TKN_SCHED_TIMER 205 +#define SOF_TKN_SCHED_TIME_DOMAIN 205 /* volume */ #define SOF_TKN_VOLUME_RAMP_STEP_TYPE 250 diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index e5c3bfa65bcfa8..07243a3af4c685 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -500,8 +500,8 @@ static const struct sof_topology_token dai_link_tokens[] = { /* scheduling */ static const struct sof_topology_token sched_tokens[] = { - {SOF_TKN_SCHED_DEADLINE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_pipe_new, deadline), 0}, + {SOF_TKN_SCHED_PERIOD, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, period), 0}, {SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, offsetof(struct sof_ipc_pipe_new, priority), 0}, {SOF_TKN_SCHED_MIPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, @@ -510,8 +510,8 @@ static const struct sof_topology_token sched_tokens[] = { offsetof(struct sof_ipc_pipe_new, core), 0}, {SOF_TKN_SCHED_FRAMES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, offsetof(struct sof_ipc_pipe_new, frames_per_sched), 0}, - {SOF_TKN_SCHED_TIMER, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, - offsetof(struct sof_ipc_pipe_new, timer_delay), 0}, + {SOF_TKN_SCHED_TIME_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, time_domain), 0}, }; /* volume */ @@ -1266,8 +1266,8 @@ static int sof_widget_load_pipeline(struct snd_soc_component *scomp, goto err; } - dev_dbg(sdev->dev, "pipeline %s: deadline %d pri %d mips %d core %d frames %d\n", - swidget->widget->name, pipeline->deadline, pipeline->priority, + dev_dbg(sdev->dev, "pipeline %s: period %d pri %d mips %d core %d frames %d\n", + swidget->widget->name, pipeline->period, pipeline->priority, pipeline->period_mips, pipeline->core, pipeline->frames_per_sched); swidget->private = (void *)pipeline; From 03670025d8bb104c2a7bd6218759b631b6a5d123 Mon Sep 17 00:00:00 2001 From: Bartosz Kokoszko Date: Mon, 25 Mar 2019 09:43:23 +0100 Subject: [PATCH 1219/1995] ASoC: SOF: remove TRACE_CLASS defines from trace.h I've removed TRACE_CLASS_* defines since they are not required by kernel (i.e. the only user of it is sof-logger). Signed-off-by: Bartosz Kokoszko --- include/uapi/sound/sof/trace.h | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/include/uapi/sound/sof/trace.h b/include/uapi/sound/sof/trace.h index 69c6e0845fad7c..ffa7288a0f16f0 100644 --- a/include/uapi/sound/sof/trace.h +++ b/include/uapi/sound/sof/trace.h @@ -24,37 +24,6 @@ struct system_time { uint32_t val_u; /* Upper dword of current host time value */ } __packed; -/* trace event classes - high 8 bits*/ -#define TRACE_CLASS_IRQ (1 << 24) -#define TRACE_CLASS_IPC (2 << 24) -#define TRACE_CLASS_PIPE (3 << 24) -#define TRACE_CLASS_HOST (4 << 24) -#define TRACE_CLASS_DAI (5 << 24) -#define TRACE_CLASS_DMA (6 << 24) -#define TRACE_CLASS_SSP (7 << 24) -#define TRACE_CLASS_COMP (8 << 24) -#define TRACE_CLASS_WAIT (9 << 24) -#define TRACE_CLASS_LOCK (10 << 24) -#define TRACE_CLASS_MEM (11 << 24) -#define TRACE_CLASS_MIXER (12 << 24) -#define TRACE_CLASS_BUFFER (13 << 24) -#define TRACE_CLASS_VOLUME (14 << 24) -#define TRACE_CLASS_SWITCH (15 << 24) -#define TRACE_CLASS_MUX (16 << 24) -#define TRACE_CLASS_SRC (17 << 24) -#define TRACE_CLASS_TONE (18 << 24) -#define TRACE_CLASS_EQ_FIR (19 << 24) -#define TRACE_CLASS_EQ_IIR (20 << 24) -#define TRACE_CLASS_SA (21 << 24) -#define TRACE_CLASS_DMIC (22 << 24) -#define TRACE_CLASS_POWER (23 << 24) -#define TRACE_CLASS_IDC (24 << 24) -#define TRACE_CLASS_CPU (25 << 24) -#define TRACE_CLASS_EDF (27 << 24) -#define TRACE_CLASS_KPB (28 << 24) -#define TRACE_CLASS_SELECTOR (29 << 24) -#define TRACE_CLASS_SCHEDULE (30 << 24) - #define LOG_ENABLE 1 /* Enable logging */ #define LOG_DISABLE 0 /* Disable logging */ From a84e3db05aa877a071a6507bbf63a332a2bd3464 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Wed, 27 Mar 2019 16:47:57 +0800 Subject: [PATCH 1220/1995] ASoC:SOF:fix the NOCODEC and HDA mutually incompatible to make NOCODEC and HDA mutually incompatible, the DSP common control part registers are needed to be set for NOCODEC mode. At least INTCTL and PP_PPCTL are needed to be set, or else the DSP will not powerup during suspend/resume. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-ctrl.c | 16 ++++++++++++++++ sound/soc/sof/intel/hda-dsp.c | 22 ++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 2 ++ 3 files changed, 40 insertions(+) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index cda8c6c6e85920..2c3645736e1f76 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -109,6 +109,22 @@ int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev) return 0; } +void hda_dsp_ctrl_ppcap_enable(struct snd_sof_dev *sdev, bool enable) +{ + u32 val = enable ? SOF_HDA_PPCTL_GPROCEN : 0; + + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + SOF_HDA_PPCTL_GPROCEN, val); +} + +void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable) +{ + u32 val = enable ? SOF_HDA_PPCTL_PIE : 0; + + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + SOF_HDA_PPCTL_PIE, val); +} + void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable) { u32 val = enable ? PCI_CGCTL_MISCBDCGE_MASK : 0; diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index c50dcc135e3871..daec2d880ed31e 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -309,6 +309,15 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state) /* disable hda bus irq and i/o */ snd_hdac_bus_stop_chip(bus); +#else + /* disable ppcap interrupt */ + hda_dsp_ctrl_ppcap_enable(sdev, false); + hda_dsp_ctrl_ppcap_int_enable(sdev, false); + + /* disable hda bus irq */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, + 0); #endif /* disable LP retention mode */ @@ -362,6 +371,8 @@ static int hda_resume(struct snd_sof_dev *sdev) snd_hdac_ext_bus_ppcap_int_enable(bus, true); #else + hda_dsp_ctrl_misc_clock_gating(sdev, false); + /* reset controller */ ret = hda_dsp_ctrl_link_reset(sdev, true); if (ret < 0) { @@ -377,6 +388,17 @@ static int hda_resume(struct snd_sof_dev *sdev) "error: failed to ready controller during resume\n"); return ret; } + + /* enable hda bus irq */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); + + hda_dsp_ctrl_misc_clock_gating(sdev, true); + + /* enable ppcap interrupt */ + hda_dsp_ctrl_ppcap_enable(sdev, true); + hda_dsp_ctrl_ppcap_int_enable(sdev, true); #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 6e1caf8331ae45..ebb97a59b59e85 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -488,6 +488,8 @@ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev); * HDA Controller Operations. */ int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev); +void hda_dsp_ctrl_ppcap_enable(struct snd_sof_dev *sdev, bool enable); +void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable); int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset); void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable); int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable); From 0442bbd24129cc5c8c6a07beb292afb8651a6ec0 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Mon, 25 Mar 2019 09:57:41 +0800 Subject: [PATCH 1221/1995] ASoC: intel: sof_rt5682: use modern representation in dailinks Use .codecs and .num_codecs instead of .codec_name and .codec_dai_name Signed-off-by: Bard liao --- sound/soc/intel/boards/sof_rt5682.c | 38 +++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 99735cc247c02f..0454741807bcfa 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -285,11 +285,26 @@ static const struct x86_cpu_id legacy_cpi_ids[] = { {} }; +static struct snd_soc_dai_link_component rt5682_component[] = { + { + .name = "i2c-10EC5682:00", + .dai_name = "rt5682-aif1", + } +}; + +static struct snd_soc_dai_link_component dmic_component[] = { + { + .name = "dmic-codec", + .dai_name = "dmic-hifi", + } +}; + static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, int ssp_port, int dmic_num, int hdmi_num) { + struct snd_soc_dai_link_component *idisp_components; struct snd_soc_dai_link *links; int i, id = 0; @@ -299,8 +314,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); links[id].id = id; - links[id].codec_name = "i2c-10EC5682:00"; - links[id].codec_dai_name = "rt5682-aif1"; + links[id].codecs = rt5682_component; + links[id].num_codecs = ARRAY_SIZE(rt5682_component); links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].init = sof_rt5682_codec_init; @@ -325,8 +340,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].id = id; links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "DMIC%02d Pin", i); - links[id].codec_name = "dmic-codec"; - links[id].codec_dai_name = "dmic-hifi"; + links[id].codecs = dmic_component; + links[id].num_codecs = ARRAY_SIZE(dmic_component); links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].ignore_suspend = 1; @@ -336,16 +351,23 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, } /* HDMI */ + if (hdmi_num > 0) { + idisp_components = devm_kzalloc(dev, + sizeof(struct snd_soc_dai_link_component) * + hdmi_num, GFP_KERNEL); + } for (i = 1; i <= hdmi_num; i++) { links[id].name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i); links[id].id = id; links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i); - links[id].codec_name = "ehdaudio0D2"; - links[id].codec_dai_name = devm_kasprintf(dev, GFP_KERNEL, - "intel-hdmi-hifi%d", - i); + idisp_components[i-1].name = "ehdaudio0D2"; + idisp_components[i-1].dai_name = devm_kasprintf(dev, GFP_KERNEL, + "intel-hdmi-" + "hifi%d", i); + links[id].codecs = &idisp_components[i-1]; + links[id].num_codecs = 1; links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].init = sof_hdmi_init; From 3681eeeb796a4a75eda29ba28f16090410619143 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Mon, 25 Mar 2019 10:26:57 +0800 Subject: [PATCH 1222/1995] ASoC: intel: sof_rt5682: set ignore_pmdown_time to rt5682 dai link Currently, On CKL+ platforms MCLK will be turned off in sof runtime suspended, and it will go into runtime suspended right after playback is stop. However, rt5682 will output static noise if sysclk turns off during playback. Set ignore_pmdown_time to power down rt5682 immediately and avoid the noise. It can be removed once we can control MCLK by driver. Signed-off-by: Bard liao --- sound/soc/intel/boards/sof_rt5682.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 0454741807bcfa..da7e6f69e98b69 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -328,6 +328,16 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssp%d-port", ssp_port); } else { + /* + * Currently, On SKL+ platforms MCLK will be turned off in sof + * runtime suspended, and it will go into runtime suspended + * right after playback is stop. However, rt5682 will output + * static noise if sysclk turns off during playback. Set + * ignore_pmdown_time to power down rt5682 immediately and + * avoid the noise. + * It can be removed once we can control MCLK by driver. + */ + links[id].ignore_pmdown_time = 1; links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port); } From e29122d68be4c25b778d849616b5bdaca45de1d1 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Tue, 26 Mar 2019 09:30:54 +0800 Subject: [PATCH 1223/1995] ASoC: Intel: sof_rt5682: test devm_ and return -ENOMEM test all devm_ based memory allocation function and return -ENOMEM if it is failed. Signed-off-by: Bard liao --- sound/soc/intel/boards/sof_rt5682.c | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index da7e6f69e98b69..007cf94c0d5d73 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -310,9 +310,15 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * (1 + dmic_num + hdmi_num), GFP_KERNEL); + if (!links) + goto devm_err; + /* SSP */ links[id].name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port); + if (!links[id].name) + goto devm_err; + links[id].id = id; links[id].codecs = rt5682_component; links[id].num_codecs = ARRAY_SIZE(rt5682_component); @@ -327,6 +333,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, if (is_legacy_cpu) { links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssp%d-port", ssp_port); + if (!links[id].cpu_dai_name) + goto devm_err; } else { /* * Currently, On SKL+ platforms MCLK will be turned off in sof @@ -340,6 +348,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].ignore_pmdown_time = 1; links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_port); + if (!links[id].cpu_dai_name) + goto devm_err; } id++; @@ -347,9 +357,15 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, for (i = 1; i <= dmic_num; i++) { links[id].name = devm_kasprintf(dev, GFP_KERNEL, "dmic%02d", i); + if (!links[id].name) + goto devm_err; + links[id].id = id; links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "DMIC%02d Pin", i); + if (!links[id].cpu_dai_name) + goto devm_err; + links[id].codecs = dmic_component; links[id].num_codecs = ARRAY_SIZE(dmic_component); links[id].platforms = platform_component; @@ -365,17 +381,28 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, idisp_components = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) * hdmi_num, GFP_KERNEL); + if (!idisp_components) + goto devm_err; } for (i = 1; i <= hdmi_num; i++) { links[id].name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i); + if (!links[id].name) + goto devm_err; + links[id].id = id; links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i); + if (!links[id].cpu_dai_name) + goto devm_err; + idisp_components[i-1].name = "ehdaudio0D2"; idisp_components[i-1].dai_name = devm_kasprintf(dev, GFP_KERNEL, "intel-hdmi-" "hifi%d", i); + if (!idisp_components[i-1].dai_name) + goto devm_err; + links[id].codecs = &idisp_components[i-1]; links[id].num_codecs = 1; links[id].platforms = platform_component; @@ -387,6 +414,9 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, } return links; + +devm_err: + return NULL; } static int sof_audio_probe(struct platform_device *pdev) @@ -420,6 +450,9 @@ static int sof_audio_probe(struct platform_device *pdev) dai_links = sof_card_dai_links_create(&pdev->dev, sof_rt5682_quirk & SOF_RT5682_SSP_MASK, dmic_num, hdmi_num); + if (!dai_links) + return -ENOMEM; + sof_audio_card_rt5682.dai_link = dai_links; sof_audio_card_rt5682.num_links = 1 + dmic_num + hdmi_num; From bedc1d388b3183c8b2fb6e491d84c932db080774 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 19 Mar 2019 16:06:14 +0100 Subject: [PATCH 1224/1995] ASoC: SOF: Intel: simplify multiple .get_reply() implementations All SOF .get_reply() implementations follow the same pattern, which can be trivially simplified to remove an "else" clause. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/bdw.c | 5 ++--- sound/soc/sof/intel/byt.c | 5 ++--- sound/soc/sof/intel/hda-ipc.c | 5 ++--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index cc7fc1d4c513ba..305ee5e0f528f0 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -491,11 +491,10 @@ static int bdw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) if (reply.hdr.size != msg->reply_size) { dev_err(sdev->dev, "error: reply expected 0x%zx got 0x%x bytes\n", msg->reply_size, reply.hdr.size); - size = msg->reply_size; ret = -EINVAL; - } else { - size = reply.hdr.size; } + + size = msg->reply_size; } /* read the message */ diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 72eb2a886a2990..d340e9348c6d0f 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -389,11 +389,10 @@ static int byt_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) if (reply.hdr.size != msg->reply_size) { dev_err(sdev->dev, "error: reply expected 0x%zx got 0x%x bytes\n", msg->reply_size, reply.hdr.size); - size = msg->reply_size; ret = -EINVAL; - } else { - size = reply.hdr.size; } + + size = msg->reply_size; } /* read the message */ diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 4d978666db5ac6..d9754deb97775b 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -98,11 +98,10 @@ int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev, if (reply.hdr.size != msg->reply_size) { dev_err(sdev->dev, "error: reply expected 0x%zx got 0x%x bytes\n", msg->reply_size, reply.hdr.size); - size = msg->reply_size; ret = -EINVAL; - } else { - size = reply.hdr.size; } + + size = msg->reply_size; } /* read the message */ From 64b105083ba8c299536b8bcbc3d57da64a4c73e1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 29 Mar 2019 08:41:38 +0100 Subject: [PATCH 1225/1995] ASoC: SOF: Intel: print sizes in decimal format Arguably for most humans sizes, printed out in decimal format are easier to read than in hexadecimal. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/bdw.c | 2 +- sound/soc/sof/intel/byt.c | 2 +- sound/soc/sof/intel/hda-ipc.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 305ee5e0f528f0..311838260febe1 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -489,7 +489,7 @@ static int bdw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) } else { /* reply correct size ? */ if (reply.hdr.size != msg->reply_size) { - dev_err(sdev->dev, "error: reply expected 0x%zx got 0x%x bytes\n", + dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", msg->reply_size, reply.hdr.size); ret = -EINVAL; } diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index d340e9348c6d0f..92f7ed004c6ee9 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -387,7 +387,7 @@ static int byt_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) } else { /* reply correct size ? */ if (reply.hdr.size != msg->reply_size) { - dev_err(sdev->dev, "error: reply expected 0x%zx got 0x%x bytes\n", + dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", msg->reply_size, reply.hdr.size); ret = -EINVAL; } diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index d9754deb97775b..69874888665179 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -96,7 +96,7 @@ int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev, } else { /* reply correct size ? */ if (reply.hdr.size != msg->reply_size) { - dev_err(sdev->dev, "error: reply expected 0x%zx got 0x%x bytes\n", + dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", msg->reply_size, reply.hdr.size); ret = -EINVAL; } From 344bfbb7dcf59fc102c7027f9472d79816633507 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 19 Mar 2019 16:28:33 +0100 Subject: [PATCH 1226/1995] ASoC: SOF: ipc: eliminate a trivial function sof_ipc_tx_msg_reply_complete() is a static function with two arguments, of which one isn't used, it only contains two lines and is only called once. Removing it makes the flow more readable. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/ipc.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index ce42376489178b..7cd9b71f1808c9 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -302,14 +302,6 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, } EXPORT_SYMBOL(sof_ipc_tx_message); -/* mark IPC message as complete - locks held by caller */ -static void sof_ipc_tx_msg_reply_complete(struct snd_sof_ipc *ipc, - struct snd_sof_ipc_msg *msg) -{ - msg->ipc_complete = true; - wake_up(&msg->waitq); -} - /* handle reply message from DSP */ int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) { @@ -333,7 +325,8 @@ int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) } /* wake up and return the error if we have waiters on this message ? */ - sof_ipc_tx_msg_reply_complete(sdev->ipc, msg); + msg->ipc_complete = true; + wake_up(&msg->waitq); spin_unlock_irqrestore(&sdev->ipc_lock, flags); From 9bfc74c46cf2044818f32dc98f0c5a194e1f8a67 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 20 Mar 2019 09:53:26 +0100 Subject: [PATCH 1227/1995] ASoC: SOF: Intel: remove an always true condition check msg->msg_data is pre-allocated during SOF probing, if the allocation fails, the probing is aborted. Moreover, in hda-ipc.c that buffer is used before being checked. Remove the redundant test. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/byt.c | 2 +- sound/soc/sof/intel/hda-ipc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 92f7ed004c6ee9..89832ff69a640d 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -396,7 +396,7 @@ static int byt_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) } /* read the message */ - if (msg->msg_data && size > 0) + if (size > 0) sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, size); diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 69874888665179..3be89f6dfe6281 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -105,7 +105,7 @@ int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev, } /* read the message */ - if (msg->msg_data && size > 0) + if (size > 0) sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, size); From df70b787b933258722b82fdb7e468304ebf26795 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 20 Mar 2019 11:30:54 +0100 Subject: [PATCH 1228/1995] ASoC: SOF: ipc: remove .get_reply() The .get_reply() callback is always called by the IPC core immediately upon a wake-up from the platform IPC drived's interrupt handler. Therefore it can be directly called from the interrupt handler, avoiding the indirection. To make this possible the message has to be accessible from the "struct snd_sof_dev" instance and the .ipc_lock spin-lock has to be taken while manipulating the message. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/apl.c | 1 - sound/soc/sof/intel/bdw.c | 16 ++++++++++++---- sound/soc/sof/intel/byt.c | 16 +++++++++++----- sound/soc/sof/intel/cnl.c | 2 +- sound/soc/sof/intel/hda-ipc.c | 15 +++++++++++---- sound/soc/sof/intel/hda.h | 3 +-- sound/soc/sof/ipc.c | 5 ++++- sound/soc/sof/ops.h | 10 ---------- sound/soc/sof/sof-priv.h | 4 ++-- 9 files changed, 42 insertions(+), 30 deletions(-) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 5b53b149c26301..c4d69abbde34a2 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -50,7 +50,6 @@ const struct snd_sof_dsp_ops sof_apl_ops = { /* ipc */ .send_msg = hda_dsp_ipc_send_msg, - .get_reply = hda_dsp_ipc_get_reply, .fw_ready = hda_dsp_ipc_fw_ready, .cmd_done = hda_dsp_ipc_cmd_done, diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 311838260febe1..f4b8b9b3f9c535 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -68,6 +68,7 @@ static const struct snd_sof_debugfs_map bdw_debugfs[] = { }; static int bdw_cmd_done(struct snd_sof_dev *sdev, int dir); +static void bdw_get_reply(struct snd_sof_dev *sdev); /* * DSP Control. @@ -288,6 +289,7 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) * because the done bit can't be set in cmd_done function * which is triggered by msg */ + bdw_get_reply(sdev); if (snd_sof_ipc_reply(sdev, ipcx)) bdw_cmd_done(sdev, SOF_IPC_DSP_REPLY); } @@ -475,14 +477,19 @@ static int bdw_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return 0; } -static int bdw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +static void bdw_get_reply(struct snd_sof_dev *sdev) { + struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; + unsigned long flags; int ret = 0; u32 size; /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); + + spin_lock_irqsave(&sdev->ipc_lock, flags); + if (reply.error < 0) { size = sizeof(reply); ret = reply.error; @@ -498,11 +505,13 @@ static int bdw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) } /* read the message */ - if (msg->msg_data && size > 0) + if (size > 0) sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, size); - return ret; + msg->reply_error = ret; + + spin_unlock_irqrestore(&sdev->ipc_lock, flags); } static int bdw_cmd_done(struct snd_sof_dev *sdev, int dir) @@ -663,7 +672,6 @@ const struct snd_sof_dsp_ops sof_bdw_ops = { /* ipc */ .send_msg = bdw_send_msg, - .get_reply = bdw_get_reply, .fw_ready = bdw_fw_ready, .cmd_done = bdw_cmd_done, diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 89832ff69a640d..26515c99256ed8 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -106,6 +106,7 @@ static const struct snd_sof_debugfs_map cht_debugfs[] = { }; static int byt_cmd_done(struct snd_sof_dev *sdev, int dir); +static void byt_get_reply(struct snd_sof_dev *sdev); /* * IPC Firmware ready. @@ -334,6 +335,7 @@ static irqreturn_t byt_irq_thread(int irq, void *context) * because the done bit can't be set in cmd_done function * which is triggered by msg */ + byt_get_reply(sdev); if (snd_sof_ipc_reply(sdev, ipcx)) byt_cmd_done(sdev, SOF_IPC_DSP_REPLY); } @@ -373,14 +375,19 @@ static int byt_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return 0; } -static int byt_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +static void byt_get_reply(struct snd_sof_dev *sdev) { + struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; + unsigned long flags; int ret = 0; u32 size; /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); + + spin_lock_irqsave(&sdev->ipc_lock, flags); + if (reply.error < 0) { size = sizeof(reply); ret = reply.error; @@ -400,7 +407,9 @@ static int byt_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, size); - return ret; + msg->reply_error = ret; + + spin_unlock_irqrestore(&sdev->ipc_lock, flags); } static int byt_cmd_done(struct snd_sof_dev *sdev, int dir) @@ -602,7 +611,6 @@ const struct snd_sof_dsp_ops sof_tng_ops = { /* ipc */ .send_msg = byt_send_msg, - .get_reply = byt_get_reply, .fw_ready = byt_fw_ready, .cmd_done = byt_cmd_done, @@ -763,7 +771,6 @@ const struct snd_sof_dsp_ops sof_byt_ops = { /* ipc */ .send_msg = byt_send_msg, - .get_reply = byt_get_reply, .fw_ready = byt_fw_ready, .cmd_done = byt_cmd_done, @@ -819,7 +826,6 @@ const struct snd_sof_dsp_ops sof_cht_ops = { /* ipc */ .send_msg = byt_send_msg, - .get_reply = byt_get_reply, .fw_ready = byt_fw_ready, .cmd_done = byt_cmd_done, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 3fb17f42e22bb7..63226a7e6e1227 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -69,6 +69,7 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) * because the done bit can't be set in cmd_done function * which is triggered by msg */ + hda_dsp_ipc_get_reply(sdev); if (snd_sof_ipc_reply(sdev, msg)) cnl_ipc_cmd_done(sdev, SOF_IPC_DSP_REPLY); @@ -193,7 +194,6 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { /* ipc */ .send_msg = cnl_ipc_send_msg, - .get_reply = hda_dsp_ipc_get_reply, .fw_ready = hda_dsp_ipc_fw_ready, .cmd_done = cnl_ipc_cmd_done, diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 3be89f6dfe6281..b7e67812a5bfc7 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -68,14 +68,17 @@ int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return 0; } -int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev, - struct snd_sof_ipc_msg *msg) +void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) { + struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; struct sof_ipc_cmd_hdr *hdr; + unsigned long flags; int ret = 0; u32 size; + spin_lock_irqsave(&sdev->ipc_lock, flags); + hdr = msg->msg_data; if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) { /* @@ -109,7 +112,9 @@ int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev, sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, size); - return ret; + msg->reply_error = ret; + + spin_unlock_irqrestore(&sdev->ipc_lock, flags); } /* IPC handler thread */ @@ -155,8 +160,10 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) HDA_DSP_REG_HIPCCTL_DONE, 0); /* handle immediate reply from DSP core - ignore ROM messages */ - if (msg != 0x1004000) + if (msg != 0x1004000) { + hda_dsp_ipc_get_reply(sdev); reply = snd_sof_ipc_reply(sdev, msg); + } /* * handle immediate reply from DSP core. If the msg is diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index ebb97a59b59e85..f9c055a07d86c0 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -467,8 +467,7 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, */ int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); -int hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev, - struct snd_sof_ipc_msg *msg); +void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev); int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id); irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context); irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context); diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 7cd9b71f1808c9..4b362088a88ee3 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -211,7 +211,7 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, ret = -ETIMEDOUT; } else { /* copy the data returned from DSP */ - ret = snd_sof_dsp_get_reply(sdev, msg); + ret = msg->reply_error; if (msg->reply_size) memcpy(reply_data, msg->reply_data, msg->reply_size); if (ret < 0) @@ -250,11 +250,14 @@ static int sof_ipc_tx_message_unlocked(struct snd_sof_ipc *ipc, u32 header, msg->header = header; msg->msg_size = msg_bytes; msg->reply_size = reply_bytes; + msg->reply_error = 0; /* attach any data */ if (msg_bytes) memcpy(msg->msg_data, msg_data, msg_bytes); + sdev->msg = msg; + ret = snd_sof_dsp_send_msg(sdev, msg); /* Next reply that we receive will be related to this message */ if (!ret) diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 23b57884c19984..d46f4f5eafe312 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -257,16 +257,6 @@ static inline int snd_sof_dsp_send_msg(struct snd_sof_dev *sdev, return -ENOTSUPP; } -static inline int snd_sof_dsp_get_reply(struct snd_sof_dev *sdev, - struct snd_sof_ipc_msg *msg) -{ - if (sof_ops(sdev)->get_reply) - return sof_ops(sdev)->get_reply(sdev, msg); - - dev_err(sdev->dev, "error: %s not defined\n", __func__); - return -ENOTSUPP; -} - static inline int snd_sof_dsp_cmd_done(struct snd_sof_dev *sdev, int dir) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 42936799f7b828..74032c563fd18e 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -115,8 +115,6 @@ struct snd_sof_dsp_ops { /* ipc */ int (*send_msg)(struct snd_sof_dev *sof_dev, struct snd_sof_ipc_msg *msg); /* mandatory */ - int (*get_reply)(struct snd_sof_dev *sof_dev, - struct snd_sof_ipc_msg *msg); /* mandatory */ int (*cmd_done)(struct snd_sof_dev *sof_dev, int dir); /* mandatory */ /* FW loading */ @@ -257,6 +255,7 @@ struct snd_sof_ipc_msg { void *reply_data; size_t msg_size; size_t reply_size; + int reply_error; wait_queue_head_t waitq; bool ipc_complete; @@ -359,6 +358,7 @@ struct snd_sof_dev { struct snd_sof_mailbox dsp_box; /* DSP initiated IPC */ struct snd_sof_mailbox host_box; /* Host initiated IPC */ struct snd_sof_mailbox stream_box; /* Stream position update */ + struct snd_sof_ipc_msg *msg; u64 irq_status; int ipc_irq; u32 next_comp_id; /* monotonic - reset during S3 */ From 04654c84366421b0b47227ca14f61b468b87dafb Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 20 Mar 2019 15:58:02 +0100 Subject: [PATCH 1229/1995] ASoC: SOF: Intel: eliminate redundant mailbox reads *_get_reply() functions on all platforms are very similar and they share the same flaw: in case of an error the response is read from the mailbox twice. This patch replaces the second of the two reads with a memcpy(). Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/bdw.c | 13 +++++-------- sound/soc/sof/intel/byt.c | 13 +++++-------- sound/soc/sof/intel/hda-ipc.c | 14 ++++++-------- 3 files changed, 16 insertions(+), 24 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index f4b8b9b3f9c535..4d809fea76e223 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -483,7 +483,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) struct sof_ipc_reply reply; unsigned long flags; int ret = 0; - u32 size; /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); @@ -491,7 +490,7 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) spin_lock_irqsave(&sdev->ipc_lock, flags); if (reply.error < 0) { - size = sizeof(reply); + memcpy(msg->reply_data, &reply, sizeof(reply)); ret = reply.error; } else { /* reply correct size ? */ @@ -501,14 +500,12 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) ret = -EINVAL; } - size = msg->reply_size; + /* read the message */ + if (msg->reply_size > 0) + sof_mailbox_read(sdev, sdev->host_box.offset, + msg->reply_data, msg->reply_size); } - /* read the message */ - if (size > 0) - sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, - size); - msg->reply_error = ret; spin_unlock_irqrestore(&sdev->ipc_lock, flags); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 26515c99256ed8..c329b6daf846f8 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -381,7 +381,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev) struct sof_ipc_reply reply; unsigned long flags; int ret = 0; - u32 size; /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); @@ -389,7 +388,7 @@ static void byt_get_reply(struct snd_sof_dev *sdev) spin_lock_irqsave(&sdev->ipc_lock, flags); if (reply.error < 0) { - size = sizeof(reply); + memcpy(msg->reply_data, &reply, sizeof(reply)); ret = reply.error; } else { /* reply correct size ? */ @@ -399,14 +398,12 @@ static void byt_get_reply(struct snd_sof_dev *sdev) ret = -EINVAL; } - size = msg->reply_size; + /* read the message */ + if (msg->reply_size > 0) + sof_mailbox_read(sdev, sdev->host_box.offset, + msg->reply_data, msg->reply_size); } - /* read the message */ - if (size > 0) - sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, - size); - msg->reply_error = ret; spin_unlock_irqrestore(&sdev->ipc_lock, flags); diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index b7e67812a5bfc7..74444b240574a8 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -75,7 +75,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) struct sof_ipc_cmd_hdr *hdr; unsigned long flags; int ret = 0; - u32 size; spin_lock_irqsave(&sdev->ipc_lock, flags); @@ -93,8 +92,9 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); } + if (reply.error < 0) { - size = sizeof(reply); + memcpy(msg->reply_data, &reply, sizeof(reply)); ret = reply.error; } else { /* reply correct size ? */ @@ -104,14 +104,12 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) ret = -EINVAL; } - size = msg->reply_size; + /* read the message */ + if (msg->reply_size > 0) + sof_mailbox_read(sdev, sdev->host_box.offset, + msg->reply_data, msg->reply_size); } - /* read the message */ - if (size > 0) - sof_mailbox_read(sdev, sdev->host_box.offset, - msg->reply_data, size); - msg->reply_error = ret; spin_unlock_irqrestore(&sdev->ipc_lock, flags); From 9c6b98077d8adb7b97e83deb74a8f9e638cd72da Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 21 Mar 2019 13:18:21 +0100 Subject: [PATCH 1230/1995] ASoC: SOF: ipc: remove the .cmd_done platform driver method .ipc_done() is always called after an IPC IRQ, either immediately or in a task, woken up by the IRQ. This can be simplified by directly executing the respective code from the IRQ thread. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/apl.c | 1 - sound/soc/sof/intel/bdw.c | 48 ++++++++------- sound/soc/sof/intel/byt.c | 54 ++++++++--------- sound/soc/sof/intel/cnl.c | 95 ++++++++++++++--------------- sound/soc/sof/intel/hda-ipc.c | 110 ++++++++++++++++------------------ sound/soc/sof/ipc.c | 5 -- sound/soc/sof/ops.c | 1 - sound/soc/sof/ops.h | 10 ---- sound/soc/sof/sof-priv.h | 1 - 9 files changed, 146 insertions(+), 179 deletions(-) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index c4d69abbde34a2..654d74175d2704 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -51,7 +51,6 @@ const struct snd_sof_dsp_ops sof_apl_ops = { /* ipc */ .send_msg = hda_dsp_ipc_send_msg, .fw_ready = hda_dsp_ipc_fw_ready, - .cmd_done = hda_dsp_ipc_cmd_done, /* debug */ .debug_map = apl_dsp_debugfs, diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 4d809fea76e223..7f22db0d5ea77a 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -67,7 +67,8 @@ static const struct snd_sof_debugfs_map bdw_debugfs[] = { SOF_DEBUGFS_ACCESS_ALWAYS}, }; -static int bdw_cmd_done(struct snd_sof_dev *sdev, int dir); +static void bdw_host_done(struct snd_sof_dev *sdev); +static void bdw_dsp_done(struct snd_sof_dev *sdev); static void bdw_get_reply(struct snd_sof_dev *sdev); /* @@ -290,8 +291,9 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) * which is triggered by msg */ bdw_get_reply(sdev); - if (snd_sof_ipc_reply(sdev, ipcx)) - bdw_cmd_done(sdev, SOF_IPC_DSP_REPLY); + snd_sof_ipc_reply(sdev, ipcx); + + bdw_dsp_done(sdev); } ipcd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD); @@ -311,6 +313,8 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) } else { snd_sof_ipc_msgs_rx(sdev); } + + bdw_host_done(sdev); } return IRQ_HANDLED; @@ -511,28 +515,27 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) spin_unlock_irqrestore(&sdev->ipc_lock, flags); } -static int bdw_cmd_done(struct snd_sof_dev *sdev, int dir) +static void bdw_host_done(struct snd_sof_dev *sdev) { - if (dir == SOF_IPC_HOST_REPLY) { - /* clear BUSY bit and set DONE bit - accept new messages */ - snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCD, - SHIM_IPCD_BUSY | SHIM_IPCD_DONE, - SHIM_IPCD_DONE); - - /* unmask busy interrupt */ - snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_BUSY, 0); - } else { - /* clear DONE bit - tell DSP we have completed */ - snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCX, - SHIM_IPCX_DONE, 0); + /* clear BUSY bit and set DONE bit - accept new messages */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCD, + SHIM_IPCD_BUSY | SHIM_IPCD_DONE, + SHIM_IPCD_DONE); + + /* unmask busy interrupt */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_BUSY, 0); +} - /* unmask Done interrupt */ - snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_DONE, 0); - } +static void bdw_dsp_done(struct snd_sof_dev *sdev) +{ + /* clear DONE bit - tell DSP we have completed */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCX, + SHIM_IPCX_DONE, 0); - return 0; + /* unmask Done interrupt */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_DONE, 0); } /* @@ -670,7 +673,6 @@ const struct snd_sof_dsp_ops sof_bdw_ops = { /* ipc */ .send_msg = bdw_send_msg, .fw_ready = bdw_fw_ready, - .cmd_done = bdw_cmd_done, /* debug */ .debug_map = bdw_debugfs, diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index c329b6daf846f8..6fb07421bd99ba 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -105,7 +105,8 @@ static const struct snd_sof_debugfs_map cht_debugfs[] = { SOF_DEBUGFS_ACCESS_ALWAYS}, }; -static int byt_cmd_done(struct snd_sof_dev *sdev, int dir); +static void byt_host_done(struct snd_sof_dev *sdev); +static void byt_dsp_done(struct snd_sof_dev *sdev); static void byt_get_reply(struct snd_sof_dev *sdev); /* @@ -313,7 +314,7 @@ static irqreturn_t byt_irq_handler(int irq, void *context) static irqreturn_t byt_irq_thread(int irq, void *context) { - struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + struct snd_sof_dev *sdev = context; u64 ipcx, ipcd; u64 imrx; @@ -336,8 +337,9 @@ static irqreturn_t byt_irq_thread(int irq, void *context) * which is triggered by msg */ byt_get_reply(sdev); - if (snd_sof_ipc_reply(sdev, ipcx)) - byt_cmd_done(sdev, SOF_IPC_DSP_REPLY); + snd_sof_ipc_reply(sdev, ipcx); + + byt_dsp_done(sdev); } /* new message from DSP */ @@ -357,6 +359,8 @@ static irqreturn_t byt_irq_thread(int irq, void *context) } else { snd_sof_ipc_msgs_rx(sdev); } + + byt_host_done(sdev); } return IRQ_HANDLED; @@ -409,29 +413,28 @@ static void byt_get_reply(struct snd_sof_dev *sdev) spin_unlock_irqrestore(&sdev->ipc_lock, flags); } -static int byt_cmd_done(struct snd_sof_dev *sdev, int dir) +static void byt_host_done(struct snd_sof_dev *sdev) { - if (dir == SOF_IPC_HOST_REPLY) { - /* clear BUSY bit and set DONE bit - accept new messages */ - snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCD, - SHIM_BYT_IPCD_BUSY | - SHIM_BYT_IPCD_DONE, - SHIM_BYT_IPCD_DONE); - - /* unmask busy interrupt */ - snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_BUSY, 0); - } else { - /* clear DONE bit - tell DSP we have completed */ - snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCX, - SHIM_BYT_IPCX_DONE, 0); + /* clear BUSY bit and set DONE bit - accept new messages */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCD, + SHIM_BYT_IPCD_BUSY | + SHIM_BYT_IPCD_DONE, + SHIM_BYT_IPCD_DONE); + + /* unmask busy interrupt */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_BUSY, 0); +} - /* unmask Done interrupt */ - snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_DONE, 0); - } +static void byt_dsp_done(struct snd_sof_dev *sdev) +{ + /* clear DONE bit - tell DSP we have completed */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCX, + SHIM_BYT_IPCX_DONE, 0); - return 0; + /* unmask Done interrupt */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_DONE, 0); } /* @@ -609,7 +612,6 @@ const struct snd_sof_dsp_ops sof_tng_ops = { /* ipc */ .send_msg = byt_send_msg, .fw_ready = byt_fw_ready, - .cmd_done = byt_cmd_done, /* debug */ .debug_map = byt_debugfs, @@ -769,7 +771,6 @@ const struct snd_sof_dsp_ops sof_byt_ops = { /* ipc */ .send_msg = byt_send_msg, .fw_ready = byt_fw_ready, - .cmd_done = byt_cmd_done, /* debug */ .debug_map = byt_debugfs, @@ -824,7 +825,6 @@ const struct snd_sof_dsp_ops sof_cht_ops = { /* ipc */ .send_msg = byt_send_msg, .fw_ready = byt_fw_ready, - .cmd_done = byt_cmd_done, /* debug */ .debug_map = cht_debugfs, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 63226a7e6e1227..66c9ac3fc9a314 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -24,7 +24,8 @@ static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = { {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, }; -static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); +static void cnl_ipc_host_done(struct snd_sof_dev *sdev); +static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev); static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) { @@ -44,6 +45,11 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL); + hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR); + + /* reenable IPC interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); /* reply message from DSP */ if (hipcida & CNL_DSP_REG_HIPCIDA_DONE && @@ -62,22 +68,20 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) CNL_DSP_REG_HIPCCTL, CNL_DSP_REG_HIPCCTL_DONE, 0); - /* - * handle immediate reply from DSP core. If the msg is - * found, set done bit in cmd_done which is called at the - * end of message processing function, else set it here - * because the done bit can't be set in cmd_done function - * which is triggered by msg - */ + /* handle immediate reply from DSP core */ hda_dsp_ipc_get_reply(sdev); - if (snd_sof_ipc_reply(sdev, msg)) - cnl_ipc_cmd_done(sdev, SOF_IPC_DSP_REPLY); + snd_sof_ipc_reply(sdev, msg); + + if (sdev->code_loading) { + sdev->code_loading = 0; + wake_up(&sdev->waitq); + } + + cnl_ipc_dsp_done(sdev); ret = IRQ_HANDLED; } - hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR); - /* new message from DSP */ if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) { hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -106,52 +110,42 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) CNL_DSP_REG_HIPCTDR_BUSY, CNL_DSP_REG_HIPCTDR_BUSY); - ret = IRQ_HANDLED; - } + cnl_ipc_host_done(sdev); - if (ret == IRQ_HANDLED) { - /* reenable IPC interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, - HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); - } - - if (sdev->code_loading) { - sdev->code_loading = 0; - wake_up(&sdev->waitq); + ret = IRQ_HANDLED; } return ret; } -static int cnl_ipc_cmd_done(struct snd_sof_dev *sdev, int dir) +static void cnl_ipc_host_done(struct snd_sof_dev *sdev) { - if (dir == SOF_IPC_HOST_REPLY) { - /* - * set done bit to ack dsp the msg has been - * processed and send reply msg to dsp - */ - snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, - CNL_DSP_REG_HIPCTDA, - CNL_DSP_REG_HIPCTDA_DONE, - CNL_DSP_REG_HIPCTDA_DONE); - } else { - /* - * set DONE bit - tell DSP we have received the reply msg - * from DSP, and processed it, don't send more reply to host - */ - snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, - CNL_DSP_REG_HIPCIDA, - CNL_DSP_REG_HIPCIDA_DONE, - CNL_DSP_REG_HIPCIDA_DONE); - - /* unmask Done interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - CNL_DSP_REG_HIPCCTL, - CNL_DSP_REG_HIPCCTL_DONE, - CNL_DSP_REG_HIPCCTL_DONE); - } + /* + * set done bit to ack dsp the msg has been + * processed and send reply msg to dsp + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCTDA, + CNL_DSP_REG_HIPCTDA_DONE, + CNL_DSP_REG_HIPCTDA_DONE); +} - return 0; +static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev) +{ + /* + * set DONE bit - tell DSP we have received the reply msg + * from DSP, and processed it, don't send more reply to host + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCIDA, + CNL_DSP_REG_HIPCIDA_DONE, + CNL_DSP_REG_HIPCIDA_DONE); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCCTL, + CNL_DSP_REG_HIPCCTL_DONE, + CNL_DSP_REG_HIPCCTL_DONE); } static int cnl_ipc_send_msg(struct snd_sof_dev *sdev, @@ -195,7 +189,6 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { /* ipc */ .send_msg = cnl_ipc_send_msg, .fw_ready = hda_dsp_ipc_fw_ready, - .cmd_done = cnl_ipc_cmd_done, /* debug */ .debug_map = cnl_dsp_debugfs, diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 74444b240574a8..e742fcd3dac2fe 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -18,41 +18,40 @@ #include "../ops.h" #include "hda.h" -int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir) +static void hda_dsp_ipc_host_done(struct snd_sof_dev *sdev) { - if (dir == SOF_IPC_HOST_REPLY) { - /* - * tell DSP cmd is done - clear busy - * interrupt and send reply msg to dsp - */ - snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, - HDA_DSP_REG_HIPCT, - HDA_DSP_REG_HIPCT_BUSY, - HDA_DSP_REG_HIPCT_BUSY); - - /* unmask BUSY interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - HDA_DSP_REG_HIPCCTL, - HDA_DSP_REG_HIPCCTL_BUSY, - HDA_DSP_REG_HIPCCTL_BUSY); - } else { - /* - * set DONE bit - tell DSP we have received the reply msg - * from DSP, and processed it, don't send more reply to host - */ - snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, - HDA_DSP_REG_HIPCIE, - HDA_DSP_REG_HIPCIE_DONE, - HDA_DSP_REG_HIPCIE_DONE); - - /* unmask Done interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - HDA_DSP_REG_HIPCCTL, - HDA_DSP_REG_HIPCCTL_DONE, - HDA_DSP_REG_HIPCCTL_DONE); - } + /* + * tell DSP cmd is done - clear busy + * interrupt and send reply msg to dsp + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCT, + HDA_DSP_REG_HIPCT_BUSY, + HDA_DSP_REG_HIPCT_BUSY); + + /* unmask BUSY interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCCTL, + HDA_DSP_REG_HIPCCTL_BUSY, + HDA_DSP_REG_HIPCCTL_BUSY); +} - return 0; +static void hda_dsp_ipc_dsp_done(struct snd_sof_dev *sdev) +{ + /* + * set DONE bit - tell DSP we have received the reply msg + * from DSP, and processed it, don't send more reply to host + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCIE, + HDA_DSP_REG_HIPCIE_DONE, + HDA_DSP_REG_HIPCIE_DONE); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCCTL, + HDA_DSP_REG_HIPCCTL_DONE, + HDA_DSP_REG_HIPCCTL_DONE); } int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) @@ -118,7 +117,8 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) /* IPC handler thread */ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) { - struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + struct snd_sof_dev *sdev = context; + irqreturn_t ret = IRQ_NONE; u32 hipci; u32 hipcie; u32 hipct; @@ -126,12 +126,10 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) u32 hipcctl; u32 msg; u32 msg_ext; - irqreturn_t ret = IRQ_NONE; - int reply = -EINVAL; /* here we handle IPC interrupts only */ if (!(sdev->irq_status & HDA_DSP_ADSPIS_IPC)) - return ret; + return IRQ_NONE; /* read IPC status */ hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -139,10 +137,13 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT); hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL); + /* reenable IPC interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); + /* is this a reply message from the DSP */ if (hipcie & HDA_DSP_REG_HIPCIE_DONE && hipcctl & HDA_DSP_REG_HIPCCTL_DONE) { - hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI); msg = hipci & HDA_DSP_REG_HIPCI_MSG_MASK; @@ -160,18 +161,17 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) /* handle immediate reply from DSP core - ignore ROM messages */ if (msg != 0x1004000) { hda_dsp_ipc_get_reply(sdev); - reply = snd_sof_ipc_reply(sdev, msg); + snd_sof_ipc_reply(sdev, msg); } - /* - * handle immediate reply from DSP core. If the msg is - * found, set done bit in cmd_done which is called at the - * end of message processing function, else set it here - * because the done bit can't be set in cmd_done function - * which is triggered by msg - */ - if (reply) - hda_dsp_ipc_cmd_done(sdev, SOF_IPC_DSP_REPLY); + /* wake up sleeper if we are loading code */ + if (sdev->code_loading) { + sdev->code_loading = 0; + wake_up(&sdev->waitq); + } + + /* set the done bit */ + hda_dsp_ipc_dsp_done(sdev); ret = IRQ_HANDLED; } @@ -203,19 +203,9 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) snd_sof_ipc_msgs_rx(sdev); } - ret = IRQ_HANDLED; - } + hda_dsp_ipc_host_done(sdev); - if (ret == IRQ_HANDLED) { - /* reenable IPC interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, - HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); - } - - /* wake up sleeper if we are loading code */ - if (sdev->code_loading) { - sdev->code_loading = 0; - wake_up(&sdev->waitq); + ret = IRQ_HANDLED; } return ret; diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 4b362088a88ee3..63f9e968cb924a 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -221,8 +221,6 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, ipc_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd); } - snd_sof_dsp_cmd_done(sdev, SOF_IPC_DSP_REPLY); - return ret; } @@ -394,9 +392,6 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) } ipc_log_header(sdev->dev, "ipc rx done", hdr.cmd); - - /* tell DSP we are done */ - snd_sof_dsp_cmd_done(sdev, SOF_IPC_HOST_REPLY); } EXPORT_SYMBOL(snd_sof_ipc_msgs_rx); diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index ba0b7a66f39521..e643d338be09ff 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -199,6 +199,5 @@ void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset) snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX); snd_sof_trace_notify_for_error(sdev); - snd_sof_dsp_cmd_done(sdev, SOF_IPC_HOST_REPLY); } EXPORT_SYMBOL(snd_sof_dsp_panic); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index d46f4f5eafe312..cba2d16b66e8ba 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -257,16 +257,6 @@ static inline int snd_sof_dsp_send_msg(struct snd_sof_dev *sdev, return -ENOTSUPP; } -static inline int snd_sof_dsp_cmd_done(struct snd_sof_dev *sdev, - int dir) -{ - if (sof_ops(sdev)->cmd_done) - return sof_ops(sdev)->cmd_done(sdev, dir); - - dev_err(sdev->dev, "error: %s not defined\n", __func__); - return -ENOTSUPP; -} - /* host DMA trace */ static inline int snd_sof_dma_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 74032c563fd18e..c4465b2d3a0432 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -115,7 +115,6 @@ struct snd_sof_dsp_ops { /* ipc */ int (*send_msg)(struct snd_sof_dev *sof_dev, struct snd_sof_ipc_msg *msg); /* mandatory */ - int (*cmd_done)(struct snd_sof_dev *sof_dev, int dir); /* mandatory */ /* FW loading */ int (*load_firmware)(struct snd_sof_dev *sof_dev); /* mandatory */ From d435088eb9aa41c721896bdcd9967cf4ae516ff9 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 19 Mar 2019 16:06:14 +0100 Subject: [PATCH 1231/1995] ASoC: SOF: hsw: simplify .get_reply() implementations All SOF .get_reply() implementations follow the same pattern, which can be trivially simplified to remove an "else" clause. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/hsw.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index b7193d21cebb48..3b8eceb97fdac9 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -490,13 +490,12 @@ static int hsw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) } else { /* reply correct size ? */ if (reply.hdr.size != msg->reply_size) { - dev_err(sdev->dev, "error: reply expected 0x%zx got 0x%x bytes\n", + dev_err(sdev->dev, "error: reply expected 0x%zx got %u bytes\n", msg->reply_size, reply.hdr.size); - size = msg->reply_size; ret = -EINVAL; - } else { - size = reply.hdr.size; } + + size = msg->reply_size; } /* read the message */ From ae4e51e1c686904bcb8343f2e6a741b2fe59de61 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 29 Mar 2019 08:55:43 +0100 Subject: [PATCH 1232/1995] ASoC: SOF: hsw: print sizes in decimal format Unlike addresses sizes are usually easier to read in decimal format. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/hsw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 3b8eceb97fdac9..922ff32f863ff3 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -490,7 +490,7 @@ static int hsw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) } else { /* reply correct size ? */ if (reply.hdr.size != msg->reply_size) { - dev_err(sdev->dev, "error: reply expected 0x%zx got %u bytes\n", + dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", msg->reply_size, reply.hdr.size); ret = -EINVAL; } From dc5f5f087bcde5c03870b53050b1f5bfb70c1639 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 20 Mar 2019 09:53:26 +0100 Subject: [PATCH 1233/1995] ASoC: SOF: hsw: remove an always true condition check msg->msg_data is pre-allocated during SOF probing, if the allocation fails, the probing is aborted. Moreover, in hda-ipc.c that buffer is used before being checked. Remove the redundant test. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/hsw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 922ff32f863ff3..41707f46a1b794 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -499,7 +499,7 @@ static int hsw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) } /* read the message */ - if (msg->msg_data && size > 0) + if (size > 0) sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, size); return ret; From 63f6059d5921eaab707350e20c8ddaeddd8e48ca Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 20 Mar 2019 11:30:54 +0100 Subject: [PATCH 1234/1995] ASoC: SOF: spi: remove .get_reply() The .get_reply() callback is always called by the IPC core immediately upon a wake-up from the platform IPC drived's interrupt handler. Therefore it can be directly called from the interrupt handler, avoiding the indirection. To make this possible the message has to be accessible from the "struct snd_sof_dev" instance and the .ipc_lock spin-lock has to be taken while manipulating the message. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/hw-spi.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index 58815c65c9c8e3..2a517c7fdd0513 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -167,20 +167,6 @@ static irqreturn_t spi_irq_handler(int irq __maybe_unused, void *context) return IRQ_NONE; } -static irqreturn_t spi_irq_thread(int irq __maybe_unused, void *context __maybe_unused) -{ - // read SPI data into local buffer and determine IPC cmd or reply - - /* - * if reply. Handle Immediate reply from DSP Core and set DSP - * state to ready - */ - - /* if cmd, Handle messages from DSP Core */ - - return IRQ_HANDLED; -} - static int spi_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { /* send the message */ @@ -221,6 +207,23 @@ static int spi_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return ret; } +static irqreturn_t spi_irq_thread(int irq __maybe_unused, void *context __maybe_unused) +{ + struct snd_sof_dev *sdev = context; + + // read SPI data into local buffer and determine IPC cmd or reply + + /* + * if reply. Handle Immediate reply from DSP Core and set DSP + * state to ready + */ + + /* if cmd, Handle messages from DSP Core */ + spi_get_reply(sdev, sdev->msg); + + return IRQ_HANDLED; +} + /* * Probe and remove. */ @@ -290,7 +293,6 @@ const struct snd_sof_dsp_ops snd_sof_spi_ops = { /* ipc */ .send_msg = spi_send_msg, - .get_reply = spi_get_reply, .fw_ready = spi_fw_ready, .cmd_done = spi_cmd_done, From bb7890c538dba7d9a4518618f2c0105aab4e00a7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 29 Mar 2019 09:05:07 +0100 Subject: [PATCH 1235/1995] ASoC: SOF: hsw: remove .get_reply() The .get_reply() callback is always called by the IPC core immediately upon a wake-up from the platform IPC drived's interrupt handler. Therefore it can be directly called from the interrupt handler, avoiding the indirection. To make this possible the message has to be accessible from the "struct snd_sof_dev" instance and the .ipc_lock spin-lock has to be taken while manipulating the message. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/hsw.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 41707f46a1b794..548a8886556ac0 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -68,6 +68,7 @@ static const struct snd_sof_debugfs_map hsw_debugfs[] = { }; static int hsw_cmd_done(struct snd_sof_dev *sdev, int dir); +static void hsw_get_reply(struct snd_sof_dev *sdev); /* * DSP Control. @@ -289,6 +290,7 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) * because the done bit can't be set in cmd_done function * which is triggered by msg */ + hsw_get_reply(sdev); if (snd_sof_ipc_reply(sdev, ipcx)) hsw_cmd_done(sdev, SOF_IPC_DSP_REPLY); } @@ -476,12 +478,16 @@ static int hsw_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return 0; } -static int hsw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +static void hsw_get_reply(struct snd_sof_dev *sdev) { + struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; + unsigned long flags; int ret = 0; u32 size; + spin_lock_irqsave(&sdev->ipc_lock, flags); + /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); if (reply.error < 0) { @@ -502,7 +508,10 @@ static int hsw_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) if (size > 0) sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, size); - return ret; + + msg->reply_error = ret; + + spin_unlock_irqrestore(&sdev->ipc_lock, flags); } static int hsw_cmd_done(struct snd_sof_dev *sdev, int dir) @@ -663,7 +672,6 @@ const struct snd_sof_dsp_ops sof_hsw_ops = { /* ipc */ .send_msg = hsw_send_msg, - .get_reply = hsw_get_reply, .fw_ready = hsw_fw_ready, .cmd_done = hsw_cmd_done, From 7f7d2658c32160210656c21e74098df1210af486 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 29 Mar 2019 09:06:17 +0100 Subject: [PATCH 1236/1995] ASoC: SOF: skl: remove .get_reply() The .get_reply() callback is always called by the IPC core immediately upon a wake-up from the platform IPC drived's interrupt handler. Therefore it can be directly called from the interrupt handler, avoiding the indirection. To make this possible the message has to be accessible from the "struct snd_sof_dev" instance and the .ipc_lock spin-lock has to be taken while manipulating the message. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/skl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 1918297bae420b..9b41c9857c3cb6 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -50,7 +50,6 @@ const struct snd_sof_dsp_ops sof_skl_ops = { /* ipc */ .send_msg = hda_dsp_ipc_send_msg, - .get_reply = hda_dsp_ipc_get_reply, .fw_ready = hda_dsp_ipc_fw_ready, .cmd_done = hda_dsp_ipc_cmd_done, From 2c787c55263da364b1993c899b189ff67756b0e9 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 20 Mar 2019 15:58:02 +0100 Subject: [PATCH 1237/1995] ASoC: SOF: hsw: eliminate redundant mailbox reads *_get_reply() functions on all platforms are very similar and they share the same flaw: in case of an error the response is read from the mailbox twice. This patch replaces the second of the two reads with a memcpy(). Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/hsw.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 548a8886556ac0..68e7a811fd04fe 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -484,14 +484,13 @@ static void hsw_get_reply(struct snd_sof_dev *sdev) struct sof_ipc_reply reply; unsigned long flags; int ret = 0; - u32 size; spin_lock_irqsave(&sdev->ipc_lock, flags); /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); if (reply.error < 0) { - size = sizeof(reply); + memcpy(msg->reply_data, &reply, sizeof(reply)); ret = reply.error; } else { /* reply correct size ? */ @@ -501,14 +500,12 @@ static void hsw_get_reply(struct snd_sof_dev *sdev) ret = -EINVAL; } - size = msg->reply_size; + /* read the message */ + if (msg->reply_size > 0) + sof_mailbox_read(sdev, sdev->host_box.offset, + msg->reply_data, msg->reply_size); } - /* read the message */ - if (size > 0) - sof_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, - size); - msg->reply_error = ret; spin_unlock_irqrestore(&sdev->ipc_lock, flags); From a74c774b1d7fc43eb6640e1b8bfe1278796b7f0a Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 21 Mar 2019 13:18:21 +0100 Subject: [PATCH 1238/1995] ASoC: SOF: spi: remove the .cmd_done platform driver method .ipc_done() is always called after an IPC IRQ, either immediately or in a task, woken up by the IRQ. This can be simplified by directly executing the respective code from the IRQ thread. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/hw-spi.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index 2a517c7fdd0513..b85d37f7ff4311 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -268,11 +268,6 @@ static int spi_sof_remove(struct snd_sof_dev *sdev) return 0; } -static int spi_cmd_done(struct snd_sof_dev *sof_dev __maybe_unused, int dir __maybe_unused) -{ - return 0; -} - /* SPI SOF ops */ const struct snd_sof_dsp_ops snd_sof_spi_ops = { /* device init */ @@ -294,7 +289,6 @@ const struct snd_sof_dsp_ops snd_sof_spi_ops = { /* ipc */ .send_msg = spi_send_msg, .fw_ready = spi_fw_ready, - .cmd_done = spi_cmd_done, /* debug */ .debug_map = NULL/*spi_debugfs*/, From 3dcbf5983ea2c66cc014a46b37d56cc2e38969d7 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 29 Mar 2019 09:09:10 +0100 Subject: [PATCH 1239/1995] ASoC: SOF: hsw: remove the .cmd_done platform driver method .ipc_done() is always called after an IPC IRQ, either immediately or in a task, woken up by the IRQ. This can be simplified by directly executing the respective code from the IRQ thread. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/hsw.c | 50 ++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 68e7a811fd04fe..66f7b1a9ec6969 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -67,7 +67,8 @@ static const struct snd_sof_debugfs_map hsw_debugfs[] = { SOF_DEBUGFS_ACCESS_ALWAYS}, }; -static int hsw_cmd_done(struct snd_sof_dev *sdev, int dir); +static void hsw_host_done(struct snd_sof_dev *sdev); +static void hsw_dsp_done(struct snd_sof_dev *sdev); static void hsw_get_reply(struct snd_sof_dev *sdev); /* @@ -269,7 +270,7 @@ static irqreturn_t hsw_irq_handler(int irq, void *context) static irqreturn_t hsw_irq_thread(int irq, void *context) { - struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + struct snd_sof_dev *sdev = context; u32 ipcx, ipcd, imrx; imrx = snd_sof_dsp_read64(sdev, HSW_DSP_BAR, SHIM_IMRX); @@ -291,8 +292,9 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) * which is triggered by msg */ hsw_get_reply(sdev); - if (snd_sof_ipc_reply(sdev, ipcx)) - hsw_cmd_done(sdev, SOF_IPC_DSP_REPLY); + snd_sof_ipc_reply(sdev, ipcx); + + hsw_dsp_done(sdev); } ipcd = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_IPCD); @@ -312,6 +314,8 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) } else { snd_sof_ipc_msgs_rx(sdev); } + + hsw_host_done(sdev); } return IRQ_HANDLED; @@ -511,28 +515,27 @@ static void hsw_get_reply(struct snd_sof_dev *sdev) spin_unlock_irqrestore(&sdev->ipc_lock, flags); } -static int hsw_cmd_done(struct snd_sof_dev *sdev, int dir) +static void hsw_host_done(struct snd_sof_dev *sdev) { - if (dir == SOF_IPC_HOST_REPLY) { - /* clear BUSY bit and set DONE bit - accept new messages */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IPCD, - SHIM_IPCD_BUSY | SHIM_IPCD_DONE, - SHIM_IPCD_DONE); - - /* unmask busy interrupt */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_BUSY, 0); - } else { - /* clear DONE bit - tell DSP we have completed */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IPCX, - SHIM_IPCX_DONE, 0); + /* clear BUSY bit and set DONE bit - accept new messages */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IPCD, + SHIM_IPCD_BUSY | SHIM_IPCD_DONE, + SHIM_IPCD_DONE); + + /* unmask busy interrupt */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_BUSY, 0); +} - /* unmask Done interrupt */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_DONE, 0); - } +static void hsw_dsp_done(struct snd_sof_dev *sdev) +{ + /* clear DONE bit - tell DSP we have completed */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IPCX, + SHIM_IPCX_DONE, 0); - return 0; + /* unmask Done interrupt */ + snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_DONE, 0); } /* @@ -670,7 +673,6 @@ const struct snd_sof_dsp_ops sof_hsw_ops = { /* ipc */ .send_msg = hsw_send_msg, .fw_ready = hsw_fw_ready, - .cmd_done = hsw_cmd_done, /* debug */ .debug_map = hsw_debugfs, From 5c78516831385c34a03db1ccd879c914382d0cde Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 29 Mar 2019 09:09:51 +0100 Subject: [PATCH 1240/1995] ASoC: SOF: skl: remove the .cmd_done platform driver method .ipc_done() is always called after an IPC IRQ, either immediately or in a task, woken up by the IRQ. This can be simplified by directly executing the respective code from the IRQ thread. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/skl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 9b41c9857c3cb6..024d2b70ec5dbf 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -51,7 +51,6 @@ const struct snd_sof_dsp_ops sof_skl_ops = { /* ipc */ .send_msg = hda_dsp_ipc_send_msg, .fw_ready = hda_dsp_ipc_fw_ready, - .cmd_done = hda_dsp_ipc_cmd_done, /* debug */ .debug_map = skl_dsp_debugfs, From c091fced95e4e104729f6b6b5c3d7700cbdba377 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 21 Mar 2019 17:10:39 +0100 Subject: [PATCH 1241/1995] ASoC: SOF: core: fix a typo in a comment Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 04a6716e9762a2..2ca716f5dd8970 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -231,7 +231,7 @@ int snd_sof_create_page_table(struct snd_sof_dev *sdev, * x = (pfn[i+1] << 4) | (pfn[i] & 0xf) * 4. put x at offset (current location + 2) in LE byte order * 5. increment current location by 5 bytes, increment i by 2 - * 6. continue to (1) + * 6. continue to (2) */ if (i & 1) put_unaligned_le32((pg_table[0] & 0xf) | pfn << 4, From 1a3023339e4c7cc9b4e132389f2b0d10b15baf21 Mon Sep 17 00:00:00 2001 From: Dragos Tarcatu Date: Thu, 28 Mar 2019 10:26:35 +0200 Subject: [PATCH 1242/1995] ASoC: SOF: topology: use the default hw_config in DAI link init If multiple hw_configs are provided in the topology, look for the default one instead of loading the first one found. Signed-off-by: Dragos Tarcatu --- sound/soc/sof/topology.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 07243a3af4c685..f4c01a5af18f6c 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2514,7 +2514,9 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_private *private = &cfg->priv; struct sof_ipc_dai_config config; struct snd_soc_tplg_hw_config *hw_config; + int num_hw_configs; int ret = 0; + int i = 0; link->platform_name = dev_name(sdev->dev); @@ -2552,15 +2554,31 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, * DAI links are expected to have at least 1 hw_config. * But some older topologies might have no hw_config for HDA dai links. */ - if (!le32_to_cpu(cfg->num_hw_configs) && - config.type != SOF_DAI_INTEL_HDA) { - dev_err(sdev->dev, "error: unexpected DAI config count %d!\n", - le32_to_cpu(cfg->num_hw_configs)); - return -EINVAL; + num_hw_configs = le32_to_cpu(cfg->num_hw_configs); + if (!num_hw_configs) { + if (config.type != SOF_DAI_INTEL_HDA) { + dev_err(sdev->dev, "error: unexpected DAI config count %d!\n", + le32_to_cpu(cfg->num_hw_configs)); + return -EINVAL; + } + } else { + dev_dbg(sdev->dev, "tplg: %d hw_configs found, default id: %d!\n", + cfg->num_hw_configs, le32_to_cpu(cfg->default_hw_config_id)); + + for (i = 0; i < num_hw_configs; i++) { + if (cfg->hw_config[i].id == cfg->default_hw_config_id) + break; + } + + if (i == num_hw_configs) { + dev_err(sdev->dev, "error: default hw_config id: %d not found!\n", + le32_to_cpu(cfg->default_hw_config_id)); + return -EINVAL; + } } /* configure dai IPC message */ - hw_config = &cfg->hw_config[0]; + hw_config = &cfg->hw_config[i]; config.hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG; config.format = le32_to_cpu(hw_config->fmt); From f304b5c20e34da0f83258c97b33bbead09b33243 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 22 Mar 2019 11:53:01 +0200 Subject: [PATCH 1243/1995] ASoC: sof: use iopoll.h macro for polled register reads Introduce a variant of readx_poll_timeout() macro from linux/iopoll.h to SOF and use it to replace the old snd_sof_dsp_register_poll() function. Due to indirection of register i/o in SOF, we can't directly use the iopoll.h macros. Signed-off-by: Kai Vehmanen --- sound/soc/sof/intel/hda-dsp.c | 53 +++++++++++++++------------- sound/soc/sof/intel/hda-loader-skl.c | 25 +++++++------ sound/soc/sof/intel/hda-loader.c | 37 ++++++++++--------- sound/soc/sof/intel/hda.h | 6 ++-- sound/soc/sof/ops.c | 40 --------------------- sound/soc/sof/ops.h | 44 +++++++++++++++++++++++ 6 files changed, 111 insertions(+), 94 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index daec2d880ed31e..bf4bcee0e5dbf2 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -27,21 +27,21 @@ int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask) { u32 adspcs; + u32 reset; int ret; /* set reset bits for cores */ + reset = HDA_DSP_ADSPCS_CRST_MASK(core_mask); snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, - HDA_DSP_ADSPCS_CRST_MASK(core_mask), - HDA_DSP_ADSPCS_CRST_MASK(core_mask)); + reset, reset), /* poll with timeout to check if operation successful */ - ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_DSP_REG_ADSPCS, - HDA_DSP_ADSPCS_CRST_MASK(core_mask), - HDA_DSP_ADSPCS_CRST_MASK(core_mask), - HDA_DSP_RESET_TIMEOUT, - HDA_DSP_REG_POLL_INTERVAL_US); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, adspcs, + ((adspcs & reset) == reset), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); /* has core entered reset ? */ adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -59,6 +59,7 @@ int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask) int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask) { + unsigned int crst; u32 adspcs; int ret; @@ -69,11 +70,12 @@ int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask) 0); /* poll with timeout to check if operation successful */ - ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_DSP_REG_ADSPCS, - HDA_DSP_ADSPCS_CRST_MASK(core_mask), 0, - HDA_DSP_RESET_TIMEOUT, - HDA_DSP_REG_POLL_INTERVAL_US); + crst = HDA_DSP_ADSPCS_CRST_MASK(core_mask); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, adspcs, + !(adspcs & crst), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); /* has core left reset ? */ adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -133,6 +135,7 @@ int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask) int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) { + unsigned int cpa; u32 adspcs; int ret; @@ -142,12 +145,12 @@ int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) HDA_DSP_ADSPCS_SPA_MASK(core_mask)); /* poll with timeout to check if operation successful */ - ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_DSP_REG_ADSPCS, - HDA_DSP_ADSPCS_CPA_MASK(core_mask), - HDA_DSP_ADSPCS_CPA_MASK(core_mask), - HDA_DSP_PU_TIMEOUT, - HDA_DSP_REG_POLL_INTERVAL_US); + cpa = HDA_DSP_ADSPCS_CPA_MASK(core_mask); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, adspcs, + (adspcs & cpa) == cpa, + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); if (ret < 0) dev_err(sdev->dev, "error: timeout on core powerup\n"); @@ -167,16 +170,18 @@ int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask) { + u32 adspcs; + /* update bits */ snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, HDA_DSP_ADSPCS_SPA_MASK(core_mask), 0); - /* poll with timeout to check if operation successful */ - return snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_DSP_REG_ADSPCS, HDA_DSP_ADSPCS_CPA_MASK(core_mask), 0, - HDA_DSP_PD_TIMEOUT, - HDA_DSP_REG_POLL_INTERVAL_US); + return snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, adspcs, + !(adspcs & HDA_DSP_ADSPCS_SPA_MASK(core_mask)), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_PD_TIMEOUT * USEC_PER_MSEC); } bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 6deeafac9c64cc..4edd78f9f57c24 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -305,6 +305,7 @@ static void cl_cleanup_skl(struct snd_sof_dev *sdev) static int cl_dsp_init_skl(struct snd_sof_dev *sdev) { + unsigned int sts; int ret; /* @@ -353,11 +354,12 @@ static int cl_dsp_init_skl(struct snd_sof_dev *sdev) hda_dsp_ipc_int_enable(sdev); /* polling the ROM init status information. */ - ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_ADSP_FW_STATUS_SKL, - HDA_DSP_ROM_STS_MASK, HDA_DSP_ROM_INIT, - HDA_DSP_INIT_TIMEOUT, - HDA_DSP_REG_POLL_INTERVAL_US); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_ADSP_FW_STATUS_SKL, sts, + ((sts & HDA_DSP_ROM_STS_MASK) + == HDA_DSP_ROM_INIT), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_INIT_TIMEOUT_US); if (ret < 0) goto err; @@ -432,6 +434,7 @@ static int cl_copy_fw_skl(struct snd_sof_dev *sdev) struct snd_sof_pdata *plat_data = sdev->pdata; const struct firmware *fw = plat_data->fw; unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; + unsigned int status; int ret = 0; dev_dbg(sdev->dev, "firmware size: 0x%zx buffer size 0x%x\n", fw->size, @@ -443,12 +446,12 @@ static int cl_copy_fw_skl(struct snd_sof_dev *sdev) return ret; } - ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_ADSP_FW_STATUS_SKL, - HDA_DSP_ROM_STS_MASK, - HDA_DSP_ROM_FW_FW_LOADED, - HDA_DSP_BASEFW_TIMEOUT, - HDA_DSP_REG_POLL_INTERVAL_US); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_ADSP_FW_STATUS_SKL, status, + ((status & HDA_DSP_ROM_STS_MASK) + == HDA_DSP_ROM_FW_FW_LOADED), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_BASEFW_TIMEOUT_US); if (ret < 0) dev_err(sdev->dev, "error: firmware transfer timeout!"); diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 4f182e6326f2e1..6cceba30eca4a2 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -82,6 +82,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; + unsigned int status; int ret; /* step 1: power up corex */ @@ -105,11 +106,12 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, } /* step 4: wait for IPC DONE bit from ROM */ - ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - chip->ipc_ack, - chip->ipc_ack_mask, chip->ipc_ack_mask, - HDA_DSP_INIT_TIMEOUT, - HDA_DSP_REG_POLL_INTERVAL_US); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + chip->ipc_ack, status, + ((status & chip->ipc_ack_mask) + == chip->ipc_ack_mask), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_INIT_TIMEOUT_US); if (ret < 0) { dev_err(sdev->dev, "error: waiting for HIPCIE done\n"); @@ -128,11 +130,13 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, hda_dsp_ipc_int_enable(sdev); /* step 7: wait for ROM init */ - ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_DSP_SRAM_REG_ROM_STATUS, - HDA_DSP_ROM_STS_MASK, HDA_DSP_ROM_INIT, - chip->rom_init_timeout, - HDA_DSP_REG_POLL_INTERVAL_US); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_STATUS, status, + ((status & HDA_DSP_ROM_STS_MASK) + == HDA_DSP_ROM_INIT), + HDA_DSP_REG_POLL_INTERVAL_US, + chip->rom_init_timeout * + USEC_PER_MSEC); if (!ret) return 0; @@ -221,6 +225,7 @@ static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) { + unsigned int reg; int ret, status; ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_START); @@ -229,12 +234,12 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) return ret; } - status = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR, - HDA_DSP_SRAM_REG_ROM_STATUS, - HDA_DSP_ROM_STS_MASK, - HDA_DSP_ROM_FW_ENTERED, - HDA_DSP_BASEFW_TIMEOUT, - HDA_DSP_REG_POLL_INTERVAL_US); + status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_STATUS, reg, + ((reg & HDA_DSP_ROM_STS_MASK) + == HDA_DSP_ROM_FW_ENTERED), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_BASEFW_TIMEOUT_US); ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_STOP); if (ret < 0) { diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index ebb97a59b59e85..46e507490c88dc 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -195,9 +195,9 @@ /* various timeout values */ #define HDA_DSP_PU_TIMEOUT 50 #define HDA_DSP_PD_TIMEOUT 50 -#define HDA_DSP_RESET_TIMEOUT 50 -#define HDA_DSP_BASEFW_TIMEOUT 3000 -#define HDA_DSP_INIT_TIMEOUT 500 +#define HDA_DSP_RESET_TIMEOUT_US 50000 +#define HDA_DSP_BASEFW_TIMEOUT_US 3000000 +#define HDA_DSP_INIT_TIMEOUT_US 500000 #define HDA_DSP_CTRL_RESET_TIMEOUT 100 #define HDA_DSP_WAIT_TIMEOUT 500 /* 500 msec */ #define HDA_DSP_REG_POLL_INTERVAL_US 500 /* 0.5 msec */ diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index ba0b7a66f39521..f547b44fed93b4 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -142,46 +142,6 @@ void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar, } EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced); -int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset, - u32 mask, u32 target, u32 timeout_ms, - u32 interval_us) -{ - u32 reg; - unsigned long tout_jiff; - int k = 0, s = interval_us; - - /* - * Split the loop into 2 sleep stages with varying resolution. - * To do it more accurately, the range of wakeups are: - * In case of interval_us = 500, - * Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms. - * Phase 2(beyond 5ms): min sleep 5ms; max sleep 10ms. - */ - - tout_jiff = jiffies + msecs_to_jiffies(timeout_ms); - do { - reg = snd_sof_dsp_read(sdev, bar, offset); - if ((reg & mask) == target) - break; - - /* Phase 2 after 5ms(500us * 10) */ - if (++k > 10) - s = interval_us * 10; - - usleep_range(s, 2 * s); - } while (time_before(jiffies, tout_jiff)); - - if ((reg & mask) == target) { - dev_dbg(sdev->dev, "FW Poll Status: reg=%#x successful\n", reg); - - return 0; - } - - dev_dbg(sdev->dev, "FW Poll Status: reg=%#x timedout\n", reg); - return -ETIME; -} -EXPORT_SYMBOL(snd_sof_dsp_register_poll); - void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset) { dev_err(sdev->dev, "error : DSP panic!\n"); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 23b57884c19984..3997c5ab727c24 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -376,6 +376,50 @@ static inline const struct snd_sof_dsp_ops return NULL; } +/** + * snd_sof_dsp_register_poll_timeout - Periodically poll an address + * until a condition is met or a timeout occurs + * @op: accessor function (takes @addr as its only argument) + * @addr: Address to poll + * @val: Variable to read the value into + * @cond: Break condition (usually involving @val) + * @sleep_us: Maximum time to sleep between reads in us (0 + * tight-loops). Should be less than ~20ms since usleep_range + * is used (see Documentation/timers/timers-howto.txt). + * @timeout_us: Timeout in us, 0 means never timeout + * + * Returns 0 on success and -ETIMEDOUT upon a timeout. In either + * case, the last read value at @addr is stored in @val. Must not + * be called from atomic context if sleep_us or timeout_us are used. + * + * This is modelled after the readx_poll_timeout macros in linux/iopoll.h. + */ +#define snd_sof_dsp_read_poll_timeout(sdev, bar, offset, val, cond, sleep_us, timeout_us) \ +({ \ + u64 __timeout_us = (timeout_us); \ + unsigned long __sleep_us = (sleep_us); \ + ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \ + might_sleep_if((__sleep_us) != 0); \ + for (;;) { \ + (val) = snd_sof_dsp_read(sdev, bar, offset); \ + if (cond) { \ + dev_dbg(sdev->dev, \ + "FW Poll Status: reg=%#x successful\n", (val)); \ + break; \ + } \ + if (__timeout_us && \ + ktime_compare(ktime_get(), __timeout) > 0) { \ + (val) = snd_sof_dsp_read(sdev, bar, offset); \ + dev_dbg(sdev->dev, \ + "FW Poll Status: reg=%#x timedout\n", (val)); \ + break; \ + } \ + if (__sleep_us) \ + usleep_range((__sleep_us >> 2) + 1, __sleep_us); \ + } \ + (cond) ? 0 : -ETIMEDOUT; \ +}) + /* This is for registers bits with attribute RWC */ bool snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset, u32 mask, u32 value); From d6d661c7521a72c2bce6f2ced11b812f449f8e43 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Tue, 2 Apr 2019 14:06:27 +0800 Subject: [PATCH 1244/1995] ASoC: SOF: Intel: fix period_bytes calculation at hw_params() We should use params_period_bytes for hdac_stream period_bytes calculation, it used params_period_size so actually wrong period bytes have being used for long time, here correct it. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index bbcef74f8a33be..3c736e1855e99d 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -104,7 +104,7 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, hstream->format_val = rate | bits | (params_channels(params) - 1); hstream->bufsize = size; - hstream->period_bytes = params_period_size(params); + hstream->period_bytes = params_period_bytes(params); hstream->no_period_wakeup = (params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) && (params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP); From 0967e0766216940cbdcd2d1d3662ea9e5beb239d Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Tue, 2 Apr 2019 14:01:52 +0800 Subject: [PATCH 1245/1995] ASoC: SOF: control: fix a PM put missing at error We still need call pm_runtime_put_autosuspend() to release dev at failure of copy_to_user(), here correct it. Signed-off-by: Keyon Jie --- sound/soc/sof/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 750663b974eb64..4a02c5003d80fe 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -539,7 +539,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, } if (copy_to_user(tlvd->tlv, cdata->data, data_size)) - return -EFAULT; + ret = -EFAULT; out: pm_runtime_mark_last_busy(sdev->dev); From f3adfd66c97c730a9db99dafabab7a94f6bcf552 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 29 Mar 2019 15:46:04 +0800 Subject: [PATCH 1246/1995] ASoC:sof: remove duplicate posn message in kernel log There is a lot of posn offset message in kernel log. Actually the posn in mailbox is never changed after it is set in hw_params. So now just print it once in hw_params and make kernel message lesser dmesg log example: sof-audio-pci 0000:00:1f.3: posn mailbox: posn offset is 0xc104c sof-audio-pci 0000:00:1f.3: posn : host 0x6c00 dai 0xcc660 wall 0x31e4fbd sof-audio-pci 0000:00:1f.3: posn mailbox: posn offset is 0xc104c sof-audio-pci 0000:00:1f.3: posn : host 0xab00 dai 0xd4460 wall 0x33d12bc sof-audio-pci 0000:00:1f.3: posn mailbox: posn offset is 0xc104c sof-audio-pci 0000:00:1f.3: posn : host 0xea00 dai 0xdc260 wall 0x35bd5bd sof-audio-pci 0000:00:1f.3: posn mailbox: posn offset is 0xc104c Signed-off-by: Rander Wang --- sound/soc/sof/ipc.c | 3 --- sound/soc/sof/pcm.c | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 63f9e968cb924a..41fb5cb2e8d4a7 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -451,9 +451,6 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) posn_offset = spcm->posn_offset[direction]; snd_sof_dsp_mailbox_read(sdev, posn_offset, &posn, sizeof(posn)); - - dev_dbg(sdev->dev, "posn mailbox: posn offset is 0x%x", - posn_offset); } dev_dbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n", diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 545eed461849cb..a083846139168b 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -171,6 +171,9 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, spcm->posn_offset[substream->stream] = sdev->stream_box.offset + posn_offset; + dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is 0x%x", + substream->stream, spcm->posn_offset[substream->stream]); + /* save pcm hw_params */ memcpy(&spcm->params[substream->stream], params, sizeof(*params)); From 654c0314a47e7a72b1092e607e21e9395d699966 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Mon, 1 Apr 2019 17:12:09 +0800 Subject: [PATCH 1247/1995] ASoc:SOF:skl make ROM init timeout skl specific make ROM init timeout platform specific, change from define to platform structure assigned. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-loader-skl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 4edd78f9f57c24..4924435a92360d 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -305,6 +305,8 @@ static void cl_cleanup_skl(struct snd_sof_dev *sdev) static int cl_dsp_init_skl(struct snd_sof_dev *sdev) { + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; unsigned int sts; int ret; @@ -359,7 +361,8 @@ static int cl_dsp_init_skl(struct snd_sof_dev *sdev) ((sts & HDA_DSP_ROM_STS_MASK) == HDA_DSP_ROM_INIT), HDA_DSP_REG_POLL_INTERVAL_US, - HDA_DSP_INIT_TIMEOUT_US); + chip->rom_init_timeout * + USEC_PER_MSEC); if (ret < 0) goto err; From 48ae1e39e4e2acd486b1e2e425e9d25cd8962192 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Fri, 15 Mar 2019 19:59:19 +0800 Subject: [PATCH 1248/1995] ASoC:SOF:skl fix some comments error fix two comments, Apollolake should be Skylake Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-loader-skl.c | 2 +- sound/soc/sof/intel/skl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c index 4924435a92360d..3a94aa378567f5 100644 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ b/sound/soc/sof/intel/hda-loader-skl.c @@ -330,7 +330,7 @@ static int cl_dsp_init_skl(struct snd_sof_dev *sdev) } else { /* * if not enabled, power down it first and - * then powerup and runthe core. + * then powerup and run the core. */ ret = hda_dsp_core_reset_power_down(sdev, HDA_DSP_CORE_MASK(0)); if (ret < 0) { diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 024d2b70ec5dbf..5aab147dbde6bb 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -89,7 +89,7 @@ const struct snd_sof_dsp_ops sof_skl_ops = { EXPORT_SYMBOL(sof_skl_ops); const struct sof_intel_dsp_desc skl_chip_info = { - /* Apollolake */ + /* Skylake */ .cores_num = 2, .init_core_mask = 1, .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1), From e4f2269b104215ae9f42ee2f54489158eee01933 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 12 Feb 2019 20:39:26 -0800 Subject: [PATCH 1249/1995] ASoC: SOF: topology: Improve handling of processing components Align all processing components to use the same IPC component constructor and bump up the ABI. Also, de-duplicate FIR and IIR handling code into one function that can deal with multiple processing component types. Signed-off-by: Liam Girdwood Signed-off-by: Ranjani Sridharan --- include/sound/sof/topology.h | 37 +--- include/uapi/sound/sof/abi.h | 2 +- include/uapi/sound/sof/tokens.h | 6 +- sound/soc/sof/topology.c | 316 ++++++++++++++++---------------- 4 files changed, 173 insertions(+), 188 deletions(-) diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h index b60a6026df3aac..5cafee2ebddbcd 100644 --- a/include/sound/sof/topology.h +++ b/include/sound/sof/topology.h @@ -163,39 +163,22 @@ struct sof_ipc_comp_tone { int32_t ramp_step; } __packed; -/** \brief Types of EFFECT */ -enum sof_ipc_effect_type { - SOF_EFFECT_NONE = 0, /**< None */ - SOF_EFFECT_INTEL_EQFIR, /**< Intel FIR */ - SOF_EFFECT_INTEL_EQIIR, /**< Intel IIR */ +/** \brief Types of processing components */ +enum sof_ipc_process_type { + SOF_PROCESS_NONE = 0, /**< None */ + SOF_PROCESS_EQFIR, /**< Intel FIR */ + SOF_PROCESS_EQIIR, /**< Intel IIR */ }; -/* general purpose EFFECT configuration */ -struct sof_ipc_comp_effect { - struct sof_ipc_hdr hdr; - uint32_t type; /** sof_ipc_effect_type */ -} __packed; - -/* FIR equalizer component */ -struct sof_ipc_comp_eq_fir { - struct sof_ipc_comp comp; - struct sof_ipc_comp_config config; - uint32_t size; - - /* reserved for future use */ - uint32_t reserved[8]; - - unsigned char data[0]; -} __packed; - -/* IIR equalizer component */ -struct sof_ipc_comp_eq_iir { +/* generic "effect", "codec" or proprietary processing component */ +struct sof_ipc_comp_process { struct sof_ipc_comp comp; struct sof_ipc_comp_config config; - uint32_t size; + uint32_t size; /**< size of bespoke data section in bytes */ + uint32_t type; /**< sof_ipc_process_type */ /* reserved for future use */ - uint32_t reserved[8]; + uint32_t reserved[7]; unsigned char data[0]; } __packed; diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index 98da1236cd66b3..37e0a90dc9e6c3 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 3 +#define SOF_ABI_MINOR 4 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 8c39da56d89140..53ea94bf1c08d3 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -98,6 +98,10 @@ /* Tone */ #define SOF_TKN_TONE_SAMPLE_RATE 800 -#define SOF_TKN_EFFECT_TYPE 900 +/* Processing Components */ +#define SOF_TKN_PROCESS_TYPE 900 + +/* for backward compatibility */ +#define SOF_TKN_EFFECT_TYPE SOF_TKN_PROCESS_TYPE #endif diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index f4c01a5af18f6c..2d1ca0180aeca3 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -235,26 +235,39 @@ static enum sof_ipc_frame find_format(const char *name) return SOF_IPC_FRAME_S32_LE; } -struct sof_effect_types { +struct sof_process_types { const char *name; - enum sof_ipc_effect_type type; + enum sof_ipc_process_type type; + enum sof_comp_type comp_type; }; -static const struct sof_effect_types sof_effects[] = { - {"EQFIR", SOF_EFFECT_INTEL_EQFIR}, - {"EQIIR", SOF_EFFECT_INTEL_EQIIR}, +static const struct sof_process_types sof_process[] = { + {"EQFIR", SOF_PROCESS_EQFIR, SOF_COMP_EQ_FIR}, + {"EQIIR", SOF_PROCESS_EQIIR, SOF_COMP_EQ_IIR}, }; -static enum sof_ipc_effect_type find_effect(const char *name) +static enum sof_ipc_process_type find_process(const char *name) { int i; - for (i = 0; i < ARRAY_SIZE(sof_effects); i++) { - if (strcmp(name, sof_effects[i].name) == 0) - return sof_effects[i].type; + for (i = 0; i < ARRAY_SIZE(sof_process); i++) { + if (strcmp(name, sof_process[i].name) == 0) + return sof_process[i].type; } - return SOF_EFFECT_NONE; + return SOF_PROCESS_NONE; +} + +static enum sof_comp_type find_process_comp_type(enum sof_ipc_process_type type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sof_process); i++) { + if (sof_process[i].type == type) + return sof_process[i].comp_type; + } + + return SOF_COMP_NONE; } /* @@ -463,12 +476,13 @@ static int get_token_dai_type(void *elem, void *object, u32 offset, u32 size) return 0; } -static int get_token_effect_type(void *elem, void *object, u32 offset, u32 size) +static int get_token_process_type(void *elem, void *object, u32 offset, + u32 size) { struct snd_soc_tplg_vendor_string_elem *velem = elem; u32 *val = (u32 *)((u8 *)object + offset); - *val = find_effect(velem->string); + *val = find_process(velem->string); return 0; } @@ -536,10 +550,10 @@ static const struct sof_topology_token tone_tokens[] = { }; /* EFFECT */ -static const struct sof_topology_token effect_tokens[] = { - {SOF_TKN_EFFECT_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, - get_token_effect_type, - offsetof(struct sof_ipc_comp_effect, type), 0}, +static const struct sof_topology_token process_tokens[] = { + {SOF_TKN_PROCESS_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, + get_token_process_type, + offsetof(struct sof_ipc_comp_process, type), 0}, }; /* PCM */ @@ -1557,212 +1571,195 @@ static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index, return ret; } -static int sof_effect_fir_load(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, - struct snd_soc_tplg_dapm_widget *tw, - struct sof_ipc_comp_reply *r) - +static int sof_process_load(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r, + int type) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &tw->priv; - struct snd_sof_control *scontrol = NULL; struct snd_soc_dapm_widget *widget = swidget->widget; const struct snd_kcontrol_new *kc = NULL; struct soc_bytes_ext *sbe; + struct soc_mixer_control *sm; + struct soc_enum *se; + struct snd_sof_control *scontrol = NULL; struct sof_abi_hdr *pdata = NULL; - struct sof_ipc_comp_eq_fir *fir; - size_t ipc_size = 0, fir_data_size = 0; - int ret; + struct sof_ipc_comp_process *process; + size_t ipc_size = 0, ipc_data_size = 0; + int ret, i, offset = 0; - /* get possible eq controls */ - kc = &widget->kcontrol_news[0]; - if (kc) { - sbe = (struct soc_bytes_ext *)kc->private_value; - scontrol = sbe->dobj.private; + if (type == SOF_COMP_NONE) { + dev_err(sdev->dev, "error: invalid process comp type %d\n", + type); + return -EINVAL; } /* - * Check if there's eq parameters in control's private member and set - * data size accordingly. If there's no parameters eq will use defaults - * in firmware (which in this case is passthrough). + * get possible component controls - get size of all pdata, + * then memcpy with headers */ - if (scontrol && scontrol->cmd == SOF_CTRL_CMD_BINARY) { - pdata = scontrol->control_data->data; - if (pdata->size > 0 && pdata->magic == SOF_ABI_MAGIC) - fir_data_size = pdata->size; - } - - ipc_size = sizeof(struct sof_ipc_comp_eq_fir) + - le32_to_cpu(private->size) + - fir_data_size; - - fir = kzalloc(ipc_size, GFP_KERNEL); - if (!fir) - return -ENOMEM; - - /* configure fir IPC message */ - fir->comp.hdr.size = ipc_size; - fir->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; - fir->comp.id = swidget->comp_id; - fir->comp.type = SOF_COMP_EQ_FIR; - fir->comp.pipeline_id = index; - fir->config.hdr.size = sizeof(fir->config); - - ret = sof_parse_tokens(scomp, &fir->config, comp_tokens, - ARRAY_SIZE(comp_tokens), private->array, - le32_to_cpu(private->size)); - if (ret != 0) { - dev_err(sdev->dev, "error: parse fir.cfg tokens failed %d\n", - le32_to_cpu(private->size)); - goto err; - } - - sof_dbg_comp_config(scomp, &fir->config); + for (i = 0; i < widget->num_kcontrols; i++) { - /* we have a private data found in control, so copy it */ - if (fir_data_size > 0) { - memcpy(&fir->data, pdata->data, pdata->size); - fir->size = fir_data_size; - } + kc = &widget->kcontrol_news[i]; - swidget->private = (void *)fir; + switch (widget->dobj.widget.kcontrol_type) { + case SND_SOC_TPLG_TYPE_MIXER: + sm = (struct soc_mixer_control *)kc->private_value; + scontrol = sm->dobj.private; + break; + case SND_SOC_TPLG_TYPE_BYTES: + sbe = (struct soc_bytes_ext *)kc->private_value; + scontrol = sbe->dobj.private; + break; + case SND_SOC_TPLG_TYPE_ENUM: + se = (struct soc_enum *)kc->private_value; + scontrol = se->dobj.private; + break; + default: + dev_err(sdev->dev, "error: unknown kcontrol type %d in widget %s\n", + widget->dobj.widget.kcontrol_type, + widget->name); + return -EINVAL; + } - ret = sof_ipc_tx_message(sdev->ipc, fir->comp.hdr.cmd, fir, - ipc_size, r, sizeof(*r)); - if (ret >= 0) - return ret; -err: - kfree(fir); - return ret; -} + if (!scontrol) { + dev_err(sdev->dev, "error: no scontrol for widget %s\n", + widget->name); + return -EINVAL; + } -static int sof_effect_iir_load(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, - struct snd_soc_tplg_dapm_widget *tw, - struct sof_ipc_comp_reply *r) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_tplg_private *private = &tw->priv; - struct snd_soc_dapm_widget *widget = swidget->widget; - const struct snd_kcontrol_new *kc = NULL; - struct soc_bytes_ext *sbe; - struct snd_sof_control *scontrol = NULL; - struct sof_abi_hdr *pdata = NULL; - struct sof_ipc_comp_eq_iir *iir; - size_t ipc_size = 0, iir_data_size = 0; - int ret; + /* don't include if no private data */ + pdata = scontrol->control_data->data; + if (!pdata) + continue; - /* get possible eq controls */ - kc = &widget->kcontrol_news[0]; - if (kc) { - sbe = (struct soc_bytes_ext *)kc->private_value; - scontrol = sbe->dobj.private; - } + /* make sure data is valid - data can be updated at runtime */ + if (pdata->magic != SOF_ABI_MAGIC) + continue; - /* - * Check if there's eq parameters in control's private member and set - * data size accordingly. If there's no parameters eq will use defaults - * in firmware (which in this case is passthrough). - */ - if (scontrol && scontrol->cmd == SOF_CTRL_CMD_BINARY) { - pdata = scontrol->control_data->data; - if (pdata->size > 0 && pdata->magic == SOF_ABI_MAGIC) - iir_data_size = pdata->size; + ipc_data_size += pdata->size; } - ipc_size = sizeof(struct sof_ipc_comp_eq_iir) + + ipc_size = sizeof(struct sof_ipc_comp_process) + le32_to_cpu(private->size) + - iir_data_size; + ipc_data_size; - iir = kzalloc(ipc_size, GFP_KERNEL); - if (!iir) + process = kzalloc(ipc_size, GFP_KERNEL); + if (!process) return -ENOMEM; /* configure iir IPC message */ - iir->comp.hdr.size = ipc_size; - iir->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; - iir->comp.id = swidget->comp_id; - iir->comp.type = SOF_COMP_EQ_IIR; - iir->comp.pipeline_id = index; - iir->config.hdr.size = sizeof(iir->config); - - ret = sof_parse_tokens(scomp, &iir->config, comp_tokens, + process->comp.hdr.size = ipc_size; + process->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + process->comp.id = swidget->comp_id; + process->comp.type = type; + process->comp.pipeline_id = index; + process->config.hdr.size = sizeof(process->config); + + ret = sof_parse_tokens(scomp, &process->config, comp_tokens, ARRAY_SIZE(comp_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse iir.cfg tokens failed %d\n", + dev_err(sdev->dev, "error: parse process.cfg tokens failed %d\n", le32_to_cpu(private->size)); goto err; } - sof_dbg_comp_config(scomp, &iir->config); + sof_dbg_comp_config(scomp, &process->config); + + /* + * found private data in control, so copy it. + * get possible component controls - get size of all pdata, + * then memcpy with headers + */ + for (i = 0; i < widget->num_kcontrols; i++) { + kc = &widget->kcontrol_news[i]; + + switch (widget->dobj.widget.kcontrol_type) { + case SND_SOC_TPLG_TYPE_MIXER: + sm = (struct soc_mixer_control *)kc->private_value; + scontrol = sm->dobj.private; + break; + case SND_SOC_TPLG_TYPE_BYTES: + sbe = (struct soc_bytes_ext *)kc->private_value; + scontrol = sbe->dobj.private; + break; + case SND_SOC_TPLG_TYPE_ENUM: + se = (struct soc_enum *)kc->private_value; + scontrol = se->dobj.private; + break; + default: + dev_err(sdev->dev, "error: unknown kcontrol type %d in widget %s\n", + widget->dobj.widget.kcontrol_type, + widget->name); + return -EINVAL; + } + + /* don't include if no private data */ + pdata = scontrol->control_data->data; + if (!pdata) + continue; + + /* make sure data is valid - data can be updated at runtime */ + if (pdata->magic != SOF_ABI_MAGIC) + continue; - /* we have a private data found in control, so copy it */ - if (iir_data_size > 0) { - memcpy(&iir->data, pdata->data, pdata->size); - iir->size = iir_data_size; + memcpy(&process->data + offset, pdata->data, pdata->size); + offset += pdata->size; } - swidget->private = (void *)iir; + process->size = ipc_data_size; + swidget->private = (void *)process; - ret = sof_ipc_tx_message(sdev->ipc, iir->comp.hdr.cmd, iir, + ret = sof_ipc_tx_message(sdev->ipc, process->comp.hdr.cmd, process, ipc_size, r, sizeof(*r)); if (ret >= 0) return ret; err: - kfree(iir); + kfree(process); return ret; } /* - * Effect Topology + * Processing Component Topology - can be "effect", "codec", or general + * "processing". */ -static int sof_widget_load_effect(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, - struct snd_soc_tplg_dapm_widget *tw, - struct sof_ipc_comp_reply *r) +static int sof_widget_load_process(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &tw->priv; - struct sof_ipc_comp_effect config; + struct sof_ipc_comp_process config; int ret; - /* check we have some tokens - we need at least effect type */ + /* check we have some tokens - we need at least process type */ if (le32_to_cpu(private->size) == 0) { - dev_err(sdev->dev, "error: effect tokens not found\n"); + dev_err(sdev->dev, "error: process tokens not found\n"); return -EINVAL; } memset(&config, 0, sizeof(config)); - /* get the effect token */ - ret = sof_parse_tokens(scomp, &config, effect_tokens, - ARRAY_SIZE(effect_tokens), private->array, + /* get the process token */ + ret = sof_parse_tokens(scomp, &config, process_tokens, + ARRAY_SIZE(process_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse effect tokens failed %d\n", + dev_err(sdev->dev, "error: parse process tokens failed %d\n", le32_to_cpu(private->size)); return ret; } - /* now load effect specific data and send IPC */ - switch (config.type) { - case SOF_EFFECT_INTEL_EQFIR: - ret = sof_effect_fir_load(scomp, index, swidget, tw, r); - break; - case SOF_EFFECT_INTEL_EQIIR: - ret = sof_effect_iir_load(scomp, index, swidget, tw, r); - break; - default: - dev_err(sdev->dev, "error: invalid effect type %d\n", - config.type); - ret = -EINVAL; - break; - } - + /* now load process specific data and send IPC */ + ret = sof_process_load(scomp, index, swidget, tw, r, + find_process_comp_type(config.type)); if (ret < 0) { - dev_err(sdev->dev, "error: effect loading failed\n"); + dev_err(sdev->dev, "error: process loading failed\n"); return ret; } @@ -1854,7 +1851,8 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, ret = sof_widget_load_siggen(scomp, index, swidget, tw, &reply); break; case snd_soc_dapm_effect: - ret = sof_widget_load_effect(scomp, index, swidget, tw, &reply); + ret = sof_widget_load_process(scomp, index, swidget, tw, + &reply); break; case snd_soc_dapm_mux: case snd_soc_dapm_demux: From 890697c91018554cb16d9c8eb7deea1e540b88ac Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 12 Feb 2019 20:41:21 -0800 Subject: [PATCH 1250/1995] ASoC: SOF: add new process comp types for hotwording Add process comp type for keyword detect, KPB and channel selector components and support for loading such comps during topology load. Signed-off-by: Liam Girdwood Signed-off-by: Ranjani Sridharan --- include/sound/sof/topology.h | 11 +++++++++-- sound/soc/sof/topology.c | 3 +++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h index 5cafee2ebddbcd..9ab62a9b99eccf 100644 --- a/include/sound/sof/topology.h +++ b/include/sound/sof/topology.h @@ -32,8 +32,12 @@ enum sof_comp_type { SOF_COMP_BUFFER, SOF_COMP_EQ_IIR, SOF_COMP_EQ_FIR, - SOF_COMP_FILEREAD, /**< host test based file IO */ - SOF_COMP_FILEWRITE, /**< host test based file IO */ + SOF_COMP_KEYWORD_DETECT, + SOF_COMP_KPB, /* A key phrase buffer component */ + SOF_COMP_SELECTOR, /**< channel selector component */ + /* keep FILEREAD/FILEWRITE as the last ones */ + SOF_COMP_FILEREAD = 10000, /**< host test based file IO */ + SOF_COMP_FILEWRITE = 10001, /**< host test based file IO */ }; /* XRUN action for component */ @@ -168,6 +172,9 @@ enum sof_ipc_process_type { SOF_PROCESS_NONE = 0, /**< None */ SOF_PROCESS_EQFIR, /**< Intel FIR */ SOF_PROCESS_EQIIR, /**< Intel IIR */ + SOF_PROCESS_KEYWORD_DETECT, /**< Keyword Detection */ + SOF_PROCESS_KPB, /**< KeyPhrase Buffer Manager */ + SOF_PROCESS_CHAN_SELECTOR, /**< Channel Selector */ }; /* generic "effect", "codec" or proprietary processing component */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 2d1ca0180aeca3..ed23f8b2f6600b 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -244,6 +244,9 @@ struct sof_process_types { static const struct sof_process_types sof_process[] = { {"EQFIR", SOF_PROCESS_EQFIR, SOF_COMP_EQ_FIR}, {"EQIIR", SOF_PROCESS_EQIIR, SOF_COMP_EQ_IIR}, + {"KEYWORD_DETECT", SOF_PROCESS_KEYWORD_DETECT, SOF_COMP_KEYWORD_DETECT}, + {"KPB", SOF_PROCESS_KPB, SOF_COMP_KPB}, + {"CHAN_SELECTOR", SOF_PROCESS_CHAN_SELECTOR, SOF_COMP_SELECTOR}, }; static enum sof_ipc_process_type find_process(const char *name) From 7d6ccfd868c9fdd3f32b5d960c2e7473d8cb9631 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 5 Mar 2019 19:56:17 -0800 Subject: [PATCH 1251/1995] ASoC: SOF: add support for binding widgets with external events Add support for binding widgets to external dapm events. Define and implement the DAPM event handler for keyword detect component. The keyword detect component is responsible for setting the pipeline params and triggering all the components in the pipeline upon receiving a PRE_PMU or a POST_PMD DAPM event indicating that the audio pipeline it is connected to has been activated. Signed-off-by: Ranjani Sridharan --- include/sound/sof/topology.h | 6 ++ sound/soc/sof/topology.c | 188 +++++++++++++++++++++++++++++++++++ 2 files changed, 194 insertions(+) diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h index 9ab62a9b99eccf..46b2a7e63167bb 100644 --- a/include/sound/sof/topology.h +++ b/include/sound/sof/topology.h @@ -247,4 +247,10 @@ struct sof_ipc_pipe_comp_connect { uint32_t sink_id; } __packed; +/* external events */ +enum sof_event_types { + SOF_EVENT_NONE = 0, + SOF_KEYWORD_DETECT_DAPM_EVENT, +}; + #endif diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index ed23f8b2f6600b..cc3127282bd440 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -10,6 +10,7 @@ #include #include +#include #include #include "sof-priv.h" #include "ops.h" @@ -38,6 +39,149 @@ #define TLV_STEP 1 #define TLV_MUTE 2 +/* send pcm params ipc */ +static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir) +{ + struct sof_ipc_pcm_params_reply ipc_params_reply; + struct snd_sof_dev *sdev = swidget->sdev; + struct sof_ipc_pcm_params pcm; + struct snd_pcm_hw_params *params; + struct snd_sof_pcm *spcm; + int ret = 0; + + memset(&pcm, 0, sizeof(pcm)); + + /* get runtime PCM params using widget's stream name */ + spcm = snd_sof_find_spcm_name(sdev, swidget->widget->sname); + if (!spcm) { + dev_err(sdev->dev, "error: cannot find PCM for %s\n", + swidget->widget->name); + return -EINVAL; + } + + params = &spcm->params[dir]; + + /* set IPC PCM params */ + pcm.hdr.size = sizeof(pcm); + pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS; + pcm.comp_id = swidget->comp_id; + pcm.params.hdr.size = sizeof(pcm.params); + pcm.params.direction = dir; + pcm.params.sample_valid_bytes = params_width(params) >> 3; + pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED; + pcm.params.rate = params_rate(params); + pcm.params.channels = params_channels(params); + pcm.params.host_period_bytes = params_period_bytes(params); + + /* set format */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16: + pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE; + break; + case SNDRV_PCM_FORMAT_S24: + pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE; + break; + case SNDRV_PCM_FORMAT_S32: + pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE; + break; + default: + return -EINVAL; + } + + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm), + &ipc_params_reply, sizeof(ipc_params_reply)); + if (ret < 0) + dev_err(sdev->dev, "error: pcm params failed for %s\n", + swidget->widget->name); + + return ret; +} + + /* send stream trigger ipc */ +static int ipc_trigger(struct snd_sof_widget *swidget, int cmd) +{ + struct snd_sof_dev *sdev = swidget->sdev; + struct sof_ipc_stream stream; + struct sof_ipc_reply reply; + int ret = 0; + + /* set IPC stream params */ + stream.hdr.size = sizeof(stream); + stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | cmd; + stream.comp_id = swidget->comp_id; + + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, + sizeof(stream), &reply, sizeof(reply)); + if (ret < 0) + dev_err(sdev->dev, "error: failed to trigger %s\n", + swidget->widget->name); + + return ret; +} + +static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_sof_widget *swidget = w->dobj.private; + struct snd_sof_dev *sdev; + int ret = 0; + + if (!swidget) + return 0; + + sdev = swidget->sdev; + + dev_dbg(sdev->dev, "received event %d for widget %s\n", + event, w->name); + + /* process events */ + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* set pcm params */ + ret = ipc_pcm_params(swidget, SOF_IPC_STREAM_CAPTURE); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to set pcm params for widget %s\n", + swidget->widget->name); + break; + } + + /* start trigger */ + ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_START); + if (ret < 0) + dev_err(sdev->dev, + "error: failed to trigger widget %s\n", + swidget->widget->name); + break; + case SND_SOC_DAPM_POST_PMD: + /* stop trigger */ + ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP); + if (ret < 0) + dev_err(sdev->dev, + "error: failed to trigger widget %s\n", + swidget->widget->name); + + /* pcm free */ + ret = ipc_trigger(swidget, SOF_IPC_STREAM_PCM_FREE); + if (ret < 0) + dev_err(sdev->dev, + "error: failed to trigger widget %s\n", + swidget->widget->name); + break; + default: + break; + } + + return ret; +} + +/* event handlers for keyword detect component */ +static const struct snd_soc_tplg_widget_events sof_kwd_events[] = { + {SOF_KEYWORD_DETECT_DAPM_EVENT, sof_keyword_dapm_event}, +}; + static inline int get_tlv_data(const int *p, int tlv[TLV_ITEMS]) { /* we only support dB scale TLV type at the moment */ @@ -1769,6 +1913,38 @@ static int sof_widget_load_process(struct snd_soc_component *scomp, int index, return 0; } +static int sof_widget_bind_event(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget, + u16 event_type) +{ + struct sof_ipc_comp *ipc_comp; + + /* validate widget event type */ + switch (event_type) { + case SOF_KEYWORD_DETECT_DAPM_EVENT: + /* only KEYWORD_DETECT comps should handle this */ + if (swidget->id != snd_soc_dapm_effect) + break; + + ipc_comp = swidget->private; + if (ipc_comp && ipc_comp->type != SOF_COMP_KEYWORD_DETECT) + break; + + /* bind event to keyword detect comp */ + return snd_soc_tplg_widget_bind_event(swidget->widget, + sof_kwd_events, + ARRAY_SIZE(sof_kwd_events), + event_type); + default: + break; + } + + dev_err(sdev->dev, + "error: invalid event type %d for widget %s\n", + event_type, swidget->widget->name); + return -EINVAL; +} + /* external widget init - used for any driver specific init */ static int sof_widget_ready(struct snd_soc_component *scomp, int index, struct snd_soc_dapm_widget *w, @@ -1881,6 +2057,18 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, return ret; } + /* bind widget to external event */ + if (tw->event_type) { + ret = sof_widget_bind_event(sdev, swidget, + le16_to_cpu(tw->event_type)); + if (ret) { + dev_err(sdev->dev, "error: widget event binding failed\n"); + kfree(swidget->private); + kfree(swidget); + return ret; + } + } + w->dobj.private = swidget; list_add(&swidget->list, &sdev->widget_list); return ret; From 5fa82ed39fc0bd625137bf44a7d3aaccfe69a2d1 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 5 Mar 2019 21:47:43 -0800 Subject: [PATCH 1252/1995] ASoC: SOF: do not send routes to/from output/out_drv widgets to the DSP output/out_drv type widgets may be added in topology for compatibility. In the case of hostless pipelines, these might be used to propagate DAPM events to the pipeline. Do not send such routes to the FW as they need not be handled by the DSP. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/topology.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index cc3127282bd440..f5bcaf7f215292 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2913,6 +2913,16 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, goto err; } + /* + * Virtual widgets of type output/out_drv may be added in topology + * for compatibility. These are not handled by the FW. + * So, don't send routes whose source/sink widget is of such types + * to the DSP. + */ + if (source_swidget->id == snd_soc_dapm_out_drv || + source_swidget->id == snd_soc_dapm_output) + goto err; + connect->source_id = source_swidget->comp_id; /* sink component */ @@ -2924,11 +2934,18 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, goto err; } + /* + * Don't send routes whose sink widget is of type + * output or out_drv to the DSP + */ + if (sink_swidget->id == snd_soc_dapm_out_drv || + sink_swidget->id == snd_soc_dapm_output) + goto err; + connect->sink_id = sink_swidget->comp_id; /* - * Some virtual routes and widgets may been added in topology for - * compatibility. For virtual routes, both sink and source are not + * For virtual routes, both sink and source are not * buffer. Since only buffer linked to component is supported by * FW, others are reported as error, add check in route function, * do not send it to FW when both source and sink are not buffer From bf3d5cf50500909cb76de489035098abf5a0424e Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 7 Mar 2019 10:47:54 -0800 Subject: [PATCH 1253/1995] ASoC: SOF: fix bug in snd_sof_find_spcm_name() In the keyword detect pipeline, there is a need for the detect component to receive the runtime PCM params from the capture pipeline. So in order to facilitate retreiving the PCM params from the capture pipeline, the detect component has to have its stream_name set to the PCM name. The function snd_sof_find_spcm_name() is currently used to acquire the PCM for a widget by matching the widget's stream name with the PCM name. If the stream_name field for the widget is not set in topology the input argument "name" will be empty. Also, not all PCM's have both playback and capture capabilities set in topology ie the caps name could be empty. If the "name" argument happens to be empty because the stream name for the widget was not in topology, snd_sof_find_spcm_name() will return the first spcm that has an empty name for either its playback or capture caps. So, add the check to make sure that the caps name is set before matching with the input argument. Also, modify signature for snd_sof_find_spcm_name to take const char * as input. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 11 ++++++++--- sound/soc/sof/sof-priv.h | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 2ca716f5dd8970..d684d8614336b3 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -25,18 +25,23 @@ */ struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev, - char *name) + const char *name) { struct snd_sof_pcm *spcm = NULL; list_for_each_entry(spcm, &sdev->pcm_list, list) { + /* match with PCM dai name */ if (strcmp(spcm->pcm.dai_name, name) == 0) return spcm; - if (strcmp(spcm->pcm.caps[0].name, name) == 0) + /* match with playback caps name if set */ + if (*spcm->pcm.caps[0].name && + !strcmp(spcm->pcm.caps[0].name, name)) return spcm; - if (strcmp(spcm->pcm.caps[1].name, name) == 0) + /* match with capture caps name if set */ + if (*spcm->pcm.caps[1].name && + !strcmp(spcm->pcm.caps[1].name, name)) return spcm; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index c4465b2d3a0432..870820f13b3f32 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -481,7 +481,7 @@ struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_sof_dev *sdev, } struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev, - char *name); + const char *name); struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev, unsigned int comp_id, int *direction); From ce5bc43fb3783d0f08eda7c643913aca2f670839 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 Apr 2019 17:22:02 -0700 Subject: [PATCH 1254/1995] ASoC: SOF: intel: ipc: don't read mailbox for CTX_SAVE If the reply from the DSP is for a CTX_SAVE ipc, don't read the mailbox, just return after setting the reply attributes. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-ipc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index e742fcd3dac2fe..d0e858045e54d5 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -86,12 +86,13 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) reply.error = 0; reply.hdr.cmd = SOF_IPC_GLB_REPLY; reply.hdr.size = sizeof(reply); - } else { - /* get IPC reply from DSP in the mailbox */ - sof_mailbox_read(sdev, sdev->host_box.offset, &reply, - sizeof(reply)); + goto out; } + /* get IPC reply from DSP in the mailbox */ + sof_mailbox_read(sdev, sdev->host_box.offset, &reply, + sizeof(reply)); + if (reply.error < 0) { memcpy(msg->reply_data, &reply, sizeof(reply)); ret = reply.error; @@ -109,6 +110,7 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) msg->reply_data, msg->reply_size); } +out: msg->reply_error = ret; spin_unlock_irqrestore(&sdev->ipc_lock, flags); From d9399e71de64bf4afc97cfc3c47db00c04a039fc Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 2 Apr 2019 08:57:50 -0700 Subject: [PATCH 1255/1995] ASoC: SOF: remove all superfluous initialization Based on Takashi's feedback. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 12 ++++++------ sound/soc/sof/intel/bdw.c | 2 +- sound/soc/sof/intel/byt.c | 4 ++-- sound/soc/sof/intel/hda-codec.c | 2 +- sound/soc/sof/intel/hda-dsp.c | 2 +- sound/soc/sof/intel/hda-loader.c | 8 ++++---- sound/soc/sof/intel/hda-pcm.c | 2 +- sound/soc/sof/intel/hda-stream.c | 4 ++-- sound/soc/sof/intel/hda.c | 4 ++-- sound/soc/sof/intel/hsw.c | 2 +- sound/soc/sof/ipc.c | 2 +- sound/soc/sof/nocodec.c | 2 +- sound/soc/sof/pcm.c | 8 ++++---- sound/soc/sof/pm.c | 12 ++++++------ sound/soc/sof/sof-acpi-dev.c | 4 ++-- sound/soc/sof/sof-pci-dev.c | 2 +- sound/soc/sof/topology.c | 16 ++++++++-------- 17 files changed, 44 insertions(+), 44 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index d684d8614336b3..4d3d527de7df53 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -27,7 +27,7 @@ struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev, const char *name) { - struct snd_sof_pcm *spcm = NULL; + struct snd_sof_pcm *spcm; list_for_each_entry(spcm, &sdev->pcm_list, list) { /* match with PCM dai name */ @@ -52,7 +52,7 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev, unsigned int comp_id, int *direction) { - struct snd_sof_pcm *spcm = NULL; + struct snd_sof_pcm *spcm; list_for_each_entry(spcm, &sdev->pcm_list, list) { if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id == comp_id) { @@ -71,7 +71,7 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev, struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev, unsigned int pcm_id) { - struct snd_sof_pcm *spcm = NULL; + struct snd_sof_pcm *spcm; list_for_each_entry(spcm, &sdev->pcm_list, list) { if (le32_to_cpu(spcm->pcm.pcm_id) == pcm_id) @@ -84,7 +84,7 @@ struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev, struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev, char *name) { - struct snd_sof_widget *swidget = NULL; + struct snd_sof_widget *swidget; list_for_each_entry(swidget, &sdev->widget_list, list) { if (strcmp(name, swidget->widget->name) == 0) @@ -98,7 +98,7 @@ struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev, struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev, char *pcm_name, int dir) { - struct snd_sof_widget *swidget = NULL; + struct snd_sof_widget *swidget; enum snd_soc_dapm_type type; if (dir == SNDRV_PCM_STREAM_PLAYBACK) @@ -117,7 +117,7 @@ struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev, struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev, char *name) { - struct snd_sof_dai *dai = NULL; + struct snd_sof_dai *dai; list_for_each_entry(dai, &sdev->dai_list, list) { if (dai->name && (strcmp(name, dai->name) == 0)) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 7f22db0d5ea77a..d407f397d24e31 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -549,7 +549,7 @@ static int bdw_probe(struct snd_sof_dev *sdev) container_of(sdev->dev, struct platform_device, dev); struct resource *mmio; u32 base, size; - int ret = 0; + int ret; /* LPE base */ mmio = platform_get_resource(pdev, IORESOURCE_MEM, diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 6fb07421bd99ba..62f9b60448ba3d 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -516,7 +516,7 @@ static int byt_pci_probe(struct snd_sof_dev *sdev) const struct sof_dev_desc *desc = pdata->desc; struct pci_dev *pci = to_pci_dev(sdev->dev); u32 base, size; - int ret = 0; + int ret; /* DSP DMA can only access low 31 bits of host memory */ ret = dma_coerce_mask_and_coherent(&pci->dev, DMA_BIT_MASK(31)); @@ -648,7 +648,7 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev) container_of(sdev->dev, struct platform_device, dev); struct resource *mmio; u32 base, size; - int ret = 0; + int ret; /* DSP DMA can only access low 31 bits of host memory */ ret = dma_coerce_mask_and_coherent(sdev->dev, DMA_BIT_MASK(31)); diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index bcec7d58465cf0..b8b37f08230940 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -97,7 +97,7 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) int hda_codec_probe_bus(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); - int i, ret = 0; + int i, ret; /* probe codecs in avail slots */ for (i = 0; i < HDA_MAX_CODECS; i++) { diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index bf4bcee0e5dbf2..311fed502e09fc 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -289,7 +289,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state) #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_bus *bus = sof_to_bus(sdev); #endif - int ret = 0; + int ret; /* disable IPC interrupts */ hda_dsp_ipc_int_disable(sdev); diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 6cceba30eca4a2..c8c03d5c07b75b 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -27,18 +27,18 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, unsigned int size, struct snd_dma_buffer *dmab, int direction) { - struct hdac_ext_stream *dsp_stream = NULL; + struct hdac_ext_stream *dsp_stream; struct hdac_stream *hstream; struct pci_dev *pci = to_pci_dev(sdev->dev); int ret; - if (direction == SNDRV_PCM_STREAM_PLAYBACK) { - dsp_stream = hda_dsp_stream_get(sdev, direction); - } else { + if (direction != SNDRV_PCM_STREAM_PLAYBACK) { dev_err(sdev->dev, "error: code loading DMA is playback only\n"); return -EINVAL; } + dsp_stream = hda_dsp_stream_get(sdev, direction); + if (!dsp_stream) { dev_err(sdev->dev, "error: no stream available\n"); return -ENODEV; diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 3c736e1855e99d..7810530bd6c493 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -144,7 +144,7 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, struct sof_intel_hda_dev *hda = (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; struct snd_sof_pcm *spcm; - snd_pcm_uframes_t pos = 0; + snd_pcm_uframes_t pos; spcm = snd_sof_find_spcm_dai(sdev, rtd); if (!spcm) { diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 5b8e589b1bd9b0..eb09cd3a6719d8 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -131,14 +131,14 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, int enable, u32 size) { struct hdac_stream *hstream = &stream->hstream; - u32 mask = 0; + u32 mask; if (!sdev->bar[HDA_DSP_SPIB_BAR]) { dev_err(sdev->dev, "error: address of spib capability is NULL\n"); return -EINVAL; } - mask |= (1 << hstream->index); + mask = (1 << hstream->index); /* enable/disable SPIB for the stream */ snd_sof_dsp_update_bits(sdev, HDA_DSP_SPIB_BAR, diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index a57374be06e6ff..52dca6d6235c22 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -249,9 +249,9 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev, static int hda_init_caps(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); - struct hdac_ext_link *hlink = NULL; + struct hdac_ext_link *hlink; struct snd_soc_acpi_mach_params *mach_params; - struct snd_soc_acpi_mach *hda_mach = NULL; + struct snd_soc_acpi_mach *hda_mach; struct snd_sof_pdata *pdata = sdev->pdata; struct snd_soc_acpi_mach *mach; const char *tplg_filename; diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 66f7b1a9ec6969..aa83b6d94b4461 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -549,7 +549,7 @@ static int hsw_probe(struct snd_sof_dev *sdev) container_of(sdev->dev, struct platform_device, dev); struct resource *mmio; u32 base, size; - int ret = 0; + int ret; /* LPE base */ mmio = platform_get_resource(pdev, IORESOURCE_MEM, diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 41fb5cb2e8d4a7..c783c9522e5a0d 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -669,7 +669,7 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc, struct sof_ipc_fw_version *v = &ready->version; struct sof_ipc_ctrl_data_params sparams; size_t send_bytes; - int err = 0; + int err; /* read or write firmware volume */ if (scontrol->readback_offset != 0) { diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index 4a66abe065c991..f84b4344dcc3e9 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -56,7 +56,7 @@ int sof_nocodec_setup(struct device *dev, const struct snd_sof_dsp_ops *ops) { struct snd_soc_dai_link *links; - int ret = 0; + int ret; if (!mach) return -EINVAL; diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index a083846139168b..0cf790225cec29 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -354,7 +354,7 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; - snd_pcm_uframes_t host = 0, dai = 0; + snd_pcm_uframes_t host, dai; /* nothing todo for BE */ if (rtd->dai_link->no_pcm) @@ -531,7 +531,7 @@ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) struct snd_sof_pcm *spcm; struct snd_pcm *pcm = rtd->pcm; struct snd_soc_tplg_stream_caps *caps; - int ret = 0, stream = SNDRV_PCM_STREAM_PLAYBACK; + int stream = SNDRV_PCM_STREAM_PLAYBACK; /* find SOF PCM for this RTD */ spcm = snd_sof_find_spcm_dai(sdev, rtd); @@ -562,7 +562,7 @@ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) /* do we need to pre-allocate capture audio buffer pages */ if (!spcm->pcm.capture) - return ret; + return 0; caps = &spcm->pcm.caps[stream]; @@ -575,7 +575,7 @@ static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) le32_to_cpu(caps->buffer_size_min), le32_to_cpu(caps->buffer_size_max)); - return ret; + return 0; } /* fixup the BE DAI link to match any values from topology */ diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 8d1cdba92706d6..0b5a605d6cdeb1 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -13,7 +13,7 @@ static int sof_restore_kcontrols(struct snd_sof_dev *sdev) { - struct snd_sof_control *scontrol = NULL; + struct snd_sof_control *scontrol; int ipc_cmd, ctrl_type; int ret = 0; @@ -63,13 +63,13 @@ static int sof_restore_kcontrols(struct snd_sof_dev *sdev) static int sof_restore_pipelines(struct snd_sof_dev *sdev) { - struct snd_sof_widget *swidget = NULL; - struct snd_sof_route *sroute = NULL; + struct snd_sof_widget *swidget; + struct snd_sof_route *sroute; struct sof_ipc_pipe_new *pipeline; struct snd_sof_dai *dai; struct sof_ipc_comp_dai *comp_dai; struct sof_ipc_cmd_hdr *hdr; - int ret = 0; + int ret; /* restore pipeline components */ list_for_each_entry_reverse(swidget, &sdev->widget_list, list) { @@ -242,7 +242,7 @@ static void sof_cache_debugfs(struct snd_sof_dev *sdev) static int sof_resume(struct device *dev, bool runtime_resume) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); - int ret = 0; + int ret; /* do nothing if dsp resume callbacks are not set */ if (!sof_ops(sdev)->resume || !sof_ops(sdev)->runtime_resume) @@ -311,7 +311,7 @@ static int sof_resume(struct device *dev, bool runtime_resume) static int sof_suspend(struct device *dev, bool runtime_suspend) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); - int ret = 0; + int ret; /* do nothing if dsp suspend callback is not set */ if (!sof_ops(sdev)->suspend) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index ae8df9988c5fc2..fe845e1affde7c 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -104,7 +104,7 @@ static const struct sof_dev_desc sof_acpi_baytrail_desc = { static bool is_byt_cr(struct platform_device *pdev) { struct device *dev = &pdev->dev; - int status = 0; + int status; if (iosf_mbi_available()) { u32 bios_status; @@ -187,7 +187,7 @@ static int sof_acpi_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach; struct snd_sof_pdata *sof_pdata; const struct snd_sof_dsp_ops *ops; - int ret = 0; + int ret; dev_dbg(&pdev->dev, "ACPI DSP detected"); diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 556c718df1a324..8d1a69de9f43de 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -216,7 +216,7 @@ static int sof_pci_probe(struct pci_dev *pci, struct snd_soc_acpi_mach *mach; struct snd_sof_pdata *sof_pdata; const struct snd_sof_dsp_ops *ops; - int ret = 0; + int ret; dev_dbg(&pci->dev, "PCI DSP detected"); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index f5bcaf7f215292..af1291987f2f35 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1024,7 +1024,7 @@ static int sof_control_load(struct snd_soc_component *scomp, int index, struct soc_bytes_ext *sbe; struct soc_enum *se; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_dobj *dobj = NULL; + struct snd_soc_dobj *dobj; struct snd_sof_control *scontrol; int ret = -EINVAL; @@ -1342,7 +1342,7 @@ int sof_load_pipeline_ipc(struct snd_sof_dev *sdev, struct sof_ipc_comp_reply *r) { struct sof_ipc_pm_core_config pm_core_config; - int ret = 0; + int ret; ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline, sizeof(*pipeline), r, sizeof(*r)); @@ -1727,14 +1727,14 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &tw->priv; struct snd_soc_dapm_widget *widget = swidget->widget; - const struct snd_kcontrol_new *kc = NULL; + const struct snd_kcontrol_new *kc; struct soc_bytes_ext *sbe; struct soc_mixer_control *sm; struct soc_enum *se; struct snd_sof_control *scontrol = NULL; struct sof_abi_hdr *pdata = NULL; struct sof_ipc_comp_process *process; - size_t ipc_size = 0, ipc_data_size = 0; + size_t ipc_size, ipc_data_size = 0; int ret, i, offset = 0; if (type == SOF_COMP_NONE) { @@ -1954,7 +1954,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, struct snd_sof_widget *swidget; struct snd_sof_dai *dai; struct sof_ipc_comp_reply reply; - struct snd_sof_control *scontrol = NULL; + struct snd_sof_control *scontrol; int ret = 0; swidget = kzalloc(sizeof(*swidget), GFP_KERNEL); @@ -2095,7 +2095,7 @@ static int sof_widget_unload(struct snd_soc_component *scomp, struct snd_soc_dobj *dobj) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - const struct snd_kcontrol_new *kc = NULL; + const struct snd_kcontrol_new *kc; struct snd_soc_dapm_widget *widget; struct sof_ipc_pipe_new *pipeline; struct snd_sof_control *scontrol; @@ -2704,7 +2704,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct sof_ipc_dai_config config; struct snd_soc_tplg_hw_config *hw_config; int num_hw_configs; - int ret = 0; + int ret; int i = 0; link->platform_name = dev_name(sdev->dev); @@ -2834,7 +2834,7 @@ static int sof_link_unload(struct snd_soc_component *scomp, struct snd_soc_dai_link *link = container_of(dobj, struct snd_soc_dai_link, dobj); - struct snd_sof_dai *sof_dai = NULL; + struct snd_sof_dai *sof_dai; int ret = 0; /* only BE link is loaded by sof */ From c7342a7dcdbb9021fbf8fec5014e2f4ed981d828 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Apr 2019 15:48:53 -0500 Subject: [PATCH 1256/1995] ASoC: SOF: Intel: rename EDISON as MERRIFIELD Feedback from Andy Shevchenko Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/Kconfig | 8 ++++---- sound/soc/sof/intel/byt.c | 4 ++-- sound/soc/sof/sof-pci-dev.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 7eb6d37911c862..fdcd90bff84b4d 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -19,7 +19,7 @@ config SND_SOC_SOF_INTEL_ACPI config SND_SOC_SOF_INTEL_PCI tristate - select SND_SOC_SOF_EDISON if SND_SOC_SOF_EDISON_SUPPORT + select SND_SOC_SOF_MERRIFIELD if SND_SOC_SOF_MERRIFIELD_SUPPORT select SND_SOC_SOF_APOLLOLAKE if SND_SOC_SOF_APOLLOLAKE_SUPPORT select SND_SOC_SOF_GEMINILAKE if SND_SOC_SOF_GEMINILAKE_SUPPORT select SND_SOC_SOF_CANNONLAKE if SND_SOC_SOF_CANNONLAKE_SUPPORT @@ -99,15 +99,15 @@ endif ## SND_SOC_SOF_INTEL_ACPI if SND_SOC_SOF_INTEL_PCI -config SND_SOC_SOF_EDISON_SUPPORT - bool "SOF support for Tangier/Edison" +config SND_SOC_SOF_MERRIFIELD_SUPPORT + bool "SOF support for Tangier/Merrifield" help This adds support for Sound Open Firmware for Intel(R) platforms using the Baytrail, Braswell or Cherrytrail processors. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_EDISON +config SND_SOC_SOF_MERRIFIELD tristate select SND_SOC_SOF_INTEL_ATOM_HIFI_EP help diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 62f9b60448ba3d..85f19b705507f2 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -508,7 +508,7 @@ static struct snd_soc_dai_driver byt_dai[] = { * Probe and remove. */ -#if IS_ENABLED(CONFIG_SND_SOC_SOF_EDISON) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) static int byt_pci_probe(struct snd_sof_dev *sdev) { @@ -636,7 +636,7 @@ const struct sof_intel_dsp_desc tng_chip_info = { }; EXPORT_SYMBOL(tng_chip_info); -#endif /* CONFIG_SND_SOC_SOF_EDISON */ +#endif /* CONFIG_SND_SOC_SOF_MERRIFIELD */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 8d1a69de9f43de..b778dffb2d25c0 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -65,7 +65,7 @@ static const struct sof_dev_desc glk_desc = { }; #endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_EDISON) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) static struct snd_soc_acpi_mach sof_tng_machines[] = { { .id = "INT343A", @@ -319,7 +319,7 @@ static void sof_pci_remove(struct pci_dev *pci) /* PCI IDs */ static const struct pci_device_id sof_pci_ids[] = { -#if IS_ENABLED(CONFIG_SND_SOC_SOF_EDISON) +#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) { PCI_DEVICE(0x8086, 0x119a), .driver_data = (unsigned long)&tng_desc}, #endif From 0b6b57612008e5269c854e6b717a2b8f92b69ed7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Apr 2019 16:00:38 -0500 Subject: [PATCH 1257/1995] ASoC: SOF: tabify Kconfigs Kconfigs are supposed to use one tab and two additional spaces for the help. Fix. Feedback from Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/Kconfig | 46 ++++++------ sound/soc/sof/intel/Kconfig | 142 ++++++++++++++++++------------------ 2 files changed, 94 insertions(+), 94 deletions(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index e08053cb8d322c..bf178b5d1a29dc 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -1,10 +1,10 @@ config SND_SOC_SOF_TOPLEVEL bool "Sound Open Firmware Support" help - This adds support for Sound Open Firmware (SOF). SOF is a free and + This adds support for Sound Open Firmware (SOF). SOF is a free and generic open source audio DSP firmware for multiple devices. - Say Y if you have such a device that is supported by SOF. - If unsure select "N". + Say Y if you have such a device that is supported by SOF. + If unsure select "N". if SND_SOC_SOF_TOPLEVEL @@ -16,10 +16,10 @@ config SND_SOC_SOF_PCI select SND_SOC_SOF_OPTIONS select SND_SOC_SOF_INTEL_PCI if SND_SOC_SOF_INTEL_TOPLEVEL help - This adds support for PCI enumeration. This option is + This adds support for PCI enumeration. This option is required to enable Intel Skylake+ devices Say Y if you need this option - If unsure select "N". + If unsure select "N". config SND_SOC_SOF_ACPI tristate "SOF ACPI enumeration support" @@ -30,10 +30,10 @@ config SND_SOC_SOF_ACPI select SND_SOC_SOF_INTEL_ACPI if SND_SOC_SOF_INTEL_TOPLEVEL select IOSF_MBI if X86 help - This adds support for ACPI enumeration. This option is required + This adds support for ACPI enumeration. This option is required to enable Intel Haswell/Broadwell/Baytrail/Cherrytrail devices Say Y if you need this option - If unsure select "N". + If unsure select "N". config SND_SOC_SOF_SPI tristate "SOF SPI support" @@ -51,13 +51,13 @@ config SND_SOC_SOF_SPI config SND_SOC_SOF_SPIDSP tristate help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_OPTIONS tristate help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level if SND_SOC_SOF_OPTIONS @@ -65,19 +65,19 @@ if SND_SOC_SOF_OPTIONS config SND_SOC_SOF_COMPRESS bool "SOF ALSA Compressed API support" help - This adds support for the ALSA compressed API in SOF + This adds support for the ALSA compressed API in SOF Say Y if you need this option - If unsure select "N". + If unsure select "N". config SND_SOC_SOF_NOCODEC tristate "SOF nocodec mode Support" help - This adds support for a dummy/nocodec machine driver fallback + This adds support for a dummy/nocodec machine driver fallback option if no known codec is detected. This is typically only enabled for developers or devices where the sound card is controlled externally - Say Y if you need this nocodec fallback option - If unsure select "N". + Say Y if you need this nocodec fallback option + If unsure select "N". config SND_SOC_SOF_DEBUG bool "SOF debugging features" @@ -85,7 +85,7 @@ config SND_SOC_SOF_DEBUG This option can be used to enable or disable individual SOF firmware and driver debugging options. Say Y if you are debugging SOF FW or drivers. - If unsure select "N". + If unsure select "N". if SND_SOC_SOF_DEBUG @@ -93,13 +93,13 @@ config SND_SOC_SOF_FORCE_NOCODEC_MODE bool "SOF force nocodec Mode" depends on SND_SOC_SOF_NOCODEC help - This forces SOF to use dummy/nocodec as machine driver, even + This forces SOF to use dummy/nocodec as machine driver, even though there is a codec detected on the real platform. This is typically only enabled for developers for debug purposes, before codec/machine driver is ready, or to exclude the impact of those drivers - Say Y if you need this force nocodec mode option - If unsure select "N". + Say Y if you need this force nocodec mode option + If unsure select "N". config SND_SOC_SOF_DEBUG_XRUN_STOP bool "SOF stop on XRUN" @@ -107,7 +107,7 @@ config SND_SOC_SOF_DEBUG_XRUN_STOP This option forces PCMs to stop on any XRUN event. This is useful to preserve any trace data ond pipeline status prior to the XRUN. Say Y if you are debugging SOF FW pipeline XRUNs. - If unsure select "N". + If unsure select "N". config SND_SOC_SOF_DEBUG_VERBOSE_IPC bool "SOF verbose IPC logs" @@ -115,7 +115,7 @@ config SND_SOC_SOF_DEBUG_VERBOSE_IPC This option enables more verbose IPC logs, with command types in human-readable form instead of just 32-bit hex dumps. This is useful if you are trying to debug IPC with the DSP firmware. - If unsure select "N". + If unsure select "N". config SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION bool "SOF force to use IPC for position update on SKL+" @@ -127,7 +127,7 @@ config SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION one choice, this setting won't impact anything. if you are trying to debug pointer update with position IPCs or where DPIB/posbuf is not ready, select "Y". - If unsure select "N". + If unsure select "N". config SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE bool "SOF enable debugfs caching" @@ -148,7 +148,7 @@ config SND_SOC_SOF select SND_SOC_TOPOLOGY select SND_SOC_COMPRESS if SND_SOC_SOF_COMPRESS=y help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level The selection is made at the top level and does not exactly follow module dependencies but since the module or built-in type is decided @@ -157,7 +157,7 @@ config SND_SOC_SOF config SND_SOC_SOF_PROBE_WORK_QUEUE bool help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level When selected, the probe is handled in two steps, for example to avoid lockdeps if request_module is used in the probe. diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index fdcd90bff84b4d..9217c323e81ba7 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -2,9 +2,9 @@ config SND_SOC_SOF_INTEL_TOPLEVEL bool "SOF support for Intel audio DSPs" depends on SND_DMA_SGBUF || COMPILE_TEST help - This adds support for Sound Open Firmware for Intel(R) platforms. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for Intel(R) platforms. + Say Y if you have such a device. + If unsure select "N". if SND_SOC_SOF_INTEL_TOPLEVEL @@ -14,7 +14,7 @@ config SND_SOC_SOF_INTEL_ACPI select SND_SOC_SOF_HASWELL if SND_SOC_SOF_HASWELL_SUPPORT select SND_SOC_SOF_BROADWELL if SND_SOC_SOF_BROADWELL_SUPPORT help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_INTEL_PCI @@ -28,14 +28,14 @@ config SND_SOC_SOF_INTEL_PCI select SND_SOC_SOF_SKYLAKE if SND_SOC_SOF_SKYLAKE_SUPPORT select SND_SOC_SOF_ICELAKE if SND_SOC_SOF_ICELAKE_SUPPORT help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_INTEL_ATOM_HIFI_EP tristate select SND_SOC_INTEL_COMMON help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_INTEL_COMMON @@ -45,7 +45,7 @@ config SND_SOC_SOF_INTEL_COMMON select SND_SOC_INTEL_MACH select SND_SOC_ACPI if ACPI help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level if SND_SOC_SOF_INTEL_ACPI @@ -53,46 +53,46 @@ if SND_SOC_SOF_INTEL_ACPI config SND_SOC_SOF_BAYTRAIL_SUPPORT bool "SOF support for Baytrail, Braswell and Cherrytrail" help - This adds support for Sound Open Firmware for Intel(R) platforms - using the Baytrail, Braswell or Cherrytrail processors. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for Intel(R) platforms + using the Baytrail, Braswell or Cherrytrail processors. + Say Y if you have such a device. + If unsure select "N". config SND_SOC_SOF_BAYTRAIL tristate select SND_SOC_SOF_INTEL_ATOM_HIFI_EP help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_HASWELL_SUPPORT bool "SOF support for Haswell" help - This adds support for Sound Open Firmware for Intel(R) platforms - using the Haswell processors. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for Intel(R) platforms + using the Haswell processors. + Say Y if you have such a device. + If unsure select "N". config SND_SOC_SOF_HASWELL tristate select SND_SOC_SOF_INTEL_COMMON help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_BROADWELL_SUPPORT bool "SOF support for Broadwell" help - This adds support for Sound Open Firmware for Intel(R) platforms - using the Broadwell processors. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for Intel(R) platforms + using the Broadwell processors. + Say Y if you have such a device. + If unsure select "N". config SND_SOC_SOF_BROADWELL tristate select SND_SOC_SOF_INTEL_COMMON help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level endif ## SND_SOC_SOF_INTEL_ACPI @@ -102,121 +102,121 @@ if SND_SOC_SOF_INTEL_PCI config SND_SOC_SOF_MERRIFIELD_SUPPORT bool "SOF support for Tangier/Merrifield" help - This adds support for Sound Open Firmware for Intel(R) platforms - using the Baytrail, Braswell or Cherrytrail processors. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for Intel(R) platforms + using the Baytrail, Braswell or Cherrytrail processors. + Say Y if you have such a device. + If unsure select "N". config SND_SOC_SOF_MERRIFIELD tristate select SND_SOC_SOF_INTEL_ATOM_HIFI_EP help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_APOLLOLAKE_SUPPORT bool "SOF support for Apollolake" help - This adds support for Sound Open Firmware for Intel(R) platforms - using the Apollolake processors. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for Intel(R) platforms + using the Apollolake processors. + Say Y if you have such a device. + If unsure select "N". config SND_SOC_SOF_APOLLOLAKE tristate select SND_SOC_SOF_HDA_COMMON help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_GEMINILAKE_SUPPORT bool "SOF support for GeminiLake" help - This adds support for Sound Open Firmware for Intel(R) platforms - using the Geminilake processors. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for Intel(R) platforms + using the Geminilake processors. + Say Y if you have such a device. + If unsure select "N". config SND_SOC_SOF_GEMINILAKE tristate select SND_SOC_SOF_HDA_COMMON help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_CANNONLAKE_SUPPORT bool "SOF support for Cannonlake" help - This adds support for Sound Open Firmware for Intel(R) platforms - using the Cannonlake processors. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for Intel(R) platforms + using the Cannonlake processors. + Say Y if you have such a device. + If unsure select "N". config SND_SOC_SOF_CANNONLAKE tristate select SND_SOC_SOF_HDA_COMMON help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_COFFEELAKE_SUPPORT bool "SOF support for CoffeeLake" help - This adds support for Sound Open Firmware for Intel(R) platforms - using the Coffeelake processors. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for Intel(R) platforms + using the Coffeelake processors. + Say Y if you have such a device. + If unsure select "N". config SND_SOC_SOF_COFFEELAKE tristate select SND_SOC_SOF_HDA_COMMON help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_KABYLAKE_SUPPORT bool "SOF support for Kabylake" help - This adds support for Sound Open Firmware for Intel(R) platforms - using the Kabylake processors. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for Intel(R) platforms + using the Kabylake processors. + Say Y if you have such a device. + If unsure select "N". config SND_SOC_SOF_KABYLAKE tristate select SND_SOC_SOF_HDA_COMMON help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_SKYLAKE_SUPPORT bool "SOF support for Skylake" help - This adds support for Sound Open Firmware for Intel(R) platforms - using the Skylake processors. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for Intel(R) platforms + using the Skylake processors. + Say Y if you have such a device. + If unsure select "N". config SND_SOC_SOF_SKYLAKE tristate select SND_SOC_SOF_HDA_COMMON help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_ICELAKE_SUPPORT bool "SOF support for Icelake" help - This adds support for Sound Open Firmware for Intel(R) platforms - using the Icelake processors. - Say Y if you have such a device. - If unsure select "N". + This adds support for Sound Open Firmware for Intel(R) platforms + using the Icelake processors. + Say Y if you have such a device. + If unsure select "N". config SND_SOC_SOF_ICELAKE tristate select SND_SOC_SOF_HDA_COMMON help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_HDA_COMMON @@ -224,7 +224,7 @@ config SND_SOC_SOF_HDA_COMMON select SND_SOC_SOF_INTEL_COMMON select SND_SOC_SOF_HDA_LINK_BASELINE help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level if SND_SOC_SOF_HDA_COMMON @@ -234,19 +234,19 @@ config SND_SOC_SOF_HDA_LINK depends on SND_SOC_SOF_NOCODEC=n select SND_SOC_SOF_PROBE_WORK_QUEUE help - This adds support for HDA links(HDA/HDMI) with Sound Open Firmware + This adds support for HDA links(HDA/HDMI) with Sound Open Firmware for Intel(R) platforms. - Say Y if you want to enable HDA links with SOF. - If unsure select "N". + Say Y if you want to enable HDA links with SOF. + If unsure select "N". config SND_SOC_SOF_HDA_AUDIO_CODEC bool "SOF support for HDAudio codecs" depends on SND_SOC_SOF_HDA_LINK help - This adds support for HDAudio codecs with Sound Open Firmware + This adds support for HDAudio codecs with Sound Open Firmware for Intel(R) platforms. - Say Y if you want to enable HDAudio codecs with SOF. - If unsure select "N". + Say Y if you want to enable HDAudio codecs with SOF. + If unsure select "N". endif ## SND_SOC_SOF_HDA_COMMON @@ -254,7 +254,7 @@ config SND_SOC_SOF_HDA_LINK_BASELINE tristate select SND_SOC_SOF_HDA if SND_SOC_SOF_HDA_LINK help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level config SND_SOC_SOF_HDA @@ -262,7 +262,7 @@ config SND_SOC_SOF_HDA select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC help - This option is not user-selectable but automagically handled by + This option is not user-selectable but automagically handled by 'select' statements at a higher level endif ## SND_SOC_SOF_INTEL_PCI From 5ce5469530099fd896cbe42554eb87a1e298c91e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Apr 2019 16:01:57 -0500 Subject: [PATCH 1258/1995] ASoC: SOF: Intel: fix dependency on SND_DMA_SGBUF The code would work even without SND_DMA_SGBUF defined, and what is really needed is X86 (same as for SST driver) Feedback from Takahi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 9217c323e81ba7..189a94274ffa6d 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -1,6 +1,6 @@ config SND_SOC_SOF_INTEL_TOPLEVEL bool "SOF support for Intel audio DSPs" - depends on SND_DMA_SGBUF || COMPILE_TEST + depends on X86 || COMPILE_TEST help This adds support for Sound Open Firmware for Intel(R) platforms. Say Y if you have such a device. From e4b237f4d91c567de70abc115f4541ee05bfbca2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 5 Apr 2019 10:54:44 -0500 Subject: [PATCH 1259/1995] ASoC: SOF: Intel: fix Merrifield help comment copy/paste mistake. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 189a94274ffa6d..875bd09a32b5fe 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -103,7 +103,7 @@ config SND_SOC_SOF_MERRIFIELD_SUPPORT bool "SOF support for Tangier/Merrifield" help This adds support for Sound Open Firmware for Intel(R) platforms - using the Baytrail, Braswell or Cherrytrail processors. + using the Tangier/Merrifield processors. Say Y if you have such a device. If unsure select "N". From 42a32634202a4b937551f086cedf6a5e467e48f7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 5 Apr 2019 10:57:03 -0500 Subject: [PATCH 1260/1995] ASoC: SOF: Intel: rename byt_pci_probe Let's use tangier_pci_probe to avoid confusion. There is no PCI probe on Baytrail proper. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/byt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 85f19b705507f2..9c47aed5d2d548 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -510,7 +510,7 @@ static struct snd_soc_dai_driver byt_dai[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) -static int byt_pci_probe(struct snd_sof_dev *sdev) +static int tangier_pci_probe(struct snd_sof_dev *sdev) { struct snd_sof_pdata *pdata = sdev->pdata; const struct sof_dev_desc *desc = pdata->desc; @@ -585,7 +585,7 @@ static int byt_pci_probe(struct snd_sof_dev *sdev) const struct snd_sof_dsp_ops sof_tng_ops = { /* device init */ - .probe = byt_pci_probe, + .probe = tangier_pci_probe, /* DSP core boot / reset */ .run = byt_run, From 2e48af902cc82afaabb7be4ca6db6e40f66584d0 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 1 Apr 2019 08:29:49 -0700 Subject: [PATCH 1261/1995] ASoC: intel: skylake: add remove() callback for component driver Topology is not unloaded in the core during unregister_component() anymore. So, add the remove() callback that will unload the topology. Signed-off-by: Ranjani Sridharan --- sound/soc/intel/skylake/skl-pcm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 56099db8f86ddf..57031b6d4d45e0 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1462,9 +1462,16 @@ static int skl_platform_soc_probe(struct snd_soc_component *component) return 0; } +static void skl_pcm_remove(struct snd_soc_component *component) +{ + /* remove topology */ + snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); +} + static const struct snd_soc_component_driver skl_component = { .name = "pcm", .probe = skl_platform_soc_probe, + .remove = skl_pcm_remove, .ops = &skl_platform_ops, .pcm_new = skl_pcm_new, .pcm_free = skl_pcm_free, From 68baf9962fae4086e9bd9cde4fcc9adeb1941fae Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 1 Apr 2019 08:31:23 -0700 Subject: [PATCH 1262/1995] ASoC: core: remove link components before cleaning up card resources When the card is registered by the machine driver, dai link components are probed after the snd_card is created. This is done in snd_soc_bind_card() which calls snd_soc_instantiate_card() to first create the snd_card and then probes the link components by calling soc_probe_link_components(). The snd_card is used by the component driver to add the kcontrols associated with dapm widgets to the card. When the machine driver is unregistered, the snd_card is freed when the card resources are cleaned up. But the snd_card needs to be valid while unloading the topology dapm widgets in order to remove the kcontrols from the card. Since, unloading topology is done when the component driver is removed, the link components should be removed in snd_soc_unbind_card(). This will ensure that the kcontrols are removed before the card resources are cleaned up and the snd_card itself is freed. Signed-off-by: Ranjani Sridharan --- sound/soc/soc-core.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6f4842977b8d0d..75f6a8085a766f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2831,10 +2831,21 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card); static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) { + struct snd_soc_pcm_runtime *rtd; + int order; + if (card->instantiated) { card->instantiated = false; snd_soc_dapm_shutdown(card); snd_soc_flush_all_delayed_work(card); + + /* remove all components used by DAI links on this card */ + for_each_comp_order(order) { + for_each_card_rtds(card, rtd) { + soc_remove_link_components(card, rtd, order); + } + } + soc_cleanup_card_resources(card); if (!unregister) list_add(&card->list, &unbind_card_list); From 449be79c54202afac6886e9d8204f88a8566357a Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 1 Apr 2019 08:33:42 -0700 Subject: [PATCH 1263/1995] ASoC: SOF: remove topology in component driver remove() Topology should be removed when the link components are removed when the machine driver is unregistered. This will prevent the NULL pointer derefernce encountered when removing widget kcontrol's from the sound card. So, remove the topology in the remove() callback for the SOF component driver. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pcm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 0cf790225cec29..4f48a8bcc1e175 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -703,6 +703,8 @@ static int sof_pcm_probe(struct snd_soc_component *component) static void sof_pcm_remove(struct snd_soc_component *component) { + /* remove topology */ + snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); } void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) From ab16eb918316ec0b6665dca6c88b4c26d4de5c37 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 1 Apr 2019 08:35:08 -0700 Subject: [PATCH 1264/1995] ASoC: SOF: core: make component driver resource-managed Previously, we couldn't make the component driver resource-managed because topology unloading was done by the core when the component driver was unregistered. But this has been fixed to allow topology removal during the component driver remove() callback and there aren't any NULL pointer dereferences anymore. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 4d3d527de7df53..b3b5ce6b04a461 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -355,9 +355,9 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) sdev->first_boot = false; /* now register audio DSP platform driver and dai */ - ret = snd_soc_register_component(sdev->dev, &sdev->plat_drv, - sof_ops(sdev)->drv, - sof_ops(sdev)->num_drv); + ret = devm_snd_soc_register_component(sdev->dev, &sdev->plat_drv, + sof_ops(sdev)->drv, + sof_ops(sdev)->num_drv); if (ret < 0) { dev_err(sdev->dev, "error: failed to register DSP DAI driver %d\n", ret); @@ -466,16 +466,16 @@ int snd_sof_device_remove(struct device *dev) if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) cancel_work_sync(&sdev->probe_work); - snd_soc_unregister_component(dev); snd_sof_fw_unload(sdev); snd_sof_ipc_free(sdev); snd_sof_free_debug(sdev); snd_sof_free_trace(sdev); snd_sof_remove(sdev); + /* - * platform_device_unregister() frees the card and its resources. - * So it should be called after unregistering the comp driver - * so that the card is valid while unregistering comp driver. + * Unregister machine driver. This will unbind the snd_card which + * will remove the component driver and unload the topology + * before freeing the snd_card. */ if (!IS_ERR_OR_NULL(pdata->pdev_mach)) platform_device_unregister(pdata->pdev_mach); From 20aed96b9b5e7a63511e9ccd7d6352d0ac7a61ce Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Apr 2019 16:15:42 -0500 Subject: [PATCH 1265/1995] ASoC: SOF: use const char * in function prototypes Be consistent, use const everywhere. Feedback from Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 6 +++--- sound/soc/sof/sof-priv.h | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index b3b5ce6b04a461..2ab737219f4ecf 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -82,7 +82,7 @@ struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev, } struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev, - char *name) + const char *name) { struct snd_sof_widget *swidget; @@ -96,7 +96,7 @@ struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev, /* find widget by stream name and direction */ struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev, - char *pcm_name, int dir) + const char *pcm_name, int dir) { struct snd_sof_widget *swidget; enum snd_soc_dapm_type type; @@ -115,7 +115,7 @@ struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev, } struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev, - char *name) + const char *name) { struct snd_sof_dai *dai; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 870820f13b3f32..0b8b99c24e890e 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -460,11 +460,12 @@ int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, void *msg_data, size_t msg_bytes, void *reply_data, size_t reply_bytes); struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev, - char *name); + const char *name); struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev, - char *pcm_name, int dir); + const char *pcm_name, + int dir); struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev, - char *name); + const char *name); static inline struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_sof_dev *sdev, From d3bf8595b38e4c905211eece260b8cbed2ea86e6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Apr 2019 16:27:42 -0500 Subject: [PATCH 1266/1995] ASoC: SOF: core: snd_sof_get_status returns void This helper is called from .dbg_dump callbacks which are themselves declared as returning void. Feedback from Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 16 ++++++++++------ sound/soc/sof/sof-priv.h | 8 ++++---- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 2ab737219f4ecf..c9a58f6fd687fa 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -151,10 +151,15 @@ static const struct sof_panic_msg panic_msg[] = { {SOF_IPC_PANIC_WFI, "invalid wait state"}, }; -int snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, - u32 tracep_code, void *oops, - struct sof_ipc_panic_info *panic_info, - void *stack, size_t stack_words) +/* + * helper to be called from .dbg_dump callbacks. No error code is + * provided, it's left as an exercise for the caller of .dbg_dump + * (typically IPC or loader) + */ +void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, + u32 tracep_code, void *oops, + struct sof_ipc_panic_info *panic_info, + void *stack, size_t stack_words) { u32 code; int i; @@ -163,7 +168,7 @@ int snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, if ((panic_code & SOF_IPC_PANIC_MAGIC_MASK) != SOF_IPC_PANIC_MAGIC) { dev_err(sdev->dev, "error: unexpected fault 0x%8.8x trace 0x%8.8x\n", panic_code, tracep_code); - return 0; /* no fault ? */ + return; /* no fault ? */ } code = panic_code & (SOF_IPC_PANIC_MAGIC_MASK | SOF_IPC_PANIC_CODE_MASK); @@ -186,7 +191,6 @@ int snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, panic_info->filename, panic_info->linenum); sof_oops(sdev, oops); sof_stack(sdev, oops, stack, stack_words); - return -EFAULT; } EXPORT_SYMBOL(snd_sof_get_status); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 0b8b99c24e890e..a5d8573ccd7361 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -538,10 +538,10 @@ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, int snd_sof_trace_update_pos(struct snd_sof_dev *sdev, struct sof_ipc_dma_trace_posn *posn); void snd_sof_trace_notify_for_error(struct snd_sof_dev *sdev); -int snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, - u32 tracep_code, void *oops, - struct sof_ipc_panic_info *panic_info, - void *stack, size_t stack_words); +void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, + u32 tracep_code, void *oops, + struct sof_ipc_panic_info *panic_info, + void *stack, size_t stack_words); int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev); /* From d7e4124fbf301bdea61490255fa91721dcef8469 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Apr 2019 16:38:38 -0500 Subject: [PATCH 1267/1995] ASoC: SOF: PCM: use snd_pcm_format_physical_width() Simplify code to determine container_bytes Feedback from Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pcm.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 4f48a8bcc1e175..55ae7c66c64f1f 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -105,19 +105,10 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, pcm.params.host_period_bytes = params_period_bytes(params); /* container size */ - switch (params_width(params)) { - case 16: - pcm.params.sample_container_bytes = 2; - break; - case 24: - pcm.params.sample_container_bytes = 4; - break; - case 32: - pcm.params.sample_container_bytes = 4; - break; - default: - return -EINVAL; - } + ret = snd_pcm_format_physical_width(params_format(params)); + if (ret < 0) + return ret; + pcm.params.sample_container_bytes = ret >> 3; /* format */ switch (params_format(params)) { From 402fa4c2fe2f4f4ad3d7a6f69ab43dc61b935cae Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Apr 2019 16:59:42 -0500 Subject: [PATCH 1268/1995] ASoC: SOF: PCM: fix hw_constraints All the information coming from topology is in bytes. Make sure we use the proper BUFFER_BYTES and PERIOD_BYTES qualifiers. Also add comment that the buffer_min value coming from topology cannot be used. Feedback from Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pcm.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 55ae7c66c64f1f..aa1c1ea8ddf07a 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -406,10 +406,10 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) /* set any runtime constraints based on topology */ snd_pcm_hw_constraint_step(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, le32_to_cpu(caps->period_size_min)); snd_pcm_hw_constraint_step(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, le32_to_cpu(caps->period_size_min)); /* set runtime config */ @@ -424,6 +424,11 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) runtime->hw.period_bytes_max = le32_to_cpu(caps->period_size_max); runtime->hw.periods_min = le32_to_cpu(caps->periods_min); runtime->hw.periods_max = le32_to_cpu(caps->periods_max); + + /* + * caps->buffer_size_min is not used since the + * snd_pcm_hardware structure only defines buffer_bytes_max + */ runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max); dev_dbg(sdev->dev, "period min %zd max %zd bytes\n", From d530dac6a337e561c0ced7999437fb295e8b8905 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Apr 2019 17:09:31 -0500 Subject: [PATCH 1269/1995] ASoC: SOF: PM: remove fallthrough statements Fallthrough comments are not needed if there is no code in a switch case. Feedback from Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pm.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 0b5a605d6cdeb1..3e3fb3b5482bc8 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -25,9 +25,7 @@ static int sof_restore_kcontrols(struct snd_sof_dev *sdev) /* notify DSP of kcontrol values */ switch (scontrol->cmd) { case SOF_CTRL_CMD_VOLUME: - /* fallthrough */ case SOF_CTRL_CMD_ENUM: - /* fallthrough */ case SOF_CTRL_CMD_SWITCH: ipc_cmd = SOF_IPC_COMP_SET_VALUE; ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET; @@ -81,7 +79,6 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev) switch (swidget->id) { case snd_soc_dapm_dai_in: - /* fallthrough */ case snd_soc_dapm_dai_out: dai = (struct snd_sof_dai *)swidget->private; comp_dai = &dai->comp_dai; From eee9da4982259bd6189b46344f1ea48d7476fb7e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Apr 2019 17:12:56 -0500 Subject: [PATCH 1270/1995] ASoC: SOF: utils: fix comments too many ands Feedback from Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index fbefddde34d2ea..2ac4c3da03206d 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -18,7 +18,7 @@ * Register IO * * The sof_io_xyz() wrappers are typically referenced in snd_sof_dsp_ops - * structures and and cannot be inlined. + * structures and cannot be inlined. */ void sof_io_write(struct snd_sof_dev *sdev, void __iomem *addr, u32 value) From 866c26f33654057422949ab1898d9b9cb916e8a7 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 1 Apr 2019 14:04:47 -0700 Subject: [PATCH 1271/1995] ASoC: core: conditionally increase module refcount on component open Recently, for Intel platforms the "ignore_module_refcount" field was introduced for the component driver. In order to avoid a deadlock preventing the PCI modules from being removed even when the card was idle, the refcounts were not incremented for the device driver module during component probe. However, this change introduced a nasty side effect: the device driver module can be unloaded while a pcm stream is open. This patch proposes to change the field to be renamed as "module_get_upon_open". When this field is set, the module refcount should be incremented on pcm open amd decremented upon pcm close. This will enable modules to be removed when no PCM playback/capture happens and prevent removal when the component is actually in use. Also, align with the skylake component driver with the new name. Fixes: b450b878('ASoC: core: don't increase component module refcount unconditionally' Signed-off-by: Ranjani Sridharan --- include/sound/soc.h | 9 +++++++-- sound/soc/intel/skylake/skl-pcm.c | 2 +- sound/soc/soc-core.c | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 1e2be35ed36f2b..482b4ea87c3c4b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -802,8 +802,13 @@ struct snd_soc_component_driver { int probe_order; int remove_order; - /* signal if the module handling the component cannot be removed */ - unsigned int ignore_module_refcount:1; + /* + * signal if the module handling the component should not be removed + * if a pcm is open. Setting this would prevent the module + * refcount being incremented in probe() but allow it be incremented + * when a pcm is opened and decremented when it is closed. + */ + unsigned int module_get_upon_open:1; /* bits */ unsigned int idle_bias_on:1; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 57031b6d4d45e0..9735e24122514f 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1475,7 +1475,7 @@ static const struct snd_soc_component_driver skl_component = { .ops = &skl_platform_ops, .pcm_new = skl_pcm_new, .pcm_free = skl_pcm_free, - .ignore_module_refcount = 1, /* do not increase the refcount in core */ + .module_get_upon_open = 1, /* increment refcount when a pcm is opened */ }; int skl_platform_register(struct device *dev) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 75f6a8085a766f..2403bec2fccf35 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -947,7 +947,7 @@ static void soc_cleanup_component(struct snd_soc_component *component) snd_soc_dapm_free(snd_soc_component_get_dapm(component)); soc_cleanup_component_debugfs(component); component->card = NULL; - if (!component->driver->ignore_module_refcount) + if (!component->driver->module_get_upon_open) module_put(component->dev->driver->owner); } @@ -1381,7 +1381,7 @@ static int soc_probe_component(struct snd_soc_card *card, return 0; } - if (!component->driver->ignore_module_refcount && + if (!component->driver->module_get_upon_open && !try_module_get(component->dev->driver->owner)) return -ENODEV; From 6aeec0232cb5057cb6609d42a206c6efb89e7b40 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 1 Apr 2019 14:11:57 -0700 Subject: [PATCH 1272/1995] ASoC: pcm: update module refcount if module_get_upon_open is set Setting the module_get_upon_open field for component driver prevents the module refcount from being incremented during component probe(). This could lead to the module being allowed to be unloaded when a pcm stream is open. So, if this field is set, the module's refcount should be incremented during pcm open to prevent module removal when the component is in use. And, the refcount should be decremented upon pcm close. Signed-off-by: Ranjani Sridharan --- sound/soc/soc-pcm.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 7fe5321000e877..4192f6900d4dd5 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -463,6 +464,9 @@ static int soc_pcm_components_close(struct snd_pcm_substream *substream, continue; component->driver->ops->close(substream); + + if (component->driver->module_get_upon_open) + module_put(component->dev->driver->owner); } return 0; @@ -513,6 +517,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) !component->driver->ops->open) continue; + if (component->driver->module_get_upon_open && + !try_module_get(component->dev->driver->owner)) + return -ENODEV; + ret = component->driver->ops->open(substream); if (ret < 0) { dev_err(component->dev, From bc524f90091d275aeb0fa21d0db064d75f512c3a Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 5 Apr 2019 09:47:55 -0700 Subject: [PATCH 1273/1995] ASoC: SOF: change the ignore_module_refcount to align with the new name The "ignore_module_refcount" field in the component driver has been renamed to "module_get_upon_open". So align with the new name. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index aa1c1ea8ddf07a..485dfb92ad5dc1 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -725,6 +725,6 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) pd->use_dai_pcm_id = true; pd->topology_name_prefix = "sof"; - /* do not increase the refcount in core */ - pd->ignore_module_refcount = 1; + /* increment module refcount when a pcm is opened */ + pd->module_get_upon_open = 1; } From 4e3c67165daaba507626cce30d59ddc2037fe42f Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 1 Apr 2019 08:20:04 -0700 Subject: [PATCH 1274/1995] ASoC: topology: Use the correct dobj to free enum control values and texts The control values and texts of the enum kcontrol associated with a widget need to be freed when the widget is removed. However, both struct snd_soc_dapm_widget and struct soc_enum contain a dobj member, which resulted in a confusion. The existing code generates a null pointer dereference by attempting to free the values and texts from the dobj which belongs to the widget instead of the dobj belonging to the enum kcontrol. The suggested fix is to use the correct dobj member (se->dobj) of the enum kcontrol. Signed-off-by: Ranjani Sridharan --- sound/soc/soc-topology.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 472f7705da9368..0f6a6ad01570c3 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -482,10 +482,11 @@ static void remove_widget(struct snd_soc_component *comp, snd_ctl_remove(card, kcontrol); - kfree(dobj->control.dvalues); + /* free enum kcontrol's dvalues and dtexts */ + kfree(se->dobj.control.dvalues); for (j = 0; j < se->items; j++) - kfree(dobj->control.dtexts[j]); - kfree(dobj->control.dtexts); + kfree(se->dobj.control.dtexts[j]); + kfree(se->dobj.control.dtexts); kfree(se); kfree(w->kcontrol_news[i].name); From 83107323a2ca69bf01679b661d933b0576b330d4 Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Sat, 30 Mar 2019 10:47:26 +0100 Subject: [PATCH 1275/1995] ASoC: SOF: add new SOF_IPC_PANIC_ASSERT code Adds new SOF_IPC_PANIC_ASSERT code to align with FW. It is caused by failed assertion inside of FW. Signed-off-by: Tomasz Lauda --- include/sound/sof/trace.h | 1 + sound/soc/sof/core.c | 1 + 2 files changed, 2 insertions(+) diff --git a/include/sound/sof/trace.h b/include/sound/sof/trace.h index 49f0f310d9029b..7d211f319a92e2 100644 --- a/include/sound/sof/trace.h +++ b/include/sound/sof/trace.h @@ -54,6 +54,7 @@ struct sof_ipc_dma_trace_posn { #define SOF_IPC_PANIC_STACK (SOF_IPC_PANIC_MAGIC | 0x8) #define SOF_IPC_PANIC_IDLE (SOF_IPC_PANIC_MAGIC | 0x9) #define SOF_IPC_PANIC_WFI (SOF_IPC_PANIC_MAGIC | 0xa) +#define SOF_IPC_PANIC_ASSERT (SOF_IPC_PANIC_MAGIC | 0xb) /* panic info include filename and line number */ struct sof_ipc_panic_info { diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index c9a58f6fd687fa..e6d6d2d74803c8 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -149,6 +149,7 @@ static const struct sof_panic_msg panic_msg[] = { {SOF_IPC_PANIC_STACK, "stack overflow"}, {SOF_IPC_PANIC_IDLE, "can't enter idle"}, {SOF_IPC_PANIC_WFI, "invalid wait state"}, + {SOF_IPC_PANIC_ASSERT, "assertion failed"}, }; /* From 970f4c5eaf73eb8391f09c6d5b33cb5b250d19d7 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 20 Mar 2019 16:15:24 -0500 Subject: [PATCH 1276/1995] ALSA: rawmidi: Fix potential Spectre v1 vulnerability info->stream is indirectly controlled by user-space, hence leading to a potential exploitation of the Spectre variant 1 vulnerability. This issue was detected with the help of Smatch: sound/core/rawmidi.c:604 __snd_rawmidi_info_select() warn: potential spectre issue 'rmidi->streams' [r] (local cap) Fix this by sanitizing info->stream before using it to index rmidi->streams. Notice that given that speculation windows are large, the policy is to kill the speculation on the first load and not worry if it can be completed with a dependent load/store [1]. [1] https://lore.kernel.org/lkml/20180423164740.GY17484@dhcp22.suse.cz/ Cc: stable@vger.kernel.org Signed-off-by: Gustavo A. R. Silva Signed-off-by: Takashi Iwai (cherry picked from commit 2b1d9c8f87235f593826b9cf46ec10247741fff9) --- sound/core/rawmidi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index ee601d7f092694..c0690d1ecd55c1 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -601,6 +602,7 @@ static int __snd_rawmidi_info_select(struct snd_card *card, return -ENXIO; if (info->stream < 0 || info->stream > 1) return -EINVAL; + info->stream = array_index_nospec(info->stream, 2); pstr = &rmidi->streams[info->stream]; if (pstr->substream_count == 0) return -ENOENT; From da8400384fb83d92b901ddfacfa919a63548ee11 Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Tue, 19 Mar 2019 17:49:31 +0000 Subject: [PATCH 1277/1995] ASoC: da7219: Expose BCLK and WCLK control through CCF For the purposes of platforms which use the codec as DAI clock master for the CPU and other codec devices, there is the need to not only expose the clock gating of BCLK and WCLK but also the ability to set those rates without going through the ASoC APIs. To make this possible, the previous CCF implementation in the driver has been extended to separate BCLK and WCLK out. WCLK is the parent clock to BCLK, and is also the clock gate for both. BCLK in HW is a factor/multiplier of WCLK so derives from whatever SR is chosen for WCLK, hence the need to make it a child of WCLK for the purposes of CCF. Enabling/disabling either BCLK or WCLK will result in clocks being ungated/gated accordingly. To simplify matters, these clocks can only be configured if the codec is set as master, otherwise CCF control is disallowed. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown (cherry picked from commit d90ba6c8b53e541913a181638c353cf7a0856256) --- include/sound/da7219.h | 8 +- sound/soc/codecs/da7219.c | 523 +++++++++++++++++++++++++++++--------- sound/soc/codecs/da7219.h | 6 +- 3 files changed, 407 insertions(+), 130 deletions(-) diff --git a/include/sound/da7219.h b/include/sound/da7219.h index 1bfcb16f2d10ab..4a36954c86c52b 100644 --- a/include/sound/da7219.h +++ b/include/sound/da7219.h @@ -33,10 +33,16 @@ enum da7219_mic_amp_in_sel { struct da7219_aad_pdata; +enum da7219_dai_clks { + DA7219_DAI_WCLK_IDX = 0, + DA7219_DAI_BCLK_IDX, + DA7219_DAI_NUM_CLKS, +}; + struct da7219_pdata { bool wakeup_source; - const char *dai_clks_name; + const char *dai_clk_names[DA7219_DAI_NUM_CLKS]; /* Mic */ enum da7219_micbias_voltage micbias_lvl; diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 121a8190f93edc..5f5fa3416af30a 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -797,6 +797,7 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w, { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); + struct clk *bclk = da7219->dai_clks[DA7219_DAI_BCLK_IDX]; u8 pll_ctrl, pll_status; int i = 0, ret; bool srm_lock = false; @@ -805,11 +806,11 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_PRE_PMU: if (da7219->master) { /* Enable DAI clks for master mode */ - if (da7219->dai_clks) { - ret = clk_prepare_enable(da7219->dai_clks); + if (bclk) { + ret = clk_prepare_enable(bclk); if (ret) { dev_err(component->dev, - "Failed to enable dai_clks\n"); + "Failed to enable DAI clks\n"); return ret; } } else { @@ -852,8 +853,8 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w, /* Disable DAI clks if in master mode */ if (da7219->master) { - if (da7219->dai_clks) - clk_disable_unprepare(da7219->dai_clks); + if (bclk) + clk_disable_unprepare(bclk); else snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, @@ -1385,17 +1386,50 @@ static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return 0; } +static int da7219_set_bclks_per_wclk(struct snd_soc_component *component, + unsigned long factor) +{ + u8 bclks_per_wclk; + + switch (factor) { + case 32: + bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32; + break; + case 64: + bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64; + break; + case 128: + bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128; + break; + case 256: + bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256; + break; + default: + return -EINVAL; + } + + snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, + DA7219_DAI_BCLKS_PER_WCLK_MASK, + bclks_per_wclk); + + return 0; +} + static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { struct snd_soc_component *component = dai->component; struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); + struct clk *wclk = da7219->dai_clks[DA7219_DAI_WCLK_IDX]; + struct clk *bclk = da7219->dai_clks[DA7219_DAI_BCLK_IDX]; unsigned int ch_mask; - u8 dai_bclks_per_wclk, slot_offset; + unsigned long sr, bclk_rate; + u8 slot_offset; u16 offset; __le16 dai_offset; u32 frame_size; + int ret; /* No channels enabled so disable TDM */ if (!tx_mask) { @@ -1432,28 +1466,26 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, */ if (da7219->master) { frame_size = slots * slot_width; - switch (frame_size) { - case 32: - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32; - break; - case 64: - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64; - break; - case 128: - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128; - break; - case 256: - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256; - break; - default: - dev_err(component->dev, "Invalid frame size %d\n", - frame_size); - return -EINVAL; - } - snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, - DA7219_DAI_BCLKS_PER_WCLK_MASK, - dai_bclks_per_wclk); + if (bclk) { + sr = clk_get_rate(wclk); + bclk_rate = sr * frame_size; + ret = clk_set_rate(bclk, bclk_rate); + if (ret) { + dev_err(component->dev, + "Failed to set TDM BCLK rate %lu: %d\n", + bclk_rate, ret); + return ret; + } + } else { + ret = da7219_set_bclks_per_wclk(component, frame_size); + if (ret) { + dev_err(component->dev, + "Failed to set TDM BCLKs per WCLK %d: %d\n", + frame_size, ret); + return ret; + } + } } dai_offset = cpu_to_le16(offset); @@ -1471,44 +1503,12 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai, return 0; } -static int da7219_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) +static int da7219_set_sr(struct snd_soc_component *component, + unsigned long rate) { - struct snd_soc_component *component = dai->component; - struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); - u8 dai_ctrl = 0, dai_bclks_per_wclk = 0, fs; - unsigned int channels; - int word_len = params_width(params); - int frame_size; - - switch (word_len) { - case 16: - dai_ctrl |= DA7219_DAI_WORD_LENGTH_S16_LE; - break; - case 20: - dai_ctrl |= DA7219_DAI_WORD_LENGTH_S20_LE; - break; - case 24: - dai_ctrl |= DA7219_DAI_WORD_LENGTH_S24_LE; - break; - case 32: - dai_ctrl |= DA7219_DAI_WORD_LENGTH_S32_LE; - break; - default: - return -EINVAL; - } - - channels = params_channels(params); - if ((channels < 1) || (channels > DA7219_DAI_CH_NUM_MAX)) { - dev_err(component->dev, - "Invalid number of channels, only 1 to %d supported\n", - DA7219_DAI_CH_NUM_MAX); - return -EINVAL; - } - dai_ctrl |= channels << DA7219_DAI_CH_NUM_SHIFT; + u8 fs; - switch (params_rate(params)) { + switch (rate) { case 8000: fs = DA7219_SR_8000; break; @@ -1546,28 +1546,103 @@ static int da7219_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + snd_soc_component_write(component, DA7219_SR, fs); + + return 0; +} + +static int da7219_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); + struct clk *wclk = da7219->dai_clks[DA7219_DAI_WCLK_IDX]; + struct clk *bclk = da7219->dai_clks[DA7219_DAI_BCLK_IDX]; + u8 dai_ctrl = 0; + unsigned int channels; + unsigned long sr, bclk_rate; + int word_len = params_width(params); + int frame_size, ret; + + switch (word_len) { + case 16: + dai_ctrl |= DA7219_DAI_WORD_LENGTH_S16_LE; + break; + case 20: + dai_ctrl |= DA7219_DAI_WORD_LENGTH_S20_LE; + break; + case 24: + dai_ctrl |= DA7219_DAI_WORD_LENGTH_S24_LE; + break; + case 32: + dai_ctrl |= DA7219_DAI_WORD_LENGTH_S32_LE; + break; + default: + return -EINVAL; + } + + channels = params_channels(params); + if ((channels < 1) || (channels > DA7219_DAI_CH_NUM_MAX)) { + dev_err(component->dev, + "Invalid number of channels, only 1 to %d supported\n", + DA7219_DAI_CH_NUM_MAX); + return -EINVAL; + } + dai_ctrl |= channels << DA7219_DAI_CH_NUM_SHIFT; + + sr = params_rate(params); + if (da7219->master && wclk) { + ret = clk_set_rate(wclk, sr); + if (ret) { + dev_err(component->dev, + "Failed to set WCLK SR %lu: %d\n", sr, ret); + return ret; + } + } else { + ret = da7219_set_sr(component, sr); + if (ret) { + dev_err(component->dev, + "Failed to set SR %lu: %d\n", sr, ret); + return ret; + } + } + /* * If we're master, then we have a limited set of BCLK rates we * support. For slave mode this isn't the case and the codec can detect * the BCLK rate automatically. */ if (da7219->master && !da7219->tdm_en) { - frame_size = word_len * 2; - if (frame_size <= 32) - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32; + if ((word_len * DA7219_DAI_CH_NUM_MAX) <= 32) + frame_size = 32; else - dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64; - - snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, - DA7219_DAI_BCLKS_PER_WCLK_MASK, - dai_bclks_per_wclk); + frame_size = 64; + + if (bclk) { + bclk_rate = frame_size * sr; + ret = clk_set_rate(bclk, bclk_rate); + if (ret) { + dev_err(component->dev, + "Failed to set BCLK rate %lu: %d\n", + bclk_rate, ret); + return ret; + } + } else { + ret = da7219_set_bclks_per_wclk(component, frame_size); + if (ret) { + dev_err(component->dev, + "Failed to set BCLKs per WCLK %d: %d\n", + frame_size, ret); + return ret; + } + } } snd_soc_component_update_bits(component, DA7219_DAI_CTRL, DA7219_DAI_WORD_LENGTH_MASK | DA7219_DAI_CH_NUM_MASK, dai_ctrl); - snd_soc_component_write(component, DA7219_SR, fs); return 0; } @@ -1672,11 +1747,14 @@ static struct da7219_pdata *da7219_fw_to_pdata(struct snd_soc_component *compone pdata->wakeup_source = device_property_read_bool(dev, "wakeup-source"); - pdata->dai_clks_name = "da7219-dai-clks"; - if (device_property_read_string(dev, "clock-output-names", - &pdata->dai_clks_name)) - dev_warn(dev, "Using default clk name: %s\n", - pdata->dai_clks_name); + pdata->dai_clk_names[DA7219_DAI_WCLK_IDX] = "da7219-dai-wclk"; + pdata->dai_clk_names[DA7219_DAI_BCLK_IDX] = "da7219-dai-bclk"; + if (device_property_read_string_array(dev, "clock-output-names", + pdata->dai_clk_names, + DA7219_DAI_NUM_CLKS) < 0) + dev_warn(dev, "Using default DAI clk names: %s, %s\n", + pdata->dai_clk_names[DA7219_DAI_WCLK_IDX], + pdata->dai_clk_names[DA7219_DAI_BCLK_IDX]); if (device_property_read_u32(dev, "dlg,micbias-lvl", &of_val32) >= 0) pdata->micbias_lvl = da7219_fw_micbias_lvl(dev, of_val32); @@ -1793,12 +1871,16 @@ static int da7219_handle_supplies(struct snd_soc_component *component) } #ifdef CONFIG_COMMON_CLK -static int da7219_dai_clks_prepare(struct clk_hw *hw) +static int da7219_wclk_prepare(struct clk_hw *hw) { struct da7219_priv *da7219 = - container_of(hw, struct da7219_priv, dai_clks_hw); + container_of(hw, struct da7219_priv, + dai_clks_hw[DA7219_DAI_WCLK_IDX]); struct snd_soc_component *component = da7219->component; + if (!da7219->master) + return -EINVAL; + snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, DA7219_DAI_CLK_EN_MASK, DA7219_DAI_CLK_EN_MASK); @@ -1806,36 +1888,48 @@ static int da7219_dai_clks_prepare(struct clk_hw *hw) return 0; } -static void da7219_dai_clks_unprepare(struct clk_hw *hw) +static void da7219_wclk_unprepare(struct clk_hw *hw) { struct da7219_priv *da7219 = - container_of(hw, struct da7219_priv, dai_clks_hw); + container_of(hw, struct da7219_priv, + dai_clks_hw[DA7219_DAI_WCLK_IDX]); struct snd_soc_component *component = da7219->component; + if (!da7219->master) + return; + snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, DA7219_DAI_CLK_EN_MASK, 0); } -static int da7219_dai_clks_is_prepared(struct clk_hw *hw) +static int da7219_wclk_is_prepared(struct clk_hw *hw) { struct da7219_priv *da7219 = - container_of(hw, struct da7219_priv, dai_clks_hw); + container_of(hw, struct da7219_priv, + dai_clks_hw[DA7219_DAI_WCLK_IDX]); struct snd_soc_component *component = da7219->component; u8 clk_reg; + if (!da7219->master) + return -EINVAL; + clk_reg = snd_soc_component_read32(component, DA7219_DAI_CLK_MODE); return !!(clk_reg & DA7219_DAI_CLK_EN_MASK); } -static unsigned long da7219_dai_clks_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) +static unsigned long da7219_wclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) { struct da7219_priv *da7219 = - container_of(hw, struct da7219_priv, dai_clks_hw); + container_of(hw, struct da7219_priv, + dai_clks_hw[DA7219_DAI_WCLK_IDX]); struct snd_soc_component *component = da7219->component; u8 fs = snd_soc_component_read32(component, DA7219_SR); + if (!da7219->master) + return 0; + switch (fs & DA7219_SR_MASK) { case DA7219_SR_8000: return 8000; @@ -1864,11 +1958,151 @@ static unsigned long da7219_dai_clks_recalc_rate(struct clk_hw *hw, } } -static const struct clk_ops da7219_dai_clks_ops = { - .prepare = da7219_dai_clks_prepare, - .unprepare = da7219_dai_clks_unprepare, - .is_prepared = da7219_dai_clks_is_prepared, - .recalc_rate = da7219_dai_clks_recalc_rate, +static long da7219_wclk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct da7219_priv *da7219 = + container_of(hw, struct da7219_priv, + dai_clks_hw[DA7219_DAI_WCLK_IDX]); + + if (!da7219->master) + return -EINVAL; + + if (rate < 11025) + return 8000; + else if (rate < 12000) + return 11025; + else if (rate < 16000) + return 12000; + else if (rate < 22050) + return 16000; + else if (rate < 24000) + return 22050; + else if (rate < 32000) + return 24000; + else if (rate < 44100) + return 32000; + else if (rate < 48000) + return 44100; + else if (rate < 88200) + return 48000; + else if (rate < 96000) + return 88200; + else + return 96000; +} + +static int da7219_wclk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct da7219_priv *da7219 = + container_of(hw, struct da7219_priv, + dai_clks_hw[DA7219_DAI_WCLK_IDX]); + struct snd_soc_component *component = da7219->component; + + if (!da7219->master) + return -EINVAL; + + return da7219_set_sr(component, rate); +} + +static unsigned long da7219_bclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct da7219_priv *da7219 = + container_of(hw, struct da7219_priv, + dai_clks_hw[DA7219_DAI_BCLK_IDX]); + struct snd_soc_component *component = da7219->component; + u8 bclks_per_wclk = snd_soc_component_read32(component, + DA7219_DAI_CLK_MODE); + + if (!da7219->master) + return 0; + + switch (bclks_per_wclk & DA7219_DAI_BCLKS_PER_WCLK_MASK) { + case DA7219_DAI_BCLKS_PER_WCLK_32: + return parent_rate * 32; + case DA7219_DAI_BCLKS_PER_WCLK_64: + return parent_rate * 64; + case DA7219_DAI_BCLKS_PER_WCLK_128: + return parent_rate * 128; + case DA7219_DAI_BCLKS_PER_WCLK_256: + return parent_rate * 256; + default: + return 0; + } +} + +static unsigned long da7219_bclk_get_factor(unsigned long rate, + unsigned long parent_rate) +{ + unsigned long factor; + + factor = rate / parent_rate; + if (factor < 64) + return 32; + else if (factor < 128) + return 64; + else if (factor < 256) + return 128; + else + return 256; +} + +static long da7219_bclk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct da7219_priv *da7219 = + container_of(hw, struct da7219_priv, + dai_clks_hw[DA7219_DAI_BCLK_IDX]); + unsigned long factor; + + if (!*parent_rate || !da7219->master) + return -EINVAL; + + /* + * We don't allow changing the parent rate as some BCLK rates can be + * derived from multiple parent WCLK rates (BCLK rates are set as a + * multiplier of WCLK in HW). We just do some rounding down based on the + * parent WCLK rate set and find the appropriate multiplier of BCLK to + * get the rounded down BCLK value. + */ + factor = da7219_bclk_get_factor(rate, *parent_rate); + + return *parent_rate * factor; +} + +static int da7219_bclk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct da7219_priv *da7219 = + container_of(hw, struct da7219_priv, + dai_clks_hw[DA7219_DAI_BCLK_IDX]); + struct snd_soc_component *component = da7219->component; + unsigned long factor; + + if (!da7219->master) + return -EINVAL; + + factor = da7219_bclk_get_factor(rate, parent_rate); + + return da7219_set_bclks_per_wclk(component, factor); +} + +static const struct clk_ops da7219_dai_clk_ops[DA7219_DAI_NUM_CLKS] = { + [DA7219_DAI_WCLK_IDX] = { + .prepare = da7219_wclk_prepare, + .unprepare = da7219_wclk_unprepare, + .is_prepared = da7219_wclk_is_prepared, + .recalc_rate = da7219_wclk_recalc_rate, + .round_rate = da7219_wclk_round_rate, + .set_rate = da7219_wclk_set_rate, + }, + [DA7219_DAI_BCLK_IDX] = { + .recalc_rate = da7219_bclk_recalc_rate, + .round_rate = da7219_bclk_round_rate, + .set_rate = da7219_bclk_set_rate, + }, }; static int da7219_register_dai_clks(struct snd_soc_component *component) @@ -1876,47 +2110,81 @@ static int da7219_register_dai_clks(struct snd_soc_component *component) struct device *dev = component->dev; struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); struct da7219_pdata *pdata = da7219->pdata; - struct clk_init_data init = {}; - struct clk *dai_clks; - struct clk_lookup *dai_clks_lookup; const char *parent_name; + int i, ret; - if (da7219->mclk) { - parent_name = __clk_get_name(da7219->mclk); - init.parent_names = &parent_name; - init.num_parents = 1; - } else { - init.parent_names = NULL; - init.num_parents = 0; - } + for (i = 0; i < DA7219_DAI_NUM_CLKS; ++i) { + struct clk_init_data init = {}; + struct clk *dai_clk; + struct clk_lookup *dai_clk_lookup; + struct clk_hw *dai_clk_hw = &da7219->dai_clks_hw[i]; - init.name = pdata->dai_clks_name; - init.ops = &da7219_dai_clks_ops; - init.flags = CLK_GET_RATE_NOCACHE; - da7219->dai_clks_hw.init = &init; + switch (i) { + case DA7219_DAI_WCLK_IDX: + /* + * If we can, make MCLK the parent of WCLK to ensure + * it's enabled as required. + */ + if (da7219->mclk) { + parent_name = __clk_get_name(da7219->mclk); + init.parent_names = &parent_name; + init.num_parents = 1; + } else { + init.parent_names = NULL; + init.num_parents = 0; + } + break; + case DA7219_DAI_BCLK_IDX: + /* Make WCLK the parent of BCLK */ + parent_name = __clk_get_name(da7219->dai_clks[DA7219_DAI_WCLK_IDX]); + init.parent_names = &parent_name; + init.num_parents = 1; + break; + default: + dev_err(dev, "Invalid clock index\n"); + ret = -EINVAL; + goto err; + } - dai_clks = devm_clk_register(dev, &da7219->dai_clks_hw); - if (IS_ERR(dai_clks)) { - dev_warn(dev, "Failed to register DAI clocks: %ld\n", - PTR_ERR(dai_clks)); - return PTR_ERR(dai_clks); - } - da7219->dai_clks = dai_clks; + init.name = pdata->dai_clk_names[i]; + init.ops = &da7219_dai_clk_ops[i]; + init.flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_GATE; + dai_clk_hw->init = &init; + + dai_clk = devm_clk_register(dev, dai_clk_hw); + if (IS_ERR(dai_clk)) { + dev_warn(dev, "Failed to register %s: %ld\n", + init.name, PTR_ERR(dai_clk)); + ret = PTR_ERR(dai_clk); + goto err; + } + da7219->dai_clks[i] = dai_clk; - /* If we're using DT, then register as provider accordingly */ - if (dev->of_node) { - devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, - &da7219->dai_clks_hw); - } else { - dai_clks_lookup = clkdev_create(dai_clks, pdata->dai_clks_name, - "%s", dev_name(dev)); - if (!dai_clks_lookup) - return -ENOMEM; - else - da7219->dai_clks_lookup = dai_clks_lookup; + /* If we're using DT, then register as provider accordingly */ + if (dev->of_node) { + devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, + dai_clk_hw); + } else { + dai_clk_lookup = clkdev_create(dai_clk, init.name, + "%s", dev_name(dev)); + if (!dai_clk_lookup) { + ret = -ENOMEM; + goto err; + } else { + da7219->dai_clks_lookup[i] = dai_clk_lookup; + } + } } return 0; + +err: + do { + if (da7219->dai_clks_lookup[i]) + clkdev_drop(da7219->dai_clks_lookup[i]); + } while (i-- > 0); + + return ret; } #else static inline int da7219_register_dai_clks(struct snd_soc_component *component) @@ -2080,12 +2348,15 @@ static int da7219_probe(struct snd_soc_component *component) static void da7219_remove(struct snd_soc_component *component) { struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); + int i; da7219_aad_exit(component); #ifdef CONFIG_COMMON_CLK - if (da7219->dai_clks_lookup) - clkdev_drop(da7219->dai_clks_lookup); + for (i = DA7219_DAI_NUM_CLKS - 1; i >= 0; --i) { + if (da7219->dai_clks_lookup[i]) + clkdev_drop(da7219->dai_clks_lookup[i]); + } #endif /* Supplies */ diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index 018819c631fbe4..f3b180bc986fde 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -820,10 +820,10 @@ struct da7219_priv { struct mutex pll_lock; #ifdef CONFIG_COMMON_CLK - struct clk_hw dai_clks_hw; + struct clk_hw dai_clks_hw[DA7219_DAI_NUM_CLKS]; #endif - struct clk_lookup *dai_clks_lookup; - struct clk *dai_clks; + struct clk_lookup *dai_clks_lookup[DA7219_DAI_NUM_CLKS]; + struct clk *dai_clks[DA7219_DAI_NUM_CLKS]; struct clk *mclk; unsigned int mclk_rate; From d86eee6ef58100de4ca447dc29ed18139ce413b5 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 22 Mar 2019 15:39:48 -0700 Subject: [PATCH 1278/1995] ASoC: intel: Fix crash at suspend/resume after failed codec registration If codec registration fails after the ASoC Intel SST driver has been probed, the kernel will Oops and crash at suspend/resume. general protection fault: 0000 [#1] PREEMPT SMP KASAN PTI CPU: 1 PID: 2811 Comm: cat Tainted: G W 4.19.30 #15 Hardware name: GOOGLE Clapper, BIOS Google_Clapper.5216.199.7 08/22/2014 RIP: 0010:snd_soc_suspend+0x5a/0xd21 Code: 03 80 3c 10 00 49 89 d7 74 0b 48 89 df e8 71 72 c4 fe 4c 89 fa 48 8b 03 48 89 45 d0 48 8d 98 a0 01 00 00 48 89 d8 48 c1 e8 03 <8a> 04 10 84 c0 0f 85 85 0c 00 00 80 3b 00 0f 84 6b 0c 00 00 48 8b RSP: 0018:ffff888035407750 EFLAGS: 00010202 RAX: 0000000000000034 RBX: 00000000000001a0 RCX: 0000000000000000 RDX: dffffc0000000000 RSI: 0000000000000008 RDI: ffff88805c417098 RBP: ffff8880354077b0 R08: dffffc0000000000 R09: ffffed100b975718 R10: 0000000000000001 R11: ffffffff949ea4a3 R12: 1ffff1100b975746 R13: dffffc0000000000 R14: ffff88805cba4588 R15: dffffc0000000000 FS: 0000794a78e91b80(0000) GS:ffff888068d00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007bd5283ccf58 CR3: 000000004b7aa000 CR4: 00000000001006e0 Call Trace: ? dpm_complete+0x67b/0x67b ? i915_gem_suspend+0x14d/0x1ad sst_soc_prepare+0x91/0x1dd ? sst_be_hw_params+0x7e/0x7e dpm_prepare+0x39a/0x88b dpm_suspend_start+0x13/0x9d suspend_devices_and_enter+0x18f/0xbd7 ? arch_suspend_enable_irqs+0x11/0x11 ? printk+0xd9/0x12d ? lock_release+0x95f/0x95f ? log_buf_vmcoreinfo_setup+0x131/0x131 ? rcu_read_lock_sched_held+0x140/0x22a ? __bpf_trace_rcu_utilization+0xa/0xa ? __pm_pr_dbg+0x186/0x190 ? pm_notifier_call_chain+0x39/0x39 ? suspend_test+0x9d/0x9d pm_suspend+0x2f4/0x728 ? trace_suspend_resume+0x3da/0x3da ? lock_release+0x95f/0x95f ? kernfs_fop_write+0x19f/0x32d state_store+0xd8/0x147 ? sysfs_kf_read+0x155/0x155 kernfs_fop_write+0x23e/0x32d __vfs_write+0x108/0x608 ? vfs_read+0x2e9/0x2e9 ? rcu_read_lock_sched_held+0x140/0x22a ? __bpf_trace_rcu_utilization+0xa/0xa ? debug_smp_processor_id+0x10/0x10 ? selinux_file_permission+0x1c5/0x3c8 ? rcu_sync_lockdep_assert+0x6a/0xad ? __sb_start_write+0x129/0x2ac vfs_write+0x1aa/0x434 ksys_write+0xfe/0x1be ? __ia32_sys_read+0x82/0x82 do_syscall_64+0xcd/0x120 entry_SYSCALL_64_after_hwframe+0x49/0xbe In the observed situation, the problem is seen because the codec driver failed to probe due to a hardware problem. max98090 i2c-193C9890:00: Failed to read device revision: -1 max98090 i2c-193C9890:00: ASoC: failed to probe component -1 cht-bsw-max98090 cht-bsw-max98090: ASoC: failed to instantiate card -1 cht-bsw-max98090 cht-bsw-max98090: snd_soc_register_card failed -1 cht-bsw-max98090: probe of cht-bsw-max98090 failed with error -1 The problem is similar to the problem solved with commit 2fc995a87f2e ("ASoC: intel: Fix crash at suspend/resume without card registration"), but codec registration fails at a later point. At that time, the pointer checked with the above mentioned commit is already set, but it is not cleared if the device is subsequently removed. Adding a remove function to clear the pointer fixes the problem. Cc: stable@vger.kernel.org Cc: Jarkko Nikula Cc: Curtis Malainey Signed-off-by: Guenter Roeck Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 8f71370f4b02730e8c27faf460af7a3586e24e1f) --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 08cea5b5cda9fa..0e8b1c5eec888b 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -706,9 +706,17 @@ static int sst_soc_probe(struct snd_soc_component *component) return sst_dsp_init_v2_dpcm(component); } +static void sst_soc_remove(struct snd_soc_component *component) +{ + struct sst_data *drv = dev_get_drvdata(component->dev); + + drv->soc_card = NULL; +} + static const struct snd_soc_component_driver sst_soc_platform_drv = { .name = DRV_NAME, .probe = sst_soc_probe, + .remove = sst_soc_remove, .ops = &sst_platform_ops, .compr_ops = &sst_platform_compr_ops, .pcm_new = sst_pcm_new, From 42f2d7b2344902fda83e72b6dac126cad00264b4 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Fri, 22 Mar 2019 12:25:35 +0800 Subject: [PATCH 1279/1995] ASoC: nau8810: fix the issue of 64 bits division Do division with div_u64 for the PLL calculation. These errors are fixed and list as follows: 1."__udivdi3" [sound/soc/codecs/snd-soc-nau8810.ko] undefined! 2."__aeabi_uldivmod" [sound/soc/codecs/snd-soc-nau8810.ko] undefined! 3. nau8810.c:(.text.nau8810_calc_pll+0xd8): undefined reference to `__udivdi3' Signed-off-by: John Hsu Signed-off-by: Mark Brown (cherry picked from commit 3a9ce0f1b2961f6c3ad2a49dcf85449784c18bb5) --- sound/soc/codecs/nau8810.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c index 125e205e668715..dd82c65cfa7f80 100644 --- a/sound/soc/codecs/nau8810.c +++ b/sound/soc/codecs/nau8810.c @@ -505,7 +505,8 @@ static int nau8810_calc_pll(unsigned int pll_in, f2_max = 0; scal_sel = ARRAY_SIZE(nau8810_mclk_scaler); for (i = 0; i < ARRAY_SIZE(nau8810_mclk_scaler); i++) { - f2 = 256ULL * fs * 4 * nau8810_mclk_scaler[i] / 10; + f2 = 256ULL * fs * 4 * nau8810_mclk_scaler[i]; + f2 = div_u64(f2, 10); if (f2 > NAU_PLL_FREQ_MIN && f2 < NAU_PLL_FREQ_MAX && f2_max < f2) { f2_max = f2; From a8165eafc30a2cbe944ae7242e72ee009a47c78f Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 21 Mar 2019 15:00:05 -0700 Subject: [PATCH 1280/1995] ASoC: AMD: Fix incorrect extern When using bare externs outside include files that types should at least match. This fixes a type confusion between bool and int. Cc: broonie@kernel.org Signed-off-by: Andi Kleen Signed-off-by: Mark Brown (cherry picked from commit eddb6084305e5418ce28b8379a6c3d0058a61463) --- sound/soc/amd/acp-da7219-max98357a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index a5daad973ce565..f001aad0c70eae 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -47,7 +47,7 @@ static struct snd_soc_jack cz_jack; static struct clk *da7219_dai_clk; -extern int bt_uart_enable; +extern bool bt_uart_enable; static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd) { From d775294d61ef94f7d4277b9d31fd5bb5599a6d65 Mon Sep 17 00:00:00 2001 From: Pankaj Bharadiya Date: Fri, 22 Mar 2019 18:00:09 +0530 Subject: [PATCH 1281/1995] ASoC: dapm: Fix NULL pointer dereference in snd_soc_dapm_free_kcontrol w_text_param can be NULL and it is being dereferenced without checking. Add the missing sanity check to prevent NULL pointer dereference. Signed-off-by: Pankaj Bharadiya Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit cacea3a90e211f0c111975535508d446a4a928d2) --- sound/soc/soc-dapm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1ec06ef6d16160..67b032ca1601f7 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3957,6 +3957,10 @@ snd_soc_dapm_free_kcontrol(struct snd_soc_card *card, int count; devm_kfree(card->dev, (void *)*private_value); + + if (!w_param_text) + return; + for (count = 0 ; count < num_params; count++) devm_kfree(card->dev, (void *)w_param_text[count]); devm_kfree(card->dev, w_param_text); From 37623eb6cf4c76ebedd764e27a6a8a9eac0ede28 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 25 Mar 2019 10:38:58 +0100 Subject: [PATCH 1282/1995] ALSA: pcm: Don't suspend stream in unrecoverable PCM state Currently PCM core sets each opened stream forcibly to SUSPENDED state via snd_pcm_suspend_all() call, and the user-space is responsible for re-triggering the resume manually either via snd_pcm_resume() or prepare call. The scheme works fine usually, but there are corner cases where the stream can't be resumed by that call: the streams still in OPEN state before finishing hw_params. When they are suspended, user-space cannot perform resume or prepare because they haven't been set up yet. The only possible recovery is to re-open the device, which isn't nice at all. Similarly, when a stream is in DISCONNECTED state, it makes no sense to change it to SUSPENDED state. Ditto for in SETUP state; which you can re-prepare directly. So, this patch addresses these issues by filtering the PCM streams to be suspended by checking the PCM state. When a stream is in either OPEN, SETUP or DISCONNECTED as well as already SUSPENDED, the suspend action is skipped. To be noted, this problem was originally reported for the PCM runtime PM on HD-audio. And, the runtime PM problem itself was already addressed (although not intended) by the code refactoring commits 3d21ef0b49f8 ("ALSA: pcm: Suspend streams globally via device type PM ops") and 17bc4815de58 ("ALSA: pci: Remove superfluous snd_pcm_suspend*() calls"). These commits eliminated the snd_pcm_suspend*() calls from the runtime PM suspend callback code path, hence the racy OPEN state won't appear while runtime PM. (FWIW, the race window is between snd_pcm_open_substream() and the first power up in azx_pcm_open().) Although the runtime PM issue was already "fixed", the same problem is still present for the system PM, hence this patch is still needed. And for stable trees, this patch alone should suffice for fixing the runtime PM problem, too. Reported-and-tested-by: Jon Hunter Cc: Signed-off-by: Takashi Iwai (cherry picked from commit 113ce08109f8e3b091399e7cc32486df1cff48e7) --- sound/core/pcm_native.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index f731f904e8ccb4..1d8452912b14af 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1445,8 +1445,15 @@ static int snd_pcm_pause(struct snd_pcm_substream *substream, int push) static int snd_pcm_pre_suspend(struct snd_pcm_substream *substream, int state) { struct snd_pcm_runtime *runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) + switch (runtime->status->state) { + case SNDRV_PCM_STATE_SUSPENDED: return -EBUSY; + /* unresumable PCM state; return -EBUSY for skipping suspend */ + case SNDRV_PCM_STATE_OPEN: + case SNDRV_PCM_STATE_SETUP: + case SNDRV_PCM_STATE_DISCONNECTED: + return -EBUSY; + } runtime->trigger_master = substream; return 0; } From ea5a0483115b7c37d55c4428ebbd253aa5fe2110 Mon Sep 17 00:00:00 2001 From: Pankaj Bharadiya Date: Fri, 22 Mar 2019 21:53:39 +0530 Subject: [PATCH 1283/1995] ASoC: dapm: Initialize private_value in snd_soc_dapm_new_dai In case of single config, private_value is left uninitialized. The private_value does need to be initialized or in snd_soc_dapm_new_control_unlocked() call failure case, it leads to a bogus free in snd_soc_dapm_free_kcontrol() Signed-off-by: Pankaj Bharadiya Signed-off-by: Mark Brown (cherry picked from commit 8633d44002ba5c98f44bacc1397190adba832fd6) --- sound/soc/soc-dapm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 67b032ca1601f7..665a6b17281e25 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -4042,7 +4042,7 @@ snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd, struct snd_soc_dapm_widget template; struct snd_soc_dapm_widget *w; const char **w_param_text; - unsigned long private_value; + unsigned long private_value = 0; char *link_name; int ret; From f6e404858913272f715c972cdbb467dae6153eb1 Mon Sep 17 00:00:00 2001 From: Jenny TC Date: Sat, 23 Mar 2019 18:40:10 +0530 Subject: [PATCH 1284/1995] ASoC: Intel: Skylake: enable S24_LE format support To enable S24_LE format, sample_type in topology fw has to be set to 1. But sample_type defined in topology firmware configuration is not getting reflected in the dsp param. This patch sets sample_type in base config so that the sample type defined in the topology firmware is reflected in the dsp params. This issues was uncovered while debugging the S24_LE format which require the MSB byte in 32 bit word to be skipped. Setting sample_type in topology firmware to 1 helps to skip MSB byte word. Signed-off-by: Jenny TC Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 36e075ce74ec4e261a638bf09d10b3348ca4d883) --- sound/soc/intel/skylake/skl-messages.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 28c4806b196a2f..4bf70b4429f030 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -483,6 +483,7 @@ static void skl_set_base_module_format(struct skl_sst *ctx, base_cfg->audio_fmt.bit_depth = format->bit_depth; base_cfg->audio_fmt.valid_bit_depth = format->valid_bit_depth; base_cfg->audio_fmt.ch_cfg = format->ch_cfg; + base_cfg->audio_fmt.sample_type = format->sample_type; dev_dbg(ctx->dev, "bit_depth=%x valid_bd=%x ch_config=%x\n", format->bit_depth, format->valid_bit_depth, From 419162a66d911ad1dc079e1e5b1d718e57a15526 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Thu, 28 Mar 2019 10:27:00 +0800 Subject: [PATCH 1285/1995] ASoC: rt5677-spi: Add ACPI ID Add the ACPI ID for the product "chromebook pixel 2015" to match the coreboot settings. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown (cherry picked from commit 2b070f6739025ecbf2ccb55daf9e19d3fb343c7e) --- sound/soc/codecs/rt5677-spi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index 84501c2020c786..167a02773a0b0a 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "rt5677-spi.h" @@ -226,9 +227,16 @@ static int rt5677_spi_probe(struct spi_device *spi) return 0; } +static const struct acpi_device_id rt5677_spi_acpi_id[] = { + { "RT5677AA", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, rt5677_spi_acpi_id); + static struct spi_driver rt5677_spi_driver = { .driver = { .name = "rt5677", + .acpi_match_table = ACPI_PTR(rt5677_spi_acpi_id), }, .probe = rt5677_spi_probe, }; From 619aabf8500c2a7cebcaa9c4b24dac59836fe5ba Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 29 Mar 2019 22:50:43 +0100 Subject: [PATCH 1286/1995] ASoC: es8316: Add support for inverted jack detect On some devices (Teclast X98+ II tablet, maybe others), the jack detection has been wired backwards, so when the ES8316 reports headphones being present it means they are actually not plugged. Use a quirk around this incorrect behaviour, which can be enabled through the 'everest,jack-detect-inverted' boolean device property. Signed-off-by: Paul Cercueil Signed-off-by: Mark Brown (cherry picked from commit 0bbcedd6bb41b82b77115fc001441ff34e7c4ea7) --- sound/soc/codecs/es8316.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 6d4a323f786b00..ec2770b3f77d58 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -43,6 +43,7 @@ struct es8316_priv { unsigned int sysclk; unsigned int allowed_rates[NR_SUPPORTED_MCLK_LRCK_RATIOS]; struct snd_pcm_hw_constraint_list sysclk_constraints; + bool jd_inverted; }; /* @@ -577,6 +578,9 @@ static irqreturn_t es8316_irq(int irq, void *data) if (!es8316->jack) goto out; + if (es8316->jd_inverted) + flags ^= ES8316_GPIO_FLAG_HP_NOT_INSERTED; + dev_dbg(comp->dev, "gpio flags %#04x\n", flags); if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) { /* Jack removed, or spurious IRQ? */ @@ -592,6 +596,8 @@ static irqreturn_t es8316_irq(int irq, void *data) /* Jack inserted, determine type */ es8316_enable_micbias_for_mic_gnd_short_detect(comp); regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags); + if (es8316->jd_inverted) + flags ^= ES8316_GPIO_FLAG_HP_NOT_INSERTED; dev_dbg(comp->dev, "gpio flags %#04x\n", flags); if (flags & ES8316_GPIO_FLAG_HP_NOT_INSERTED) { /* Jack unplugged underneath us */ @@ -633,6 +639,14 @@ static void es8316_enable_jack_detect(struct snd_soc_component *component, { struct es8316_priv *es8316 = snd_soc_component_get_drvdata(component); + /* + * Init es8316->jd_inverted here and not in the probe, as we cannot + * guarantee that the bytchr-es8316 driver, which might set this + * property, will probe before us. + */ + es8316->jd_inverted = device_property_read_bool(component->dev, + "everest,jack-detect-inverted"); + mutex_lock(&es8316->lock); es8316->jack = jack; From c7bc7b6e2e9e0bac2a343180c8d56effc886efcb Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 18 Mar 2019 23:00:54 +0300 Subject: [PATCH 1287/1995] ACPI / utils: Introduce acpi_dev_get_first_match_dev() helper The acpi_dev_get_first_match_name() is missing put_device() call and thus keeping reference counting unbalanced. In order to fix the issue introduce a new helper to convert existing users one-by-one to a better API. Signed-off-by: Andy Shevchenko Reviewed-by: Hans de Goede Reviewed-by: Mika Westerberg Acked-by: Mark Brown Signed-off-by: Rafael J. Wysocki (cherry picked from commit 817b4d64da036f5559297a2fdb82b8b14f4ffdcd) --- drivers/acpi/utils.c | 24 ++++++++++++++++++++++-- include/acpi/acpi_bus.h | 3 +++ include/linux/acpi.h | 6 ++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 78db97687f26a1..7a62c97c857861 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -739,6 +739,7 @@ EXPORT_SYMBOL(acpi_dev_found); struct acpi_dev_match_info { const char *dev_name; + struct acpi_device *adev; struct acpi_device_id hid[2]; const char *uid; s64 hrv; @@ -759,6 +760,7 @@ static int acpi_dev_match_cb(struct device *dev, void *data) return 0; match->dev_name = acpi_dev_name(adev); + match->adev = adev; if (match->hrv == -1) return 1; @@ -805,16 +807,34 @@ bool acpi_dev_present(const char *hid, const char *uid, s64 hrv) EXPORT_SYMBOL(acpi_dev_present); /** - * acpi_dev_get_first_match_name - Return name of first match of ACPI device + * acpi_dev_get_first_match_dev - Return the first match of ACPI device * @hid: Hardware ID of the device. * @uid: Unique ID of the device, pass NULL to not check _UID * @hrv: Hardware Revision of the device, pass -1 to not check _HRV * - * Return device name if a matching device was present + * Return the first match of ACPI device if a matching device was present * at the moment of invocation, or NULL otherwise. * + * The caller is responsible to call put_device() on the returned device. + * * See additional information in acpi_dev_present() as well. */ +struct acpi_device * +acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv) +{ + struct acpi_dev_match_info match = {}; + struct device *dev; + + strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id)); + match.uid = uid; + match.hrv = hrv; + + dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb); + return dev ? match.adev : NULL; +} +EXPORT_SYMBOL(acpi_dev_get_first_match_dev); + +/* DEPRECATED, use acpi_dev_get_first_match_dev() instead */ const char * acpi_dev_get_first_match_name(const char *hid, const char *uid, s64 hrv) { diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 0300374101cded..2063e9e2f3845f 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -91,6 +91,9 @@ acpi_evaluate_dsm_typed(acpi_handle handle, const guid_t *guid, u64 rev, bool acpi_dev_found(const char *hid); bool acpi_dev_present(const char *hid, const char *uid, s64 hrv); +struct acpi_device * +acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv); + const char * acpi_dev_get_first_match_name(const char *hid, const char *uid, s64 hrv); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 03b4c4f225d002..b2c7df5ea3ebe2 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -664,6 +664,12 @@ static inline bool acpi_dev_present(const char *hid, const char *uid, s64 hrv) return false; } +static inline struct acpi_device * +acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv) +{ + return NULL; +} + static inline const char * acpi_dev_get_first_match_name(const char *hid, const char *uid, s64 hrv) { From b379e8835a67eb53bd46b648d75679b4ddfb5a6c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 28 Mar 2019 19:17:21 +0200 Subject: [PATCH 1288/1995] extcon: axp288: Convert to use acpi_dev_get_first_match_dev() acpi_dev_get_first_match_name() is deprecated and going to be removed because it leaks a reference. Convert the driver to use acpi_dev_get_first_match_dev() instead. Signed-off-by: Andy Shevchenko Acked-by: Chanwoo Choi Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki (cherry picked from commit 0cf064db948aca1e760fc513594536f761dee1cd) --- drivers/extcon/extcon-axp288.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c index a983708b77a66a..50f9402fb32539 100644 --- a/drivers/extcon/extcon-axp288.c +++ b/drivers/extcon/extcon-axp288.c @@ -333,7 +333,7 @@ static int axp288_extcon_probe(struct platform_device *pdev) struct axp288_extcon_info *info; struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); struct device *dev = &pdev->dev; - const char *name; + struct acpi_device *adev; int ret, i, pirq; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); @@ -357,9 +357,10 @@ static int axp288_extcon_probe(struct platform_device *pdev) if (ret) return ret; - name = acpi_dev_get_first_match_name("INT3496", NULL, -1); - if (name) { - info->id_extcon = extcon_get_extcon_dev(name); + adev = acpi_dev_get_first_match_dev("INT3496", NULL, -1); + if (adev) { + info->id_extcon = extcon_get_extcon_dev(acpi_dev_name(adev)); + put_device(&adev->dev); if (!info->id_extcon) return -EPROBE_DEFER; From 996fe15660483634ee4f8320f730abae972234fc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 28 Mar 2019 19:17:22 +0200 Subject: [PATCH 1289/1995] gpio: merrifield: Convert to use acpi_dev_get_first_match_dev() acpi_dev_get_first_match_name() is deprecated and going to be removed because it leaks a reference. Convert the driver to use acpi_dev_get_first_match_dev() instead. Signed-off-by: Andy Shevchenko Reviewed-by: Hans de Goede Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki (cherry picked from commit d00d2109c3679bf87d412b1667bcb6d42c1ac12f) --- drivers/gpio/gpio-merrifield.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 7c659fdaa6d586..2383dc78b1235f 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -377,10 +377,20 @@ static void mrfld_irq_init_hw(struct mrfld_gpio *priv) } } -static const char *mrfld_gpio_get_pinctrl_dev_name(void) +static const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv) { - const char *dev_name = acpi_dev_get_first_match_name("INTC1002", NULL, -1); - return dev_name ? dev_name : "pinctrl-merrifield"; + struct acpi_device *adev; + const char *name; + + adev = acpi_dev_get_first_match_dev("INTC1002", NULL, -1); + if (adev) { + name = devm_kstrdup(priv->dev, acpi_dev_name(adev), GFP_KERNEL); + put_device(&adev->dev); + } else { + name = "pinctrl-merrifield"; + } + + return name; } static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -441,7 +451,7 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id return retval; } - pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(); + pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(priv); for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) { range = &mrfld_gpio_ranges[i]; retval = gpiochip_add_pin_range(&priv->chip, From 0181e54b84bd312c34b634814b34e2c43b07db29 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 28 Mar 2019 19:17:23 +0200 Subject: [PATCH 1290/1995] ASoC: Intel: bytcht_da7213: Convert to use acpi_dev_get_first_match_dev() acpi_dev_get_first_match_name() is deprecated and going to be removed because it leaks a reference. Convert the driver to use acpi_dev_get_first_match_dev() instead. Signed-off-by: Andy Shevchenko Acked-by: Pierre-Louis Bossart Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki (cherry picked from commit 1b55f1c6fd64efd7b1339664edc1222ad99f9c9b) --- sound/soc/intel/boards/bytcht_da7213.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index b8e884803777b3..4decba33815659 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -226,7 +226,7 @@ static int bytcht_da7213_probe(struct platform_device *pdev) struct snd_soc_card *card; struct snd_soc_acpi_mach *mach; const char *platform_name; - const char *i2c_name = NULL; + struct acpi_device *adev; int dai_index = 0; int ret_val = 0; int i; @@ -244,10 +244,11 @@ static int bytcht_da7213_probe(struct platform_device *pdev) } /* fixup codec name based on HID */ - i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); - if (i2c_name) { + adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); + if (adev) { snprintf(codec_name, sizeof(codec_name), - "%s%s", "i2c-", i2c_name); + "i2c-%s", acpi_dev_name(adev)); + put_device(&adev->dev); dailink[dai_index].codec_name = codec_name; } From d08fb45e131a6dd9fc0494c16bacd92bfcc4be25 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 28 Mar 2019 19:17:24 +0200 Subject: [PATCH 1291/1995] ASoC: Intel: bytcht_es8316: Convert to use acpi_dev_get_first_match_dev() acpi_dev_get_first_match_name() is deprecated and going to be removed because it leaks a reference. Convert the driver to use acpi_dev_get_first_match_dev() instead. Signed-off-by: Andy Shevchenko Acked-by: Pierre-Louis Bossart Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki (cherry picked from commit 645056da677082811b978f6285bf1ec0be947340) --- sound/soc/intel/boards/bytcht_es8316.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index d2a7e6ba11aec1..6937c00cf63d19 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -442,7 +442,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; const char *platform_name; - const char *i2c_name = NULL; + struct acpi_device *adev; struct device *codec_dev; int dai_index = 0; int i; @@ -463,10 +463,11 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) } /* fixup codec name based on HID */ - i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); - if (i2c_name) { + adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); + if (adev) { snprintf(codec_name, sizeof(codec_name), - "%s%s", "i2c-", i2c_name); + "i2c-%s", acpi_dev_name(adev)); + put_device(&adev->dev); byt_cht_es8316_dais[dai_index].codec_name = codec_name; } From e13e1202545fb9f1b2ab9b7c00fdd44b7dcc63d4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 28 Mar 2019 19:17:25 +0200 Subject: [PATCH 1292/1995] ASoC: Intel: bytcr_rt5640: Convert to use acpi_dev_get_first_match_dev() acpi_dev_get_first_match_name() is deprecated and going to be removed because it leaks a reference. Convert the driver to use acpi_dev_get_first_match_dev() instead. Signed-off-by: Andy Shevchenko Acked-by: Pierre-Louis Bossart Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki (cherry picked from commit a320d89e67d6a08af18603b538021087a41bb182) --- sound/soc/intel/boards/bytcr_rt5640.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 940eb27158da7e..f9175cf6747ebb 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1154,7 +1154,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) struct byt_rt5640_private *priv; struct snd_soc_acpi_mach *mach; const char *platform_name; - const char *i2c_name = NULL; + struct acpi_device *adev; int ret_val = 0; int dai_index = 0; int i; @@ -1178,11 +1178,11 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) } /* fixup codec name based on HID */ - i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); - if (i2c_name) { + adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); + if (adev) { snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name), - "%s%s", "i2c-", i2c_name); - + "i2c-%s", acpi_dev_name(adev)); + put_device(&adev->dev); byt_rt5640_dais[dai_index].codec_name = byt_rt5640_codec_name; } From 4860845eec172d48e8782dbe3823b424007b3c74 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 28 Mar 2019 19:17:26 +0200 Subject: [PATCH 1293/1995] ASoC: Intel: bytcr_rt5651: Convert to use acpi_dev_get_first_match_dev() acpi_dev_get_first_match_name() is deprecated and going to be removed because it leaks a reference. Convert the driver to use acpi_dev_get_first_match_dev() instead. Signed-off-by: Andy Shevchenko Acked-by: Pierre-Louis Bossart Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki (cherry picked from commit 7075e9babb5db302907cf32b1db688eb83c85f77) --- sound/soc/intel/boards/bytcr_rt5651.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 4ed59f41ee8357..21c6675abd19af 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -885,8 +885,8 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) struct byt_rt5651_private *priv; struct snd_soc_acpi_mach *mach; const char *platform_name; + struct acpi_device *adev; struct device *codec_dev; - const char *i2c_name = NULL; const char *hp_swapped; bool is_bytcr = false; int ret_val = 0; @@ -912,14 +912,16 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) } /* fixup codec name based on HID */ - i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); - if (!i2c_name) { + adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); + if (adev) { + snprintf(byt_rt5651_codec_name, sizeof(byt_rt5651_codec_name), + "i2c-%s", acpi_dev_name(adev)); + put_device(&adev->dev); + byt_rt5651_dais[dai_index].codec_name = byt_rt5651_codec_name; + } else { dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); return -ENODEV; } - snprintf(byt_rt5651_codec_name, sizeof(byt_rt5651_codec_name), - "%s%s", "i2c-", i2c_name); - byt_rt5651_dais[dai_index].codec_name = byt_rt5651_codec_name; codec_dev = bus_find_device_by_name(&i2c_bus_type, NULL, byt_rt5651_codec_name); From 2716d1ed1aa03d19061b5e953ab5bd4ab9684788 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 28 Mar 2019 19:17:27 +0200 Subject: [PATCH 1294/1995] ASoC: Intel: cht_bsw_rt5645: Convert to use acpi_dev_get_first_match_dev() acpi_dev_get_first_match_name() is deprecated and going to be removed because it leaks a reference. Convert the driver to use acpi_dev_get_first_match_dev() instead. Signed-off-by: Andy Shevchenko Acked-by: Pierre-Louis Bossart Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki (cherry picked from commit fe4c283a79db91ac0d4402a363024789275c3fd1) --- sound/soc/intel/boards/cht_bsw_rt5645.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index cbc2d458483f3d..32dbeaf1ab9408 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -532,7 +532,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach; const char *platform_name; struct cht_mc_private *drv; - const char *i2c_name = NULL; + struct acpi_device *adev; bool found = false; bool is_bytcr = false; int dai_index = 0; @@ -573,10 +573,11 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } /* fixup codec name based on HID */ - i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); - if (i2c_name) { + adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); + if (adev) { snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name), - "%s%s", "i2c-", i2c_name); + "i2c-%s", acpi_dev_name(adev)); + put_device(&adev->dev); cht_dailink[dai_index].codec_name = cht_rt5645_codec_name; } From c1984359789c3dea39312d55d241d243c27a0204 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 28 Mar 2019 19:17:28 +0200 Subject: [PATCH 1295/1995] ASoC: Intel: cht_bsw_rt5672: Convert to use acpi_dev_get_first_match_dev() acpi_dev_get_first_match_name() is deprecated and going to be removed because it leaks a reference. Convert the driver to use acpi_dev_get_first_match_dev() instead. Signed-off-by: Andy Shevchenko Acked-by: Pierre-Louis Bossart Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki (cherry picked from commit b664e6fe2225972e0eb3df0bb8dbedd1a0fc641f) --- sound/soc/intel/boards/cht_bsw_rt5672.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 3d5a2b3a06f081..0f7770822388eb 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -401,7 +401,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) struct cht_mc_private *drv; struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; const char *platform_name; - const char *i2c_name; + struct acpi_device *adev; int i; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); @@ -411,10 +411,11 @@ static int snd_cht_mc_probe(struct platform_device *pdev) strcpy(drv->codec_name, RT5672_I2C_DEFAULT); /* fixup codec name based on HID */ - i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); - if (i2c_name) { + adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); + if (adev) { snprintf(drv->codec_name, sizeof(drv->codec_name), - "i2c-%s", i2c_name); + "i2c-%s", acpi_dev_name(adev)); + put_device(&adev->dev); for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { if (!strcmp(cht_dailink[i].codec_name, RT5672_I2C_DEFAULT)) { From f34e236d7a120fce880f85acae9f854854096fd1 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 1 Apr 2019 15:03:54 +0200 Subject: [PATCH 1296/1995] ASoC: dpcm: skip missing substream while applying symmetry If for any reason, the backend does not have the requested substream (like capture on a playback only backend), the BE will be skipped in dpcm_be_dai_startup(). However, dpcm_apply_symmetry() does not skip those BE and will dereference the be_substream (NULL) pointer anyway. Like in dpcm_be_dai_startup(), just skip those BE. Fixes: 906c7d690c3b ("ASoC: dpcm: Apply symmetry for DPCM") Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown (cherry picked from commit 6246f283d5e02ac757bd8d9bacde8fdc54c4582d) --- sound/soc/soc-pcm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 7fe5321000e877..2d5d5cac4ba602 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1911,10 +1911,15 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = snd_soc_dpcm_get_substream(be, stream); - struct snd_soc_pcm_runtime *rtd = be_substream->private_data; + struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai *codec_dai; int i; + /* A backend may not have the requested substream */ + if (!be_substream) + continue; + + rtd = be_substream->private_data; if (rtd->dai_link->be_hw_params_fixup) continue; From c6345e52ee215cf77fcb14d8970bcbfbd3a26bad Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 1 Mar 2019 19:08:53 -0600 Subject: [PATCH 1297/1995] ASoC: dapm: set power_check callback for widgets that shouldnt be always on Currently, buffers, schedulers, src's, encoders, decoders and effect type dapm widgets remain always on as their power_check method is not set. Setting this callback allows these widgets in the audio path to be powered managed properly. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 6e3bfcff191ec9476ca5ef9b2ad85a15ba829374) --- sound/soc/soc-dapm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 665a6b17281e25..65ee0bb5dd0bd2 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3650,6 +3650,13 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, case snd_soc_dapm_dac: case snd_soc_dapm_aif_in: case snd_soc_dapm_pga: + case snd_soc_dapm_buffer: + case snd_soc_dapm_scheduler: + case snd_soc_dapm_effect: + case snd_soc_dapm_src: + case snd_soc_dapm_asrc: + case snd_soc_dapm_encoder: + case snd_soc_dapm_decoder: case snd_soc_dapm_out_drv: case snd_soc_dapm_micbias: case snd_soc_dapm_line: From 13e09cd99b1f4748a92d67c47d82b983a155836c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Mar 2019 19:08:51 -0600 Subject: [PATCH 1298/1995] ASoC: core: support driver alias names for FE topology overrides When the same machine driver is reused between platforms but with a different alias, using the driver name is not enough. Add additional fallback case to use the card device name. Tested on GeminiLake with bxt_da7219_max98357a machine driver Suggested-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit e194098bf9098083f8ae9687924a6878540f8561) --- sound/soc/soc-core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d887576597290d..6f4842977b8d0d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1974,10 +1974,13 @@ static void soc_check_tplg_fes(struct snd_soc_card *card) continue; /* for this machine ? */ + if (!strcmp(component->driver->ignore_machine, + card->dev->driver->name)) + goto match; if (strcmp(component->driver->ignore_machine, - card->dev->driver->name)) + dev_name(card->dev))) continue; - +match: /* machine matches, so override the rtd data */ for_each_card_prelinks(card, i, dai_link) { From eb3f2b672baaaf32eeb6705fe5e3d496f1be0bee Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 1 Mar 2019 19:08:52 -0600 Subject: [PATCH 1299/1995] ASoC: topology: Align tplg pointer increment across all kcontrols This aligns all kcontrol tplg pointer increments to be consistent in the respective create methods and ensures that the position is pointing to the next widget rather the current invalid widget. Signed-off-by: Liam Girdwood Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 02b6424509e0c8a36d02b0ee36445be8d1fb128a) --- sound/soc/soc-topology.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index c6a30d000f59fe..472f7705da9368 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -996,8 +996,6 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, for (i = 0; i < count; i++) { ec = (struct snd_soc_tplg_enum_control *)tplg->pos; - tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + - ec->priv.size); /* validate kcontrol */ if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == @@ -1008,6 +1006,9 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, if (se == NULL) return -ENOMEM; + tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + + ec->priv.size); + dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n", ec->hdr.name, ec->items); @@ -1284,14 +1285,14 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( if (sm == NULL) goto err; - tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) + - mc->priv.size); - /* validate kcontrol */ if (strnlen(mc->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) goto err_str; + tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) + + mc->priv.size); + dev_dbg(tplg->dev, " adding DAPM widget mixer control %s at %d\n", mc->hdr.name, i); @@ -1377,6 +1378,9 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( if (se == NULL) goto err; + tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + + ec->priv.size); + dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n", ec->hdr.name); @@ -1441,9 +1445,6 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( ec->hdr.name); goto err_se; } - - tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + - ec->priv.size); } return kc; From 5855a986fd93a583b089d795e59e61e3c34e61ed Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 2 Apr 2019 12:20:49 +0200 Subject: [PATCH 1300/1995] ASoC: Intel: cht_bsw_max98090_ti: Enable codec clock once and keep it enabled Users have been seeing sound stability issues with max98090 codecs since: commit 648e921888ad ("clk: x86: Stop marking clocks as CLK_IS_CRITICAL") At first that commit broke sound for Chromebook Swanky and Clapper models, the problem was that the machine-driver has been controlling the wrong clock on those models since support for them was added. This was hidden by clk-pmc-atom.c keeping the actual clk on unconditionally. With the machine-driver controlling the proper clock, sound works again but we are seeing bug reports describing it as: low volume, "sounds like played at 10x speed" and instable. When these issues are hit the following message is seen in dmesg: "max98090 i2c-193C9890:00: PLL unlocked". Attempts have been made to fix this by inserting a delay between enabling the clk and enabling and checking the pll, but this has not helped. It seems that at least on boards which use pmc_plt_clk_0 as clock, if we ever disable the clk, the pll looses its lock and after that we get various issues. This commit fixes this by enabling the clock once at probe time on these boards. In essence this restores the old behavior of clk-pmc-atom.c always keeping the clk on on these boards. Fixes: 648e921888ad ("clk: x86: Stop marking clocks as CLK_IS_CRITICAL") Reported-by: Mogens Jensen Reported-by: Dean Wallace Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 4bcdec39c454c4e8f9512115bdcc3efec1ba5f55) --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 47 +++++++++++++++++--- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 3263b0495853c2..c0e0844f75b9fe 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -43,6 +43,7 @@ struct cht_mc_private { struct clk *mclk; struct snd_soc_jack jack; bool ts3a227e_present; + int quirks; }; static int platform_clock_control(struct snd_soc_dapm_widget *w, @@ -54,6 +55,10 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); int ret; + /* See the comment in snd_cht_mc_probe() */ + if (ctx->quirks & QUIRK_PMC_PLT_CLK_0) + return 0; + codec_dai = snd_soc_card_get_codec_dai(card, CHT_CODEC_DAI); if (!codec_dai) { dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n"); @@ -223,6 +228,10 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) "jack detection gpios not added, error %d\n", ret); } + /* See the comment in snd_cht_mc_probe() */ + if (ctx->quirks & QUIRK_PMC_PLT_CLK_0) + return 0; + /* * The firmware might enable the clock at * boot (this information may or may not @@ -423,16 +432,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev) const char *mclk_name; struct snd_soc_acpi_mach *mach; const char *platform_name; - int quirks = 0; - - dmi_id = dmi_first_match(cht_max98090_quirk_table); - if (dmi_id) - quirks = (unsigned long)dmi_id->driver_data; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); if (!drv) return -ENOMEM; + dmi_id = dmi_first_match(cht_max98090_quirk_table); + if (dmi_id) + drv->quirks = (unsigned long)dmi_id->driver_data; + drv->ts3a227e_present = acpi_dev_found("104C227E"); if (!drv->ts3a227e_present) { /* no need probe TI jack detection chip */ @@ -458,7 +466,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) snd_soc_card_cht.dev = &pdev->dev; snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); - if (quirks & QUIRK_PMC_PLT_CLK_0) + if (drv->quirks & QUIRK_PMC_PLT_CLK_0) mclk_name = "pmc_plt_clk_0"; else mclk_name = "pmc_plt_clk_3"; @@ -471,6 +479,21 @@ static int snd_cht_mc_probe(struct platform_device *pdev) return PTR_ERR(drv->mclk); } + /* + * Boards which have the MAX98090's clk connected to clk_0 do not seem + * to like it if we muck with the clock. If we disable the clock when + * it is unused we get "max98090 i2c-193C9890:00: PLL unlocked" errors + * and the PLL never seems to lock again. + * So for these boards we enable it here once and leave it at that. + */ + if (drv->quirks & QUIRK_PMC_PLT_CLK_0) { + ret_val = clk_prepare_enable(drv->mclk); + if (ret_val < 0) { + dev_err(&pdev->dev, "MCLK enable error: %d\n", ret_val); + return ret_val; + } + } + ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); if (ret_val) { dev_err(&pdev->dev, @@ -481,11 +504,23 @@ static int snd_cht_mc_probe(struct platform_device *pdev) return ret_val; } +static int snd_cht_mc_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); + + if (ctx->quirks & QUIRK_PMC_PLT_CLK_0) + clk_disable_unprepare(ctx->mclk); + + return 0; +} + static struct platform_driver snd_cht_mc_driver = { .driver = { .name = "cht-bsw-max98090", }, .probe = snd_cht_mc_probe, + .remove = snd_cht_mc_remove, }; module_platform_driver(snd_cht_mc_driver) From 9bcae15d746208128c8064e869076b3a6b93d737 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 4 Apr 2019 17:30:39 -0700 Subject: [PATCH 1301/1995] ASoC: intel: skylake: add remove() callback for component driver Topology is not unloaded in the core during unregister_component() anymore. So, add the remove() callback that will unload the topology. Signed-off-by: Ranjani Sridharan Signed-off-by: Mark Brown (cherry picked from commit 2e05ddd2c9f8000751d52fcf35b8318da46026bc) --- sound/soc/intel/skylake/skl-pcm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 56099db8f86ddf..57031b6d4d45e0 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1462,9 +1462,16 @@ static int skl_platform_soc_probe(struct snd_soc_component *component) return 0; } +static void skl_pcm_remove(struct snd_soc_component *component) +{ + /* remove topology */ + snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); +} + static const struct snd_soc_component_driver skl_component = { .name = "pcm", .probe = skl_platform_soc_probe, + .remove = skl_pcm_remove, .ops = &skl_platform_ops, .pcm_new = skl_pcm_new, .pcm_free = skl_pcm_free, From 2e96f98389b7f0319a4786a66448a3f47ccd2b3d Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 4 Apr 2019 17:30:40 -0700 Subject: [PATCH 1302/1995] ASoC: core: remove link components before cleaning up card resources When the card is registered by the machine driver, dai link components are probed after the snd_card is created. This is done in snd_soc_bind_card() which calls snd_soc_instantiate_card() to first create the snd_card and then probes the link components by calling soc_probe_link_components(). The snd_card is used by the component driver to add the kcontrols associated with dapm widgets to the card. When the machine driver is unregistered, the snd_card is freed when the card resources are cleaned up. But the snd_card needs to be valid while unloading the topology dapm widgets in order to remove the kcontrols from the card. Since, unloading topology is done when the component driver is removed, the link components should be removed in snd_soc_unbind_card(). This will ensure that the kcontrols are removed before the card resources are cleaned up and the snd_card itself is freed. Signed-off-by: Ranjani Sridharan Signed-off-by: Mark Brown (cherry picked from commit f96fb7d198ca624fe33c4145a004eb5a3d0eddec) --- sound/soc/soc-core.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6f4842977b8d0d..75f6a8085a766f 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2831,10 +2831,21 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card); static void snd_soc_unbind_card(struct snd_soc_card *card, bool unregister) { + struct snd_soc_pcm_runtime *rtd; + int order; + if (card->instantiated) { card->instantiated = false; snd_soc_dapm_shutdown(card); snd_soc_flush_all_delayed_work(card); + + /* remove all components used by DAI links on this card */ + for_each_comp_order(order) { + for_each_card_rtds(card, rtd) { + soc_remove_link_components(card, rtd, order); + } + } + soc_cleanup_card_resources(card); if (!unregister) list_add(&card->list, &unbind_card_list); From b0ce1f29f129915ffd9f00b98aa90249aa5f6626 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Apr 2019 14:13:57 -0500 Subject: [PATCH 1303/1995] ASoC: topology: fix endianness issues Use le16/32/64_to_cpu() as needed to make Sparse happy. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 5aebe7c7f9c20ef225c0c3a25c06a20c3938e390) --- sound/soc/soc-topology.c | 291 +++++++++++++++++++++++---------------- 1 file changed, 170 insertions(+), 121 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 472f7705da9368..03c4dbdfc58400 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -197,8 +197,8 @@ static int tplc_chan_get_reg(struct soc_tplg *tplg, int i; for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) { - if (chan[i].id == map) - return chan[i].reg; + if (le32_to_cpu(chan[i].id) == map) + return le32_to_cpu(chan[i].reg); } return -EINVAL; @@ -210,8 +210,8 @@ static int tplc_chan_get_shift(struct soc_tplg *tplg, int i; for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) { - if (chan[i].id == map) - return chan[i].shift; + if (le32_to_cpu(chan[i].id) == map) + return le32_to_cpu(chan[i].shift); } return -EINVAL; @@ -592,7 +592,7 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr, const struct snd_soc_tplg_bytes_ext_ops *ext_ops; int num_ops, i; - if (hdr->ops.info == SND_SOC_TPLG_CTL_BYTES + if (le32_to_cpu(hdr->ops.info) == SND_SOC_TPLG_CTL_BYTES && k->iface & SNDRV_CTL_ELEM_IFACE_MIXER && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE && k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { @@ -708,9 +708,9 @@ static int soc_tplg_create_tlv_db_scale(struct soc_tplg *tplg, p[0] = SNDRV_CTL_TLVT_DB_SCALE; p[1] = item_len; - p[2] = scale->min; - p[3] = (scale->step & TLV_DB_SCALE_MASK) - | (scale->mute ? TLV_DB_SCALE_MUTE : 0); + p[2] = le32_to_cpu(scale->min); + p[3] = (le32_to_cpu(scale->step) & TLV_DB_SCALE_MASK) + | (le32_to_cpu(scale->mute) ? TLV_DB_SCALE_MUTE : 0); kc->tlv.p = (void *)p; return 0; @@ -720,13 +720,14 @@ static int soc_tplg_create_tlv(struct soc_tplg *tplg, struct snd_kcontrol_new *kc, struct snd_soc_tplg_ctl_hdr *tc) { struct snd_soc_tplg_ctl_tlv *tplg_tlv; + u32 access = le32_to_cpu(tc->access); - if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)) + if (!(access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)) return 0; - if (!(tc->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) { + if (!(access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) { tplg_tlv = &tc->tlv; - switch (tplg_tlv->type) { + switch (le32_to_cpu(tplg_tlv->type)) { case SNDRV_CTL_TLVT_DB_SCALE: return soc_tplg_create_tlv_db_scale(tplg, kc, &tplg_tlv->scale); @@ -777,7 +778,7 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count, return -ENOMEM; tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + - be->priv.size); + le32_to_cpu(be->priv.size)); dev_dbg(tplg->dev, "ASoC: adding bytes kcontrol %s with access 0x%x\n", @@ -787,9 +788,9 @@ static int soc_tplg_dbytes_create(struct soc_tplg *tplg, unsigned int count, kc.name = be->hdr.name; kc.private_value = (long)sbe; kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc.access = be->hdr.access; + kc.access = le32_to_cpu(be->hdr.access); - sbe->max = be->max; + sbe->max = le32_to_cpu(be->max); sbe->dobj.type = SND_SOC_DOBJ_BYTES; sbe->dobj.ops = tplg->ops; INIT_LIST_HEAD(&sbe->dobj.list); @@ -857,7 +858,7 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, if (sm == NULL) return -ENOMEM; tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) + - mc->priv.size); + le32_to_cpu(mc->priv.size)); dev_dbg(tplg->dev, "ASoC: adding mixer kcontrol %s with access 0x%x\n", @@ -867,7 +868,7 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, kc.name = mc->hdr.name; kc.private_value = (long)sm; kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc.access = mc->hdr.access; + kc.access = le32_to_cpu(mc->hdr.access); /* we only support FL/FR channel mapping atm */ sm->reg = tplc_chan_get_reg(tplg, mc->channel, @@ -879,10 +880,10 @@ static int soc_tplg_dmixer_create(struct soc_tplg *tplg, unsigned int count, sm->rshift = tplc_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FR); - sm->max = mc->max; - sm->min = mc->min; - sm->invert = mc->invert; - sm->platform_max = mc->platform_max; + sm->max = le32_to_cpu(mc->max); + sm->min = le32_to_cpu(mc->min); + sm->invert = le32_to_cpu(mc->invert); + sm->platform_max = le32_to_cpu(mc->platform_max); sm->dobj.index = tplg->index; sm->dobj.ops = tplg->ops; sm->dobj.type = SND_SOC_DOBJ_MIXER; @@ -933,7 +934,7 @@ static int soc_tplg_denum_create_texts(struct soc_enum *se, int i, ret; se->dobj.control.dtexts = - kcalloc(ec->items, sizeof(char *), GFP_KERNEL); + kcalloc(le32_to_cpu(ec->items), sizeof(char *), GFP_KERNEL); if (se->dobj.control.dtexts == NULL) return -ENOMEM; @@ -965,15 +966,22 @@ static int soc_tplg_denum_create_texts(struct soc_enum *se, static int soc_tplg_denum_create_values(struct soc_enum *se, struct snd_soc_tplg_enum_control *ec) { - if (ec->items > sizeof(*ec->values)) + int i; + + if (le32_to_cpu(ec->items) > sizeof(*ec->values)) return -EINVAL; - se->dobj.control.dvalues = kmemdup(ec->values, - ec->items * sizeof(u32), + se->dobj.control.dvalues = kzalloc(le32_to_cpu(ec->items) * + sizeof(u32), GFP_KERNEL); if (!se->dobj.control.dvalues) return -ENOMEM; + /* convert from little-endian */ + for (i = 0; i < le32_to_cpu(ec->items); i++) { + se->dobj.control.dvalues[i] = le32_to_cpu(ec->values[i]); + } + return 0; } @@ -1007,7 +1015,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, return -ENOMEM; tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + - ec->priv.size); + le32_to_cpu(ec->priv.size)); dev_dbg(tplg->dev, "ASoC: adding enum kcontrol %s size %d\n", ec->hdr.name, ec->items); @@ -1016,7 +1024,7 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, kc.name = ec->hdr.name; kc.private_value = (long)se; kc.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc.access = ec->hdr.access; + kc.access = le32_to_cpu(ec->hdr.access); se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); se->shift_l = tplc_chan_get_shift(tplg, ec->channel, @@ -1024,14 +1032,14 @@ static int soc_tplg_denum_create(struct soc_tplg *tplg, unsigned int count, se->shift_r = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FL); - se->items = ec->items; - se->mask = ec->mask; + se->items = le32_to_cpu(ec->items); + se->mask = le32_to_cpu(ec->mask); se->dobj.index = tplg->index; se->dobj.type = SND_SOC_DOBJ_ENUM; se->dobj.ops = tplg->ops; INIT_LIST_HEAD(&se->dobj.list); - switch (ec->hdr.ops.info) { + switch (le32_to_cpu(ec->hdr.ops.info)) { case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: case SND_SOC_TPLG_CTL_ENUM_VALUE: err = soc_tplg_denum_create_values(se, ec); @@ -1104,23 +1112,24 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg, int i; if (tplg->pass != SOC_TPLG_PASS_MIXER) { - tplg->pos += hdr->size + hdr->payload_size; + tplg->pos += le32_to_cpu(hdr->size) + + le32_to_cpu(hdr->payload_size); return 0; } dev_dbg(tplg->dev, "ASoC: adding %d kcontrols at 0x%lx\n", hdr->count, soc_tplg_get_offset(tplg)); - for (i = 0; i < hdr->count; i++) { + for (i = 0; i < le32_to_cpu(hdr->count); i++) { control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos; - if (control_hdr->size != sizeof(*control_hdr)) { + if (le32_to_cpu(control_hdr->size) != sizeof(*control_hdr)) { dev_err(tplg->dev, "ASoC: invalid control size\n"); return -EINVAL; } - switch (control_hdr->ops.info) { + switch (le32_to_cpu(control_hdr->ops.info)) { case SND_SOC_TPLG_CTL_VOLSW: case SND_SOC_TPLG_CTL_STROBE: case SND_SOC_TPLG_CTL_VOLSW_SX: @@ -1128,17 +1137,20 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg, case SND_SOC_TPLG_CTL_RANGE: case SND_SOC_TPLG_DAPM_CTL_VOLSW: case SND_SOC_TPLG_DAPM_CTL_PIN: - soc_tplg_dmixer_create(tplg, 1, hdr->payload_size); + soc_tplg_dmixer_create(tplg, 1, + le32_to_cpu(hdr->payload_size)); break; case SND_SOC_TPLG_CTL_ENUM: case SND_SOC_TPLG_CTL_ENUM_VALUE: case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: - soc_tplg_denum_create(tplg, 1, hdr->payload_size); + soc_tplg_denum_create(tplg, 1, + le32_to_cpu(hdr->payload_size)); break; case SND_SOC_TPLG_CTL_BYTES: - soc_tplg_dbytes_create(tplg, 1, hdr->payload_size); + soc_tplg_dbytes_create(tplg, 1, + le32_to_cpu(hdr->payload_size)); break; default: soc_bind_err(tplg, control_hdr, i); @@ -1166,17 +1178,22 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg, struct snd_soc_dapm_context *dapm = &tplg->comp->dapm; struct snd_soc_tplg_dapm_graph_elem *elem; struct snd_soc_dapm_route **routes; - int count = hdr->count, i, j; + int count, i, j; int ret = 0; + count = le32_to_cpu(hdr->count); + if (tplg->pass != SOC_TPLG_PASS_GRAPH) { - tplg->pos += hdr->size + hdr->payload_size; + tplg->pos += + le32_to_cpu(hdr->size) + + le32_to_cpu(hdr->payload_size); + return 0; } if (soc_tplg_check_elem_count(tplg, sizeof(struct snd_soc_tplg_dapm_graph_elem), - count, hdr->payload_size, "graph")) { + count, le32_to_cpu(hdr->payload_size), "graph")) { dev_err(tplg->dev, "ASoC: invalid count %d for DAPM routes\n", count); @@ -1291,7 +1308,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dmixer_create( goto err_str; tplg->pos += (sizeof(struct snd_soc_tplg_mixer_control) + - mc->priv.size); + le32_to_cpu(mc->priv.size)); dev_dbg(tplg->dev, " adding DAPM widget mixer control %s at %d\n", mc->hdr.name, i); @@ -1404,7 +1421,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( se->mask = ec->mask; se->dobj.index = tplg->index; - switch (ec->hdr.ops.info) { + switch (le32_to_cpu(ec->hdr.ops.info)) { case SND_SOC_TPLG_CTL_ENUM_VALUE: case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: err = soc_tplg_denum_create_values(se, ec); @@ -1495,7 +1512,7 @@ static struct snd_kcontrol_new *soc_tplg_dapm_widget_dbytes_create( goto err; tplg->pos += (sizeof(struct snd_soc_tplg_bytes_control) + - be->priv.size); + le32_to_cpu(be->priv.size)); dev_dbg(tplg->dev, "ASoC: adding bytes kcontrol %s with access 0x%x\n", @@ -1567,7 +1584,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, memset(&template, 0, sizeof(template)); /* map user to kernel widget ID */ - template.id = get_widget_id(w->id); + template.id = get_widget_id(le32_to_cpu(w->id)); if (template.id < 0) return template.id; @@ -1580,18 +1597,20 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, ret = -ENOMEM; goto err; } - template.reg = w->reg; - template.shift = w->shift; - template.mask = w->mask; - template.subseq = w->subseq; + template.reg = le32_to_cpu(w->reg); + template.shift = le32_to_cpu(w->shift); + template.mask = le32_to_cpu(w->mask); + template.subseq = le32_to_cpu(w->subseq); template.on_val = w->invert ? 0 : 1; template.off_val = w->invert ? 1 : 0; - template.ignore_suspend = w->ignore_suspend; - template.event_flags = w->event_flags; + template.ignore_suspend = le32_to_cpu(w->ignore_suspend); + template.event_flags = le16_to_cpu(w->event_flags); template.dobj.index = tplg->index; tplg->pos += - (sizeof(struct snd_soc_tplg_dapm_widget) + w->priv.size); + (sizeof(struct snd_soc_tplg_dapm_widget) + + le32_to_cpu(w->priv.size)); + if (w->num_kcontrols == 0) { kcontrol_type = 0; template.num_kcontrols = 0; @@ -1602,7 +1621,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, dev_dbg(tplg->dev, "ASoC: template %s has %d controls of type %x\n", w->name, w->num_kcontrols, control_hdr->type); - switch (control_hdr->ops.info) { + switch (le32_to_cpu(control_hdr->ops.info)) { case SND_SOC_TPLG_CTL_VOLSW: case SND_SOC_TPLG_CTL_STROBE: case SND_SOC_TPLG_CTL_VOLSW_SX: @@ -1610,7 +1629,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, case SND_SOC_TPLG_CTL_RANGE: case SND_SOC_TPLG_DAPM_CTL_VOLSW: kcontrol_type = SND_SOC_TPLG_TYPE_MIXER; /* volume mixer */ - template.num_kcontrols = w->num_kcontrols; + template.num_kcontrols = le32_to_cpu(w->num_kcontrols); template.kcontrol_news = soc_tplg_dapm_widget_dmixer_create(tplg, template.num_kcontrols); @@ -1625,7 +1644,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: kcontrol_type = SND_SOC_TPLG_TYPE_ENUM; /* enumerated mixer */ - template.num_kcontrols = w->num_kcontrols; + template.num_kcontrols = le32_to_cpu(w->num_kcontrols); template.kcontrol_news = soc_tplg_dapm_widget_denum_create(tplg, template.num_kcontrols); @@ -1636,7 +1655,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, break; case SND_SOC_TPLG_CTL_BYTES: kcontrol_type = SND_SOC_TPLG_TYPE_BYTES; /* bytes control */ - template.num_kcontrols = w->num_kcontrols; + template.num_kcontrols = le32_to_cpu(w->num_kcontrols); template.kcontrol_news = soc_tplg_dapm_widget_dbytes_create(tplg, template.num_kcontrols); @@ -1648,7 +1667,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, default: dev_err(tplg->dev, "ASoC: invalid widget control type %d:%d:%d\n", control_hdr->ops.get, control_hdr->ops.put, - control_hdr->ops.info); + le32_to_cpu(control_hdr->ops.info)); ret = -EINVAL; goto hdr_err; } @@ -1698,7 +1717,9 @@ static int soc_tplg_dapm_widget_elems_load(struct soc_tplg *tplg, struct snd_soc_tplg_hdr *hdr) { struct snd_soc_tplg_dapm_widget *widget; - int ret, count = hdr->count, i; + int ret, count, i; + + count = le32_to_cpu(hdr->count); if (tplg->pass != SOC_TPLG_PASS_WIDGET) return 0; @@ -1707,7 +1728,7 @@ static int soc_tplg_dapm_widget_elems_load(struct soc_tplg *tplg, for (i = 0; i < count; i++) { widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos; - if (widget->size != sizeof(*widget)) { + if (le32_to_cpu(widget->size) != sizeof(*widget)) { dev_err(tplg->dev, "ASoC: invalid widget size\n"); return -EINVAL; } @@ -1749,13 +1770,13 @@ static void set_stream_info(struct snd_soc_pcm_stream *stream, struct snd_soc_tplg_stream_caps *caps) { stream->stream_name = kstrdup(caps->name, GFP_KERNEL); - stream->channels_min = caps->channels_min; - stream->channels_max = caps->channels_max; - stream->rates = caps->rates; - stream->rate_min = caps->rate_min; - stream->rate_max = caps->rate_max; - stream->formats = caps->formats; - stream->sig_bits = caps->sig_bits; + stream->channels_min = le32_to_cpu(caps->channels_min); + stream->channels_max = le32_to_cpu(caps->channels_max); + stream->rates = le32_to_cpu(caps->rates); + stream->rate_min = le32_to_cpu(caps->rate_min); + stream->rate_max = le32_to_cpu(caps->rate_max); + stream->formats = le64_to_cpu(caps->formats); + stream->sig_bits = le32_to_cpu(caps->sig_bits); } static void set_dai_flags(struct snd_soc_dai_driver *dai_drv, @@ -1790,7 +1811,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, if (strlen(pcm->dai_name)) dai_drv->name = kstrdup(pcm->dai_name, GFP_KERNEL); - dai_drv->id = pcm->dai_id; + dai_drv->id = le32_to_cpu(pcm->dai_id); if (pcm->playback) { stream = &dai_drv->playback; @@ -1865,7 +1886,7 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, link->name = kstrdup(pcm->pcm_name, GFP_KERNEL); link->stream_name = kstrdup(pcm->pcm_name, GFP_KERNEL); } - link->id = pcm->pcm_id; + link->id = le32_to_cpu(pcm->pcm_id); if (strlen(pcm->dai_name)) link->cpu_dai_name = kstrdup(pcm->dai_name, GFP_KERNEL); @@ -1875,10 +1896,12 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, /* enable DPCM */ link->dynamic = 1; - link->dpcm_playback = pcm->playback; - link->dpcm_capture = pcm->capture; + link->dpcm_playback = le32_to_cpu(pcm->playback); + link->dpcm_capture = le32_to_cpu(pcm->capture); if (pcm->flag_mask) - set_link_flags(link, pcm->flag_mask, pcm->flags); + set_link_flags(link, + le32_to_cpu(pcm->flag_mask), + le32_to_cpu(pcm->flags)); /* pass control to component driver for optional further init */ ret = soc_tplg_dai_link_load(tplg, link, NULL); @@ -1917,7 +1940,7 @@ static int soc_tplg_pcm_create(struct soc_tplg *tplg, static void stream_caps_new_ver(struct snd_soc_tplg_stream_caps *dest, struct snd_soc_tplg_stream_caps_v4 *src) { - dest->size = sizeof(*dest); + dest->size = cpu_to_le32(sizeof(*dest)); memcpy(dest->name, src->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); dest->formats = src->formats; dest->rates = src->rates; @@ -1951,7 +1974,7 @@ static int pcm_new_ver(struct soc_tplg *tplg, *pcm = NULL; - if (src->size != sizeof(*src_v4)) { + if (le32_to_cpu(src->size) != sizeof(*src_v4)) { dev_err(tplg->dev, "ASoC: invalid PCM size\n"); return -EINVAL; } @@ -1962,7 +1985,7 @@ static int pcm_new_ver(struct soc_tplg *tplg, if (!dest) return -ENOMEM; - dest->size = sizeof(*dest); /* size of latest abi version */ + dest->size = cpu_to_le32(sizeof(*dest)); /* size of latest abi version */ memcpy(dest->pcm_name, src_v4->pcm_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); memcpy(dest->dai_name, src_v4->dai_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); dest->pcm_id = src_v4->pcm_id; @@ -1971,7 +1994,7 @@ static int pcm_new_ver(struct soc_tplg *tplg, dest->capture = src_v4->capture; dest->compress = src_v4->compress; dest->num_streams = src_v4->num_streams; - for (i = 0; i < dest->num_streams; i++) + for (i = 0; i < le32_to_cpu(dest->num_streams); i++) memcpy(&dest->stream[i], &src_v4->stream[i], sizeof(struct snd_soc_tplg_stream)); @@ -1986,25 +2009,30 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, struct snd_soc_tplg_hdr *hdr) { struct snd_soc_tplg_pcm *pcm, *_pcm; - int count = hdr->count; + int count; + int size; int i; bool abi_match; + count = le32_to_cpu(hdr->count); + if (tplg->pass != SOC_TPLG_PASS_PCM_DAI) return 0; /* check the element size and count */ pcm = (struct snd_soc_tplg_pcm *)tplg->pos; - if (pcm->size > sizeof(struct snd_soc_tplg_pcm) - || pcm->size < sizeof(struct snd_soc_tplg_pcm_v4)) { + size = le32_to_cpu(pcm->size); + if (size > sizeof(struct snd_soc_tplg_pcm) + || size < sizeof(struct snd_soc_tplg_pcm_v4)) { dev_err(tplg->dev, "ASoC: invalid size %d for PCM elems\n", - pcm->size); + size); return -EINVAL; } if (soc_tplg_check_elem_count(tplg, - pcm->size, count, - hdr->payload_size, "PCM DAI")) { + size, count, + le32_to_cpu(hdr->payload_size), + "PCM DAI")) { dev_err(tplg->dev, "ASoC: invalid count %d for PCM DAI elems\n", count); return -EINVAL; @@ -2012,11 +2040,12 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, for (i = 0; i < count; i++) { pcm = (struct snd_soc_tplg_pcm *)tplg->pos; + size = le32_to_cpu(pcm->size); /* check ABI version by size, create a new version of pcm * if abi not match. */ - if (pcm->size == sizeof(*pcm)) { + if (size == sizeof(*pcm)) { abi_match = true; _pcm = pcm; } else { @@ -2030,7 +2059,7 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, /* offset by version-specific struct size and * real priv data size */ - tplg->pos += pcm->size + _pcm->priv.size; + tplg->pos += size + le32_to_cpu(_pcm->priv.size); if (!abi_match) kfree(_pcm); /* free the duplicated one */ @@ -2058,12 +2087,13 @@ static void set_link_hw_format(struct snd_soc_dai_link *link, unsigned char invert_bclk, invert_fsync; int i; - for (i = 0; i < cfg->num_hw_configs; i++) { + for (i = 0; i < le32_to_cpu(cfg->num_hw_configs); i++) { hw_config = &cfg->hw_config[i]; if (hw_config->id != cfg->default_hw_config_id) continue; - link->dai_fmt = hw_config->fmt & SND_SOC_DAIFMT_FORMAT_MASK; + link->dai_fmt = le32_to_cpu(hw_config->fmt) & + SND_SOC_DAIFMT_FORMAT_MASK; /* clock gating */ switch (hw_config->clock_gated) { @@ -2127,7 +2157,8 @@ static int link_new_ver(struct soc_tplg *tplg, *link = NULL; - if (src->size != sizeof(struct snd_soc_tplg_link_config_v4)) { + if (le32_to_cpu(src->size) != + sizeof(struct snd_soc_tplg_link_config_v4)) { dev_err(tplg->dev, "ASoC: invalid physical link config size\n"); return -EINVAL; } @@ -2139,10 +2170,10 @@ static int link_new_ver(struct soc_tplg *tplg, if (!dest) return -ENOMEM; - dest->size = sizeof(*dest); + dest->size = cpu_to_le32(sizeof(*dest)); dest->id = src_v4->id; dest->num_streams = src_v4->num_streams; - for (i = 0; i < dest->num_streams; i++) + for (i = 0; i < le32_to_cpu(dest->num_streams); i++) memcpy(&dest->stream[i], &src_v4->stream[i], sizeof(struct snd_soc_tplg_stream)); @@ -2175,7 +2206,7 @@ static int soc_tplg_link_config(struct soc_tplg *tplg, else stream_name = NULL; - link = snd_soc_find_dai_link(tplg->comp->card, cfg->id, + link = snd_soc_find_dai_link(tplg->comp->card, le32_to_cpu(cfg->id), name, stream_name); if (!link) { dev_err(tplg->dev, "ASoC: physical link %s (id %d) not exist\n", @@ -2189,7 +2220,9 @@ static int soc_tplg_link_config(struct soc_tplg *tplg, /* flags */ if (cfg->flag_mask) - set_link_flags(link, cfg->flag_mask, cfg->flags); + set_link_flags(link, + le32_to_cpu(cfg->flag_mask), + le32_to_cpu(cfg->flags)); /* pass control to component driver for optional further init */ ret = soc_tplg_dai_link_load(tplg, link, cfg); @@ -2213,27 +2246,33 @@ static int soc_tplg_link_elems_load(struct soc_tplg *tplg, struct snd_soc_tplg_hdr *hdr) { struct snd_soc_tplg_link_config *link, *_link; - int count = hdr->count; + int count; + int size; int i, ret; bool abi_match; + count = le32_to_cpu(hdr->count); + if (tplg->pass != SOC_TPLG_PASS_LINK) { - tplg->pos += hdr->size + hdr->payload_size; + tplg->pos += le32_to_cpu(hdr->size) + + le32_to_cpu(hdr->payload_size); return 0; }; /* check the element size and count */ link = (struct snd_soc_tplg_link_config *)tplg->pos; - if (link->size > sizeof(struct snd_soc_tplg_link_config) - || link->size < sizeof(struct snd_soc_tplg_link_config_v4)) { + size = le32_to_cpu(link->size); + if (size > sizeof(struct snd_soc_tplg_link_config) + || size < sizeof(struct snd_soc_tplg_link_config_v4)) { dev_err(tplg->dev, "ASoC: invalid size %d for physical link elems\n", - link->size); + size); return -EINVAL; } if (soc_tplg_check_elem_count(tplg, - link->size, count, - hdr->payload_size, "physical link config")) { + size, count, + le32_to_cpu(hdr->payload_size), + "physical link config")) { dev_err(tplg->dev, "ASoC: invalid count %d for physical link elems\n", count); return -EINVAL; @@ -2242,7 +2281,8 @@ static int soc_tplg_link_elems_load(struct soc_tplg *tplg, /* config physical DAI links */ for (i = 0; i < count; i++) { link = (struct snd_soc_tplg_link_config *)tplg->pos; - if (link->size == sizeof(*link)) { + size = le32_to_cpu(link->size); + if (size == sizeof(*link)) { abi_match = true; _link = link; } else { @@ -2259,7 +2299,7 @@ static int soc_tplg_link_elems_load(struct soc_tplg *tplg, /* offset by version-specific struct size and * real priv data size */ - tplg->pos += link->size + _link->priv.size; + tplg->pos += size + le32_to_cpu(_link->priv.size); if (!abi_match) kfree(_link); /* free the duplicated one */ @@ -2279,13 +2319,15 @@ static int soc_tplg_link_elems_load(struct soc_tplg *tplg, static int soc_tplg_dai_config(struct soc_tplg *tplg, struct snd_soc_tplg_dai *d) { - struct snd_soc_dai_link_component dai_component = {0}; + struct snd_soc_dai_link_component dai_component; struct snd_soc_dai *dai; struct snd_soc_dai_driver *dai_drv; struct snd_soc_pcm_stream *stream; struct snd_soc_tplg_stream_caps *caps; int ret; + memset(&dai_component, 0, sizeof(dai_component)); + dai_component.dai_name = d->dai_name; dai = snd_soc_find_dai(&dai_component); if (!dai) { @@ -2294,7 +2336,7 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg, return -EINVAL; } - if (d->dai_id != dai->id) { + if (le32_to_cpu(d->dai_id) != dai->id) { dev_err(tplg->dev, "ASoC: physical DAI %s id mismatch\n", d->dai_name); return -EINVAL; @@ -2317,7 +2359,9 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg, } if (d->flag_mask) - set_dai_flags(dai_drv, d->flag_mask, d->flags); + set_dai_flags(dai_drv, + le32_to_cpu(d->flag_mask), + le32_to_cpu(d->flags)); /* pass control to component driver for optional further init */ ret = soc_tplg_dai_load(tplg, dai_drv, NULL, dai); @@ -2334,22 +2378,24 @@ static int soc_tplg_dai_elems_load(struct soc_tplg *tplg, struct snd_soc_tplg_hdr *hdr) { struct snd_soc_tplg_dai *dai; - int count = hdr->count; + int count; int i; + count = le32_to_cpu(hdr->count); + if (tplg->pass != SOC_TPLG_PASS_BE_DAI) return 0; /* config the existing BE DAIs */ for (i = 0; i < count; i++) { dai = (struct snd_soc_tplg_dai *)tplg->pos; - if (dai->size != sizeof(*dai)) { + if (le32_to_cpu(dai->size) != sizeof(*dai)) { dev_err(tplg->dev, "ASoC: invalid physical DAI size\n"); return -EINVAL; } soc_tplg_dai_config(tplg, dai); - tplg->pos += (sizeof(*dai) + dai->priv.size); + tplg->pos += (sizeof(*dai) + le32_to_cpu(dai->priv.size)); } dev_dbg(tplg->dev, "ASoC: Configure %d BE DAIs\n", count); @@ -2371,25 +2417,28 @@ static int manifest_new_ver(struct soc_tplg *tplg, { struct snd_soc_tplg_manifest *dest; struct snd_soc_tplg_manifest_v4 *src_v4; + int size; *manifest = NULL; - if (src->size != sizeof(*src_v4)) { + size = le32_to_cpu(src->size); + if (size != sizeof(*src_v4)) { dev_warn(tplg->dev, "ASoC: invalid manifest size %d\n", - src->size); - if (src->size) + size); + if (size) return -EINVAL; - src->size = sizeof(*src_v4); + src->size = cpu_to_le32(sizeof(*src_v4)); } dev_warn(tplg->dev, "ASoC: old version of manifest\n"); src_v4 = (struct snd_soc_tplg_manifest_v4 *)src; - dest = kzalloc(sizeof(*dest) + src_v4->priv.size, GFP_KERNEL); + dest = kzalloc(sizeof(*dest) + le32_to_cpu(src_v4->priv.size), + GFP_KERNEL); if (!dest) return -ENOMEM; - dest->size = sizeof(*dest); /* size of latest abi version */ + dest->size = cpu_to_le32(sizeof(*dest)); /* size of latest abi version */ dest->control_elems = src_v4->control_elems; dest->widget_elems = src_v4->widget_elems; dest->graph_elems = src_v4->graph_elems; @@ -2398,7 +2447,7 @@ static int manifest_new_ver(struct soc_tplg *tplg, dest->priv.size = src_v4->priv.size; if (dest->priv.size) memcpy(dest->priv.data, src_v4->priv.data, - src_v4->priv.size); + le32_to_cpu(src_v4->priv.size)); *manifest = dest; return 0; @@ -2417,7 +2466,7 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg, manifest = (struct snd_soc_tplg_manifest *)tplg->pos; /* check ABI version by size, create a new manifest if abi not match */ - if (manifest->size == sizeof(*manifest)) { + if (le32_to_cpu(manifest->size) == sizeof(*manifest)) { abi_match = true; _manifest = manifest; } else { @@ -2444,10 +2493,10 @@ static int soc_valid_header(struct soc_tplg *tplg, if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size) return 0; - if (hdr->size != sizeof(*hdr)) { + if (le32_to_cpu(hdr->size) != sizeof(*hdr)) { dev_err(tplg->dev, "ASoC: invalid header size for type %d at offset 0x%lx size 0x%zx.\n", - hdr->type, soc_tplg_get_hdr_offset(tplg), + le32_to_cpu(hdr->type), soc_tplg_get_hdr_offset(tplg), tplg->fw->size); return -EINVAL; } @@ -2461,7 +2510,7 @@ static int soc_valid_header(struct soc_tplg *tplg, return -EINVAL; } - if (hdr->magic != SND_SOC_TPLG_MAGIC) { + if (le32_to_cpu(hdr->magic) != SND_SOC_TPLG_MAGIC) { dev_err(tplg->dev, "ASoC: pass %d does not have a valid header got %x at offset 0x%lx size 0x%zx.\n", tplg->pass, hdr->magic, @@ -2470,8 +2519,8 @@ static int soc_valid_header(struct soc_tplg *tplg, } /* Support ABI from version 4 */ - if (hdr->abi > SND_SOC_TPLG_ABI_VERSION - || hdr->abi < SND_SOC_TPLG_ABI_VERSION_MIN) { + if (le32_to_cpu(hdr->abi) > SND_SOC_TPLG_ABI_VERSION || + le32_to_cpu(hdr->abi) < SND_SOC_TPLG_ABI_VERSION_MIN) { dev_err(tplg->dev, "ASoC: pass %d invalid ABI version got 0x%x need 0x%x at offset 0x%lx size 0x%zx.\n", tplg->pass, hdr->abi, @@ -2486,7 +2535,7 @@ static int soc_valid_header(struct soc_tplg *tplg, return -EINVAL; } - if (tplg->pass == hdr->type) + if (tplg->pass == le32_to_cpu(hdr->type)) dev_dbg(tplg->dev, "ASoC: Got 0x%x bytes of type %d version %d vendor %d at pass %d\n", hdr->payload_size, hdr->type, hdr->version, @@ -2502,13 +2551,13 @@ static int soc_tplg_load_header(struct soc_tplg *tplg, tplg->pos = tplg->hdr_pos + sizeof(struct snd_soc_tplg_hdr); /* check for matching ID */ - if (hdr->index != tplg->req_index && + if (le32_to_cpu(hdr->index) != tplg->req_index && tplg->req_index != SND_SOC_TPLG_INDEX_ALL) return 0; - tplg->index = hdr->index; + tplg->index = le32_to_cpu(hdr->index); - switch (hdr->type) { + switch (le32_to_cpu(hdr->type)) { case SND_SOC_TPLG_TYPE_MIXER: case SND_SOC_TPLG_TYPE_ENUM: case SND_SOC_TPLG_TYPE_BYTES: @@ -2564,7 +2613,7 @@ static int soc_tplg_process_headers(struct soc_tplg *tplg) return ret; /* goto next header */ - tplg->hdr_pos += hdr->payload_size + + tplg->hdr_pos += le32_to_cpu(hdr->payload_size) + sizeof(struct snd_soc_tplg_hdr); hdr = (struct snd_soc_tplg_hdr *)tplg->hdr_pos; } From fde490498d48366a17efd1fd2909b4c5a1112f79 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Apr 2019 14:13:58 -0500 Subject: [PATCH 1304/1995] ASoC: topology: fix big-endian check Use an explicit define to avoid Sparse issues coming from the use of cpu_to_be32 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 2114171d9cce1a897bee394b06f6c224247f095c) --- sound/soc/soc-topology.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 03c4dbdfc58400..51903ca7614b4d 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -30,6 +30,8 @@ #include #include +#define SOC_TPLG_MAGIC_BIG_ENDIAN 0x436F5341 /* ASoC in reverse */ + /* * We make several passes over the data (since it wont necessarily be ordered) * and process objects in the following order. This guarantees the component @@ -2502,7 +2504,7 @@ static int soc_valid_header(struct soc_tplg *tplg, } /* big endian firmware objects not supported atm */ - if (hdr->magic == cpu_to_be32(SND_SOC_TPLG_MAGIC)) { + if (hdr->magic == SOC_TPLG_MAGIC_BIG_ENDIAN) { dev_err(tplg->dev, "ASoC: pass %d big endian not supported header got %x at offset 0x%lx size 0x%zx.\n", tplg->pass, hdr->magic, From b5ece71d1799818e37b68051a6c7ae4bbeee89e0 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 4 Apr 2019 22:34:37 -0700 Subject: [PATCH 1305/1995] ASoC: SOF: remove unnecessary casts and use container_of() Remove unnecessary casts and use container_of wherever possible. Feedback from Takashi Iwai. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/hw-spi.c | 6 ++---- sound/soc/sof/intel/bdw.c | 4 ++-- sound/soc/sof/intel/byt.c | 2 +- sound/soc/sof/intel/cnl.c | 2 +- sound/soc/sof/intel/hda-dai.c | 4 ++-- sound/soc/sof/intel/hda-ipc.c | 2 +- sound/soc/sof/intel/hda-loader.c | 2 +- sound/soc/sof/intel/hda-pcm.c | 6 ++---- sound/soc/sof/intel/hda-stream.c | 7 +++---- sound/soc/sof/intel/hda-trace.c | 12 ++++-------- sound/soc/sof/intel/hda.c | 5 ++--- sound/soc/sof/intel/hda.h | 8 ++++---- sound/soc/sof/intel/hsw.c | 2 +- sound/soc/sof/loader.c | 10 +++++----- sound/soc/sof/pm.c | 6 +++--- sound/soc/sof/sof-acpi-dev.c | 2 +- sound/soc/sof/topology.c | 30 +++++++++++++++--------------- sound/soc/sof/trace.c | 2 +- 18 files changed, 51 insertions(+), 61 deletions(-) diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index b85d37f7ff4311..883f53767294b5 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -154,8 +154,7 @@ static irqreturn_t spi_irq_handler(int irq __maybe_unused, void *context) { const struct snd_sof_dev *sdev = context; struct snd_sof_pdata *sof_pdata = sdev->pdata; - struct sof_spi_dev *sof_spi = - (struct sof_spi_dev *)sof_pdata->hw_pdata; + struct sof_spi_dev *sof_spi = sof_pdata->hw_pdata; // on SPI based devices this will likely come via a SoC GPIO IRQ @@ -233,8 +232,7 @@ static int spi_sof_probe(struct snd_sof_dev *sdev) struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev); struct snd_sof_pdata *sof_pdata = sdev->pdata; - struct sof_spi_dev *sof_spi = - (struct sof_spi_dev *)sof_pdata->hw_pdata; + struct sof_spi_dev *sof_spi = sof_pdata->hw_pdata; /* get IRQ from Device tree or ACPI - register our IRQ */ struct irq_data *irqd; struct spi_device *spi = to_spi_device(pdev->dev.parent); diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index d407f397d24e31..2483eaa5957105 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -255,7 +255,7 @@ static void bdw_dump(struct snd_sof_dev *sdev, u32 flags) static irqreturn_t bdw_irq_handler(int irq, void *context) { - struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + struct snd_sof_dev *sdev = context; u32 isr; int ret = IRQ_NONE; @@ -269,7 +269,7 @@ static irqreturn_t bdw_irq_handler(int irq, void *context) static irqreturn_t bdw_irq_thread(int irq, void *context) { - struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + struct snd_sof_dev *sdev = context; u32 ipcx, ipcd, imrx; imrx = snd_sof_dsp_read64(sdev, BDW_DSP_BAR, SHIM_IMRX); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 9c47aed5d2d548..2975cbea950642 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -300,7 +300,7 @@ static void byt_dump(struct snd_sof_dev *sdev, u32 flags) static irqreturn_t byt_irq_handler(int irq, void *context) { - struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + struct snd_sof_dev *sdev = context; u64 isr; int ret = IRQ_NONE; diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 66c9ac3fc9a314..d5866585c637c1 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -29,7 +29,7 @@ static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev); static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) { - struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + struct snd_sof_dev *sdev = context; u32 hipci; u32 hipcctl; u32 hipcida; diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index e7ecbb23eb055d..21ccc0866abc95 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -64,7 +64,7 @@ static int hda_link_dma_get_channels(struct snd_soc_dai *dai, return -EBUSY; } - snd_soc_dai_set_dma_data(dai, &substream, (void *)stream); + snd_soc_dai_set_dma_data(dai, &substream, stream); *tx_slot = hdac_stream(stream)->stream_tag - 1; dev_dbg(bus->dev, "link dma channel %d for playback", *tx_slot); @@ -79,7 +79,7 @@ static int hda_link_dma_get_channels(struct snd_soc_dai *dai, return -EBUSY; } - snd_soc_dai_set_dma_data(dai, &substream, (void *)stream); + snd_soc_dai_set_dma_data(dai, &substream, stream); *rx_slot = hdac_stream(stream)->stream_tag - 1; dev_dbg(bus->dev, "link dma channel %d for capture", *rx_slot); diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index d0e858045e54d5..6924d8504d09c3 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -216,7 +216,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) /* is this IRQ for ADSP ? - we only care about IPC here */ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) { - struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + struct snd_sof_dev *sdev = context; int ret = IRQ_NONE; spin_lock(&sdev->hw_lock); diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index c8c03d5c07b75b..6a44bc349e44ce 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -259,7 +259,7 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) struct firmware stripped_firmware; int ret, ret1, tag, i; - chip_info = (struct sof_intel_dsp_desc *)desc->chip_info; + chip_info = desc->chip_info; stripped_firmware.data = plat_data->fw->data; stripped_firmware.size = plat_data->fw->size; diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 7810530bd6c493..5714a79fbe1a16 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -88,8 +88,7 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, { struct hdac_stream *hstream = substream->runtime->private_data; struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream); - struct sof_intel_hda_dev *hda = - (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct snd_dma_buffer *dmab; int ret; u32 size, rate, bits; @@ -141,8 +140,7 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct hdac_stream *hstream = substream->runtime->private_data; - struct sof_intel_hda_dev *hda = - (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct snd_sof_pcm *spcm; snd_pcm_uframes_t pos; diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index eb09cd3a6719d8..f5f2bc8571ae2b 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -80,8 +80,7 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, struct hdac_stream *stream) { - struct sof_intel_hda_dev *hda = - (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct sof_intel_dsp_bdl *bdl; int i, offset, period_bytes, periods; int remain, ioc; @@ -433,7 +432,7 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) { - struct hdac_bus *bus = (struct hdac_bus *)context; + struct hdac_bus *bus = context; u32 status; if (!pm_runtime_active(bus->dev)) @@ -464,7 +463,7 @@ irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) { - struct hdac_bus *bus = (struct hdac_bus *)context; + struct hdac_bus *bus = context; struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); struct hdac_stream *s; u32 status = snd_hdac_chip_readl(bus, INTSTS); diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c index 6fd77d511118c7..33b23bd6a01e1b 100644 --- a/sound/soc/sof/intel/hda-trace.c +++ b/sound/soc/sof/intel/hda-trace.c @@ -21,8 +21,7 @@ static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev) { - struct sof_intel_hda_dev *hda = - (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct hdac_ext_stream *stream = hda->dtrace_stream; struct hdac_stream *hstream = &stream->hstream; struct snd_dma_buffer *dmab = &sdev->dmatb; @@ -40,8 +39,7 @@ static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev) int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag) { - struct sof_intel_hda_dev *hda = - (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; int ret; hda->dtrace_stream = hda_dsp_stream_get(sdev, @@ -72,8 +70,7 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag) int hda_dsp_trace_release(struct snd_sof_dev *sdev) { - struct sof_intel_hda_dev *hda = - (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct hdac_stream *hstream; if (hda->dtrace_stream) { @@ -91,8 +88,7 @@ int hda_dsp_trace_release(struct snd_sof_dev *sdev) int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd) { - struct sof_intel_hda_dev *hda = - (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; return hda_dsp_stream_trigger(sdev, hda->dtrace_stream, cmd); } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 52dca6d6235c22..b8fc19790f3b80 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -381,7 +381,7 @@ static const struct sof_intel_dsp_desc const struct sof_dev_desc *desc = pdata->desc; const struct sof_intel_dsp_desc *chip_info; - chip_info = (struct sof_intel_dsp_desc *)desc->chip_info; + chip_info = desc->chip_info; return chip_info; } @@ -618,8 +618,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) int hda_dsp_remove(struct snd_sof_dev *sdev) { - struct sof_intel_hda_dev *hda = - (struct sof_intel_hda_dev *)sdev->pdata->hw_pdata; + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct hdac_bus *bus = sof_to_bus(sdev); struct pci_dev *pci = to_pci_dev(sdev->dev); const struct sof_intel_dsp_desc *chip = hda->desc; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 67147228253908..a11196b9acf858 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -374,15 +374,15 @@ struct sof_intel_hda_dev { static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s) { - struct sof_intel_hda_dev *hda = - (struct sof_intel_hda_dev *)s->pdata->hw_pdata; + struct sof_intel_hda_dev *hda = s->pdata->hw_pdata; + return &hda->hbus.core; } static inline struct hda_bus *sof_to_hbus(struct snd_sof_dev *s) { - struct sof_intel_hda_dev *hda = - (struct sof_intel_hda_dev *)s->pdata->hw_pdata; + struct sof_intel_hda_dev *hda = s->pdata->hw_pdata; + return &hda->hbus; } diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index aa83b6d94b4461..ee921ab5360b4b 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -253,7 +253,7 @@ static void hsw_dump(struct snd_sof_dev *sdev, u32 flags) static irqreturn_t hsw_irq_handler(int irq, void *context) { - struct snd_sof_dev *sdev = (struct snd_sof_dev *)context; + struct snd_sof_dev *sdev = context; u32 isr; int ret = IRQ_NONE; diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 657c0dd5c01348..dafa4dec196125 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -17,7 +17,8 @@ static int get_ext_windows(struct snd_sof_dev *sdev, struct sof_ipc_ext_data_hdr *ext_hdr) { - struct sof_ipc_window *w = (struct sof_ipc_window *)ext_hdr; + struct sof_ipc_window *w = + container_of(ext_hdr, struct sof_ipc_window, ext_hdr); size_t size; if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS) @@ -47,7 +48,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) /* get first header */ snd_sof_dsp_block_read(sdev, bar, offset, ext_data, sizeof(*ext_hdr)); - ext_hdr = (struct sof_ipc_ext_data_hdr *)ext_data; + ext_hdr = ext_data; while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) { /* read in ext structure */ @@ -80,7 +81,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) offset += ext_hdr->hdr.size; snd_sof_dsp_block_read(sdev, bar, offset, ext_data, sizeof(*ext_hdr)); - ext_hdr = (struct sof_ipc_ext_data_hdr *)ext_data; + ext_hdr = ext_data; } kfree(ext_data); @@ -145,8 +146,7 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, return -EINVAL; } snd_sof_dsp_block_write(sdev, sdev->mmio_bar, offset, - (void *)((u8 *)block + sizeof(*block)), - block->size); + block + 1, block->size); /* minus body size of block */ remaining -= block->size; diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 3e3fb3b5482bc8..fde92efd8a4560 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -80,7 +80,7 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev) switch (swidget->id) { case snd_soc_dapm_dai_in: case snd_soc_dapm_dai_out: - dai = (struct snd_sof_dai *)swidget->private; + dai = swidget->private; comp_dai = &dai->comp_dai; ret = sof_ipc_tx_message(sdev->ipc, comp_dai->comp.hdr.cmd, @@ -95,11 +95,11 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev) * and power up the core that the pipeline is * scheduled on. */ - pipeline = (struct sof_ipc_pipe_new *)swidget->private; + pipeline = swidget->private; ret = sof_load_pipeline_ipc(sdev, pipeline, &r); break; default: - hdr = (struct sof_ipc_cmd_hdr *)swidget->private; + hdr = swidget->private; ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, swidget->private, hdr->size, &r, sizeof(r)); diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index fe845e1affde7c..e9cf69874b5b1f 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -195,7 +195,7 @@ static int sof_acpi_probe(struct platform_device *pdev) if (!sof_pdata) return -ENOMEM; - desc = (const struct sof_dev_desc *)device_get_match_data(dev); + desc = device_get_match_data(dev); if (!desc) return -ENODEV; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index af1291987f2f35..0d001606834749 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -428,7 +428,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_mixer_control *mc = - (struct snd_soc_tplg_mixer_control *)hdr; + container_of(hdr, struct snd_soc_tplg_mixer_control, hdr); struct sof_ipc_ctrl_data *cdata; int tlv[TLV_ITEMS]; unsigned int i; @@ -491,7 +491,7 @@ static int sof_control_load_enum(struct snd_soc_component *scomp, { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_enum_control *ec = - (struct snd_soc_tplg_enum_control *)hdr; + container_of(hdr, struct snd_soc_tplg_enum_control, hdr); /* validate topology data */ if (le32_to_cpu(ec->num_channels) > SND_SOC_TPLG_MAX_CHAN) @@ -524,7 +524,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc_ctrl_data *cdata; struct snd_soc_tplg_bytes_control *control = - (struct snd_soc_tplg_bytes_control *)hdr; + container_of(hdr, struct snd_soc_tplg_bytes_control, hdr); struct soc_bytes_ext *sbe = (struct soc_bytes_ext *)kc->private_value; int max_size = sbe->max; @@ -907,7 +907,7 @@ static void sof_parse_word_tokens(struct snd_soc_component *scomp, /* pdm config array index */ if (sdev->private) - index = (u32 *)sdev->private; + index = sdev->private; /* matched - determine offset */ switch (tokens[j].token) { @@ -1242,7 +1242,7 @@ static int sof_widget_load_buffer(struct snd_soc_component *scomp, int index, dev_dbg(sdev->dev, "buffer %s: size %d caps 0x%x\n", swidget->widget->name, buffer->size, buffer->caps); - swidget->private = (void *)buffer; + swidget->private = buffer; ret = sof_ipc_tx_message(sdev->ipc, buffer->comp.hdr.cmd, buffer, sizeof(*buffer), r, sizeof(*r)); @@ -1323,7 +1323,7 @@ static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index, dev_dbg(sdev->dev, "loaded host %s\n", swidget->widget->name); sof_dbg_comp_config(scomp, &host->config); - swidget->private = (void *)host; + swidget->private = host; ret = sof_ipc_tx_message(sdev->ipc, host->comp.hdr.cmd, host, sizeof(*host), r, sizeof(*r)); @@ -1431,7 +1431,7 @@ static int sof_widget_load_pipeline(struct snd_soc_component *scomp, swidget->widget->name, pipeline->period, pipeline->priority, pipeline->period_mips, pipeline->core, pipeline->frames_per_sched); - swidget->private = (void *)pipeline; + swidget->private = pipeline; /* send ipc's to create pipeline comp and power up schedule core */ ret = sof_load_pipeline_ipc(sdev, pipeline, r); @@ -1480,7 +1480,7 @@ static int sof_widget_load_mixer(struct snd_soc_component *scomp, int index, sof_dbg_comp_config(scomp, &mixer->config); - swidget->private = (void *)mixer; + swidget->private = mixer; ret = sof_ipc_tx_message(sdev->ipc, mixer->comp.hdr.cmd, mixer, sizeof(*mixer), r, sizeof(*r)); @@ -1527,7 +1527,7 @@ static int sof_widget_load_mux(struct snd_soc_component *scomp, int index, sof_dbg_comp_config(scomp, &mux->config); - swidget->private = (void *)mux; + swidget->private = mux; ret = sof_ipc_tx_message(sdev->ipc, mux->comp.hdr.cmd, mux, sizeof(*mux), r, sizeof(*r)); @@ -1589,7 +1589,7 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, sof_dbg_comp_config(scomp, &volume->config); - swidget->private = (void *)volume; + swidget->private = volume; ret = sof_ipc_tx_message(sdev->ipc, volume->comp.hdr.cmd, volume, sizeof(*volume), r, sizeof(*r)); @@ -1648,7 +1648,7 @@ static int sof_widget_load_src(struct snd_soc_component *scomp, int index, swidget->widget->name, src->source_rate, src->sink_rate); sof_dbg_comp_config(scomp, &src->config); - swidget->private = (void *)src; + swidget->private = src; ret = sof_ipc_tx_message(sdev->ipc, src->comp.hdr.cmd, src, sizeof(*src), r, sizeof(*r)); @@ -1707,7 +1707,7 @@ static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index, swidget->widget->name, tone->frequency, tone->amplitude); sof_dbg_comp_config(scomp, &tone->config); - swidget->private = (void *)tone; + swidget->private = tone; ret = sof_ipc_tx_message(sdev->ipc, tone->comp.hdr.cmd, tone, sizeof(*tone), r, sizeof(*r)); @@ -1858,7 +1858,7 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, } process->size = ipc_data_size; - swidget->private = (void *)process; + swidget->private = process; ret = sof_ipc_tx_message(sdev->ipc, process->comp.hdr.cmd, process, ipc_size, r, sizeof(*r)); @@ -2116,7 +2116,7 @@ static int sof_widget_unload(struct snd_soc_component *scomp, switch (swidget->id) { case snd_soc_dapm_dai_in: case snd_soc_dapm_dai_out: - dai = (struct snd_sof_dai *)swidget->private; + dai = swidget->private; if (dai) { /* free dai config */ @@ -2127,7 +2127,7 @@ static int sof_widget_unload(struct snd_soc_component *scomp, case snd_soc_dapm_scheduler: /* power down the pipeline schedule core */ - pipeline = (struct sof_ipc_pipe_new *)swidget->private; + pipeline = swidget->private; ret = snd_sof_dsp_core_power_down(sdev, 1 << pipeline->core); if (ret < 0) dev_err(sdev->dev, "error: powering down pipeline schedule core %d\n", diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index 8c95e3453b6fb3..c537243ddfec40 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -85,7 +85,7 @@ static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer, count = avail > count ? count : avail; /* copy available trace data to debugfs */ - rem = copy_to_user(buffer, (void *)((u8 *)(dfse->buf) + lpos), count); + rem = copy_to_user(buffer, ((u8 *)(dfse->buf) + lpos), count); if (rem) return -EFAULT; From abfab3266c93f33563ccb76b308198b81b3aa102 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 5 Apr 2019 08:19:49 +0200 Subject: [PATCH 1306/1995] ASoC: SOF: intel: detect all ROM Stream Tag IPC messages The currently ignored IPC 0x1004000 is only one of several possible ROM IPC messages. Detect and ignore all of them. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/hda-ipc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 6924d8504d09c3..0be89d1dce3d36 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -116,6 +116,12 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) spin_unlock_irqrestore(&sdev->ipc_lock, flags); } +static bool hda_dsp_ipc_is_sof(uint32_t msg) +{ + return (msg & (HDA_DSP_IPC_PURGE_FW | 0xf << 9)) != msg || + (msg & HDA_DSP_IPC_PURGE_FW) != HDA_DSP_IPC_PURGE_FW; +} + /* IPC handler thread */ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) { @@ -161,7 +167,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) HDA_DSP_REG_HIPCCTL_DONE, 0); /* handle immediate reply from DSP core - ignore ROM messages */ - if (msg != 0x1004000) { + if (hda_dsp_ipc_is_sof(msg)) { hda_dsp_ipc_get_reply(sdev); snd_sof_ipc_reply(sdev, msg); } From 72c6ba68b51bb4bb58360fe92e3be728960bb52a Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 8 Apr 2019 23:17:20 +0300 Subject: [PATCH 1307/1995] ASoC: SOF: fix a race in reading debugfs trace offset Debugfs trace offset is accessed both by debugfs trace client as well as the IPC irq handler. Ensure the trace offset is read only once in the sof_wait_trace_avail() function by reading the value with READ_ONCE() to a local variable. Feedback from Takashi Iwai Signed-off-by: Kai Vehmanen --- sound/soc/sof/trace.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index c537243ddfec40..d588e4b70fad3e 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -17,18 +17,19 @@ static size_t sof_wait_trace_avail(struct snd_sof_dev *sdev, loff_t pos, size_t buffer_size) { wait_queue_entry_t wait; + loff_t host_offset = READ_ONCE(sdev->host_offset); /* * If host offset is less than local pos, it means write pointer of * host DMA buffer has been wrapped. We should output the trace data * at the end of host DMA buffer at first. */ - if (sdev->host_offset < pos) + if (host_offset < pos) return buffer_size - pos; /* If there is available trace data now, it is unnecessary to wait. */ - if (sdev->host_offset > pos) - return sdev->host_offset - pos; + if (host_offset > pos) + return host_offset - pos; /* wait for available trace data from FW */ init_waitqueue_entry(&wait, current); @@ -42,10 +43,11 @@ static size_t sof_wait_trace_avail(struct snd_sof_dev *sdev, remove_wait_queue(&sdev->trace_sleep, &wait); /* return bytes available for copy */ - if (sdev->host_offset < pos) + host_offset = READ_ONCE(sdev->host_offset); + if (host_offset < pos) return buffer_size - pos; - return sdev->host_offset - pos; + return host_offset - pos; } static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer, From c096b50865218393cc660c27492e3097be88df57 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 5 Apr 2019 09:04:24 +0200 Subject: [PATCH 1308/1995] ASoC: SOF: ipc: remove a left-over logging entry A recent commit f3adfd66c97c ("ASoC:sof: remove duplicate posn message in kernel log")' removed a redundant logging entry in ipc_period_elapsed() but it missed a similar ont in ipc_xrun(). Remove the latter one too. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/ipc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index c783c9522e5a0d..7e0aa9a1b49634 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -493,9 +493,6 @@ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) posn_offset = spcm->posn_offset[direction]; snd_sof_dsp_mailbox_read(sdev, posn_offset, &posn, sizeof(posn)); - - dev_dbg(sdev->dev, "posn mailbox: posn offset is 0x%x", - posn_offset); } dev_dbg(sdev->dev, "posn XRUN: host %llx comp %d size %d\n", From a90a76666df0ac0151cb42aaf167964fc83b9ed3 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 5 Apr 2019 09:06:46 +0200 Subject: [PATCH 1309/1995] ASoC: SOF: ipc: remove a redundant test Even if the stream position IPC from the DSP isn't using the stream mailbox, there is no need to read the complete message to get a message ID, it must be the same as the one, obtained earlier from the same mailbox. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/ipc.c | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 7e0aa9a1b49634..fc998d244b54b8 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -428,17 +428,7 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) u32 posn_offset; int direction; - /* check if we have stream box */ - if (sdev->stream_box.size == 0) { - /* read back full message */ - snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn, - sizeof(posn)); - - spcm = snd_sof_find_spcm_comp(sdev, posn.comp_id, &direction); - } else { - spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction); - } - + spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction); if (!spcm) { dev_err(sdev->dev, "error: period elapsed for unknown stream, msg_id %d\n", @@ -446,11 +436,15 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) return; } - /* have stream box read from stream box */ if (sdev->stream_box.size != 0) { + /* have stream box read from stream box */ posn_offset = spcm->posn_offset[direction]; snd_sof_dsp_mailbox_read(sdev, posn_offset, &posn, sizeof(posn)); + } else { + /* read back full message */ + snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn, + sizeof(posn)); } dev_dbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n", @@ -471,28 +465,22 @@ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) u32 posn_offset; int direction; - /* check if we have stream MMIO on this platform */ - if (sdev->stream_box.size == 0) { - /* read back full message */ - snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn, - sizeof(posn)); - - spcm = snd_sof_find_spcm_comp(sdev, posn.comp_id, &direction); - } else { - spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction); - } - + spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction); if (!spcm) { dev_err(sdev->dev, "error: XRUN for unknown stream, msg_id %d\n", msg_id); return; } - /* have stream box read from stream box */ if (sdev->stream_box.size != 0) { + /* have stream box read from stream box */ posn_offset = spcm->posn_offset[direction]; snd_sof_dsp_mailbox_read(sdev, posn_offset, &posn, sizeof(posn)); + } else { + /* read back full message */ + snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn, + sizeof(posn)); } dev_dbg(sdev->dev, "posn XRUN: host %llx comp %d size %d\n", From 1ed83bbdf6368a4a079d085c161f641b19c633cc Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 29 Mar 2019 17:48:11 +0100 Subject: [PATCH 1310/1995] ASoC: SOF: IPC: remove direct mailbox reading from SOF core Obtaining data from the DSP by reading the mailbox is Intel-specific, move them from the SOF core to Intel-specific drivers. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/Kconfig | 8 +++ sound/soc/sof/intel/Makefile | 4 ++ sound/soc/sof/intel/apl.c | 3 ++ sound/soc/sof/intel/bdw.c | 7 +++ sound/soc/sof/intel/byt.c | 21 ++++++++ sound/soc/sof/intel/cnl.c | 3 ++ sound/soc/sof/intel/hda-ipc.c | 47 ++++++++++++++++ sound/soc/sof/intel/hda-stream.c | 21 ++++++-- sound/soc/sof/intel/hda.h | 15 +++++- sound/soc/sof/intel/intel-ipc.c | 93 ++++++++++++++++++++++++++++++++ sound/soc/sof/intel/shim.h | 4 ++ sound/soc/sof/ipc.c | 43 +++++---------- sound/soc/sof/ops.h | 22 ++++++++ sound/soc/sof/pcm.c | 33 ++++++------ sound/soc/sof/sof-priv.h | 23 +++++++- 15 files changed, 294 insertions(+), 53 deletions(-) create mode 100644 sound/soc/sof/intel/intel-ipc.c diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 875bd09a32b5fe..9deb126f5d15a2 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -31,9 +31,16 @@ config SND_SOC_SOF_INTEL_PCI This option is not user-selectable but automagically handled by 'select' statements at a higher level +config SND_SOC_SOF_INTEL_HIFI_EP_IPC + tristate + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + config SND_SOC_SOF_INTEL_ATOM_HIFI_EP tristate select SND_SOC_INTEL_COMMON + select SND_SOC_SOF_INTEL_HIFI_EP_IPC help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -91,6 +98,7 @@ config SND_SOC_SOF_BROADWELL_SUPPORT config SND_SOC_SOF_BROADWELL tristate select SND_SOC_SOF_INTEL_COMMON + select SND_SOC_SOF_INTEL_HIFI_EP_IPC help This option is not user-selectable but automagically handled by 'select' statements at a higher level diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index 7a52b89eea863a..03b22924d0c4eb 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -5,6 +5,9 @@ ccflags-y += -DDEBUG snd-sof-intel-byt-objs := byt.o snd-sof-intel-hsw-objs := hsw.o snd-sof-intel-bdw-objs := bdw.o + +snd-sof-intel-ipc-objs := intel-ipc.o + snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \ hda-dai.o hda-bus.o hda-loader-skl.o \ @@ -15,5 +18,6 @@ snd-sof-intel-hda-objs := hda-codec.o obj-$(CONFIG_SND_SOC_SOF_INTEL_ATOM_HIFI_EP) += snd-sof-intel-byt.o obj-$(CONFIG_SND_SOC_SOF_HASWELL) += snd-sof-intel-hsw.o obj-$(CONFIG_SND_SOC_SOF_BROADWELL) += snd-sof-intel-bdw.o +obj-$(CONFIG_SND_SOC_SOF_INTEL_HIFI_EP_IPC) += snd-sof-intel-ipc.o obj-$(CONFIG_SND_SOC_SOF_HDA_COMMON) += snd-sof-intel-hda-common.o obj-$(CONFIG_SND_SOC_SOF_HDA) += snd-sof-intel-hda.o diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 654d74175d2704..2fe7fe2ac55369 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -52,6 +52,9 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .send_msg = hda_dsp_ipc_send_msg, .fw_ready = hda_dsp_ipc_fw_ready, + .ipc_msg_data = hda_ipc_msg_data, + .ipc_pcm_params = hda_ipc_pcm_params, + /* debug */ .debug_map = apl_dsp_debugfs, .debug_map_count = ARRAY_SIZE(apl_dsp_debugfs), diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 2483eaa5957105..5210dd77cced15 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -674,11 +674,18 @@ const struct snd_sof_dsp_ops sof_bdw_ops = { .send_msg = bdw_send_msg, .fw_ready = bdw_fw_ready, + .ipc_msg_data = intel_ipc_msg_data, + .ipc_pcm_params = intel_ipc_pcm_params, + /* debug */ .debug_map = bdw_debugfs, .debug_map_count = ARRAY_SIZE(bdw_debugfs), .dbg_dump = bdw_dump, + /* stream callbacks */ + .pcm_open = intel_pcm_open, + .pcm_close = intel_pcm_close, + /* Module loading */ .load_module = snd_sof_parse_module_memcpy, diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 2975cbea950642..0bd2a3c38df8fd 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -613,11 +613,18 @@ const struct snd_sof_dsp_ops sof_tng_ops = { .send_msg = byt_send_msg, .fw_ready = byt_fw_ready, + .ipc_msg_data = intel_ipc_msg_data, + .ipc_pcm_params = intel_ipc_pcm_params, + /* debug */ .debug_map = byt_debugfs, .debug_map_count = ARRAY_SIZE(byt_debugfs), .dbg_dump = byt_dump, + /* stream callbacks */ + .pcm_open = intel_pcm_open, + .pcm_close = intel_pcm_close, + /* module loading */ .load_module = snd_sof_parse_module_memcpy, @@ -772,11 +779,18 @@ const struct snd_sof_dsp_ops sof_byt_ops = { .send_msg = byt_send_msg, .fw_ready = byt_fw_ready, + .ipc_msg_data = intel_ipc_msg_data, + .ipc_pcm_params = intel_ipc_pcm_params, + /* debug */ .debug_map = byt_debugfs, .debug_map_count = ARRAY_SIZE(byt_debugfs), .dbg_dump = byt_dump, + /* stream callbacks */ + .pcm_open = intel_pcm_open, + .pcm_close = intel_pcm_close, + /* module loading */ .load_module = snd_sof_parse_module_memcpy, @@ -826,11 +840,18 @@ const struct snd_sof_dsp_ops sof_cht_ops = { .send_msg = byt_send_msg, .fw_ready = byt_fw_ready, + .ipc_msg_data = intel_ipc_msg_data, + .ipc_pcm_params = intel_ipc_pcm_params, + /* debug */ .debug_map = cht_debugfs, .debug_map_count = ARRAY_SIZE(cht_debugfs), .dbg_dump = byt_dump, + /* stream callbacks */ + .pcm_open = intel_pcm_open, + .pcm_close = intel_pcm_close, + /* module loading */ .load_module = snd_sof_parse_module_memcpy, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index d5866585c637c1..9ac2e0ebb83400 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -190,6 +190,9 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .send_msg = cnl_ipc_send_msg, .fw_ready = hda_dsp_ipc_fw_ready, + .ipc_msg_data = hda_ipc_msg_data, + .ipc_pcm_params = hda_ipc_pcm_params, + /* debug */ .debug_map = cnl_dsp_debugfs, .debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs), diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 0be89d1dce3d36..525d508817c776 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -402,3 +402,50 @@ int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return 0; } + +void hda_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz) +{ + if (!substream || !sdev->stream_box.size) { + snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); + } else { + struct hdac_stream *hstream = substream->runtime->private_data; + struct sof_intel_hda_stream *hda_stream; + + hda_stream = container_of(hstream, + struct sof_intel_hda_stream, + hda_stream.hstream); + + /* The stream might already be closed */ + if (hstream) + snd_sof_dsp_mailbox_read(sdev, + hda_stream->stream.posn_offset, + p, sz); + } +} + +int hda_ipc_pcm_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct sof_intel_hda_stream *hda_stream; + /* validate offset */ + size_t posn_offset = reply->posn_offset; + + hda_stream = container_of(hstream, struct sof_intel_hda_stream, + hda_stream.hstream); + + /* check if offset is overflow or it is not aligned */ + if (posn_offset > sdev->stream_box.size || + posn_offset % sizeof(struct sof_ipc_stream_posn) != 0) + return -EINVAL; + + hda_stream->stream.posn_offset = sdev->stream_box.offset + posn_offset; + + dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu", + substream->stream, hda_stream->stream.posn_offset); + + return 0; +} diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index f5f2bc8571ae2b..6290b2df5e621d 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -551,11 +551,15 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) /* create capture streams */ for (i = 0; i < num_capture; i++) { + struct sof_intel_hda_stream *hda_stream; - stream = devm_kzalloc(sdev->dev, sizeof(*stream), GFP_KERNEL); - if (!stream) + hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream), + GFP_KERNEL); + if (!hda_stream) return -ENOMEM; + stream = &hda_stream->hda_stream; + stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] + SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i; @@ -600,11 +604,15 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) /* create playback streams */ for (i = num_capture; i < num_total; i++) { + struct sof_intel_hda_stream *hda_stream; - stream = devm_kzalloc(sdev->dev, sizeof(*stream), GFP_KERNEL); - if (!stream) + hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream), + GFP_KERNEL); + if (!hda_stream) return -ENOMEM; + stream = &hda_stream->hda_stream; + /* we always have DSP support */ stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] + SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i; @@ -657,6 +665,7 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev) struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_stream *s, *_s; struct hdac_ext_stream *stream; + struct sof_intel_hda_stream *hda_stream; /* free position buffer */ if (bus->posbuf.area) @@ -676,6 +685,8 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev) snd_dma_free_pages(&s->bdl); list_del(&s->list); stream = stream_to_hdac_ext_stream(s); - devm_kfree(sdev->dev, stream); + hda_stream = container_of(stream, struct sof_intel_hda_stream, + hda_stream); + devm_kfree(sdev->dev, hda_stream); } } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index a11196b9acf858..e49d9c92dd1c8b 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -12,6 +12,7 @@ #define __SOF_INTEL_HDA_H #include +#include #include "shim.h" /* PCI registers */ @@ -360,7 +361,7 @@ struct sof_intel_hda_dev { /* hw config */ const struct sof_intel_dsp_desc *desc; - /*trace */ + /* trace */ struct hdac_ext_stream *dtrace_stream; /* if position update IPC needed */ @@ -386,6 +387,11 @@ static inline struct hda_bus *sof_to_hbus(struct snd_sof_dev *s) return &hda->hbus; } +struct sof_intel_hda_stream { + struct hdac_ext_stream hda_stream; + struct sof_intel_stream stream; +}; + #define bus_to_sof_hda(bus) \ container_of(bus, struct sof_intel_hda_dev, hbus.core) @@ -462,6 +468,13 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream, int enable, u32 size); +void hda_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz); +int hda_ipc_pcm_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply); + /* * DSP IPC Operations. */ diff --git a/sound/soc/sof/intel/intel-ipc.c b/sound/soc/sof/intel/intel-ipc.c new file mode 100644 index 00000000000000..675be109920c2d --- /dev/null +++ b/sound/soc/sof/intel/intel-ipc.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2019 Intel Corporation. All rights reserved. +// +// Authors: Guennadi Liakhovetski + +/* Intel-specific SOF IPC code */ + +#include +#include +#include +#include + +#include +#include + +#include "../ops.h" +#include "../sof-priv.h" + +struct intel_stream { + size_t posn_offset; +}; + +/* Mailbox-based Intel IPC implementation */ +void intel_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz) +{ + if (!substream || !sdev->stream_box.size) { + snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); + } else { + struct intel_stream *stream = substream->runtime->private_data; + + /* The stream might already be closed */ + if (stream) + snd_sof_dsp_mailbox_read(sdev, stream->posn_offset, + p, sz); + } +} +EXPORT_SYMBOL(intel_ipc_msg_data); + +int intel_ipc_pcm_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply) +{ + struct intel_stream *stream = substream->runtime->private_data; + size_t posn_offset = reply->posn_offset; + + /* check if offset is overflow or it is not aligned */ + if (posn_offset > sdev->stream_box.size || + posn_offset % sizeof(struct sof_ipc_stream_posn) != 0) + return -EINVAL; + + stream->posn_offset = sdev->stream_box.offset + posn_offset; + + dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu", + substream->stream, stream->posn_offset); + + return 0; +} +EXPORT_SYMBOL(intel_ipc_pcm_params); + +int intel_pcm_open(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct intel_stream *stream = kmalloc(sizeof(*stream), GFP_KERNEL); + + if (!stream) + return -ENOMEM; + + /* binding pcm substream to hda stream */ + substream->runtime->private_data = stream; + + return 0; +} +EXPORT_SYMBOL(intel_pcm_open); + +int intel_pcm_close(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct intel_stream *stream = substream->runtime->private_data; + + substream->runtime->private_data = NULL; + kfree(stream); + + return 0; +} +EXPORT_SYMBOL(intel_pcm_close); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 617da2dda17270..11fd77cb4e6d0b 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -176,4 +176,8 @@ extern const struct sof_intel_dsp_desc bdw_chip_info; extern const struct sof_intel_dsp_desc hsw_chip_info; extern const struct sof_intel_dsp_desc tng_chip_info; +struct sof_intel_stream { + size_t posn_offset; +}; + #endif diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index fc998d244b54b8..512c6f0b3deea3 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -343,7 +343,7 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) int err = 0; /* read back header */ - snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &hdr, sizeof(hdr)); + snd_sof_ipc_msg_data(sdev, NULL, &hdr, sizeof(hdr)); ipc_log_header(sdev->dev, "ipc rx", hdr.cmd); cmd = hdr.cmd & SOF_GLB_TYPE_MASK; @@ -406,8 +406,7 @@ static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id) switch (msg_id) { case SOF_IPC_TRACE_DMA_POSITION: /* read back full message */ - snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn, - sizeof(posn)); + snd_sof_ipc_msg_data(sdev, NULL, &posn, sizeof(posn)); snd_sof_trace_update_pos(sdev, &posn); break; default: @@ -423,9 +422,9 @@ static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id) static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) { + struct snd_sof_pcm_stream *stream; struct sof_ipc_stream_posn posn; struct snd_sof_pcm *spcm; - u32 posn_offset; int direction; spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction); @@ -436,33 +435,25 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) return; } - if (sdev->stream_box.size != 0) { - /* have stream box read from stream box */ - posn_offset = spcm->posn_offset[direction]; - snd_sof_dsp_mailbox_read(sdev, posn_offset, &posn, - sizeof(posn)); - } else { - /* read back full message */ - snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn, - sizeof(posn)); - } + stream = &spcm->stream[direction]; + snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); dev_dbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n", posn.host_posn, posn.dai_posn, posn.wallclock); - memcpy(&spcm->stream[direction].posn, &posn, sizeof(posn)); + memcpy(&stream->posn, &posn, sizeof(posn)); /* only inform ALSA for period_wakeup mode */ - if (!spcm->stream[direction].substream->runtime->no_period_wakeup) - snd_pcm_period_elapsed(spcm->stream[direction].substream); + if (!stream->substream->runtime->no_period_wakeup) + snd_pcm_period_elapsed(stream->substream); } /* DSP notifies host of an XRUN within FW */ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) { + struct snd_sof_pcm_stream *stream; struct sof_ipc_stream_posn posn; struct snd_sof_pcm *spcm; - u32 posn_offset; int direction; spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction); @@ -472,24 +463,16 @@ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) return; } - if (sdev->stream_box.size != 0) { - /* have stream box read from stream box */ - posn_offset = spcm->posn_offset[direction]; - snd_sof_dsp_mailbox_read(sdev, posn_offset, &posn, - sizeof(posn)); - } else { - /* read back full message */ - snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, &posn, - sizeof(posn)); - } + stream = &spcm->stream[direction]; + snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); dev_dbg(sdev->dev, "posn XRUN: host %llx comp %d size %d\n", posn.host_posn, posn.xrun_comp_id, posn.xrun_size); #if defined(CONFIG_SND_SOC_SOF_DEBUG_XRUN_STOP) /* stop PCM on XRUN - used for pipeline debug */ - memcpy(&spcm->stream[direction].posn, &posn, sizeof(posn)); - snd_pcm_stop_xrun(spcm->stream[direction].substream); + memcpy(&stream->posn, &posn, sizeof(posn)); + snd_pcm_stop_xrun(stream->substream); #endif } diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 8633b587325f4a..f0af78c834fcc8 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -330,6 +330,28 @@ snd_sof_pcm_platform_trigger(struct snd_sof_dev *sdev, return 0; } +/* host DSP message data */ +static inline void snd_sof_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz) +{ + if (sof_ops(sdev) && sof_ops(sdev)->ipc_msg_data) + sof_ops(sdev)->ipc_msg_data(sdev, substream, p, sz); +} + +/* host configure DSP HW parameters */ +static inline int +snd_sof_ipc_pcm_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply) +{ + if (sof_ops(sdev) && sof_ops(sdev)->ipc_pcm_params) + return sof_ops(sdev)->ipc_pcm_params(sdev, substream, reply); + + dev_err(sdev->dev, "error: %s not defined\n", __func__); + return -ENOTSUPP; +} + /* host stream pointer */ static inline snd_pcm_uframes_t snd_sof_pcm_platform_pointer(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 485dfb92ad5dc1..c81ac2e690b82c 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -38,6 +38,20 @@ static int create_page_table(struct snd_pcm_substream *substream, spcm->stream[stream].page_table.area, size); } +static int sof_pcm_dsp_params(struct snd_sof_pcm *spcm, struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply) +{ + struct snd_sof_dev *sdev = spcm->sdev; + /* validate offset */ + int ret = snd_sof_ipc_pcm_params(sdev, substream, reply); + + if (ret < 0) + dev_err(sdev->dev, "error: got wrong reply for PCM %d\n", + spcm->pcm.pcm_id); + + return ret; +} + /* this may get called several times by oss emulation */ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -50,7 +64,6 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_sof_pcm *spcm; struct sof_ipc_pcm_params pcm; struct sof_ipc_pcm_params_reply ipc_params_reply; - int posn_offset; int ret; /* nothing todo for BE */ @@ -149,21 +162,9 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, return ret; } - /* validate offset */ - posn_offset = ipc_params_reply.posn_offset; - - /* check if offset is overflow or it is not aligned */ - if (posn_offset > sdev->stream_box.size || - posn_offset % sizeof(struct sof_ipc_stream_posn) != 0) { - dev_err(sdev->dev, "error: got wrong posn offset 0x%x for PCM %d\n", - posn_offset, spcm->pcm.pcm_id); - return -EINVAL; - } - spcm->posn_offset[substream->stream] = - sdev->stream_box.offset + posn_offset; - - dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is 0x%x", - substream->stream, spcm->posn_offset[substream->stream]); + ret = sof_pcm_dsp_params(spcm, substream, &ipc_params_reply); + if (ret < 0) + return ret; /* save pcm hw_params */ memcpy(&spcm->params[substream->stream], params, sizeof(*params)); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index a5d8573ccd7361..468fa942655b31 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -148,6 +148,16 @@ struct snd_sof_dsp_ops { snd_pcm_uframes_t (*pcm_pointer)(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); /* optional */ + /* host read DSP stream data */ + void (*ipc_msg_data)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz); /* mandatory */ + + /* host configure DSP HW parameters */ + int (*ipc_pcm_params)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply); /* mandatory */ + /* pre/post firmware run */ int (*pre_fw_run)(struct snd_sof_dev *sof_dev); /* optional */ int (*post_fw_run)(struct snd_sof_dev *sof_dev); /* optional */ @@ -273,7 +283,6 @@ struct snd_sof_pcm { struct snd_sof_dev *sdev; struct snd_soc_tplg_pcm pcm; struct snd_sof_pcm_stream stream[2]; - u32 posn_offset[2]; struct list_head list; /* list in sdev pcm list */ struct snd_pcm_hw_params params[2]; int restore_stream[2]; /* restore hw_params for paused stream */ @@ -610,4 +619,16 @@ void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, size_t size); +void intel_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz); +int intel_ipc_pcm_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply); + +int intel_pcm_open(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); +int intel_pcm_close(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); + #endif From e5795c1ef86d681a7a0bf3e3c1fb164fa37a3a8f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 1 Apr 2019 16:37:57 +0200 Subject: [PATCH 1311/1995] ASoC: SOF: skl: remove direct mailbox reading from SOF core Obtaining data from the DSP by reading the mailbox is Intel-specific, move them from the SOF core to Intel-specific drivers. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/skl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 5aab147dbde6bb..413613e44a3053 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -52,6 +52,9 @@ const struct snd_sof_dsp_ops sof_skl_ops = { .send_msg = hda_dsp_ipc_send_msg, .fw_ready = hda_dsp_ipc_fw_ready, + .ipc_msg_data = hda_ipc_msg_data, + .ipc_pcm_params = hda_ipc_pcm_params, + /* debug */ .debug_map = skl_dsp_debugfs, .debug_map_count = ARRAY_SIZE(skl_dsp_debugfs), From d71b37768283f554a21fa7387a768d045f55fd90 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 1 Apr 2019 16:42:35 +0200 Subject: [PATCH 1312/1995] ASoC: SOF: hsw: remove direct mailbox reading from SOF core Obtaining data from the DSP by reading the mailbox is Intel-specific, move them from the SOF core to Intel-specific drivers. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/Kconfig | 1 + sound/soc/sof/intel/hsw.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 9deb126f5d15a2..c20f2d3164498b 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -83,6 +83,7 @@ config SND_SOC_SOF_HASWELL_SUPPORT config SND_SOC_SOF_HASWELL tristate select SND_SOC_SOF_INTEL_COMMON + select SND_SOC_SOF_INTEL_HIFI_EP_IPC help This option is not user-selectable but automagically handled by 'select' statements at a higher level diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index ee921ab5360b4b..4b802a5a8ed0b0 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -674,11 +674,18 @@ const struct snd_sof_dsp_ops sof_hsw_ops = { .send_msg = hsw_send_msg, .fw_ready = hsw_fw_ready, + .ipc_msg_data = intel_ipc_msg_data, + .ipc_pcm_params = intel_ipc_pcm_params, + /* debug */ .debug_map = hsw_debugfs, .debug_map_count = ARRAY_SIZE(hsw_debugfs), .dbg_dump = hsw_dump, + /* stream callbacks */ + .pcm_open = intel_pcm_open, + .pcm_close = intel_pcm_close, + /* Module loading */ .load_module = snd_sof_parse_module_memcpy, From 34164fef11dcfd2b0b3ca6a0ed7aa6fb40ae9ce1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 1 Apr 2019 17:13:02 +0200 Subject: [PATCH 1313/1995] ASoC: SOF: remove .mailbox_{read,write}() operations IPC implementation using mailboxes is hardware-specific, no need to export it globally. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/apl.c | 4 ---- sound/soc/sof/intel/bdw.c | 4 ---- sound/soc/sof/intel/byt.c | 12 ------------ sound/soc/sof/intel/cnl.c | 4 ---- sound/soc/sof/intel/hda-ipc.c | 7 +++---- sound/soc/sof/intel/intel-ipc.c | 5 ++--- sound/soc/sof/ops.h | 25 ------------------------- sound/soc/sof/sof-priv.h | 6 ------ 8 files changed, 5 insertions(+), 62 deletions(-) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 2fe7fe2ac55369..8c628260694467 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -44,10 +44,6 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .irq_handler = hda_dsp_ipc_irq_handler, .irq_thread = hda_dsp_ipc_irq_thread, - /* mailbox */ - .mailbox_read = sof_mailbox_read, - .mailbox_write = sof_mailbox_write, - /* ipc */ .send_msg = hda_dsp_ipc_send_msg, .fw_ready = hda_dsp_ipc_fw_ready, diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 5210dd77cced15..fe357e7881ff52 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -666,10 +666,6 @@ const struct snd_sof_dsp_ops sof_bdw_ops = { .block_read = sof_block_read, .block_write = sof_block_write, - /* mailbox */ - .mailbox_read = sof_mailbox_read, - .mailbox_write = sof_mailbox_write, - /* ipc */ .send_msg = bdw_send_msg, .fw_ready = bdw_fw_ready, diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 0bd2a3c38df8fd..8428e28bdab214 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -605,10 +605,6 @@ const struct snd_sof_dsp_ops sof_tng_ops = { .irq_handler = byt_irq_handler, .irq_thread = byt_irq_thread, - /* mailbox */ - .mailbox_read = sof_mailbox_read, - .mailbox_write = sof_mailbox_write, - /* ipc */ .send_msg = byt_send_msg, .fw_ready = byt_fw_ready, @@ -771,10 +767,6 @@ const struct snd_sof_dsp_ops sof_byt_ops = { .irq_handler = byt_irq_handler, .irq_thread = byt_irq_thread, - /* mailbox */ - .mailbox_read = sof_mailbox_read, - .mailbox_write = sof_mailbox_write, - /* ipc */ .send_msg = byt_send_msg, .fw_ready = byt_fw_ready, @@ -832,10 +824,6 @@ const struct snd_sof_dsp_ops sof_cht_ops = { .irq_handler = byt_irq_handler, .irq_thread = byt_irq_thread, - /* mailbox */ - .mailbox_read = sof_mailbox_read, - .mailbox_write = sof_mailbox_write, - /* ipc */ .send_msg = byt_send_msg, .fw_ready = byt_fw_ready, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 9ac2e0ebb83400..3e95c1e5e49120 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -182,10 +182,6 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .irq_handler = hda_dsp_ipc_irq_handler, .irq_thread = cnl_ipc_irq_thread, - /* mailbox */ - .mailbox_read = sof_mailbox_read, - .mailbox_write = sof_mailbox_write, - /* ipc */ .send_msg = cnl_ipc_send_msg, .fw_ready = hda_dsp_ipc_fw_ready, diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 525d508817c776..d691d3486ae12c 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -408,7 +408,7 @@ void hda_ipc_msg_data(struct snd_sof_dev *sdev, void *p, size_t sz) { if (!substream || !sdev->stream_box.size) { - snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); + sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); } else { struct hdac_stream *hstream = substream->runtime->private_data; struct sof_intel_hda_stream *hda_stream; @@ -419,9 +419,8 @@ void hda_ipc_msg_data(struct snd_sof_dev *sdev, /* The stream might already be closed */ if (hstream) - snd_sof_dsp_mailbox_read(sdev, - hda_stream->stream.posn_offset, - p, sz); + sof_mailbox_read(sdev, hda_stream->stream.posn_offset, + p, sz); } } diff --git a/sound/soc/sof/intel/intel-ipc.c b/sound/soc/sof/intel/intel-ipc.c index 675be109920c2d..4edd92151fd5fb 100644 --- a/sound/soc/sof/intel/intel-ipc.c +++ b/sound/soc/sof/intel/intel-ipc.c @@ -30,14 +30,13 @@ void intel_ipc_msg_data(struct snd_sof_dev *sdev, void *p, size_t sz) { if (!substream || !sdev->stream_box.size) { - snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); + sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); } else { struct intel_stream *stream = substream->runtime->private_data; /* The stream might already be closed */ if (stream) - snd_sof_dsp_mailbox_read(sdev, stream->posn_offset, - p, sz); + sof_mailbox_read(sdev, stream->posn_offset, p, sz); } } EXPORT_SYMBOL(intel_ipc_msg_data); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index f0af78c834fcc8..e209ef86a27934 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -221,31 +221,6 @@ static inline void snd_sof_dsp_block_write(struct snd_sof_dev *sdev, u32 bar, dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__); } -/* mailbox */ -static inline void snd_sof_dsp_mailbox_read(struct snd_sof_dev *sdev, - u32 offset, void *message, - size_t bytes) -{ - if (sof_ops(sdev)->mailbox_read) { - sof_ops(sdev)->mailbox_read(sdev, offset, message, bytes); - return; - } - - dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__); -} - -static inline void snd_sof_dsp_mailbox_write(struct snd_sof_dev *sdev, - u32 offset, void *message, - size_t bytes) -{ - if (sof_ops(sdev)->mailbox_write) { - sof_ops(sdev)->mailbox_write(sdev, offset, message, bytes); - return; - } - - dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__); -} - /* ipc */ static inline int snd_sof_dsp_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 468fa942655b31..49bc445d22c7e1 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -106,12 +106,6 @@ struct snd_sof_dsp_ops { irqreturn_t (*irq_handler)(int irq, void *context); /* mandatory */ irqreturn_t (*irq_thread)(int irq, void *context); /* mandatory */ - /* mailbox */ - void (*mailbox_read)(struct snd_sof_dev *sof_dev, u32 offset, - void *addr, size_t bytes); /* mandatory */ - void (*mailbox_write)(struct snd_sof_dev *sof_dev, u32 offset, - void *addr, size_t bytes); /* mandatory */ - /* ipc */ int (*send_msg)(struct snd_sof_dev *sof_dev, struct snd_sof_ipc_msg *msg); /* mandatory */ From d409a67152531f002fde2b9e001b9a8d7baa476d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 1 Apr 2019 17:19:59 +0200 Subject: [PATCH 1314/1995] ASoC: SOF: spi: remove .mailbox_{read,write}() operations IPC implementation using mailboxes is hardware-specific and it is meaningless on serial busses like SPI. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/hw-spi.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index 883f53767294b5..42a837fdc859b3 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -280,10 +280,6 @@ const struct snd_sof_dsp_ops snd_sof_spi_ops = { .irq_handler = spi_irq_handler, .irq_thread = spi_irq_thread, - /* mailbox */ - .mailbox_read = spi_mailbox_read, - .mailbox_write = spi_mailbox_write, - /* ipc */ .send_msg = spi_send_msg, .fw_ready = spi_fw_ready, From 774136e0ea2417ca215baffb70223cf9cb750a80 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 1 Apr 2019 17:21:53 +0200 Subject: [PATCH 1315/1995] ASoC: SOF: hsw: remove .mailbox_{read,write}() operations IPC implementation using mailboxes is hardware-specific, no need to export it globally. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/hsw.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 4b802a5a8ed0b0..55e430c73ae11e 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -666,10 +666,6 @@ const struct snd_sof_dsp_ops sof_hsw_ops = { .block_read = sof_block_read, .block_write = sof_block_write, - /* mailbox */ - .mailbox_read = sof_mailbox_read, - .mailbox_write = sof_mailbox_write, - /* ipc */ .send_msg = hsw_send_msg, .fw_ready = hsw_fw_ready, From 7db31c4a79255d68ad15b4bf47c05036d7e49b30 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 1 Apr 2019 17:22:09 +0200 Subject: [PATCH 1316/1995] ASoC: SOF: skl: remove .mailbox_{read,write}() operations IPC implementation using mailboxes is hardware-specific, no need to export it globally. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/skl.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c index 413613e44a3053..34f7aa93c86597 100644 --- a/sound/soc/sof/intel/skl.c +++ b/sound/soc/sof/intel/skl.c @@ -44,10 +44,6 @@ const struct snd_sof_dsp_ops sof_skl_ops = { .irq_handler = hda_dsp_ipc_irq_handler, .irq_thread = hda_dsp_ipc_irq_thread, - /* mailbox */ - .mailbox_read = sof_mailbox_read, - .mailbox_write = sof_mailbox_write, - /* ipc */ .send_msg = hda_dsp_ipc_send_msg, .fw_ready = hda_dsp_ipc_fw_ready, From 8b742b87b2f9b2a53702db995789d4c19e91b0c6 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 2 Apr 2019 16:57:43 +0200 Subject: [PATCH 1317/1995] ASoC: SOF: IPC: remove a superfluous function argument snd_sof_fw_parse_ext_data() is always called for the MMIO BAR, remove the argument and specify the BAR explicitly. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/bdw.c | 2 +- sound/soc/sof/intel/byt.c | 2 +- sound/soc/sof/intel/hda-ipc.c | 3 +-- sound/soc/sof/intel/hsw.c | 2 +- sound/soc/sof/loader.c | 8 ++++---- sound/soc/sof/sof-priv.h | 2 +- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index fe357e7881ff52..4c17cb347ffd7d 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -459,7 +459,7 @@ static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return ret; /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + + snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + sizeof(struct sof_ipc_fw_ready)); bdw_get_windows(sdev); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 8428e28bdab214..b4a71ba18dbc9e 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -248,7 +248,7 @@ static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return ret; /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + + snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + sizeof(struct sof_ipc_fw_ready)); byt_get_windows(sdev); diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index d691d3486ae12c..7fbd1cca6240b9 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -394,8 +394,7 @@ int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return ret; /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, - HDA_DSP_MBOX_UPLINK_OFFSET + + snd_sof_fw_parse_ext_data(sdev, HDA_DSP_MBOX_UPLINK_OFFSET + sizeof(struct sof_ipc_fw_ready)); ipc_get_windows(sdev); diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 55e430c73ae11e..2b4a44fa6f3912 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -460,7 +460,7 @@ static int hsw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return ret; /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + + snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + sizeof(struct sof_ipc_fw_ready)); hsw_get_windows(sdev); diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index dafa4dec196125..72445f10e7b672 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -35,7 +35,7 @@ static int get_ext_windows(struct snd_sof_dev *sdev, } /* parse the extended FW boot data structures from FW boot message */ -int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) +int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) { struct sof_ipc_ext_data_hdr *ext_hdr; void *ext_data; @@ -46,14 +46,14 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) return -ENOMEM; /* get first header */ - snd_sof_dsp_block_read(sdev, bar, offset, ext_data, + snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, ext_data, sizeof(*ext_hdr)); ext_hdr = ext_data; while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) { /* read in ext structure */ offset += sizeof(*ext_hdr); - snd_sof_dsp_block_read(sdev, bar, offset, + snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, (void *)((u8 *)ext_data + sizeof(*ext_hdr)), ext_hdr->hdr.size - sizeof(*ext_hdr)); @@ -79,7 +79,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) /* move to next header */ offset += ext_hdr->hdr.size; - snd_sof_dsp_block_read(sdev, bar, offset, ext_data, + snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, ext_data, sizeof(*ext_hdr)); ext_hdr = ext_data; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 49bc445d22c7e1..876d128e16237b 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -444,7 +444,7 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev); int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, struct snd_sof_mod_hdr *module); void snd_sof_fw_unload(struct snd_sof_dev *sdev); -int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset); +int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset); /* * IPC low level APIs. From a79122dfd52be8281e45567de13f7e74965f1342 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 2 Apr 2019 17:29:38 +0200 Subject: [PATCH 1318/1995] ASoC: SOF: IPC: remove a superfluous argument from functions .block_read() and .block_write() operations as well as their respective implementations sof_block_read() and sof_block_write() are always used with the MMIO BAR. Remove the argument and specify the BAR explicitly. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/hw-spi.c | 4 ++-- sound/soc/sof/intel/bdw.c | 3 +-- sound/soc/sof/intel/byt.c | 3 +-- sound/soc/sof/intel/hda-ipc.c | 3 +-- sound/soc/sof/intel/hda.c | 6 +++--- sound/soc/sof/intel/hsw.c | 3 +-- sound/soc/sof/ipc.c | 4 ++-- sound/soc/sof/loader.c | 9 ++++----- sound/soc/sof/ops.h | 8 ++++---- sound/soc/sof/sof-priv.h | 8 ++++---- sound/soc/sof/utils.c | 8 ++++---- 11 files changed, 27 insertions(+), 32 deletions(-) diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index 42a837fdc859b3..144098ced14b3a 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -36,7 +36,7 @@ * Memory copy. */ -static void spi_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, +static void spi_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, size_t size) { u8 *buf; @@ -62,7 +62,7 @@ static void spi_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, } } -static void spi_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, +static void spi_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, size_t size) { int ret; diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 4c17cb347ffd7d..da11a2f1240ebb 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -445,8 +445,7 @@ static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return 0; /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, - sizeof(*fw_ready)); + sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, fw_ready->dspbox_size, diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index b4a71ba18dbc9e..b2e01f628356f6 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -234,8 +234,7 @@ static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return 0; /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, - sizeof(*fw_ready)); + sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, fw_ready->dspbox_size, diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 7fbd1cca6240b9..009d0d95f92b3e 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -385,8 +385,7 @@ int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return 0; /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, - sizeof(*fw_ready)); + sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); /* make sure ABI version is compatible */ ret = snd_sof_ipc_valid(sdev); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index b8fc19790f3b80..b5694dba1b5089 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -109,15 +109,15 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev, u32 *stack, size_t stack_words) { /* first read registers */ - sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset, xoops, + sof_block_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); /* then get panic info */ - sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset + + sof_block_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), panic_info, sizeof(*panic_info)); /* then get the stack */ - sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset + + sof_block_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + sizeof(*panic_info), stack, stack_words * sizeof(u32)); } diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 2b4a44fa6f3912..950b5617ff27ea 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -446,8 +446,7 @@ static int hsw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return 0; /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, - sizeof(*fw_ready)); + sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, fw_ready->dspbox_size, diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 512c6f0b3deea3..f1d95f232789a9 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -645,12 +645,12 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc, send_bytes = sizeof(struct sof_ipc_ctrl_value_chan) * cdata->num_elems; if (send) - snd_sof_dsp_block_write(sdev, sdev->mmio_bar, + snd_sof_dsp_block_write(sdev, scontrol->readback_offset, cdata->chanv, send_bytes); else - snd_sof_dsp_block_read(sdev, sdev->mmio_bar, + snd_sof_dsp_block_read(sdev, scontrol->readback_offset, cdata->chanv, send_bytes); return 0; diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 72445f10e7b672..b46fe778185465 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -46,14 +46,14 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) return -ENOMEM; /* get first header */ - snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, ext_data, + snd_sof_dsp_block_read(sdev, offset, ext_data, sizeof(*ext_hdr)); ext_hdr = ext_data; while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) { /* read in ext structure */ offset += sizeof(*ext_hdr); - snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, + snd_sof_dsp_block_read(sdev, offset, (void *)((u8 *)ext_data + sizeof(*ext_hdr)), ext_hdr->hdr.size - sizeof(*ext_hdr)); @@ -79,7 +79,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) /* move to next header */ offset += ext_hdr->hdr.size; - snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, ext_data, + snd_sof_dsp_block_read(sdev, offset, ext_data, sizeof(*ext_hdr)); ext_hdr = ext_data; } @@ -145,8 +145,7 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, block->size); return -EINVAL; } - snd_sof_dsp_block_write(sdev, sdev->mmio_bar, offset, - block + 1, block->size); + snd_sof_dsp_block_write(sdev, offset, block + 1, block->size); /* minus body size of block */ remaining -= block->size; diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index e209ef86a27934..34378272e4211d 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -199,22 +199,22 @@ static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar, } /* block IO */ -static inline void snd_sof_dsp_block_read(struct snd_sof_dev *sdev, u32 bar, +static inline void snd_sof_dsp_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, size_t bytes) { if (sof_ops(sdev)->block_read) { - sof_ops(sdev)->block_read(sdev, bar, offset, dest, bytes); + sof_ops(sdev)->block_read(sdev, offset, dest, bytes); return; } dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__); } -static inline void snd_sof_dsp_block_write(struct snd_sof_dev *sdev, u32 bar, +static inline void snd_sof_dsp_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, size_t bytes) { if (sof_ops(sdev)->block_write) { - sof_ops(sdev)->block_write(sdev, bar, offset, src, bytes); + sof_ops(sdev)->block_write(sdev, offset, src, bytes); return; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 876d128e16237b..eeb08c44b02370 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -95,10 +95,10 @@ struct snd_sof_dsp_ops { void __iomem *addr); /* mandatory */ /* memcpy IO */ - void (*block_read)(struct snd_sof_dev *sof_dev, u32 bar, + void (*block_read)(struct snd_sof_dev *sof_dev, u32 offset, void *dest, size_t size); /* mandatory */ - void (*block_write)(struct snd_sof_dev *sof_dev, u32 bar, + void (*block_write)(struct snd_sof_dev *sof_dev, u32 offset, void *src, size_t size); /* mandatory */ @@ -608,9 +608,9 @@ void sof_mailbox_write(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes); void sof_mailbox_read(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes); -void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, +void sof_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, size_t size); -void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, +void sof_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, size_t size); void intel_ipc_msg_data(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index 2ac4c3da03206d..b92d713e15887e 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -71,10 +71,10 @@ EXPORT_SYMBOL(sof_mailbox_read); * Memory copy. */ -void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, +void sof_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, size_t size) { - void __iomem *dest = sdev->bar[bar] + offset; + void __iomem *dest = sdev->bar[sdev->mmio_bar] + offset; const u8 *src_byte = src; u32 affected_mask; u32 tmp; @@ -102,10 +102,10 @@ void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, } EXPORT_SYMBOL(sof_block_write); -void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, +void sof_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, size_t size) { - void __iomem *src = sdev->bar[bar] + offset; + void __iomem *src = sdev->bar[sdev->mmio_bar] + offset; memcpy_fromio(dest, src, size); } From 72c72641975946ae4f773c10c7f1e70044677a46 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 5 Apr 2019 14:46:52 -0700 Subject: [PATCH 1319/1995] ASoC: SOF: rename restore_stream to hw_params_upon_resume Rename the restore_stream field in struct snd_sof_pcm to hw_params_upon_resume to be more indicative of what it will be used for. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/sof-priv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index eeb08c44b02370..61e5fb18e760ef 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -279,7 +279,7 @@ struct snd_sof_pcm { struct snd_sof_pcm_stream stream[2]; struct list_head list; /* list in sdev pcm list */ struct snd_pcm_hw_params params[2]; - int restore_stream[2]; /* restore hw_params for paused stream */ + int hw_params_upon_resume[2]; /* set up hw_params upon resume */ }; /* ALSA SOF Kcontrol device */ From 3f14e7cd7af017c0cece61b7a3d4c5d310fb3396 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 5 Apr 2019 15:30:09 -0700 Subject: [PATCH 1320/1995] ASoC: SOF: pcm: do not add SNDRV_PCM_INFO_RESUME to runtime hw info This change is based on Takashi Iwai's feedback. The SOF driver cannot guarantee that the stream will be restarted from the exact same position after system resume. So, it should not advertise the SNDRV_PCM_INFO_RESUME in the runtime hw info. So this patch removes it. This actually simplifies the resume flow in the driver as the userspace restarts the stream and we can set the hw_params internally in the pcm prepare() op. So this patch adds the prepare() pcm op which sets up the hw_params in case the stream was marked for hw_params set up during system suspend. Finally, the resume trigger is also implemented as before for compatibility reasons, as suggested in the documentation. But in theory, this will never be called when SNDRV_PCM_INFO_RESUME is not set. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pcm.c | 100 +++++++++++++++----------------------------- 1 file changed, 34 insertions(+), 66 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index c81ac2e690b82c..f996e66a2189ef 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -169,9 +169,6 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, /* save pcm hw_params */ memcpy(&spcm->params[substream->stream], params, sizeof(*params)); - /* unset restore_stream */ - spcm->restore_stream[substream->stream] = 0; - return ret; } @@ -209,27 +206,33 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) return ret; } -static int sof_restore_hw_params(struct snd_pcm_substream *substream, - struct snd_sof_pcm *spcm, - struct snd_sof_dev *sdev) +static int sof_pcm_prepare(struct snd_pcm_substream *substream) { - snd_pcm_uframes_t host; - u64 host_posn; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm; int ret; - /* resume stream */ - host_posn = spcm->stream[substream->stream].posn.host_posn; - host = bytes_to_frames(substream->runtime, host_posn); - dev_dbg(sdev->dev, - "PCM: resume stream %d dir %d DMA position %lu\n", - spcm->pcm.pcm_id, substream->stream, host); + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + + /* + * check if hw_params needs to be set-up again. + * This is only needed when resuming from system sleep. + */ + if (!spcm->hw_params_upon_resume[substream->stream]) + return 0; + + dev_dbg(sdev->dev, "pcm: prepare stream %d dir %d\n", spcm->pcm.pcm_id, + substream->stream); /* set hw_params */ - ret = sof_pcm_hw_params(substream, - &spcm->params[substream->stream]); + ret = sof_pcm_hw_params(substream, &spcm->params[substream->stream]); if (ret < 0) { - dev_err(sdev->dev, - "error: set pcm hw_params after resume\n"); + dev_err(sdev->dev, "error: set pcm hw_params after resume\n"); return ret; } @@ -249,7 +252,6 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_sof_pcm *spcm; struct sof_ipc_stream stream; struct sof_ipc_reply reply; - int ret; /* nothing todo for BE */ if (rtd->dai_link->no_pcm) @@ -271,60 +273,23 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_PAUSE; break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - - /* check if the stream hw_params needs to be restored */ - if (spcm->restore_stream[substream->stream]) { - - /* restore hw_params */ - ret = sof_restore_hw_params(substream, spcm, sdev); - if (ret < 0) - return ret; - - /* unset restore_stream */ - spcm->restore_stream[substream->stream] = 0; - - /* trigger start */ - stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_START; - } else { - - /* trigger pause release */ - stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE; - } + stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE; break; - case SNDRV_PCM_TRIGGER_START: - /* fall through */ case SNDRV_PCM_TRIGGER_RESUME: - - /* check if the stream hw_params needs to be restored */ - if (spcm->restore_stream[substream->stream]) { - - /* restore hw_params */ - ret = sof_restore_hw_params(substream, spcm, sdev); - if (ret < 0) - return ret; - - /* unset restore_stream */ - spcm->restore_stream[substream->stream] = 0; + /* set up hw_params */ + ret = sof_pcm_prepare(substream); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to set up hw_params upon resume\n"); + return ret; } - /* trigger stream */ + /* fallthrough */ + case SNDRV_PCM_TRIGGER_START: stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_START; - break; case SNDRV_PCM_TRIGGER_SUSPEND: - /* fallthrough */ case SNDRV_PCM_TRIGGER_STOP: - - /* Check if stream was marked for restore before suspend */ - if (spcm->restore_stream[substream->stream]) { - - /* unset restore_stream */ - spcm->restore_stream[substream->stream] = 0; - - /* do not send ipc as the stream hasn't been set up */ - return 0; - } - stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; break; default: @@ -395,6 +360,9 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); + /* Clear hw_params_upon_resume flag */ + spcm->hw_params_upon_resume[substream->stream] = 0; + caps = &spcm->pcm.caps[substream->stream]; ret = pm_runtime_get_sync(sdev->dev); @@ -418,7 +386,6 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP; runtime->hw.formats = le64_to_cpu(caps->formats); runtime->hw.period_bytes_min = le32_to_cpu(caps->period_size_min); @@ -509,6 +476,7 @@ static struct snd_pcm_ops sof_pcm_ops = { .close = sof_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = sof_pcm_hw_params, + .prepare = sof_pcm_prepare, .hw_free = sof_pcm_hw_free, .trigger = sof_pcm_trigger, .pointer = sof_pcm_pointer, From 08eaa4e2a78da56be24c6fed89a338f573400736 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 5 Apr 2019 15:40:43 -0700 Subject: [PATCH 1321/1995] ASoC: SOF: intel: hda: add prepare op for BE dai link Add prepare op for BE dai link that will be used for setting up hw_params if the stream was marked for hw_params set up during system suspend. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dai.c | 37 +++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 21ccc0866abc95..830328af19c5ef 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -165,26 +165,58 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream, return hda_link_dma_params(link_dev, &p_params); } +static int hda_link_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(dai->component); + struct snd_sof_pcm *spcm; + int stream = substream->stream; + + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + + /* setup hw_params again only if resuming from system suspend */ + if (!spcm->hw_params_upon_resume[stream]) + return 0; + + dev_dbg(sdev->dev, "hda: prepare stream %d dir %d\n", + spcm->pcm.pcm_id, substream->stream); + + return hda_link_hw_params(substream, &rtd->dpcm[stream].hw_params, + dai); +} + static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct hdac_ext_stream *link_dev = snd_soc_dai_get_dma_data(dai, substream); + int ret; dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: + /* set up hw_params */ + ret = hda_link_pcm_prepare(substream, dai); + if (ret < 0) { + dev_err(dai->dev, + "error: setting up hw_params during resume\n"); + return ret; + } + + /* fallthrough */ case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: snd_hdac_ext_link_stream_start(link_dev); break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: snd_hdac_ext_link_stream_clear(link_dev); break; - default: return -EINVAL; } @@ -255,6 +287,7 @@ static const struct snd_soc_dai_ops hda_link_dai_ops = { .hw_params = hda_link_hw_params, .hw_free = hda_link_hw_free, .trigger = hda_link_pcm_trigger, + .prepare = hda_link_pcm_prepare, .get_channel_map = hda_link_dma_get_channels, }; #endif From c24c2447358978a38edcb32d7fe3e0d33ab48760 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 5 Apr 2019 15:42:30 -0700 Subject: [PATCH 1322/1995] ASoC: SOF: pm: set hw_params_upon_resume for suspended streams This patch does 3 things: 1. restore_stream member for struct snd_sof_pcm has been renamed to hw_params_upon_resume. So align with the new name. 2. Previously, we set the flag for all streams but with the recent change to not advertise INFO_RESUME in the SOF driver, it is sufficient to set the flag only for those streams that have been previously suspended. 3. rename the sof_restore_stream() function to sof_set_hw_params_upon_resume() to align with the above name change. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pm.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index fde92efd8a4560..fc599e1b6f65e6 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -204,16 +204,28 @@ static int sof_send_pm_ipc(struct snd_sof_dev *sdev, int cmd) sizeof(pm_ctx), &reply, sizeof(reply)); } -static void sof_set_restore_stream(struct snd_sof_dev *sdev) +static void sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev) { + struct snd_pcm_substream *substream; struct snd_sof_pcm *spcm; + snd_pcm_state_t state; + int dir; - /* suspend all running streams */ + /* + * SOF requires hw_params to be set-up internally upon resume. + * So, set the flag to indicate this for those streams that + * have been suspended. + */ list_for_each_entry(spcm, &sdev->pcm_list, list) { - - spcm->restore_stream[0] = 1; - spcm->restore_stream[1] = 1; - + for (dir = 0; dir <= SNDRV_PCM_STREAM_CAPTURE; dir++) { + substream = spcm->stream[dir].substream; + if (!substream || !substream->runtime) + continue; + + state = substream->runtime->status->state; + if (state == SNDRV_PCM_STATE_SUSPENDED) + spcm->hw_params_upon_resume[dir] = 1; + } } } @@ -319,7 +331,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) /* set restore_stream for all streams during system suspend */ if (!runtime_suspend) - sof_set_restore_stream(sdev); + sof_set_hw_params_upon_resume(sdev); #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) /* cache debugfs contents during runtime suspend */ From d20b622ca4d193b59fa37d9d81f7c9251af57959 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 5 Apr 2019 17:22:06 -0700 Subject: [PATCH 1323/1995] ASoC: SOF: pcm: send PCM_FREE ipc after STOP trigger during suspend PCM_FREE ipc should be sent to the DSP after the STOP trigger during system suspend to prevent hw_params errors upon resuming. This is usually done during pcm close but since we do not close the pcm during suspend, this needs to be done explicitly. This will fix issues with stream resuming with pulseaudio. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pcm.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index f996e66a2189ef..5a00db5b2e1b1e 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -252,6 +252,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_sof_pcm *spcm; struct sof_ipc_stream stream; struct sof_ipc_reply reply; + int ret; /* nothing todo for BE */ if (rtd->dai_link->no_pcm) @@ -299,6 +300,22 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) snd_sof_pcm_platform_trigger(sdev, substream, cmd); + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, + sizeof(stream), &reply, sizeof(reply)); + + if (ret < 0 || cmd != SNDRV_PCM_TRIGGER_SUSPEND) + return ret; + + /* + * The hw_free op is usually called when the pcm stream is closed. + * Since the stream is not closed during suspend, the DSP needs to be + * notified explicitly to free pcm to prevent errors upon resume. + */ + stream.hdr.size = sizeof(stream); + stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE; + stream.comp_id = spcm->stream[substream->stream].comp_id; + /* send IPC to the DSP */ return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, sizeof(stream), &reply, sizeof(reply)); From e4f9f00c1cd0beef447e948b21724b45b2cf6556 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 9 Apr 2019 12:41:53 -0500 Subject: [PATCH 1324/1995] ASoC: SOF: topology: fix endianness issue Sparse complains of following warning. Fix. topology.c:453:15: warning: restricted __le32 degrades to integer topology.c:467:52: warning: restricted __le32 degrades to integer Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/topology.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 0d001606834749..734e0480294ec8 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -450,7 +450,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, scontrol->num_channels = le32_to_cpu(mc->num_channels); /* set cmd for mixer control */ - if (mc->max == 1) { + if (le32_to_cpu(mc->max) == 1) { scontrol->cmd = SOF_CTRL_CMD_SWITCH; goto out; } @@ -464,7 +464,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, } /* set up volume table */ - ret = set_up_volume_table(scontrol, tlv, mc->max + 1); + ret = set_up_volume_table(scontrol, tlv, le32_to_cpu(mc->max) + 1); if (ret < 0) { dev_err(sdev->dev, "error: setting up volume table\n"); return ret; From 3c1306c3ae6ce00498961f59ba7ff62fdf20b538 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 4 Apr 2019 19:48:33 -0700 Subject: [PATCH 1325/1995] ASoC: topology: Use the correct dobj to free enum control values and texts The control values and texts of the enum kcontrol associated with a widget need to be freed when the widget is removed. However, both struct snd_soc_dapm_widget and struct soc_enum contain a dobj member, which resulted in a confusion. The existing code generates a null pointer dereference by attempting to free the values and texts from the dobj which belongs to the widget instead of the dobj belonging to the enum kcontrol. The suggested fix is to use the correct dobj member (se->dobj) of the enum kcontrol. Signed-off-by: Ranjani Sridharan Signed-off-by: Mark Brown (cherry picked from commit 54f8844e3f6cf898450a6c85f70fa997f0aa72b9) --- sound/soc/soc-topology.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 51903ca7614b4d..3299ebb48c1a0d 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -484,10 +484,11 @@ static void remove_widget(struct snd_soc_component *comp, snd_ctl_remove(card, kcontrol); - kfree(dobj->control.dvalues); + /* free enum kcontrol's dvalues and dtexts */ + kfree(se->dobj.control.dvalues); for (j = 0; j < se->items; j++) - kfree(dobj->control.dtexts[j]); - kfree(dobj->control.dtexts); + kfree(se->dobj.control.dtexts[j]); + kfree(se->dobj.control.dtexts); kfree(se); kfree(w->kcontrol_news[i].name); From 745ca682a5064b479f7e942717cafd2bdec5096b Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 29 Mar 2019 22:50:44 +0100 Subject: [PATCH 1326/1995] ASoC: Intel: bytcht_es8316: Add quirk for inverted jack detect Add a quirk to support boards whose jack detection mechanism is inverted. It will set the 'everest,jack-detect-inverted' boolean device property for the es8316 codec driver. Signed-off-by: Paul Cercueil Signed-off-by: Mark Brown (cherry picked from commit ba49cf6f8e4ad44ee752eb13413a26a7191893ae) --- sound/soc/intel/boards/bytcht_es8316.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 6937c00cf63d19..ccf552e92d5386 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -40,6 +40,9 @@ #include "../atom/sst-atom-controls.h" #include "../common/sst-dsp.h" +/* jd-inv + terminating entry */ +#define MAX_NO_PROPS 2 + struct byt_cht_es8316_private { struct clk *mclk; struct snd_soc_jack jack; @@ -55,6 +58,7 @@ enum { #define BYT_CHT_ES8316_MAP(quirk) ((quirk) & GENMASK(3, 0)) #define BYT_CHT_ES8316_SSP0 BIT(16) #define BYT_CHT_ES8316_MONO_SPEAKER BIT(17) +#define BYT_CHT_ES8316_JD_INVERTED BIT(18) static int quirk; @@ -72,6 +76,8 @@ static void log_quirks(struct device *dev) dev_info(dev, "quirk SSP0 enabled"); if (quirk & BYT_CHT_ES8316_MONO_SPEAKER) dev_info(dev, "quirk MONO_SPEAKER enabled\n"); + if (quirk & BYT_CHT_ES8316_JD_INVERTED) + dev_info(dev, "quirk JD_INVERTED enabled\n"); } static int byt_cht_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, @@ -438,12 +444,14 @@ static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = { static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { static const char * const mic_name[] = { "in1", "in2" }; + struct property_entry props[MAX_NO_PROPS] = {}; struct byt_cht_es8316_private *priv; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; const char *platform_name; struct acpi_device *adev; struct device *codec_dev; + unsigned int cnt = 0; int dai_index = 0; int i; int ret = 0; @@ -513,6 +521,15 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) if (!codec_dev) return -EPROBE_DEFER; + if (quirk & BYT_CHT_ES8316_JD_INVERTED) + props[cnt++] = PROPERTY_ENTRY_BOOL("everest,jack-detect-inverted"); + + if (cnt) { + ret = device_add_properties(codec_dev, props); + if (ret) + return ret; + } + devm_acpi_dev_add_driver_gpios(codec_dev, byt_cht_es8316_gpios); priv->speaker_en_gpio = gpiod_get_index(codec_dev, "speaker-enable", 0, From 011e0f1d5bc513e018549958f834fb08f25a407c Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Fri, 29 Mar 2019 22:50:45 +0100 Subject: [PATCH 1327/1995] ASoC: Intel: bytcht_es8316: Add quirk for the Teclast X98+ II The Teclast X98+ II is a Cherrytrail tablet, which require two quirks: - it has stereo speakers, - its jack detection mechanism is inverted. Signed-off-by: Paul Cercueil Signed-off-by: Mark Brown (cherry picked from commit a8d218f4fe8116395e4c4a13b63029ecf00d4035) --- sound/soc/intel/boards/bytcht_es8316.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index ccf552e92d5386..38975827e276ae 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -441,11 +442,25 @@ static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = { { }, }; +/* Please keep this list alphabetically sorted */ +static const struct dmi_system_id byt_cht_es8316_quirk_table[] = { + { /* Teclast X98 Plus II */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"), + DMI_MATCH(DMI_PRODUCT_NAME, "X98 Plus II"), + }, + .driver_data = (void *)(BYT_CHT_ES8316_INTMIC_IN1_MAP + | BYT_CHT_ES8316_JD_INVERTED), + }, + {} +}; + static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) { static const char * const mic_name[] = { "in1", "in2" }; struct property_entry props[MAX_NO_PROPS] = {}; struct byt_cht_es8316_private *priv; + const struct dmi_system_id *dmi_id; struct device *dev = &pdev->dev; struct snd_soc_acpi_mach *mach; const char *platform_name; @@ -488,7 +503,10 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) return ret; /* Check for BYTCR or other platform and setup quirks */ - if (x86_match_cpu(baytrail_cpu_ids) && + dmi_id = dmi_first_match(byt_cht_es8316_quirk_table); + if (dmi_id) { + quirk = (int)dmi_id->driver_data; + } else if (x86_match_cpu(baytrail_cpu_ids) && mach->mach_params.acpi_ipc_irq_index == 0) { /* On BYTCR default to SSP0, internal-mic-in2-map, mono-spk */ quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP | From 1a66ffbd3fa94adebe7c56c30b8baf50d58e3292 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 5 Apr 2019 09:57:08 -0700 Subject: [PATCH 1328/1995] ASoC: core: conditionally increase module refcount on component open Recently, for Intel platforms the "ignore_module_refcount" field was introduced for the component driver. In order to avoid a deadlock preventing the PCI modules from being removed even when the card was idle, the refcounts were not incremented for the device driver module during component probe. However, this change introduced a nasty side effect: the device driver module can be unloaded while a pcm stream is open. This patch proposes to change the field to be renamed as "module_get_upon_open". When this field is set, the module refcount should be incremented on pcm open amd decremented upon pcm close. This will enable modules to be removed when no PCM playback/capture happens and prevent removal when the component is actually in use. Also, align with the skylake component driver with the new name. Fixes: b450b878('ASoC: core: don't increase component module refcount unconditionally' Signed-off-by: Ranjani Sridharan Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit b4ed6b51f356224c6c71540ed94087f7f09b84af) --- include/sound/soc.h | 9 +++++++-- sound/soc/intel/skylake/skl-pcm.c | 2 +- sound/soc/soc-core.c | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 1e2be35ed36f2b..482b4ea87c3c4b 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -802,8 +802,13 @@ struct snd_soc_component_driver { int probe_order; int remove_order; - /* signal if the module handling the component cannot be removed */ - unsigned int ignore_module_refcount:1; + /* + * signal if the module handling the component should not be removed + * if a pcm is open. Setting this would prevent the module + * refcount being incremented in probe() but allow it be incremented + * when a pcm is opened and decremented when it is closed. + */ + unsigned int module_get_upon_open:1; /* bits */ unsigned int idle_bias_on:1; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 57031b6d4d45e0..9735e24122514f 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1475,7 +1475,7 @@ static const struct snd_soc_component_driver skl_component = { .ops = &skl_platform_ops, .pcm_new = skl_pcm_new, .pcm_free = skl_pcm_free, - .ignore_module_refcount = 1, /* do not increase the refcount in core */ + .module_get_upon_open = 1, /* increment refcount when a pcm is opened */ }; int skl_platform_register(struct device *dev) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 75f6a8085a766f..2403bec2fccf35 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -947,7 +947,7 @@ static void soc_cleanup_component(struct snd_soc_component *component) snd_soc_dapm_free(snd_soc_component_get_dapm(component)); soc_cleanup_component_debugfs(component); component->card = NULL; - if (!component->driver->ignore_module_refcount) + if (!component->driver->module_get_upon_open) module_put(component->dev->driver->owner); } @@ -1381,7 +1381,7 @@ static int soc_probe_component(struct snd_soc_card *card, return 0; } - if (!component->driver->ignore_module_refcount && + if (!component->driver->module_get_upon_open && !try_module_get(component->dev->driver->owner)) return -ENODEV; From 85df16186b1c224569502252880f5cd093ef4c8e Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 5 Apr 2019 09:57:09 -0700 Subject: [PATCH 1329/1995] ASoC: pcm: update module refcount if module_get_upon_open is set Setting the module_get_upon_open field for component driver prevents the module refcount from being incremented during component probe(). This could lead to the module being allowed to be unloaded when a pcm stream is open. So, if this field is set, the module's refcount should be incremented during pcm open to prevent module removal when the component is in use. And, the refcount should be decremented upon pcm close. Signed-off-by: Ranjani Sridharan Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 52034add758e268c39110f33d46e2a9492e82aef) --- sound/soc/soc-pcm.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 2d5d5cac4ba602..d21247546f7f76 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -463,6 +464,9 @@ static int soc_pcm_components_close(struct snd_pcm_substream *substream, continue; component->driver->ops->close(substream); + + if (component->driver->module_get_upon_open) + module_put(component->dev->driver->owner); } return 0; @@ -513,6 +517,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) !component->driver->ops->open) continue; + if (component->driver->module_get_upon_open && + !try_module_get(component->dev->driver->owner)) + return -ENODEV; + ret = component->driver->ops->open(substream); if (ret < 0) { dev_err(component->dev, From 5d61724a507b5f683609263a7a201ea1db0a7462 Mon Sep 17 00:00:00 2001 From: Jenny TC Date: Tue, 26 Mar 2019 22:50:56 +0530 Subject: [PATCH 1330/1995] ASoC: Intel: kbl_da7219_max98927: remove headset kbl_da7219_max98927 supports two configurations - One with da7219 & max98927/373 and other one with max98927/373 alone. This patch removes the headset dais from max98927/373 configuration. Since the snd_soc_dapm_ignore_suspend for DMIC is called from da7219_codec_init, the code is re-arranged to invoke snd_soc_dapm_ignore_suspend from kabylake_dmic_init. Signed-off-by: Jenny TC Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 2390c9b473da217ee086e5382869ade82c217a30) --- sound/soc/intel/boards/kbl_da7219_max98927.c | 52 +++++++++----------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c index 2768a572d0651b..f72a7bf028d725 100644 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ b/sound/soc/intel/boards/kbl_da7219_max98927.c @@ -52,7 +52,6 @@ struct kbl_codec_private { enum { KBL_DPCM_AUDIO_PB = 0, - KBL_DPCM_AUDIO_CP, KBL_DPCM_AUDIO_ECHO_REF_CP, KBL_DPCM_AUDIO_REF_CP, KBL_DPCM_AUDIO_DMIC_CP, @@ -60,6 +59,7 @@ enum { KBL_DPCM_AUDIO_HDMI2_PB, KBL_DPCM_AUDIO_HDMI3_PB, KBL_DPCM_AUDIO_HS_PB, + KBL_DPCM_AUDIO_CP, }; static int platform_clock_control(struct snd_soc_dapm_widget *w, @@ -311,6 +311,12 @@ static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) da7219_aad_jack_det(component, &ctx->kabylake_headset); + return 0; +} + +static int kabylake_dmic_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); if (ret) dev_err(rtd->dev, "SoC DMIC - Ignore suspend failed %d\n", ret); @@ -581,20 +587,6 @@ static struct snd_soc_dai_link kabylake_dais[] = { .dpcm_playback = 1, .ops = &kabylake_da7219_fe_ops, }, - [KBL_DPCM_AUDIO_CP] = { - .name = "Kbl Audio Capture Port", - .stream_name = "Audio Record", - .cpu_dai_name = "System Pin", - .platform_name = "0000:00:1f.3", - .dynamic = 1, - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &kabylake_da7219_fe_ops, - }, [KBL_DPCM_AUDIO_ECHO_REF_CP] = { .name = "Kbl Audio Echo Reference cap", .stream_name = "Echoreference Capture", @@ -690,6 +682,20 @@ static struct snd_soc_dai_link kabylake_dais[] = { .ops = &kabylake_da7219_fe_ops, }, + [KBL_DPCM_AUDIO_CP] = { + .name = "Kbl Audio Capture Port", + .stream_name = "Audio Record", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_capture = 1, + .ops = &kabylake_da7219_fe_ops, + }, /* Back End DAI links */ { @@ -733,6 +739,7 @@ static struct snd_soc_dai_link kabylake_dais[] = { .cpu_dai_name = "DMIC01 Pin", .codec_name = "dmic-codec", .codec_dai_name = "dmic-hifi", + .init = kabylake_dmic_init, .platform_name = "0000:00:1f.3", .be_hw_params_fixup = kabylake_dmic_fixup, .ignore_suspend = 1, @@ -792,20 +799,6 @@ static struct snd_soc_dai_link kabylake_max98_927_373_dais[] = { .dpcm_playback = 1, .ops = &kabylake_da7219_fe_ops, }, - [KBL_DPCM_AUDIO_CP] = { - .name = "Kbl Audio Capture Port", - .stream_name = "Audio Record", - .cpu_dai_name = "System Pin", - .platform_name = "0000:00:1f.3", - .dynamic = 1, - .codec_name = "snd-soc-dummy", - .codec_dai_name = "snd-soc-dummy-dai", - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &kabylake_da7219_fe_ops, - }, [KBL_DPCM_AUDIO_ECHO_REF_CP] = { .name = "Kbl Audio Echo Reference cap", .stream_name = "Echoreference Capture", @@ -911,6 +904,7 @@ static struct snd_soc_dai_link kabylake_max98_927_373_dais[] = { .cpu_dai_name = "DMIC01 Pin", .codec_name = "dmic-codec", .codec_dai_name = "dmic-hifi", + .init = kabylake_dmic_init, .platform_name = "0000:00:1f.3", .be_hw_params_fixup = kabylake_dmic_fixup, .ignore_suspend = 1, From 508de5a5a150048bf3925d3b6d0e7c1f95540aaf Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Apr 2019 10:57:32 -0500 Subject: [PATCH 1331/1995] ASoC: Intel: bytcht_es8316: fix compilation warning and quirk handling Remove warning and align quirk management with other machine drivers. No need to be creative here. bytcht_es8316.c:508:11: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] quirk = (int)dmi_id->driver_data; ^ Fixes: a8d218f4fe811 ('ASoC: Intel: bytcht_es8316: Add quirk for the Teclast X98+ II') Cc: Paul Cercueil Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bytcht_es8316.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 38975827e276ae..42e9e1e50e9c88 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -61,9 +61,9 @@ enum { #define BYT_CHT_ES8316_MONO_SPEAKER BIT(17) #define BYT_CHT_ES8316_JD_INVERTED BIT(18) -static int quirk; +static unsigned long quirk; -static int quirk_override = -1; +static int quirk_override; module_param_named(quirk, quirk_override, int, 0444); MODULE_PARM_DESC(quirk, "Board-specific quirk override"); @@ -505,7 +505,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) /* Check for BYTCR or other platform and setup quirks */ dmi_id = dmi_first_match(byt_cht_es8316_quirk_table); if (dmi_id) { - quirk = (int)dmi_id->driver_data; + quirk = (unsigned long)dmi_id->driver_data; } else if (x86_match_cpu(baytrail_cpu_ids) && mach->mach_params.acpi_ipc_irq_index == 0) { /* On BYTCR default to SSP0, internal-mic-in2-map, mono-spk */ @@ -516,8 +516,9 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) quirk = BYT_CHT_ES8316_INTMIC_IN1_MAP | BYT_CHT_ES8316_MONO_SPEAKER; } - if (quirk_override != -1) { - dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", quirk, + if (quirk_override) { + dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", + (unsigned int)quirk, quirk_override); quirk = quirk_override; } From 2acf0ff40dedf6591da49767ccd86b7a055e1e81 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Tue, 9 Apr 2019 21:55:28 +0300 Subject: [PATCH 1332/1995] Asoc: SOF: loader: check for unsigned wrap in subtraction fix a check with possible unsigned wrap based on feedback from Takashi Iwai. Signed-off-by: Jaska Uimonen --- sound/soc/sof/loader.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index b46fe778185465..8450b6d42fd086 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -106,13 +106,15 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, /* module->size doesn't include header size */ remaining = module->size; for (count = 0; count < module->num_blocks; count++) { - /* minus header size of block */ - remaining -= sizeof(*block); - if (remaining < block->size) { + /* check for wrap */ + if (remaining < sizeof(*block)) { dev_err(sdev->dev, "error: not enough data remaining\n"); return -EINVAL; } + /* minus header size of block */ + remaining -= sizeof(*block); + if (block->size == 0) { dev_warn(sdev->dev, "warning: block %d size zero\n", count); @@ -147,6 +149,11 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, } snd_sof_dsp_block_write(sdev, offset, block + 1, block->size); + if (remaining < block->size) { + dev_err(sdev->dev, "error: not enough data remaining\n"); + return -EINVAL; + } + /* minus body size of block */ remaining -= block->size; /* next block */ @@ -202,19 +209,34 @@ static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw) /* parse each module */ module = (struct snd_sof_mod_hdr *)((u8 *)(fw->data) + sizeof(*header)); remaining = fw->size - sizeof(*header); + /* check for wrap */ + if (remaining > fw->size) { + dev_err(sdev->dev, "error: fw size smaller than header size\n"); + return -EINVAL; + } + for (count = 0; count < header->num_modules; count++) { - /* minus header size of module */ - remaining -= sizeof(*module); - if (remaining < module->size) { + /* check for wrap */ + if (remaining < sizeof(*module)) { dev_err(sdev->dev, "error: not enough data remaining\n"); return -EINVAL; } + + /* minus header size of module */ + remaining -= sizeof(*module); + /* module */ ret = load_module(sdev, module); if (ret < 0) { dev_err(sdev->dev, "error: invalid module %d\n", count); return ret; } + + if (remaining < module->size) { + dev_err(sdev->dev, "error: not enough data remaining\n"); + return -EINVAL; + } + /* minus body size of module */ remaining -= module->size; module = (struct snd_sof_mod_hdr *)((u8 *)module From 7710a43fc7f9094f4d1021f1a890182d1fa34130 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Wed, 10 Apr 2019 14:16:14 +0800 Subject: [PATCH 1333/1995] ASoC: SOF: save reply data for SOF_IPC_PM_CTX_SAVE In hda-ipc, the code missed saving the reply data for SOF_IPC_PM_CTX_SAVE case. Signed-off-by: Libin Yang --- sound/soc/sof/intel/hda-ipc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 009d0d95f92b3e..82fdf2d92e7319 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -86,6 +86,7 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) reply.error = 0; reply.hdr.cmd = SOF_IPC_GLB_REPLY; reply.hdr.size = sizeof(reply); + memcpy(msg->reply_data, &reply, sizeof(reply)); goto out; } From b1e3ad6605bd7e69b9f7baa99e9caea25cba6962 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Mon, 8 Apr 2019 16:22:15 +0800 Subject: [PATCH 1334/1995] ASoC: SOF: hda-ipc: handle unexpected IPC reply Sometimes, driver will receive the unexpected ipc reply from DSP. The unexpected ipc reply belongs to none ipc sent before in the kernel driver. In this case, the driver should ignore the unexpected ipc reply. Signed-off-by: Libin Yang --- sound/soc/sof/intel/hda-ipc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 82fdf2d92e7319..bcc5017c41702a 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -75,6 +75,15 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) unsigned long flags; int ret = 0; + /* + * Sometimes, there is unexpected reply ipc arriving. The reply + * ipc belongs to none of the ipcs sent from driver. + * In this case, the driver must ignore the ipc. + */ + if (!msg) { + dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); + return; + } spin_lock_irqsave(&sdev->ipc_lock, flags); hdr = msg->msg_data; From e147588f7b2603245bcbc6d39708b03a8a045f25 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Wed, 10 Apr 2019 16:43:49 +0800 Subject: [PATCH 1335/1995] ASoC: SOF: hw-spi: handle unexpected IPC reply Sometimes, driver will receive the unexpected ipc reply from DSP. The unexpected ipc reply belongs to none ipc sent before in the kernel driver. In this case, the driver should ignore the unexpected ipc reply. Signed-off-by: Libin Yang --- sound/soc/sof/hw-spi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index 144098ced14b3a..83844664667927 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -181,6 +181,16 @@ static int spi_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) int ret = 0; u32 size; + /* + * Sometimes, there is unexpected reply ipc arriving. The reply + * ipc belongs to none of the ipcs sent from driver. + * In this case, the driver must ignore the ipc. + */ + if (!msg) { + dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); + return 0; + } + /* get reply */ spi_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); if (reply.error < 0) { From 19e6adb8d22f3b4201db339dbbadbbdcb1c8cfc4 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Wed, 10 Apr 2019 16:45:38 +0800 Subject: [PATCH 1336/1995] ASoC: SOF: bdw: handle unexpected IPC reply Sometimes, driver will receive the unexpected ipc reply from DSP. The unexpected ipc reply belongs to none ipc sent before in the kernel driver. In this case, the driver should ignore the unexpected ipc reply. Signed-off-by: Libin Yang --- sound/soc/sof/intel/bdw.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index da11a2f1240ebb..cd869e3be4033f 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -487,6 +487,16 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) unsigned long flags; int ret = 0; + /* + * Sometimes, there is unexpected reply ipc arriving. The reply + * ipc belongs to none of the ipcs sent from driver. + * In this case, the driver must ignore the ipc. + */ + if (!msg) { + dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); + return; + } + /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); From fbb22529d74b0ec2a5dcfa748e3d5b55994ebb36 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Wed, 10 Apr 2019 16:46:45 +0800 Subject: [PATCH 1337/1995] ASoC: SOF: byt: handle unexpected IPC reply Sometimes, driver will receive the unexpected ipc reply from DSP. The unexpected ipc reply belongs to none ipc sent before in the kernel driver. In this case, the driver should ignore the unexpected ipc reply. Signed-off-by: Libin Yang --- sound/soc/sof/intel/byt.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index b2e01f628356f6..ef8aa59b953135 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -385,6 +385,16 @@ static void byt_get_reply(struct snd_sof_dev *sdev) unsigned long flags; int ret = 0; + /* + * Sometimes, there is unexpected reply ipc arriving. The reply + * ipc belongs to none of the ipcs sent from driver. + * In this case, the driver must ignore the ipc. + */ + if (!msg) { + dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); + return; + } + /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); From a0de6c85203feffc67b1e1745067c20028a3f397 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Wed, 10 Apr 2019 16:49:57 +0800 Subject: [PATCH 1338/1995] ASoC: SOF: hsw: handle unexpected IPC reply Sometimes, driver will receive the unexpected ipc reply from DSP. The unexpected ipc reply belongs to none ipc sent before in the kernel driver. In this case, the driver should ignore the unexpected ipc reply. Signed-off-by: Libin Yang --- sound/soc/sof/intel/hsw.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 950b5617ff27ea..8e07ed0c555532 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -488,6 +488,16 @@ static void hsw_get_reply(struct snd_sof_dev *sdev) unsigned long flags; int ret = 0; + /* + * Sometimes, there is unexpected reply ipc arriving. The reply + * ipc belongs to none of the ipcs sent from driver. + * In this case, the driver must ignore the ipc. + */ + if (!msg) { + dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); + return; + } + spin_lock_irqsave(&sdev->ipc_lock, flags); /* get reply */ From dc99ad68b87572a7385843072d807523ad3c80e2 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 10 Apr 2019 23:31:44 -0700 Subject: [PATCH 1339/1995] ASoC: SOF: fix typos in comments Just a bit of clean up. No change in functionality. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/control.c | 10 +++++----- sound/soc/sof/core.c | 4 ++-- sound/soc/sof/intel/hda-ipc.c | 8 +++----- sound/soc/sof/ipc.c | 6 +++--- sound/soc/sof/pcm.c | 19 +++++++++---------- sound/soc/sof/topology.c | 10 +++++----- 6 files changed, 27 insertions(+), 30 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 4a02c5003d80fe..11762c4580f102 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -221,7 +221,7 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, return ret; } - /* get all the mixer data from DSP */ + /* get all the enum data from DSP */ snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_VALUE, SOF_CTRL_TYPE_VALUE_CHAN_GET, @@ -267,7 +267,7 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, cdata->chanv[i].channel = i; } - /* notify DSP of mixer updates */ + /* notify DSP of enum updates */ snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_VALUE, SOF_CTRL_TYPE_VALUE_CHAN_GET, @@ -311,7 +311,7 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, return ret; } - /* get all the mixer data from DSP */ + /* get all the binary data from DSP */ snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_DATA, SOF_CTRL_TYPE_DATA_GET, @@ -377,7 +377,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, /* copy from kcontrol */ memcpy(data, ucontrol->value.bytes.data, data->size); - /* notify DSP of mixer updates */ + /* notify DSP of byte control updates */ snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_DATA, SOF_CTRL_TYPE_DATA_SET, @@ -461,7 +461,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, return ret; } - /* notify DSP of mixer updates */ + /* notify DSP of byte control updates */ snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_DATA, SOF_CTRL_TYPE_DATA_SET, diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index e6d6d2d74803c8..1e62f525c11d18 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -188,7 +188,7 @@ void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, dev_err(sdev->dev, "error: trace point %8.8x\n", tracep_code); out: - dev_err(sdev->dev, "error: panic happen at %s:%d\n", + dev_err(sdev->dev, "error: panic at %s:%d\n", panic_info->filename, panic_info->linenum); sof_oops(sdev, oops); sof_stack(sdev, oops, stack, stack_words); @@ -198,7 +198,7 @@ EXPORT_SYMBOL(snd_sof_get_status); /* * Generic buffer page table creation. * Take the each physical page address and drop the least significant unused - * bites from each (based on PAGE_SIZE). Then pack valid page address bits + * bits from each (based on PAGE_SIZE). Then pack valid page address bits * into compressed page table. */ diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index bcc5017c41702a..1b15c8214cb5f9 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -217,7 +217,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) /* this is a PANIC message !! */ snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext)); } else { - /* normal message - process normally*/ + /* normal message - process normally */ snd_sof_ipc_msgs_rx(sdev); } @@ -259,9 +259,7 @@ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) return ret; } -/* - * IPC Firmware ready. - */ +/* IPC Firmware ready */ static void ipc_get_windows(struct snd_sof_dev *sdev) { @@ -444,7 +442,7 @@ int hda_ipc_pcm_params(struct snd_sof_dev *sdev, hda_stream = container_of(hstream, struct sof_intel_hda_stream, hda_stream.hstream); - /* check if offset is overflow or it is not aligned */ + /* check for unaligned offset or overflow */ if (posn_offset > sdev->stream_box.size || posn_offset % sizeof(struct sof_ipc_stream_posn) != 0) return -EINVAL; diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index f1d95f232789a9..b293f72c875ca4 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -706,11 +706,11 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc, return err; } - /* data is bigger than max ipc size, chop to smaller pieces */ + /* data is bigger than max ipc size, chop into smaller pieces */ dev_dbg(sdev->dev, "large ipc size %u, control size %u\n", cdata->rhdr.hdr.size, scontrol->size); - /* large messages is only supported from abi 3.3.0 onwards */ + /* large messages is only supported from ABI 3.3.0 onwards */ if (v->abi_version < SOF_ABI_VER(3, 3, 0)) { dev_err(sdev->dev, "error: incompatible FW ABI version\n"); return -EINVAL; @@ -800,7 +800,7 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) ipc->sdev = sdev; msg = &ipc->msg; - /* Indicate, that we aren't sending a message ATM */ + /* indicate that we aren't sending a message ATM */ msg->ipc_complete = true; /* pre-allocate message data */ diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 5a00db5b2e1b1e..5034df71ba5708 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -66,7 +66,7 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, struct sof_ipc_pcm_params_reply ipc_params_reply; int ret; - /* nothing todo for BE */ + /* nothing to do for BE */ if (rtd->dai_link->no_pcm) return 0; @@ -183,7 +183,7 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) struct sof_ipc_reply reply; int ret; - /* nothing todo for BE */ + /* nothing to do for BE */ if (rtd->dai_link->no_pcm) return 0; @@ -254,7 +254,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct sof_ipc_reply reply; int ret; - /* nothing todo for BE */ + /* nothing to do for BE */ if (rtd->dai_link->no_pcm) return 0; @@ -330,11 +330,11 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) struct snd_sof_pcm *spcm; snd_pcm_uframes_t host, dai; - /* nothing todo for BE */ + /* nothing to do for BE */ if (rtd->dai_link->no_pcm) return 0; - /* if have dsp ops pointer callback, use that directly */ + /* use dsp ops pointer callback directly if set */ if (sof_ops(sdev)->pcm_pointer) return sof_ops(sdev)->pcm_pointer(sdev, substream); @@ -366,7 +366,7 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) int ret; int err; - /* nothing todo for BE */ + /* nothing to do for BE */ if (rtd->dai_link->no_pcm) return 0; @@ -377,7 +377,7 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); - /* Clear hw_params_upon_resume flag */ + /* clear hw_params_upon_resume flag */ spcm->hw_params_upon_resume[substream->stream] = 0; caps = &spcm->pcm.caps[substream->stream]; @@ -457,7 +457,7 @@ static int sof_pcm_close(struct snd_pcm_substream *substream) struct snd_sof_pcm *spcm; int err; - /* nothing todo for BE */ + /* nothing to do for BE */ if (rtd->dai_link->no_pcm) return 0; @@ -634,7 +634,6 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, dai->comp_dai.config.frame_fmt, dai->dai_config->type); } - /* TODO: add any other DMIC specific fixups */ break; case SOF_DAI_INTEL_HDA: /* do nothing for HDA dai_link */ @@ -675,7 +674,7 @@ static int sof_pcm_probe(struct snd_soc_component *component) /* * Some platforms in SOF, ex: BYT, may not have their platform PM * callbacks set. Increment the usage count so as to - * prevent the device entering runtime suspend. + * prevent the device from entering runtime suspend. */ if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume) pm_runtime_get_noresume(sdev->dev); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 734e0480294ec8..dfe6f50e0d71ea 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1293,7 +1293,7 @@ static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index, if (!host) return -ENOMEM; - /* configure mixer IPC message */ + /* configure host comp IPC message */ host->comp.hdr.size = sizeof(*host); host->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; host->comp.id = swidget->comp_id; @@ -1562,7 +1562,7 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, goto err; } - /* configure dai IPC message */ + /* configure volume IPC message */ volume->comp.hdr.size = sizeof(*volume); volume->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; volume->comp.id = swidget->comp_id; @@ -1618,7 +1618,7 @@ static int sof_widget_load_src(struct snd_soc_component *scomp, int index, if (!src) return -ENOMEM; - /* configure mixer IPC message */ + /* configure src IPC message */ src->comp.hdr.size = sizeof(*src); src->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; src->comp.id = swidget->comp_id; @@ -1677,7 +1677,7 @@ static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index, if (!tone) return -ENOMEM; - /* configure mixer IPC message */ + /* configure siggen IPC message */ tone->comp.hdr.size = sizeof(*tone); tone->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; tone->comp.id = swidget->comp_id; @@ -2192,7 +2192,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, int stream = SNDRV_PCM_STREAM_PLAYBACK; int ret = 0; - /* don't need to do anything for BEs atm */ + /* nothing to do for BEs atm */ if (!pcm) return 0; From 8e89640298c748245d18d983e15ecb4328e6fac6 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 10 Apr 2019 00:10:17 +0300 Subject: [PATCH 1340/1995] ASoC: SOF: handle unaligned read position in debugfs reads Read position for debugfs reads may not be aligned to 32bit and this may lead to invalid accesses to iomem. Handle unaligned positions explicitly. Feedback from Takashi Iwai Signed-off-by: Kai Vehmanen --- sound/soc/sof/debug.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index b5ba606d2ac6e1..55f1d808dba04f 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -22,10 +22,11 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, { struct snd_sof_dfsentry *dfse = file->private_data; struct snd_sof_dev *sdev = dfse->sdev; - int size; - u32 *buf; loff_t pos = *ppos; size_t size_ret; + int skip = 0; + int size; + u8 *buf; size = dfse->size; @@ -38,9 +39,19 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, if (count > size - pos) count = size - pos; + /* align io read start to u32 multiple */ + pos = ALIGN_DOWN(pos, 4); + /* intermediate buffer size must be u32 multiple */ size = ALIGN(count, 4); + /* if start position is unaligned, read extra u32 */ + if (unlikely(pos != *ppos)) { + skip = *ppos - pos; + if (pos + size + 4 < dfse->size) + size += 4; + } + buf = kzalloc(size, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -79,7 +90,8 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, } /* copy to userspace */ - size_ret = copy_to_user(buffer, buf, count); + size_ret = copy_to_user(buffer, buf + skip, count); + kfree(buf); /* update count & position if copy succeeded */ From 85c400e2385902920a033f0f26b476b485a56a14 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Mon, 8 Apr 2019 02:25:48 +0800 Subject: [PATCH 1341/1995] ASoC: SOF: topology: add abi checking Now we have abi information in topology manifest, therefore we can add abi checking to avoid using a mismatched topology. Signed-off-by: Bard liao --- sound/soc/sof/topology.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index dfe6f50e0d71ea..2a13391e685dd6 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -39,6 +39,9 @@ #define TLV_STEP 1 #define TLV_MUTE 2 +/* size of tplg abi in byte */ +#define SOF_TPLG_ABI_SIZE 3 + /* send pcm params ipc */ static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir) { @@ -3046,8 +3049,28 @@ static void sof_complete(struct snd_soc_component *scomp) static int sof_manifest(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_manifest *man) { - /* not currently parsed */ - return 0; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + + /* backward compatible with tplg without ABI info */ + if (!man->priv.size) { + dev_dbg(sdev->dev, "No topology ABI info\n"); + return 0; + } + + if (man->priv.size == SOF_TPLG_ABI_SIZE) { + dev_info(sdev->dev, + "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n", + man->priv.data[0], man->priv.data[1], + man->priv.data[2], SOF_ABI_MAJOR, SOF_ABI_MINOR, + SOF_ABI_PATCH); + if (SOF_ABI_VER(man->priv.data[0], man->priv.data[1], + man->priv.data[2]) <= SOF_ABI_VERSION) + return 0; + } + dev_err(sdev->dev, + "error: Incompatible ABI version %d:%d:%d\n", + man->priv.data[0], man->priv.data[1], man->priv.data[2]); + return -EINVAL; } /* vendor specific kcontrol handlers available for binding */ From 7adfaac75f5cf9c6225b0242ed190515591ca159 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 10 Apr 2019 17:40:11 +0300 Subject: [PATCH 1342/1995] Revert "ASoC: SOF: IPC: remove a superfluous argument from functions" bar argument is used on i.MX This reverts commit a79122dfd52be8281e45567de13f7e74965f1342. --- sound/soc/sof/hw-spi.c | 4 ++-- sound/soc/sof/intel/bdw.c | 3 ++- sound/soc/sof/intel/byt.c | 3 ++- sound/soc/sof/intel/hda-ipc.c | 3 ++- sound/soc/sof/intel/hda.c | 6 +++--- sound/soc/sof/intel/hsw.c | 3 ++- sound/soc/sof/ipc.c | 4 ++-- sound/soc/sof/loader.c | 9 +++++---- sound/soc/sof/ops.h | 8 ++++---- sound/soc/sof/sof-priv.h | 8 ++++---- sound/soc/sof/utils.c | 8 ++++---- 11 files changed, 32 insertions(+), 27 deletions(-) diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c index 83844664667927..7e1eaf9ac9e0a6 100644 --- a/sound/soc/sof/hw-spi.c +++ b/sound/soc/sof/hw-spi.c @@ -36,7 +36,7 @@ * Memory copy. */ -static void spi_block_read(struct snd_sof_dev *sdev, u32 offset, +static void spi_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, size_t size) { u8 *buf; @@ -62,7 +62,7 @@ static void spi_block_read(struct snd_sof_dev *sdev, u32 offset, } } -static void spi_block_write(struct snd_sof_dev *sdev, u32 offset, +static void spi_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, size_t size) { int ret; diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index cd869e3be4033f..9122902d9b2348 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -445,7 +445,8 @@ static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return 0; /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); + sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, + sizeof(*fw_ready)); snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, fw_ready->dspbox_size, diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index ef8aa59b953135..f66b19d8be0282 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -234,7 +234,8 @@ static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return 0; /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); + sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, + sizeof(*fw_ready)); snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, fw_ready->dspbox_size, diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 1b15c8214cb5f9..6af727d360c527 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -393,7 +393,8 @@ int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return 0; /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); + sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, + sizeof(*fw_ready)); /* make sure ABI version is compatible */ ret = snd_sof_ipc_valid(sdev); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index b5694dba1b5089..b8fc19790f3b80 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -109,15 +109,15 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev, u32 *stack, size_t stack_words) { /* first read registers */ - sof_block_read(sdev, sdev->dsp_oops_offset, xoops, + sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); /* then get panic info */ - sof_block_read(sdev, sdev->dsp_oops_offset + + sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset + sizeof(*xoops), panic_info, sizeof(*panic_info)); /* then get the stack */ - sof_block_read(sdev, sdev->dsp_oops_offset + + sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset + sizeof(*xoops) + sizeof(*panic_info), stack, stack_words * sizeof(u32)); } diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index 8e07ed0c555532..d7cf33b6fe2bed 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -446,7 +446,8 @@ static int hsw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return 0; /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, offset, fw_ready, sizeof(*fw_ready)); + sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, + sizeof(*fw_ready)); snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, fw_ready->dspbox_size, diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index b293f72c875ca4..d00373ceca12a3 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -645,12 +645,12 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc, send_bytes = sizeof(struct sof_ipc_ctrl_value_chan) * cdata->num_elems; if (send) - snd_sof_dsp_block_write(sdev, + snd_sof_dsp_block_write(sdev, sdev->mmio_bar, scontrol->readback_offset, cdata->chanv, send_bytes); else - snd_sof_dsp_block_read(sdev, + snd_sof_dsp_block_read(sdev, sdev->mmio_bar, scontrol->readback_offset, cdata->chanv, send_bytes); return 0; diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 8450b6d42fd086..a81d6511f5807f 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -46,14 +46,14 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) return -ENOMEM; /* get first header */ - snd_sof_dsp_block_read(sdev, offset, ext_data, + snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, ext_data, sizeof(*ext_hdr)); ext_hdr = ext_data; while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) { /* read in ext structure */ offset += sizeof(*ext_hdr); - snd_sof_dsp_block_read(sdev, offset, + snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, (void *)((u8 *)ext_data + sizeof(*ext_hdr)), ext_hdr->hdr.size - sizeof(*ext_hdr)); @@ -79,7 +79,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) /* move to next header */ offset += ext_hdr->hdr.size; - snd_sof_dsp_block_read(sdev, offset, ext_data, + snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, ext_data, sizeof(*ext_hdr)); ext_hdr = ext_data; } @@ -147,7 +147,8 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, block->size); return -EINVAL; } - snd_sof_dsp_block_write(sdev, offset, block + 1, block->size); + snd_sof_dsp_block_write(sdev, sdev->mmio_bar, offset, + block + 1, block->size); if (remaining < block->size) { dev_err(sdev->dev, "error: not enough data remaining\n"); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 34378272e4211d..e209ef86a27934 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -199,22 +199,22 @@ static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar, } /* block IO */ -static inline void snd_sof_dsp_block_read(struct snd_sof_dev *sdev, +static inline void snd_sof_dsp_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, size_t bytes) { if (sof_ops(sdev)->block_read) { - sof_ops(sdev)->block_read(sdev, offset, dest, bytes); + sof_ops(sdev)->block_read(sdev, bar, offset, dest, bytes); return; } dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__); } -static inline void snd_sof_dsp_block_write(struct snd_sof_dev *sdev, +static inline void snd_sof_dsp_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, size_t bytes) { if (sof_ops(sdev)->block_write) { - sof_ops(sdev)->block_write(sdev, offset, src, bytes); + sof_ops(sdev)->block_write(sdev, bar, offset, src, bytes); return; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 61e5fb18e760ef..d14f0694fa170b 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -95,10 +95,10 @@ struct snd_sof_dsp_ops { void __iomem *addr); /* mandatory */ /* memcpy IO */ - void (*block_read)(struct snd_sof_dev *sof_dev, + void (*block_read)(struct snd_sof_dev *sof_dev, u32 bar, u32 offset, void *dest, size_t size); /* mandatory */ - void (*block_write)(struct snd_sof_dev *sof_dev, + void (*block_write)(struct snd_sof_dev *sof_dev, u32 bar, u32 offset, void *src, size_t size); /* mandatory */ @@ -608,9 +608,9 @@ void sof_mailbox_write(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes); void sof_mailbox_read(struct snd_sof_dev *sdev, u32 offset, void *message, size_t bytes); -void sof_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, +void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, size_t size); -void sof_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, +void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, size_t size); void intel_ipc_msg_data(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index b92d713e15887e..2ac4c3da03206d 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -71,10 +71,10 @@ EXPORT_SYMBOL(sof_mailbox_read); * Memory copy. */ -void sof_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, +void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, size_t size) { - void __iomem *dest = sdev->bar[sdev->mmio_bar] + offset; + void __iomem *dest = sdev->bar[bar] + offset; const u8 *src_byte = src; u32 affected_mask; u32 tmp; @@ -102,10 +102,10 @@ void sof_block_write(struct snd_sof_dev *sdev, u32 offset, void *src, } EXPORT_SYMBOL(sof_block_write); -void sof_block_read(struct snd_sof_dev *sdev, u32 offset, void *dest, +void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, size_t size) { - void __iomem *src = sdev->bar[sdev->mmio_bar] + offset; + void __iomem *src = sdev->bar[bar] + offset; memcpy_fromio(dest, src, size); } From e4c4fa5b5cb21cc8174e227b4fd16c628377d296 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 10 Apr 2019 17:40:23 +0300 Subject: [PATCH 1343/1995] Revert "ASoC: SOF: IPC: remove a superfluous function argument" bar argument is used on i.MX This reverts commit 8b742b87b2f9b2a53702db995789d4c19e91b0c6. --- sound/soc/sof/intel/bdw.c | 2 +- sound/soc/sof/intel/byt.c | 2 +- sound/soc/sof/intel/hda-ipc.c | 3 ++- sound/soc/sof/intel/hsw.c | 2 +- sound/soc/sof/loader.c | 8 ++++---- sound/soc/sof/sof-priv.h | 2 +- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 9122902d9b2348..065cb868bdface 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -459,7 +459,7 @@ static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return ret; /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + + snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + sizeof(struct sof_ipc_fw_ready)); bdw_get_windows(sdev); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index f66b19d8be0282..7bf9143d310673 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -248,7 +248,7 @@ static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return ret; /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + + snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + sizeof(struct sof_ipc_fw_ready)); byt_get_windows(sdev); diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 6af727d360c527..a938f568dbb1c3 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -402,7 +402,8 @@ int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return ret; /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, HDA_DSP_MBOX_UPLINK_OFFSET + + snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, + HDA_DSP_MBOX_UPLINK_OFFSET + sizeof(struct sof_ipc_fw_ready)); ipc_get_windows(sdev); diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c index d7cf33b6fe2bed..5389d55d07a228 100644 --- a/sound/soc/sof/intel/hsw.c +++ b/sound/soc/sof/intel/hsw.c @@ -460,7 +460,7 @@ static int hsw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) return ret; /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, MBOX_OFFSET + + snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + sizeof(struct sof_ipc_fw_ready)); hsw_get_windows(sdev); diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index a81d6511f5807f..e73314ccd54ffb 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -35,7 +35,7 @@ static int get_ext_windows(struct snd_sof_dev *sdev, } /* parse the extended FW boot data structures from FW boot message */ -int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) +int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) { struct sof_ipc_ext_data_hdr *ext_hdr; void *ext_data; @@ -46,14 +46,14 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) return -ENOMEM; /* get first header */ - snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, ext_data, + snd_sof_dsp_block_read(sdev, bar, offset, ext_data, sizeof(*ext_hdr)); ext_hdr = ext_data; while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) { /* read in ext structure */ offset += sizeof(*ext_hdr); - snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, + snd_sof_dsp_block_read(sdev, bar, offset, (void *)((u8 *)ext_data + sizeof(*ext_hdr)), ext_hdr->hdr.size - sizeof(*ext_hdr)); @@ -79,7 +79,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset) /* move to next header */ offset += ext_hdr->hdr.size; - snd_sof_dsp_block_read(sdev, sdev->mmio_bar, offset, ext_data, + snd_sof_dsp_block_read(sdev, bar, offset, ext_data, sizeof(*ext_hdr)); ext_hdr = ext_data; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index d14f0694fa170b..36f487f66a768e 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -444,7 +444,7 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev); int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, struct snd_sof_mod_hdr *module); void snd_sof_fw_unload(struct snd_sof_dev *sdev); -int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 offset); +int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset); /* * IPC low level APIs. From 02f59323e83050bb9e7d28fafc98ac64ca97fcb8 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Thu, 11 Apr 2019 14:52:50 +0800 Subject: [PATCH 1344/1995] ASoC: SOF: pcm: skip pcm_prepare for BE dai pcm_prepare also need to skip BE dai. This will fix snd_sof_find_spcm_dai fail issue, since we do not have spcm for BE dai. Signed-off-by: Pan Xiuli --- sound/soc/sof/pcm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 5034df71ba5708..be4984c4da4eb8 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -215,6 +215,10 @@ static int sof_pcm_prepare(struct snd_pcm_substream *substream) struct snd_sof_pcm *spcm; int ret; + /* nothing to do for BE */ + if (rtd->dai_link->no_pcm) + return 0; + spcm = snd_sof_find_spcm_dai(sdev, rtd); if (!spcm) return -EINVAL; From 0d77d1ccc781c8c03e970a7196518ff2fffb7293 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 9 Apr 2019 12:33:06 +0200 Subject: [PATCH 1345/1995] ASoC: SOF: core: check for mandatory operations during probing Some of struct snd_sof_dsp_ops members are declared as mandatory even though not all platforms provide them. Others are indeed mandatory but a failure to provide them will not be fatal and the driver will continue to run. This patch cleans up mandatory operation flags and adds a check for them to snd_sof_device_probe(). After such a check verifying them in individual wrappers isn't necessary any more. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 7 +++++++ sound/soc/sof/ops.h | 43 +++++++++------------------------------- sound/soc/sof/sof-priv.h | 20 +++++++++++-------- 3 files changed, 28 insertions(+), 42 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 1e62f525c11d18..61f6bf35878fc0 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -433,6 +433,13 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) sdev->first_boot = true; dev_set_drvdata(dev, sdev); + /* check all mandatory ops */ + if (!sof_ops(sdev) || sof_ops(sdev)->probe || !sof_ops(sdev)->run || + !sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write || + !sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware || + !sof_ops(sdev)->ipc_msg_data || !sof_ops(sdev)->ipc_pcm_params) + return -EINVAL; + INIT_LIST_HEAD(&sdev->pcm_list); INIT_LIST_HEAD(&sdev->kcontrol_list); INIT_LIST_HEAD(&sdev->widget_list); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index e209ef86a27934..2a5d4c63f160f8 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -21,14 +21,12 @@ #define sof_ops(sdev) \ ((sdev)->pdata->desc->ops) +/* Mandatory operations are verified during probing */ + /* init */ static inline int snd_sof_probe(struct snd_sof_dev *sdev) { - if (sof_ops(sdev)->probe) - return sof_ops(sdev)->probe(sdev); - - dev_err(sdev->dev, "error: %s not defined\n", __func__); - return -ENOTSUPP; + return sof_ops(sdev)->probe(sdev); } static inline int snd_sof_remove(struct snd_sof_dev *sdev) @@ -47,11 +45,7 @@ static inline int snd_sof_remove(struct snd_sof_dev *sdev) */ static inline int snd_sof_dsp_run(struct snd_sof_dev *sdev) { - if (sof_ops(sdev)->run) - return sof_ops(sdev)->run(sdev); - - dev_err(sdev->dev, "error: %s not defined\n", __func__); - return -ENOTSUPP; + return sof_ops(sdev)->run(sdev); } static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev) @@ -202,34 +196,20 @@ static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar, static inline void snd_sof_dsp_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, size_t bytes) { - if (sof_ops(sdev)->block_read) { - sof_ops(sdev)->block_read(sdev, bar, offset, dest, bytes); - return; - } - - dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__); + sof_ops(sdev)->block_read(sdev, bar, offset, dest, bytes); } static inline void snd_sof_dsp_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, size_t bytes) { - if (sof_ops(sdev)->block_write) { - sof_ops(sdev)->block_write(sdev, bar, offset, src, bytes); - return; - } - - dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__); + sof_ops(sdev)->block_write(sdev, bar, offset, src, bytes); } /* ipc */ static inline int snd_sof_dsp_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { - if (sof_ops(sdev)->send_msg) - return sof_ops(sdev)->send_msg(sdev, msg); - - dev_err(sdev->dev, "error: %s not defined\n", __func__); - return -ENOTSUPP; + return sof_ops(sdev)->send_msg(sdev, msg); } /* host DMA trace */ @@ -310,8 +290,7 @@ static inline void snd_sof_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, void *p, size_t sz) { - if (sof_ops(sdev) && sof_ops(sdev)->ipc_msg_data) - sof_ops(sdev)->ipc_msg_data(sdev, substream, p, sz); + sof_ops(sdev)->ipc_msg_data(sdev, substream, p, sz); } /* host configure DSP HW parameters */ @@ -320,11 +299,7 @@ snd_sof_ipc_pcm_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, const struct sof_ipc_pcm_params_reply *reply) { - if (sof_ops(sdev) && sof_ops(sdev)->ipc_pcm_params) - return sof_ops(sdev)->ipc_pcm_params(sdev, substream, reply); - - dev_err(sdev->dev, "error: %s not defined\n", __func__); - return -ENOTSUPP; + return sof_ops(sdev)->ipc_pcm_params(sdev, substream, reply); } /* host stream pointer */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 36f487f66a768e..35e78ffecce2fe 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -84,15 +84,19 @@ struct snd_sof_dsp_ops { int (*core_power_down)(struct snd_sof_dev *sof_dev, unsigned int core_mask); /* optional */ - /* Register IO */ + /* + * Register IO: only used by respective drivers themselves, + * TODO: consider removing these operations and calling respective + * implementations directly + */ void (*write)(struct snd_sof_dev *sof_dev, void __iomem *addr, - u32 value); /* mandatory */ + u32 value); /* optional */ u32 (*read)(struct snd_sof_dev *sof_dev, - void __iomem *addr); /* mandatory */ + void __iomem *addr); /* optional */ void (*write64)(struct snd_sof_dev *sof_dev, void __iomem *addr, - u64 value); /* mandatory */ + u64 value); /* optional */ u64 (*read64)(struct snd_sof_dev *sof_dev, - void __iomem *addr); /* mandatory */ + void __iomem *addr); /* optional */ /* memcpy IO */ void (*block_read)(struct snd_sof_dev *sof_dev, u32 bar, @@ -103,8 +107,8 @@ struct snd_sof_dsp_ops { size_t size); /* mandatory */ /* doorbell */ - irqreturn_t (*irq_handler)(int irq, void *context); /* mandatory */ - irqreturn_t (*irq_thread)(int irq, void *context); /* mandatory */ + irqreturn_t (*irq_handler)(int irq, void *context); /* optional */ + irqreturn_t (*irq_thread)(int irq, void *context); /* optional */ /* ipc */ int (*send_msg)(struct snd_sof_dev *sof_dev, @@ -118,7 +122,7 @@ struct snd_sof_dsp_ops { * FW ready checks for ABI compatibility and creates * memory windows at first boot */ - int (*fw_ready)(struct snd_sof_dev *sdev, u32 msg_id); /* mandatory */ + int (*fw_ready)(struct snd_sof_dev *sdev, u32 msg_id); /* optional */ /* connect pcm substream to a host stream */ int (*pcm_open)(struct snd_sof_dev *sdev, From b7457ec2bfd0b9815182bec70a64a20aebc31561 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 11 Apr 2019 18:40:16 -0700 Subject: [PATCH 1346/1995] ASoC: SOF: core: fix typo while checking for mandatory ops Add the missing "!" to fix the typo when checking if probe is defined. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 61f6bf35878fc0..39cbd84ff9c8ca 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -434,7 +434,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) dev_set_drvdata(dev, sdev); /* check all mandatory ops */ - if (!sof_ops(sdev) || sof_ops(sdev)->probe || !sof_ops(sdev)->run || + if (!sof_ops(sdev) || !sof_ops(sdev)->probe || !sof_ops(sdev)->run || !sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write || !sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware || !sof_ops(sdev)->ipc_msg_data || !sof_ops(sdev)->ipc_pcm_params) From 8149bcf2d138c13dee2d27dd2b89065d3c227195 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 11 Apr 2019 16:30:00 -0500 Subject: [PATCH 1347/1995] ASoC: SOF: topology: fix endianness issue Run. Sparse. Please. it's not complicated: make M=sound/soc/sof C=2 Fixes: 85c400e23859 ('ASoC: SOF: topology: add abi checking') Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/topology.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 2a13391e685dd6..2b9de1b97447b7 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -3050,14 +3050,17 @@ static int sof_manifest(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_manifest *man) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + u32 size; + + size = le32_to_cpu(man->priv.size); /* backward compatible with tplg without ABI info */ - if (!man->priv.size) { + if (!size) { dev_dbg(sdev->dev, "No topology ABI info\n"); return 0; } - if (man->priv.size == SOF_TPLG_ABI_SIZE) { + if (size == SOF_TPLG_ABI_SIZE) { dev_info(sdev->dev, "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n", man->priv.data[0], man->priv.data[1], From 46c2b852b448d5bd6b054b60da0e59c5b7720d05 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 11 Apr 2019 17:34:44 -0500 Subject: [PATCH 1348/1995] ASoC: SOF: loader: don't use devm_kasprintf for fw_filename The name is not persistent and use once, just use kasprintf and free Feedback from Takashi Iwai Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/loader.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index e73314ccd54ffb..81c7452aae1718 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -260,10 +260,9 @@ int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev) if (plat_data->fw) return 0; - fw_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, - "%s/%s", - plat_data->fw_filename_prefix, - plat_data->fw_filename); + fw_filename = kasprintf(GFP_KERNEL, "%s/%s", + plat_data->fw_filename_prefix, + plat_data->fw_filename); if (!fw_filename) return -ENOMEM; @@ -273,6 +272,9 @@ int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev) dev_err(sdev->dev, "error: request firmware %s failed err: %d\n", fw_filename, ret); } + + kfree(fw_filename); + return ret; } EXPORT_SYMBOL(snd_sof_load_firmware_raw); From 2de29fae6a2dadda3eb084023be2167be85115e1 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 12 Apr 2019 14:35:02 +0800 Subject: [PATCH 1349/1995] ASoC: SOF: cnl: add pointer ops to use DPIB position Add .pcm_pointer ops for cannonlake to read DPIB/posbuf and get pointer for ALSA, to align with apollolake. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/cnl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 3e95c1e5e49120..36ae9b88d0dc3d 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -199,6 +199,7 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .pcm_close = hda_dsp_pcm_close, .pcm_hw_params = hda_dsp_pcm_hw_params, .pcm_trigger = hda_dsp_pcm_trigger, + .pcm_pointer = hda_dsp_pcm_pointer, /* firmware loading */ .load_firmware = snd_sof_load_firmware_raw, From 99f5077261a254f47ed9b788a65dd812c97222c3 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 25 Mar 2019 16:39:24 +0800 Subject: [PATCH 1350/1995] ASoC: Intel: skl_hda_dsp_generic: add DMIC support Add dmic dai links using naming conventions used in previous machine drivers. Tested on whiskylake & icelake with SOF driver. Due to a missing topology file, the DMIC functionality could not be tested with the Skylake driver but was tested for non-regressions on a GeminiLake platform without DMICs. Signed-off-by: Rander Wang --- sound/soc/intel/boards/skl_hda_dsp_common.c | 22 ++++++++++++++++++-- sound/soc/intel/boards/skl_hda_dsp_common.h | 2 +- sound/soc/intel/boards/skl_hda_dsp_generic.c | 17 ++++++++++++++- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c index 3fdbf239da741b..8b68f41a5b8856 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.c +++ b/sound/soc/intel/boards/skl_hda_dsp_common.c @@ -78,7 +78,6 @@ struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = { .platform_name = "0000:00:1f.3", .dpcm_playback = 1, .dpcm_capture = 1, - .init = NULL, .no_pcm = 1, }, { @@ -90,7 +89,26 @@ struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = { .platform_name = "0000:00:1f.3", .dpcm_playback = 1, .dpcm_capture = 1, - .init = NULL, + .no_pcm = 1, + }, + { + .name = "dmic01", + .id = 6, + .cpu_dai_name = "DMIC01 Pin", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", + .platform_name = "0000:00:1f.3", + .dpcm_capture = 1, + .no_pcm = 1, + }, + { + .name = "dmic16k", + .id = 7, + .cpu_dai_name = "DMIC16k Pin", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", + .platform_name = "0000:00:1f.3", + .dpcm_capture = 1, .no_pcm = 1, }, }; diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h index 87c50aff56cdd7..daa582e513b20f 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.h +++ b/sound/soc/intel/boards/skl_hda_dsp_common.h @@ -15,7 +15,7 @@ #include #include -#define HDA_DSP_MAX_BE_DAI_LINKS 5 +#define HDA_DSP_MAX_BE_DAI_LINKS 7 struct skl_hda_hdmi_pcm { struct list_head head; diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index b9a21e64ead2ec..e69dc36b6600e8 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -97,6 +97,9 @@ static struct snd_soc_card hda_soc_card = { }; #define IDISP_DAI_COUNT 3 +#define HDAC_DAI_COUNT 2 +#define DMIC_DAI_COUNT 2 + /* there are two routes per iDisp output */ #define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2) #define IDISP_CODEC_MASK 0x4 @@ -112,8 +115,20 @@ static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params) codec_count = hweight_long(codec_mask); if (codec_count == 1 && codec_mask & IDISP_CODEC_MASK) { - num_links = IDISP_DAI_COUNT; + num_links = IDISP_DAI_COUNT + DMIC_DAI_COUNT; num_route = IDISP_ROUTE_COUNT; + + /* + * rearrange the dai link array and make the + * dmic dai links follow idsp dai links for only + * num_links of dai links need to be registered + * to ASoC. + */ + for (i = 0; i < DMIC_DAI_COUNT; i++) { + skl_hda_be_dai_links[IDISP_DAI_COUNT + i] = + skl_hda_be_dai_links[IDISP_DAI_COUNT + + HDAC_DAI_COUNT + i]; + } } else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) { num_links = ARRAY_SIZE(skl_hda_be_dai_links); num_route = ARRAY_SIZE(skl_hda_map), From f894d929cbd0b5578e2f4aca57eed21b4efee448 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 15 Apr 2019 14:33:06 +0800 Subject: [PATCH 1351/1995] SoC: Intel: skl_hda_dsp_generic:refine code style Semicolon is better than comma. Signed-off-by: Rander Wang --- sound/soc/intel/boards/skl_hda_dsp_generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index e69dc36b6600e8..fc52d3a32354fa 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -131,7 +131,7 @@ static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params) } } else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) { num_links = ARRAY_SIZE(skl_hda_be_dai_links); - num_route = ARRAY_SIZE(skl_hda_map), + num_route = ARRAY_SIZE(skl_hda_map); card->dapm_widgets = skl_hda_widgets; card->num_dapm_widgets = ARRAY_SIZE(skl_hda_widgets); } else { From 2508851646225bf84eb609363753206c21c24123 Mon Sep 17 00:00:00 2001 From: Xun Zhang Date: Thu, 4 Apr 2019 21:51:01 +0800 Subject: [PATCH 1352/1995] ASoC: codecs: rt5682: initialize mutex before using In rt5682 codec driver, a mutex called "calibrate_mutex" is used in rt5682_calibrate() before initialization, which causes warning in lock debug. Move the initialization before the usage of mutex. Signed-off-by: Xun Zhang --- sound/soc/codecs/rt5682.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 86a7fa31c294b2..505fb3d7b1c5eb 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2588,6 +2588,7 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, rt5682_reset(rt5682->regmap); + mutex_init(&rt5682->calibrate_mutex); rt5682_calibrate(rt5682); ret = regmap_multi_reg_write(rt5682->regmap, patch_list, @@ -2654,7 +2655,6 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, INIT_DELAYED_WORK(&rt5682->jd_check_work, rt5682_jd_check_handler); - mutex_init(&rt5682->calibrate_mutex); if (i2c->irq) { ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, From a19a023e9b6e8715db3542260f7ec6d099d477e1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 17 Apr 2019 14:41:40 -0500 Subject: [PATCH 1353/1995] ASoC: SOF: add Kconfig option for strict ABI checks When the kernel is more recent than firmware files, it will always behave in backwards-compatible ways. Add optional behavior to check if the kernel is older than the firmware files, so that the kernel fails early instead of attempting to use new functionality if does not support. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/Kconfig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index bf178b5d1a29dc..589acc77d163ed 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -79,6 +79,21 @@ config SND_SOC_SOF_NOCODEC Say Y if you need this nocodec fallback option If unsure select "N". +config SND_SOC_SOF_STRICT_ABI_CHECKS + bool "SOF strict ABI checks" + help + This option enables strict ABI checks for firmware and topology + files. + When these files are more recent than the kernel, the kernel + will handle the functionality it supports and may report errors + during topology creation or run-time usage if new functionality + is invoked. + This option will stop topology creation and firmware load upfront. + It is intended for SOF CI/releases and not for users or distros. + Say Y if you want strict ABI checks for an SOF release + If you are not involved in SOF releases and CI development + select "N". + config SND_SOC_SOF_DEBUG bool "SOF debugging features" help From 6ea809871877e4023f03eb5ae432e3d998bb320b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 17 Apr 2019 14:44:35 -0500 Subject: [PATCH 1354/1995] ASOC: SOF: ipc: add support for stricter ABI checks Fail early if firmware is more recent than kernel and Kconfig is selected. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/ipc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index d00373ceca12a3..bf58d58e737964 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -762,6 +762,15 @@ int snd_sof_ipc_valid(struct snd_sof_dev *sdev) return -EINVAL; } + if (v->abi_version > SOF_ABI_VERSION) { + if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) { + dev_warn(sdev->dev, "warn: FW ABI is more recent than kernel\n"); + } else { + dev_err(sdev->dev, "error: FW ABI is more recent than kernel\n"); + return -EINVAL; + } + } + if (ready->debug.bits.build) { dev_info(sdev->dev, "Firmware debug build %d on %s-%s - options:\n" From 498a3fe4938caf594e8aa81d0226fcc4df19ef4b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 17 Apr 2019 14:45:49 -0500 Subject: [PATCH 1355/1995] ASoC: SOF: topology: add support for stricter ABI checks Fail early if topology is more recent than kernel and Kconfig is selected. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/topology.c | 43 ++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 2b9de1b97447b7..b04b99cc0ff8c0 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -3051,6 +3051,7 @@ static int sof_manifest(struct snd_soc_component *scomp, int index, { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); u32 size; + u32 abi_version; size = le32_to_cpu(man->priv.size); @@ -3060,20 +3061,36 @@ static int sof_manifest(struct snd_soc_component *scomp, int index, return 0; } - if (size == SOF_TPLG_ABI_SIZE) { - dev_info(sdev->dev, - "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n", - man->priv.data[0], man->priv.data[1], - man->priv.data[2], SOF_ABI_MAJOR, SOF_ABI_MINOR, - SOF_ABI_PATCH); - if (SOF_ABI_VER(man->priv.data[0], man->priv.data[1], - man->priv.data[2]) <= SOF_ABI_VERSION) - return 0; + if (size != SOF_TPLG_ABI_SIZE) { + dev_err(sdev->dev, "error: invalid topology ABI size\n"); + return -EINVAL; } - dev_err(sdev->dev, - "error: Incompatible ABI version %d:%d:%d\n", - man->priv.data[0], man->priv.data[1], man->priv.data[2]); - return -EINVAL; + + dev_info(sdev->dev, + "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n", + man->priv.data[0], man->priv.data[1], + man->priv.data[2], SOF_ABI_MAJOR, SOF_ABI_MINOR, + SOF_ABI_PATCH); + + abi_version = SOF_ABI_VER(man->priv.data[0], + man->priv.data[1], + man->priv.data[2]); + + if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) { + dev_err(sdev->dev, "error: incompatible topology ABI version\n"); + return -EINVAL; + } + + if (abi_version > SOF_ABI_VERSION) { + if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) { + dev_warn(sdev->dev, "warn: topology ABI is more recent than kernel\n"); + } else { + dev_err(sdev->dev, "error: topology ABI is more recent than kernel\n"); + return -EINVAL; + } + } + + return 0; } /* vendor specific kcontrol handlers available for binding */ From 90860434f04773357e5e55726bafd0a0a72430c5 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Fri, 12 Apr 2019 11:15:11 +0800 Subject: [PATCH 1356/1995] ASoC: SOF: soundwire: add initial soundwire support Add soundwire dai type and update ABI version. Signed-off-by: Pan Xiuli --- include/sound/sof/dai.h | 1 + include/uapi/sound/sof/abi.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 3b67c93ff101b5..3d174e20aa5309 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -49,6 +49,7 @@ enum sof_ipc_dai_type { SOF_DAI_INTEL_SSP, /**< Intel SSP */ SOF_DAI_INTEL_DMIC, /**< Intel DMIC */ SOF_DAI_INTEL_HDA, /**< Intel HD/A */ + SOF_DAI_INTEL_SOUNDWIRE, /**< Intel SoundWire */ }; /* general purpose DAI configuration */ diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index 37e0a90dc9e6c3..13a4eca04577cb 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 4 +#define SOF_ABI_MINOR 5 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ From 96eec9848916a699a7372ac7795b9c807ba5da3f Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 8 Apr 2019 17:08:58 +0800 Subject: [PATCH 1357/1995] ASoC: Intel: kbl: fix wrong number of channels Fix wrong setting on number of channels. The context wants to set constraint to 2 channels instead of 4. Signed-off-by: Tzung-Bi Shih Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit d6ba3f815bc5f3c4249d15c8bc5fbb012651b4a4) --- sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index 7044d8c2b18737..879f14257a3ea4 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -405,7 +405,7 @@ static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { }; static const unsigned int dmic_2ch[] = { - 4, + 2, }; static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { From 43a49ab35d614e2d5964a56e3e9e82bbad07d667 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 8 Apr 2019 12:30:25 -0700 Subject: [PATCH 1358/1995] ASoC: pcm: fix error handling when try_module_get() fails. Handle error before returning when try_module_get() fails to prevent inconsistent mutex lock/unlock. Fixes: 52034add7 (ASoC: pcm: update module refcount if module_get_upon_open is set) Signed-off-by: Ranjani Sridharan Signed-off-by: Mark Brown (cherry picked from commit 70802487bb9145a4f8b26f5a11d0e7f83c25100a) --- sound/soc/soc-pcm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index d21247546f7f76..be80a12fba27cc 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -518,8 +518,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) continue; if (component->driver->module_get_upon_open && - !try_module_get(component->dev->driver->owner)) - return -ENODEV; + !try_module_get(component->dev->driver->owner)) { + ret = -ENODEV; + goto module_err; + } ret = component->driver->ops->open(substream); if (ret < 0) { @@ -636,7 +638,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) component_err: soc_pcm_components_close(substream, component); - +module_err: if (cpu_dai->driver->ops->shutdown) cpu_dai->driver->ops->shutdown(substream, cpu_dai); out: From 36d7d5a6d6b9089304fceb10e0fc668f36037389 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 10 Apr 2019 12:49:55 +0200 Subject: [PATCH 1359/1995] ALSA: hda: Fix racy display power access snd_hdac_display_power() doesn't handle the concurrent calls carefully enough, and it may lead to the doubly get_power or put_power calls, when a runtime PM and an async work get called in racy way. This patch addresses it by reusing the bus->lock mutex that has been used for protecting the link state change in ext bus code, so that it can protect against racy display state changes. The initialization of bus->lock was moved from snd_hdac_ext_bus_init() to snd_hdac_bus_init() as well accordingly. Testcase: igt/i915_pm_rpm/module-reload #glk-dsi Reported-by: Chris Wilson Reviewed-by: Chris Wilson Cc: Imre Deak Signed-off-by: Takashi Iwai (cherry picked from commit d7a181da2dfa3190487c446042ba01e07d851c74) --- sound/hda/ext/hdac_ext_bus.c | 1 - sound/hda/hdac_bus.c | 1 + sound/hda/hdac_component.c | 6 +++++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c index 9c37d9af3023f6..ec7715c6b0c02c 100644 --- a/sound/hda/ext/hdac_ext_bus.c +++ b/sound/hda/ext/hdac_ext_bus.c @@ -107,7 +107,6 @@ int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev, INIT_LIST_HEAD(&bus->hlink_list); bus->idx = idx++; - mutex_init(&bus->lock); bus->cmd_dma_state = true; return 0; diff --git a/sound/hda/hdac_bus.c b/sound/hda/hdac_bus.c index 012305177f6822..ad8eee08013fb8 100644 --- a/sound/hda/hdac_bus.c +++ b/sound/hda/hdac_bus.c @@ -38,6 +38,7 @@ int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev, INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); spin_lock_init(&bus->reg_lock); mutex_init(&bus->cmd_mutex); + mutex_init(&bus->lock); bus->irq = -1; return 0; } diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c index 5c95933e739a43..1ea51e3b942a03 100644 --- a/sound/hda/hdac_component.c +++ b/sound/hda/hdac_component.c @@ -69,13 +69,15 @@ void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) dev_dbg(bus->dev, "display power %s\n", enable ? "enable" : "disable"); + + mutex_lock(&bus->lock); if (enable) set_bit(idx, &bus->display_power_status); else clear_bit(idx, &bus->display_power_status); if (!acomp || !acomp->ops) - return; + goto unlock; if (bus->display_power_status) { if (!bus->display_power_active) { @@ -92,6 +94,8 @@ void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable) bus->display_power_active = false; } } + unlock: + mutex_unlock(&bus->lock); } EXPORT_SYMBOL_GPL(snd_hdac_display_power); From 682953642b7ad21205c1ff0712516b65f341f922 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Fri, 19 Apr 2019 09:53:12 +0800 Subject: [PATCH 1360/1995] ASoC: pcm: save fixed-up hw_params of BE Some drivers mandate setting up hw params after resuming from system sleep. Since, the hw_params ioctl is not invoked upon resuming, the fixed-up BE dai hw params should be saved so the driver can use it in its resume sequence. Signed-off-by: Libin Yang Signed-off-by: Mark Brown (cherry picked from commit ae061d2a857f84ad47b77b04c3ad37478651ab6c) --- sound/soc/soc-pcm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index be80a12fba27cc..0d50a446f50dc4 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2166,6 +2166,10 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) } } + /* copy the fixed-up hw params for BE dai */ + memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params, + sizeof(struct snd_pcm_hw_params)); + /* only allow hw_params() if no connected FEs are running */ if (!snd_soc_dpcm_can_be_params(fe, be, stream)) continue; From cbb40ae213ef57764eee399c7014cbf549b81e12 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 18 Apr 2019 10:48:48 +0800 Subject: [PATCH 1361/1995] ASoC: Intel: Haswell: Remove set but not used variable 'stage_type' Fixes gcc '-Wunused-but-set-variable' warning: sound/soc/intel/haswell/sst-haswell-ipc.c: In function 'hsw_stream_message': sound/soc/intel/haswell/sst-haswell-ipc.c:669:29: warning: variable 'stage_type' set but not used [-Wunused-but-set-variable] It is never used since introduction in commit ba57f68235cf ("ASoC: Intel: create haswell folder and move haswell platform files in") Signed-off-by: YueHaibing Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 479879701758206a2cc75176119fcc9dacc40846) --- sound/soc/intel/haswell/sst-haswell-ipc.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index 31fcdf12c67def..74acf9c651615b 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -345,11 +345,6 @@ static inline u32 msg_get_stream_type(u32 msg) return (msg & IPC_STR_TYPE_MASK) >> IPC_STR_TYPE_SHIFT; } -static inline u32 msg_get_stage_type(u32 msg) -{ - return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT; -} - static inline u32 msg_get_stream_id(u32 msg) { return (msg & IPC_STR_ID_MASK) >> IPC_STR_ID_SHIFT; @@ -666,13 +661,12 @@ static int hsw_module_message(struct sst_hsw *hsw, u32 header) static int hsw_stream_message(struct sst_hsw *hsw, u32 header) { - u32 stream_msg, stream_id, stage_type; + u32 stream_msg, stream_id; struct sst_hsw_stream *stream; int handled = 0; stream_msg = msg_get_stream_type(header); stream_id = msg_get_stream_id(header); - stage_type = msg_get_stage_type(header); stream = get_stream_by_id(hsw, stream_id); if (stream == NULL) From e80987ec97fdd4e89c35456a64541384cd364eb9 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Sat, 13 Apr 2019 21:18:12 +0800 Subject: [PATCH 1362/1995] ASoC: codec: hdac_hdmi add device_link to card device In resume from S3, HDAC HDMI codec driver dapm event callback may be operated before HDMI codec driver turns on the display audio power domain because of the contest between display driver and hdmi codec driver. This patch adds the device_link between soc card device (consumer) and hdmi codec device (supplier) to make sure the sequence is always correct. Signed-off-by: Libin Yang Reviewed-by: Takashi Iwai Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown Cc: stable@vger.kernel.org (cherry picked from commit 01c8327667c249818d3712c3e25c7ad2aca7f389) --- sound/soc/codecs/hdac_hdmi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 5eeb0fe836a9a9..4de1fbfa882782 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1854,6 +1854,17 @@ static int hdmi_codec_probe(struct snd_soc_component *component) /* Imp: Store the card pointer in hda_codec */ hdmi->card = dapm->card->snd_card; + /* + * Setup a device_link between card device and HDMI codec device. + * The card device is the consumer and the HDMI codec device is + * the supplier. With this setting, we can make sure that the audio + * domain in display power will be always turned on before operating + * on the HDMI audio codec registers. + * Let's use the flag DL_FLAG_AUTOREMOVE_CONSUMER. This can make + * sure the device link is freed when the machine driver is removed. + */ + device_link_add(component->card->dev, &hdev->dev, DL_FLAG_RPM_ACTIVE | + DL_FLAG_AUTOREMOVE_CONSUMER); /* * hdac_device core already sets the state to active and calls * get_noresume. So enable runtime and set the device to suspend. From e5ad54a40f554d0c7e0ed4b4d6bcff89d1f3c7ef Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Thu, 18 Apr 2019 14:19:18 +0800 Subject: [PATCH 1363/1995] ASoC: SOF: Intel: hda: add the SSP Host Device memory space The DSP SSP device memory can be conditionally accessed by the host(depending on access policy). Add the SSP base memory offset of APL and CNL. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index e49d9c92dd1c8b..e66a231578702a 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -339,6 +339,13 @@ #define HDA_ADSP_FW_STATUS_SKL HDA_ADSP_SRAM0_BASE_SKL #define HDA_ADSP_ERROR_CODE_SKL (HDA_ADSP_FW_STATUS_SKL + 0x4) +/* Host Device Memory Space */ +#define APL_SSP_BASE_OFFSET 0x2000 +#define CNL_SSP_BASE_OFFSET 0x10000 + +/* Host Device Memory Size of a Single SSP */ +#define SSP_DEV_MEM_SIZE 0x1000 + #define HDA_IDISP_CODEC(x) ((x) & BIT(2)) struct sof_intel_dsp_bdl { From f29294039fa9f5902dae03cd6ad3cb4a7c425e27 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Thu, 18 Apr 2019 14:35:13 +0800 Subject: [PATCH 1364/1995] ASoC: SOF: Intel: hda: add SSP info to the chip info struct add SSP info of APL and CNL, to the sof_intel_dsp_desc structure. The max SSP count the platform support and the SSP base address. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/apl.c | 2 ++ sound/soc/sof/intel/cnl.c | 2 ++ sound/soc/sof/intel/hda.h | 4 ++++ sound/soc/sof/intel/shim.h | 2 ++ 4 files changed, 10 insertions(+) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 8c628260694467..026dde83962186 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -105,5 +105,7 @@ const struct sof_intel_dsp_desc apl_chip_info = { .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, .ipc_ctl = HDA_DSP_REG_HIPCCTL, .rom_init_timeout = 150, + .ssp_count = APL_SSP_COUNT, + .ssp_base_offset = APL_SSP_BASE_OFFSET, }; EXPORT_SYMBOL(apl_chip_info); diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 36ae9b88d0dc3d..3afd96d9c92575 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -246,5 +246,7 @@ const struct sof_intel_dsp_desc cnl_chip_info = { .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, .ipc_ctl = CNL_DSP_REG_HIPCCTL, .rom_init_timeout = 300, + .ssp_count = CNL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, }; EXPORT_SYMBOL(cnl_chip_info); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index e66a231578702a..28e0fb10c85988 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -346,6 +346,10 @@ /* Host Device Memory Size of a Single SSP */ #define SSP_DEV_MEM_SIZE 0x1000 +/* SSP Count of the Platform */ +#define APL_SSP_COUNT 6 +#define CNL_SSP_COUNT 3 + #define HDA_IDISP_CODEC(x) ((x) & BIT(2)) struct sof_intel_dsp_bdl { diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 11fd77cb4e6d0b..f7a3f62e45d44b 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -162,6 +162,8 @@ struct sof_intel_dsp_desc { int ipc_ack_mask; int ipc_ctl; int rom_init_timeout; + int ssp_count; /* ssp count of the platform */ + int ssp_base_offset; /* base address of the SSPs */ }; extern const struct snd_sof_dsp_ops sof_tng_ops; From 596d392b78b3f33da72c7971b209877b963c1463 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Thu, 18 Apr 2019 14:42:26 +0800 Subject: [PATCH 1365/1995] ASoC: SOF: Intel: hda: set I2S slave before enabling DSP By default, the I2S ports are configured in master mode during DSP powerup sequences, the FS and BCLK lines will be driven on startup, even when the topology file explicitly requires the SSP to be slave. This may be problematic for external components configured in master mode who don't expect the Intel SOC/PCH to drive. Fix by configuring the SSP as slave before the SSP outputs are enabled to avoid this transient behavior. When the topology file configures the SSP as clock master, the initial slave configuration will be overridden. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-loader.c | 11 +++++++++++ sound/soc/sof/intel/hda.h | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 6a44bc349e44ce..6427f0b3a2f113 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -84,6 +84,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, const struct sof_intel_dsp_desc *chip = hda->desc; unsigned int status; int ret; + int i; /* step 1: power up corex */ ret = hda_dsp_core_power_up(sdev, chip->cores_mask); @@ -92,6 +93,16 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, goto err; } + /* DSP is powered up, set all SSPs to slave mode */ + for (i = 0; i < chip->ssp_count; i++) { + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, + chip->ssp_base_offset + + i * SSP_DEV_MEM_SIZE + + SSP_SSC1_OFFSET, + SSP_SET_SLAVE, + SSP_SET_SLAVE); + } + /* step 2: purge FW request */ snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, chip->ipc_req_mask | (HDA_DSP_IPC_PURGE_FW | diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 28e0fb10c85988..7d78110c65a609 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -350,6 +350,12 @@ #define APL_SSP_COUNT 6 #define CNL_SSP_COUNT 3 +/* SSP Registers */ +#define SSP_SSC1_OFFSET 0x4 +#define SSP_SET_SCLK_SLAVE BIT(25) +#define SSP_SET_SFRM_SLAVE BIT(24) +#define SSP_SET_SLAVE (SSP_SET_SCLK_SLAVE | SSP_SET_SFRM_SLAVE) + #define HDA_IDISP_CODEC(x) ((x) & BIT(2)) struct sof_intel_dsp_bdl { From 0be8cac11316f354fa05ff72b3c3d4008f024144 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Tue, 23 Apr 2019 15:04:29 +0800 Subject: [PATCH 1366/1995] ASoC: SOF: Intel: hda: set bus->idx as 0 Setting the bus->idx as 0, for we only have one HDA bus atm. This need to be fixed when there are more than one HDA bus. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-bus.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c index 62cc9921bb5597..a7e6d8227df6f4 100644 --- a/sound/soc/sof/intel/hda-bus.c +++ b/sound/soc/sof/intel/hda-bus.c @@ -80,8 +80,6 @@ static const struct hdac_io_ops io_ops = { void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, const struct hdac_ext_bus_ops *ext_ops) { - static int idx; - memset(bus, 0, sizeof(*bus)); bus->dev = dev; @@ -90,7 +88,12 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, bus->irq = -1; bus->ext_ops = ext_ops; - bus->idx = idx++; + + /* + * There is only one HDA bus atm. keep the index as 0. + * Need to fix when there are more than one HDA bus. + */ + bus->idx = 0; spin_lock_init(&bus->reg_lock); From 2e945691f2c09ddf533e7bab6a875d99ccac7c46 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 22 Apr 2019 16:43:50 -0500 Subject: [PATCH 1367/1995] ASoC: SOF: Intel: hda-pcm: remove useless dependency on hdac_ext Nothing depends on definitions in hdaudio_ext.h, don't include it Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-pcm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 5714a79fbe1a16..9b730f18352918 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -15,7 +15,6 @@ * Hardware interface for generic Intel audio DSP HDA IP */ -#include #include #include #include "../ops.h" From a1043e8bc785c186a5bd4cb1f5ae25d9e9ea0aee Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 17 Apr 2019 18:07:46 +0800 Subject: [PATCH 1368/1995] ASoC: SOF: PCM: add period_elapsed work to fix race condition in interrupt context The IPC implementation in SOF requires sending IPCs serially: we should not send a new IPC command to the firmware before we get an ACK (or time out) from firmware, and the IRQ processing is complete. snd_pcm_period_elapsed() can be called in interrupt context before IRQ_HANDLED is returned. When the PCM is done draining, a STOP IPC will then be sent, which breaks the expectation that IPCs are handled serially and leads to IPC timeouts. This patch adds a workqueue to defer the call to snd_pcm_elapsed() after the IRQ is handled. Signed-off-by: Keyon Jie --- sound/soc/sof/pcm.c | 48 ++++++++++++++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 50 insertions(+) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index be4984c4da4eb8..649968841dad9f 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -52,6 +52,48 @@ static int sof_pcm_dsp_params(struct snd_sof_pcm *spcm, struct snd_pcm_substream return ret; } +/* + * sof pcm period elapse work + */ +static void sof_pcm_period_elapsed_work(struct work_struct *work) +{ + struct snd_sof_pcm_stream *sps = + container_of(work, struct snd_sof_pcm_stream, + period_elapsed_work); + + snd_pcm_period_elapsed(sps->substream); +} + +/* + * sof pcm period elapse, this could be called at irq thread context. + */ +void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm; + + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) { + dev_err(sdev->dev, + "error: period elapsed for unknown stream!\n"); + return; + } + + /* + * snd_pcm_period_elapsed() can be called in interrupt context + * before IRQ_HANDLED is returned. Inside snd_pcm_period_elapsed(), + * when the PCM is done draining or xrun happened, a STOP IPC will + * then be sent and this IPC will hit IPC timeout. + * To avoid sending IPC before the previous IPC is handled, we + * schedule delayed work here to call the snd_pcm_period_elapsed(). + */ + schedule_work(&spcm->stream[substream->stream].period_elapsed_work); +} +EXPORT_SYMBOL(snd_sof_pcm_period_elapsed); + /* this may get called several times by oss emulation */ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -169,6 +211,9 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, /* save pcm hw_params */ memcpy(&spcm->params[substream->stream], params, sizeof(*params)); + INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work, + sof_pcm_period_elapsed_work); + return ret; } @@ -203,6 +248,9 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) sizeof(stream), &reply, sizeof(reply)); snd_pcm_lib_free_pages(substream); + + cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work); + return ret; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 35e78ffecce2fe..675bb10c82f597 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -274,6 +274,7 @@ struct snd_sof_pcm_stream { struct snd_dma_buffer page_table; struct sof_ipc_stream_posn posn; struct snd_pcm_substream *substream; + struct work_struct period_elapsed_work; }; /* ALSA SOF PCM device */ @@ -495,6 +496,7 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev, int *direction); struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev, unsigned int pcm_id); +void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream); /* * Stream IPC From 0e24a0d4b3bf76ef4ab1700fe59bea34aa84f296 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 17 Apr 2019 19:00:51 +0800 Subject: [PATCH 1369/1995] ASoC: SOF: Intel: use snd_sof_pcm_period_elapsed Switch to a wrapper function which schedules the actual call of snd_pcm_period_elapsed after the current IPC is completed. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-stream.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 6290b2df5e621d..47eff161c60e3d 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -465,8 +465,8 @@ irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) { struct hdac_bus *bus = context; struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); - struct hdac_stream *s; u32 status = snd_hdac_chip_readl(bus, INTSTS); + struct hdac_stream *s; u32 sd_status; /* check streams */ @@ -486,7 +486,7 @@ irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) /* Inform ALSA only in case not do that with IPC */ if (sof_hda->no_ipc_position) - snd_pcm_period_elapsed(s->substream); + snd_sof_pcm_period_elapsed(s->substream); } } From f7e9d4a170ff0942bfab7d48f476dba5f8387c71 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Thu, 18 Apr 2019 18:05:19 +0800 Subject: [PATCH 1370/1995] ASoC: SOF: ipc: use snd_sof_pcm_period_elapsed Switch to a wrapper function which schedules the actual call of snd_pcm_period_elapsed after the current IPC is completed. Signed-off-by: Keyon Jie --- sound/soc/sof/ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index bf58d58e737964..437e80a07bc2c4 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -445,7 +445,7 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) /* only inform ALSA for period_wakeup mode */ if (!stream->substream->runtime->no_period_wakeup) - snd_pcm_period_elapsed(stream->substream); + snd_sof_pcm_period_elapsed(stream->substream); } /* DSP notifies host of an XRUN within FW */ From 508c08347bf73965b8c3f49efb6627a032cebbe6 Mon Sep 17 00:00:00 2001 From: Sathya Prakash M R Date: Thu, 28 Mar 2019 15:29:24 +0530 Subject: [PATCH 1371/1995] ASoC: Intel: boards: Update speaker info to sof-rt5682 Update speaker AMP to sof-rt5682 based on platform Signed-off-by: Sathya Prakash M R Signed-off-by: Ranjani Sridharan --- sound/soc/intel/boards/sof_rt5682.c | 124 ++++++++++++++++++++++------ 1 file changed, 99 insertions(+), 25 deletions(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 007cf94c0d5d73..823033c87db9e1 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -3,6 +3,7 @@ /* * Intel SOF Machine Driver with Realtek rt5682 Codec + * and speaker codec MAX98357A */ #include #include @@ -21,18 +22,21 @@ #include "../../codecs/rt5682.h" #include "../../codecs/hdac_hdmi.h" -#define DUAL_CHANNEL 2 -#define QUAD_CHANNEL 4 #define NAME_SIZE 32 -#define SOF_RT5682_SSP(quirk) ((quirk) & GENMASK(2, 0)) -#define SOF_RT5682_SSP_MASK (GENMASK(2, 0)) -#define SOF_RT5682_MCLK_EN BIT(3) -#define SOF_RT5682_MCLK_24MHZ BIT(4) +#define SOF_RT5682_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0)) +#define SOF_RT5682_SSP_CODEC_MASK (GENMASK(2, 0)) +#define SOF_RT5682_MCLK_EN BIT(3) +#define SOF_RT5682_MCLK_24MHZ BIT(4) +#define SOF_SPEAKER_AMP_PRESENT BIT(5) +#define SOF_RT5682_SSP_AMP(quirk) ((quirk) & GENMASK(8, 6)) +#define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6)) +#define SOF_RT5682_SSP_AMP_SHIFT 6 + /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP(0); + SOF_RT5682_SSP_CODEC(0); static int is_legacy_cpu; @@ -64,7 +68,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | SOF_RT5682_MCLK_24MHZ | - SOF_RT5682_SSP(1)), + SOF_RT5682_SSP_CODEC(1)), }, { .callback = sof_rt5682_quirk_cb, @@ -74,7 +78,9 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | SOF_RT5682_MCLK_24MHZ | - SOF_RT5682_SSP(0)), + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(1)), }, { .callback = sof_rt5682_quirk_cb, @@ -83,7 +89,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"), }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP(0)), + SOF_RT5682_SSP_CODEC(0)), }, {} }; @@ -238,7 +244,6 @@ static int sof_card_late_probe(struct snd_soc_card *card) i++; } - if (!component) return -EINVAL; @@ -248,11 +253,13 @@ static int sof_card_late_probe(struct snd_soc_card *card) static const struct snd_kcontrol_new sof_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Spk"), }; static const struct snd_soc_dapm_widget sof_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SPK("Spk", NULL), }; static const struct snd_soc_dapm_route sof_map[] = { @@ -265,6 +272,24 @@ static const struct snd_soc_dapm_route sof_map[] = { }; +static const struct snd_soc_dapm_route speaker_map[] = { + /* speaker */ + { "Spk", NULL, "Speaker" }, +}; + +static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map, + ARRAY_SIZE(speaker_map)); + + if (ret) + dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); + return ret; +} + /* sof audio machine driver for rt5682 codec */ static struct snd_soc_card sof_audio_card_rt5682 = { .name = "sof_rt5682", @@ -299,8 +324,16 @@ static struct snd_soc_dai_link_component dmic_component[] = { } }; +static struct snd_soc_dai_link_component max98357a_component[] = { + { + .name = "MX98357A:00", + .dai_name = "HiFi", + } +}; + static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, - int ssp_port, + int ssp_codec, + int ssp_amp, int dmic_num, int hdmi_num) { @@ -309,13 +342,13 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, int i, id = 0; links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * - (1 + dmic_num + hdmi_num), GFP_KERNEL); + sof_audio_card_rt5682.num_links, GFP_KERNEL); if (!links) goto devm_err; - /* SSP */ + /* codec SSP */ links[id].name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d-Codec", ssp_port); + "SSP%d-Codec", ssp_codec); if (!links[id].name) goto devm_err; @@ -332,7 +365,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].no_pcm = 1; if (is_legacy_cpu) { links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, - "ssp%d-port", ssp_port); + "ssp%d-port", + ssp_codec); if (!links[id].cpu_dai_name) goto devm_err; } else { @@ -347,7 +381,8 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, */ links[id].ignore_pmdown_time = 1; links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", ssp_port); + "SSP%d Pin", + ssp_codec); if (!links[id].cpu_dai_name) goto devm_err; } @@ -413,8 +448,39 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, id++; } - return links; + /* speaker amp */ + if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) { + links[id].name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d-Codec", ssp_amp); + if (!links[id].name) + goto devm_err; + links[id].id = id; + links[id].codecs = max98357a_component; + links[id].num_codecs = ARRAY_SIZE(max98357a_component); + links[id].platforms = platform_component; + links[id].num_platforms = ARRAY_SIZE(platform_component); + links[id].init = speaker_codec_init, + links[id].nonatomic = true; + links[id].dpcm_playback = 1; + links[id].no_pcm = 1; + if (is_legacy_cpu) { + links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, + "ssp%d-port", + ssp_amp); + if (!links[id].cpu_dai_name) + goto devm_err; + + } else { + links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", + ssp_amp); + if (!links[id].cpu_dai_name) + goto devm_err; + } + } + + return links; devm_err: return NULL; } @@ -425,7 +491,7 @@ static int sof_audio_probe(struct platform_device *pdev) struct snd_soc_acpi_mach *mach; struct sof_card_private *ctx; int dmic_num, hdmi_num; - int ret; + int ret, ssp_amp, ssp_codec; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); if (!ctx) @@ -436,7 +502,7 @@ static int sof_audio_probe(struct platform_device *pdev) dmic_num = 0; hdmi_num = 0; /* default quirk for legacy cpu */ - sof_rt5682_quirk = SOF_RT5682_SSP(2); + sof_rt5682_quirk = SOF_RT5682_SSP_CODEC(2); } else { dmic_num = 1; hdmi_num = 3; @@ -444,17 +510,24 @@ static int sof_audio_probe(struct platform_device *pdev) dmi_check_system(sof_rt5682_quirk_table); - dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", - sof_rt5682_quirk); + dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk); + + ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >> + SOF_RT5682_SSP_AMP_SHIFT; - dai_links = sof_card_dai_links_create(&pdev->dev, sof_rt5682_quirk & - SOF_RT5682_SSP_MASK, + ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK; + + /* compute number of dai links */ + sof_audio_card_rt5682.num_links = 1 + dmic_num + hdmi_num; + if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) + sof_audio_card_rt5682.num_links++; + + dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp, dmic_num, hdmi_num); if (!dai_links) return -ENOMEM; sof_audio_card_rt5682.dai_link = dai_links; - sof_audio_card_rt5682.num_links = 1 + dmic_num + hdmi_num; INIT_LIST_HEAD(&ctx->hdmi_pcm_list); @@ -485,5 +558,6 @@ module_platform_driver(sof_audio) /* Module information */ MODULE_DESCRIPTION("SOF Audio Machine driver"); MODULE_AUTHOR("Bard Liao "); +MODULE_AUTHOR("Sathya Prakash M R "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:sof_rt5682"); From db2c2d29d0a1b6fded9271d056625e92bda971be Mon Sep 17 00:00:00 2001 From: Sathya Prakash M R Date: Thu, 28 Mar 2019 15:30:17 +0530 Subject: [PATCH 1372/1995] ASoC: Intel: acpi match for cml m/c driver and topology Select appropriate tplg in acpi match table based on codecs in platform Signed-off-by: Sathya Prakash M R Signed-off-by: Ranjani Sridharan --- sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index 39343ff9bf3456..7d0230070e624a 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -14,6 +14,11 @@ static struct skl_machine_pdata cnl_pdata = { .use_tplg_pcm = true, }; +static struct snd_soc_acpi_codecs cml_codecs = { + .num_codecs = 1, + .codecs = {"10EC5682"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { { .id = "INT34C2", @@ -37,6 +42,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .sof_fw_filename = "sof-cnl.ri", .sof_tplg_filename = "sof-cml-rt5682.tplg", }, + { + .id = "MX98357A", + .drv_name = "sof_rt5682", + .quirk_data = &cml_codecs, + .sof_fw_filename = "sof-cnl.ri", + .sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg", + }, + {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_machines); From ae1339192c4b10d98bfbdffa55eeac054b0de1bf Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 17 Apr 2019 18:31:36 +0800 Subject: [PATCH 1373/1995] ASoC: SOF: Intel: hda-ipc: simplify handling of IPC IRQ When using a shared IRQ between IPC interrupt and stream IOC interrupt, the interrupt handlers need to check the interrupt source before scheduling their respective IRQ threads. In the case of IPC handler, it should check if it is an IPC interrupt before waking up the IPC IRQ thread. The IPC IRQ thread, once scheduled, does not need to check the IRQ source again. So, remove the superfluous check in the thread. Remove the irq_status field from snd_sof_dev struct also as it is no longer needed. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/cnl.c | 4 ---- sound/soc/sof/intel/hda-ipc.c | 13 +++++-------- sound/soc/sof/sof-priv.h | 1 - 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 3afd96d9c92575..d128839b24504b 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -39,10 +39,6 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) u32 msg_ext; irqreturn_t ret = IRQ_NONE; - /* here we handle IPC interrupts only */ - if (!(sdev->irq_status & HDA_DSP_ADSPIS_IPC)) - return ret; - hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL); hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR); diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index a938f568dbb1c3..73ead7070cdefd 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -145,10 +145,6 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) u32 msg; u32 msg_ext; - /* here we handle IPC interrupts only */ - if (!(sdev->irq_status & HDA_DSP_ADSPIS_IPC)) - return IRQ_NONE; - /* read IPC status */ hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE); @@ -234,19 +230,20 @@ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) { struct snd_sof_dev *sdev = context; int ret = IRQ_NONE; + u32 irq_status; spin_lock(&sdev->hw_lock); /* store status */ - sdev->irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_DSP_REG_ADSPIS); + irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS); + dev_vdbg(sdev->dev, "irq handler: irq_status:0x%x\n", irq_status); /* invalid message ? */ - if (sdev->irq_status == 0xffffffff) + if (irq_status == 0xffffffff) goto out; /* IPC message ? */ - if (sdev->irq_status & HDA_DSP_ADSPIS_IPC) { + if (irq_status & HDA_DSP_ADSPIS_IPC) { /* disable IPC interrupt */ snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 675bb10c82f597..bbc285018f9a72 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -366,7 +366,6 @@ struct snd_sof_dev { struct snd_sof_mailbox host_box; /* Host initiated IPC */ struct snd_sof_mailbox stream_box; /* Stream position update */ struct snd_sof_ipc_msg *msg; - u64 irq_status; int ipc_irq; u32 next_comp_id; /* monotonic - reset during S3 */ From d3c4d4ff20e1d18870f1c1492037979991777351 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Thu, 18 Apr 2019 17:31:05 +0800 Subject: [PATCH 1374/1995] ASoC: SOF: Intel: hda-stream: store stream capabilities Add stream_max into struct sof_intel_hda_dev to store the total hda stream number that the platform can support, and initialize it at stream_init. This can be used later e.g. for stream bitmask. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-stream.c | 4 ++++ sound/soc/sof/intel/hda.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 47eff161c60e3d..39f4212bde4bab 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -500,6 +500,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) struct hdac_ext_stream *stream; struct hdac_stream *hstream; struct pci_dev *pci = to_pci_dev(sdev->dev); + struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); int sd_offset; int i, num_playback, num_capture, num_total, ret; u32 gcap; @@ -657,6 +658,9 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) list_add_tail(&hstream->list, &bus->stream_list); } + /* store total stream count (playback + capture) from GCAP */ + sof_hda->stream_max = num_total; + return 0; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 7d78110c65a609..59ae6f8a1beaee 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -384,6 +384,9 @@ struct sof_intel_hda_dev { /* if position update IPC needed */ u32 no_ipc_position; + /* the maximum number of streams (playback + capture) supported */ + u32 stream_max; + int irq; /* DMIC device */ From af71673268613c85b92a3475e3531be0ffdb4a41 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 17 Apr 2019 18:52:20 +0800 Subject: [PATCH 1375/1995] ASoC: SOF: Intel: hda-stream: handle real stream interrupts only The stream and IPC share the same interrupt. The stream interrupt handler mistakenly uses the ipc interrupt and return IRQ_HANDLED, causing the ipc interrupt to be missed. Make sure the stream interrupt handler only deals with stream-related interrupts. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-stream.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 39f4212bde4bab..c92006f894992a 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -433,6 +433,8 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) { struct hdac_bus *bus = context; + struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); + u32 stream_mask; u32 status; if (!pm_runtime_active(bus->dev)) @@ -441,7 +443,10 @@ irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) spin_lock(&bus->reg_lock); status = snd_hdac_chip_readl(bus, INTSTS); - if (status == 0 || status == 0xffffffff) { + stream_mask = GENMASK(sof_hda->stream_max - 1, 0) | AZX_INT_CTRL_EN; + + /* Not stream interrupt or register inaccessible, ignore it.*/ + if (!(status & stream_mask) || status == 0xffffffff) { spin_unlock(&bus->reg_lock); return IRQ_NONE; } From 53e42981dda5fbfc8c3c4545314d02b26a48bc29 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Mon, 22 Apr 2019 01:16:36 +0800 Subject: [PATCH 1376/1995] ALSA: hda: fix unregister device twice on ASoC driver snd_hda_codec_device_new() is used by both legacy HDA and ASoC driver. However, we will call snd_hdac_device_unregister() in snd_hdac_ext_bus_device_remove() for ASoC device. This patch uses the type flag in hdac_device struct to determine is it a ASoC device or legacy HDA device and call snd_hdac_device_unregister() in snd_hda_codec_dev_free() only if it is a legacy HDA device. Signed-off-by: Bard liao --- sound/pci/hda/hda_codec.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9f8d59e7e89f46..ae1b7475dc81fb 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -841,7 +841,13 @@ static int snd_hda_codec_dev_free(struct snd_device *device) struct hda_codec *codec = device->device_data; codec->in_freeing = 1; - snd_hdac_device_unregister(&codec->core); + /* + * snd_hda_codec_device_new() is used by legacy HDA and ASoC driver. + * We can't unregister ASoC device since it will be unregistered in + * snd_hdac_ext_bus_device_remove(). + */ + if (codec->core.type == HDA_DEV_LEGACY) + snd_hdac_device_unregister(&codec->core); codec_display_power(codec, false); put_device(hda_codec_dev(codec)); return 0; From 281d453333ef2dc0c0e6d0ad82d048f873594cab Mon Sep 17 00:00:00 2001 From: Bard liao Date: Mon, 22 Apr 2019 03:03:27 +0800 Subject: [PATCH 1377/1995] ASoC: hdac_hda: overwrite hdev type to HDA_DEV_ASOC In ASoC driver, snd_hdac_device_register() will be called by snd_hdac_ext_bus_device_init() and snd_hdac_device_unregister() will called by snd_hdac_ext_bus_device_remove(). However when ASoC codec driver call snd_hda_codec_device_new() to create a new hda codec, it will assign snd_hda_codec_dev_free() to the dev_free ops and snd_hda_codec_dev_free() will call snd_hdac_device_unregister(). As a result, snd_hdac_device_unregister() will be called twice in ASoC driver. To prevent it, we use hdev type to determine if the hda codec is registered by legacy HDA driver or ASoC driver and unregister device in snd_hda_codec_dev_free() only if it is a legacy HDA device. This patch will overwrite the hdev type so that we can know it is a ASoC device. Signed-off-by: Bard liao --- sound/soc/codecs/hdac_hda.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index f889d94c8e3cf7..7d494025691498 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -328,6 +328,12 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) dev_err(&hdev->dev, "failed to create hda codec %d\n", ret); goto error_no_pm; } + /* + * Overwrite type to HDA_DEV_ASOC since it is a ASoC driver + * hda_codec.c will check this flag to determine if unregister + * device is needed. + */ + hdev->type = HDA_DEV_ASOC; /* * snd_hda_codec_device_new decrements the usage count so call get pm From c4d7097761a68c4eacdbb8948dfdac182980e3e4 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 17 Apr 2019 16:10:32 +0800 Subject: [PATCH 1378/1995] ALSA: hda/realtek - add two more pin configuration sets to quirk table We have two Dell laptops which have the codec 10ec0236 and 10ec0256 respectively, the headset mic on them can't work, need to apply the quirk of ALC255_FIXUP_DELL1_MIC_NO_PRESENCE. So adding their pin configurations in the pin quirk table. Cc: Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai (cherry picked from commit b26e36b7ef36a8a3a147b1609b2505f8a4ecf511) --- sound/pci/hda/patch_realtek.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1ffa36e987b40d..2c88c02afd1c8b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7139,6 +7139,8 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x12, 0x90a60140}, {0x14, 0x90170150}, {0x21, 0x02211020}), + SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x21, 0x02211020}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, {0x14, 0x90170110}, {0x21, 0x02211020}), @@ -7249,6 +7251,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x21, 0x0221101f}), SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, ALC256_STANDARD_PINS), + SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x14, 0x90170110}, + {0x1b, 0x01011020}, + {0x21, 0x0221101f}), SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC, {0x14, 0x90170110}, {0x1b, 0x90a70130}, From 6896b25ef27677748a92679669e038560bd26e5b Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Wed, 24 Apr 2019 16:34:25 +0800 Subject: [PATCH 1379/1995] ALSA: hda/realtek - Add new Dell platform for headset mode Add two Dell platform for headset mode. [ Note: this is a further correction / addition of the previous pin-based quirks for Dell machines; another entry for ALC236 with the d-mic pin 0x12 and an entry for ALC295 -- tiwai ] Fixes: b26e36b7ef36 ("ALSA: hda/realtek - add two more pin configuration sets to quirk table") Signed-off-by: Kailang Yang Cc: Signed-off-by: Takashi Iwai (cherry picked from commit 0a29c57b76624723b6b00c027e0e992d130ace49) --- sound/pci/hda/patch_realtek.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 2c88c02afd1c8b..a83e9df2c24ba4 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7141,6 +7141,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x21, 0x02211020}), SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x21, 0x02211020}), + SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x40000000}, + {0x14, 0x90170110}, + {0x21, 0x02211020}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, {0x14, 0x90170110}, {0x21, 0x02211020}), @@ -7398,6 +7402,9 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x12, 0x90a60130}, {0x17, 0x90170110}, {0x21, 0x04211020}), + SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x14, 0x90170110}, + {0x21, 0x04211020}), SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, ALC295_STANDARD_PINS, {0x17, 0x21014020}, From 98e82451fb8f91a3cca9c7b817e2ac902b677352 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 26 Apr 2019 15:22:52 -0700 Subject: [PATCH 1380/1995] ASoC: SOF: intel: hda: add hw_params_upon_resume flag for hda stream The prepare() ioctl for BE dai link gets called both when the stream is started and when it is resumed from suspend. SOF uses this ioctl to set the hw params again only if the stream has been suspended. When the stream is started, the hw_params ioctl gets called before prepare() and hw_params is set for the BE dai link. So the prepare call does not need to do anything further. When the stream resumes after system suspend, SOF requires that the hw_params be set again for the BE dai. In order to determine which streams should set the hw params during prepare(), an internal flag called "hw_params_upon_resume" is introduced in struct sof_intel_hda_stream. The flag is set for hda streams when the sof device suspends and is cleared after hw_params is set. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/apl.c | 1 + sound/soc/sof/intel/cnl.c | 1 + sound/soc/sof/intel/hda-dai.c | 23 ++++++++++++++--------- sound/soc/sof/intel/hda-dsp.c | 16 ++++++++++++++++ sound/soc/sof/intel/hda.h | 2 ++ sound/soc/sof/ops.h | 6 ++++++ sound/soc/sof/pm.c | 3 +++ sound/soc/sof/sof-priv.h | 1 + 8 files changed, 44 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 026dde83962186..d1fb2f2ba1e1cc 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -91,6 +91,7 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .resume = hda_dsp_resume, .runtime_suspend = hda_dsp_runtime_suspend, .runtime_resume = hda_dsp_runtime_resume, + .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, }; EXPORT_SYMBOL(sof_apl_ops); diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index d128839b24504b..2eac20bbcaea03 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -225,6 +225,7 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .resume = hda_dsp_resume, .runtime_suspend = hda_dsp_runtime_suspend, .runtime_resume = hda_dsp_runtime_resume, + .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, }; EXPORT_SYMBOL(sof_cnl_ops); diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 830328af19c5ef..e1decf25aeace3 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -131,12 +131,17 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream, struct hdac_ext_stream *link_dev; struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct sof_intel_hda_stream *hda_stream; struct hda_pipe_params p_params = {0}; struct hdac_ext_link *link; int stream_tag; link_dev = snd_soc_dai_get_dma_data(dai, substream); + hda_stream = container_of(link_dev, struct sof_intel_hda_stream, + hda_stream); + hda_stream->hw_params_upon_resume = 0; + link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name); if (!link) return -EINVAL; @@ -168,22 +173,22 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream, static int hda_link_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct hdac_ext_stream *link_dev = + snd_soc_dai_get_dma_data(dai, substream); + struct sof_intel_hda_stream *hda_stream; struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(dai->component); - struct snd_sof_pcm *spcm; + snd_soc_component_get_drvdata(dai->component); + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); int stream = substream->stream; - spcm = snd_sof_find_spcm_dai(sdev, rtd); - if (!spcm) - return -EINVAL; + hda_stream = container_of(link_dev, struct sof_intel_hda_stream, + hda_stream); /* setup hw_params again only if resuming from system suspend */ - if (!spcm->hw_params_upon_resume[stream]) + if (!hda_stream->hw_params_upon_resume) return 0; - dev_dbg(sdev->dev, "hda: prepare stream %d dir %d\n", - spcm->pcm.pcm_id, substream->stream); + dev_dbg(sdev->dev, "hda: prepare stream dir %d\n", substream->stream); return hda_link_hw_params(substream, &rtd->dpcm[stream].hw_params, dai); diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 311fed502e09fc..5b73115a0b7873 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -453,3 +453,19 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state) return 0; } + +void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct sof_intel_hda_stream *hda_stream; + struct hdac_ext_stream *stream; + struct hdac_stream *s; + + /* set internal flag for BE */ + list_for_each_entry(s, &bus->stream_list, list) { + stream = stream_to_hdac_ext_stream(s); + hda_stream = container_of(stream, struct sof_intel_hda_stream, + hda_stream); + hda_stream->hw_params_upon_resume = 1; + } +} diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 59ae6f8a1beaee..2ff403f1e257ac 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -410,6 +410,7 @@ static inline struct hda_bus *sof_to_hbus(struct snd_sof_dev *s) struct sof_intel_hda_stream { struct hdac_ext_stream hda_stream; struct sof_intel_stream stream; + int hw_params_upon_resume; /* set up hw_params upon resume */ }; #define bus_to_sof_hda(bus) \ @@ -444,6 +445,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state); int hda_dsp_resume(struct snd_sof_dev *sdev); int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state); int hda_dsp_runtime_resume(struct snd_sof_dev *sdev); +void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev); void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags); void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 2a5d4c63f160f8..b8e2bf1fee2474 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -134,6 +134,12 @@ static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev, return 0; } +static inline void snd_sof_dsp_hw_params_upon_resume(struct snd_sof_dev *sdev) +{ + if (sof_ops(sdev)->set_hw_params_upon_resume) + sof_ops(sdev)->set_hw_params_upon_resume(sdev); +} + static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq) { if (sof_ops(sdev)->set_clk) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index fc599e1b6f65e6..8ef1d51025d8bb 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -227,6 +227,9 @@ static void sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev) spcm->hw_params_upon_resume[dir] = 1; } } + + /* set internal flag for BE */ + snd_sof_dsp_hw_params_upon_resume(sdev); } #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index bbc285018f9a72..170adc21ef1753 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -166,6 +166,7 @@ struct snd_sof_dsp_ops { int (*runtime_suspend)(struct snd_sof_dev *sof_dev, int state); /* optional */ int (*runtime_resume)(struct snd_sof_dev *sof_dev); /* optional */ + void (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */ /* DSP clocking */ int (*set_clk)(struct snd_sof_dev *sof_dev, u32 freq); /* optional */ From 48d8eb50b187c5cff8fee3834d72cd497d150224 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Sat, 27 Apr 2019 05:41:42 +0800 Subject: [PATCH 1381/1995] ASoC: SOF: IPC: add ipc dump function Dump IPC status when IPC timed out. IPC status is platform specific and need bind to plaform. Signed-off-by: Pan Xiuli --- sound/soc/sof/ipc.c | 1 + sound/soc/sof/ops.h | 6 ++++++ sound/soc/sof/sof-priv.h | 1 + 3 files changed, 8 insertions(+) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 437e80a07bc2c4..ba1bb17a8d1e5f 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -207,6 +207,7 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, dev_err(sdev->dev, "error: ipc timed out for 0x%x size %d\n", hdr->cmd, hdr->size); snd_sof_dsp_dbg_dump(ipc->sdev, SOF_DBG_REGS | SOF_DBG_MBOX); + snd_sof_ipc_dump(ipc->sdev); snd_sof_trace_notify_for_error(ipc->sdev); ret = -ETIMEDOUT; } else { diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index b8e2bf1fee2474..80fc3b374c2b3b 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -155,6 +155,12 @@ static inline void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, u32 flags) return sof_ops(sdev)->dbg_dump(sdev, flags); } +static inline void snd_sof_ipc_dump(struct snd_sof_dev *sdev) +{ + if (sof_ops(sdev)->ipc_dump) + return sof_ops(sdev)->ipc_dump(sdev); +} + /* register IO */ static inline void snd_sof_dsp_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, u32 value) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 170adc21ef1753..1e85d6f9c5c308 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -176,6 +176,7 @@ struct snd_sof_dsp_ops { int debug_map_count; /* optional */ void (*dbg_dump)(struct snd_sof_dev *sof_dev, u32 flags); /* optional */ + void (*ipc_dump)(struct snd_sof_dev *sof_dev); /* optional */ /* host DMA trace initialization */ int (*trace_init)(struct snd_sof_dev *sdev, From 16840c6b4b9c44bca58e0bca44f6899a372b283e Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Sat, 27 Apr 2019 05:44:29 +0800 Subject: [PATCH 1382/1995] ASoC: SOF: Intel: APL: add ipc dump function Add IPC dump function for APL plaform Signed-off-by: Pan Xiuli --- sound/soc/sof/intel/apl.c | 1 + sound/soc/sof/intel/hda.c | 18 ++++++++++++++++++ sound/soc/sof/intel/hda.h | 1 + 3 files changed, 20 insertions(+) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index d1fb2f2ba1e1cc..f215d80dce2c3e 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -55,6 +55,7 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .debug_map = apl_dsp_debugfs, .debug_map_count = ARRAY_SIZE(apl_dsp_debugfs), .dbg_dump = hda_dsp_dump, + .ipc_dump = hda_ipc_dump, /* stream callbacks */ .pcm_open = hda_dsp_pcm_open, diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index b8fc19790f3b80..c7d419d340c8ac 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -179,6 +179,24 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) } } +void hda_ipc_dump(struct snd_sof_dev *sdev) +{ + u32 hipcie; + u32 hipct; + u32 hipcctl; + + /* read IPC status */ + hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE); + hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT); + hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL); + + /* dump the IPC regs */ + /* TODO: parse the raw msg */ + dev_err(sdev->dev, + "error: host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n", + hipcie, hipct, hipcctl); +} + static int hda_init(struct snd_sof_dev *sdev) { struct hda_bus *hbus; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 2ff403f1e257ac..b9ef5f8eb36c39 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -448,6 +448,7 @@ int hda_dsp_runtime_resume(struct snd_sof_dev *sdev); void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev); void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags); void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags); +void hda_ipc_dump(struct snd_sof_dev *sdev); /* * DSP PCM Operations. From a5ea42b5fddf8688ab541f5c6e9f425de5a8f295 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Sat, 27 Apr 2019 05:47:41 +0800 Subject: [PATCH 1383/1995] ASoC: SOF: Intel: CNL: add ipc dump function Add ipc dump function to CNL+ platforms. Signed-off-by: Pan Xiuli --- sound/soc/sof/intel/cnl.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 2eac20bbcaea03..08a1a3d3c08d65 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -158,6 +158,24 @@ static int cnl_ipc_send_msg(struct snd_sof_dev *sdev, return 0; } +static void cnl_ipc_dump(struct snd_sof_dev *sdev) +{ + u32 hipcctl; + u32 hipcida; + u32 hipctdr; + + /* read IPC status */ + hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); + hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL); + hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR); + + /* dump the IPC regs */ + /* TODO: parse the raw msg */ + dev_err(sdev->dev, + "error: host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n", + hipcida, hipctdr, hipcctl); +} + /* cannonlake ops */ const struct snd_sof_dsp_ops sof_cnl_ops = { /* probe and remove */ @@ -189,6 +207,7 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .debug_map = cnl_dsp_debugfs, .debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs), .dbg_dump = hda_dsp_dump, + .ipc_dump = cnl_ipc_dump, /* stream callbacks */ .pcm_open = hda_dsp_pcm_open, From 2b106e5e0b90e2c8e3d64f3c7447402d9c6b69b1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 16 Apr 2019 15:25:00 +0200 Subject: [PATCH 1384/1995] ALSA: info: Fix racy addition/deletion of nodes The ALSA proc helper manages the child nodes in a linked list, but its addition and deletion is done without any lock. This leads to a corruption if they are operated concurrently. Usually this isn't a problem because the proc entries are added sequentially in the driver probe procedure itself. But the card registrations are done often asynchronously, and the crash could be actually reproduced with syzkaller. This patch papers over it by protecting the link addition and deletion with the parent's mutex. There is "access" mutex that is used for the file access, and this can be reused for this purpose as well. Reported-by: syzbot+48df349490c36f9f54ab@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai (cherry picked from commit 8c2f870890fd28e023b0fcf49dcee333f2c8bad7) --- sound/core/info.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sound/core/info.c b/sound/core/info.c index 96a074019c33c2..0eb169acc85031 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -713,8 +713,11 @@ snd_info_create_entry(const char *name, struct snd_info_entry *parent, INIT_LIST_HEAD(&entry->list); entry->parent = parent; entry->module = module; - if (parent) + if (parent) { + mutex_lock(&parent->access); list_add_tail(&entry->list, &parent->children); + mutex_unlock(&parent->access); + } return entry; } @@ -792,7 +795,12 @@ void snd_info_free_entry(struct snd_info_entry * entry) list_for_each_entry_safe(p, n, &entry->children, list) snd_info_free_entry(p); - list_del(&entry->list); + p = entry->parent; + if (p) { + mutex_lock(&p->access); + list_del(&entry->list); + mutex_unlock(&p->access); + } kfree(entry->name); if (entry->private_free) entry->private_free(entry); From 94f2e1eb6e138e5638cd1ddfa096ce10a9dfb2e1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 16 Apr 2019 17:06:33 +0200 Subject: [PATCH 1385/1995] ALSA: core: Fix card races between register and disconnect There is a small race window in the card disconnection code that allows the registration of another card with the very same card id. This leads to a warning in procfs creation as caught by syzkaller. The problem is that we delete snd_cards and snd_cards_lock entries at the very beginning of the disconnection procedure. This makes the slot available to be assigned for another card object while the disconnection procedure is being processed. Then it becomes possible to issue a procfs registration with the existing file name although we check the conflict beforehand. The fix is simply to move the snd_cards and snd_cards_lock clearances at the end of the disconnection procedure. The references to these entries are merely either from the global proc files like /proc/asound/cards or from the card registration / disconnection, so it should be fine to shift at the very end. Reported-by: syzbot+48df349490c36f9f54ab@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai (cherry picked from commit 2a3f7221acddfe1caa9ff09b3a8158c39b2fdeac) --- sound/core/init.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sound/core/init.c b/sound/core/init.c index 0c4dc40376a709..079c12d64b0e31 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -382,14 +382,7 @@ int snd_card_disconnect(struct snd_card *card) card->shutdown = 1; spin_unlock(&card->files_lock); - /* phase 1: disable fops (user space) operations for ALSA API */ - mutex_lock(&snd_card_mutex); - snd_cards[card->number] = NULL; - clear_bit(card->number, snd_cards_lock); - mutex_unlock(&snd_card_mutex); - - /* phase 2: replace file->f_op with special dummy operations */ - + /* replace file->f_op with special dummy operations */ spin_lock(&card->files_lock); list_for_each_entry(mfile, &card->files_list, list) { /* it's critical part, use endless loop */ @@ -405,7 +398,7 @@ int snd_card_disconnect(struct snd_card *card) } spin_unlock(&card->files_lock); - /* phase 3: notify all connected devices about disconnection */ + /* notify all connected devices about disconnection */ /* at this point, they cannot respond to any calls except release() */ #if IS_ENABLED(CONFIG_SND_MIXER_OSS) @@ -421,6 +414,13 @@ int snd_card_disconnect(struct snd_card *card) device_del(&card->card_dev); card->registered = false; } + + /* disable fops (user space) operations for ALSA API */ + mutex_lock(&snd_card_mutex); + snd_cards[card->number] = NULL; + clear_bit(card->number, snd_cards_lock); + mutex_unlock(&snd_card_mutex); + #ifdef CONFIG_PM wake_up(&card->power_sleep); #endif From e07401725d0c51e5a37ab12e8b61bb689ff37425 Mon Sep 17 00:00:00 2001 From: Xun Zhang Date: Fri, 19 Apr 2019 15:53:49 -0500 Subject: [PATCH 1386/1995] ASoC: codecs: rt5682: initialize mutex before using In rt5682 codec driver, a mutex called "calibrate_mutex" is used in rt5682_calibrate() before initialization, which causes warning in lock debug. Move the initialization before the usage of mutex. Signed-off-by: Xun Zhang Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit c46ab1510de1d3dd9871ae36fbec0da3e0d2d6c5) --- sound/soc/codecs/rt5682.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 86a7fa31c294b2..505fb3d7b1c5eb 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2588,6 +2588,7 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, rt5682_reset(rt5682->regmap); + mutex_init(&rt5682->calibrate_mutex); rt5682_calibrate(rt5682); ret = regmap_multi_reg_write(rt5682->regmap, patch_list, @@ -2654,7 +2655,6 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, INIT_DELAYED_WORK(&rt5682->jd_check_work, rt5682_jd_check_handler); - mutex_init(&rt5682->calibrate_mutex); if (i2c->irq) { ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, From c0912dc04dbb7707f06f072e0a5355d83ff8215e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Apr 2019 15:12:16 -0500 Subject: [PATCH 1387/1995] ASoC: Intel: bytcht_es8316: fix compilation warning Remove warning below, align with other machine drivers. bytcht_es8316.c:508:11: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] quirk = (int)dmi_id->driver_data; ^ Fixes: a8d218f4fe811 ('ASoC: Intel: bytcht_es8316: Add quirk for the Teclast X98+ II') Signed-off-by: Pierre-Louis Bossart Reviewed-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit 1fb1e93a1dc7c9673917a8081e144f48bde46495) --- sound/soc/intel/boards/bytcht_es8316.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 38975827e276ae..e8c585ffd04d76 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -61,7 +61,7 @@ enum { #define BYT_CHT_ES8316_MONO_SPEAKER BIT(17) #define BYT_CHT_ES8316_JD_INVERTED BIT(18) -static int quirk; +static unsigned long quirk; static int quirk_override = -1; module_param_named(quirk, quirk_override, int, 0444); @@ -505,7 +505,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) /* Check for BYTCR or other platform and setup quirks */ dmi_id = dmi_first_match(byt_cht_es8316_quirk_table); if (dmi_id) { - quirk = (int)dmi_id->driver_data; + quirk = (unsigned long)dmi_id->driver_data; } else if (x86_match_cpu(baytrail_cpu_ids) && mach->mach_params.acpi_ipc_irq_index == 0) { /* On BYTCR default to SSP0, internal-mic-in2-map, mono-spk */ @@ -517,7 +517,8 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) BYT_CHT_ES8316_MONO_SPEAKER; } if (quirk_override != -1) { - dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", quirk, + dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", + (unsigned int)quirk, quirk_override); quirk = quirk_override; } From c75e6c8d9b125bfebf24a9f207fc1cd50e334247 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Apr 2019 15:12:17 -0500 Subject: [PATCH 1388/1995] ASoC: Intel: bytcr_rt5640: align quirk override handling As discussed on alsa-devel, a zero value is useful to get rid of all quirks. Set default to -1 and align types as done in other machine drivers. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit 2fb2a19af17ac6da3c9b5c6ea4c51b7353290587) --- sound/soc/intel/boards/bytcr_rt5640.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index f9175cf6747ebb..dc22df9a99fb5f 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -98,8 +98,8 @@ struct byt_rt5640_private { static bool is_bytcr; static unsigned long byt_rt5640_quirk = BYT_RT5640_MCLK_EN; -static unsigned int quirk_override; -module_param_named(quirk, quirk_override, uint, 0444); +static int quirk_override = -1; +module_param_named(quirk, quirk_override, int, 0444); MODULE_PARM_DESC(quirk, "Board-specific quirk override"); static void log_quirks(struct device *dev) @@ -1254,7 +1254,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) dmi_id = dmi_first_match(byt_rt5640_quirk_table); if (dmi_id) byt_rt5640_quirk = (unsigned long)dmi_id->driver_data; - if (quirk_override) { + if (quirk_override != -1) { dev_info(&pdev->dev, "Overriding quirk 0x%x => 0x%x\n", (unsigned int)byt_rt5640_quirk, quirk_override); byt_rt5640_quirk = quirk_override; From e4762d8c031514afa6769c0691361ae73686790b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 19 Apr 2019 15:12:18 -0500 Subject: [PATCH 1389/1995] ASoC: Intel: bytcr_rt5651: align quirk override handling As discussed on alsa-devel, a zero value is useful to get rid of all quirks. Set default to -1 and align types as done in other machine drivers. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Hans de Goede Signed-off-by: Mark Brown (cherry picked from commit fb45befa7ea07399372266f09e562b26db5693c9) --- sound/soc/intel/boards/bytcr_rt5651.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 21c6675abd19af..ca657c3e5726d9 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -102,8 +102,8 @@ static const struct acpi_gpio_mapping *byt_rt5651_gpios; static unsigned long byt_rt5651_quirk = BYT_RT5651_DEFAULT_QUIRKS | BYT_RT5651_IN2_MAP; -static unsigned int quirk_override; -module_param_named(quirk, quirk_override, uint, 0444); +static int quirk_override = -1; +module_param_named(quirk, quirk_override, int, 0444); MODULE_PARM_DESC(quirk, "Board-specific quirk override"); static void log_quirks(struct device *dev) @@ -987,7 +987,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) /* check quirks before creating card */ dmi_check_system(byt_rt5651_quirk_table); - if (quirk_override) { + if (quirk_override != -1) { dev_info(&pdev->dev, "Overriding quirk 0x%x => 0x%x\n", (unsigned int)byt_rt5651_quirk, quirk_override); byt_rt5651_quirk = quirk_override; From 59552c4a6f4656ba92c6b4b4a8fec43464a4a75f Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:05:06 -0500 Subject: [PATCH 1390/1995] ASoC: SOF: Add Sound Open Firmware driver core The Sound Open Firmware driver core is a generic architecture independent layer that allows SOF to be used on many different architectures and platforms. It abstracts DSP operations and IO methods so that the target DSP can be an internal memory mapped or external SPI or I2C based device. This abstraction also allows SOF to be run on many different VMs on the same physical HW. SOF also requires some data in ASoC PCM runtime data for looking up SOF data during ASoC PCM operations. Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit c16211d6226dbde8819b84da07508083a1138a06) --- include/sound/sof.h | 94 ++++++ sound/soc/sof/core.c | 506 +++++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 632 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 1232 insertions(+) create mode 100644 include/sound/sof.h create mode 100644 sound/soc/sof/core.c create mode 100644 sound/soc/sof/sof-priv.h diff --git a/include/sound/sof.h b/include/sound/sof.h new file mode 100644 index 00000000000000..54f65ec33a6c3f --- /dev/null +++ b/include/sound/sof.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __INCLUDE_SOUND_SOF_H +#define __INCLUDE_SOUND_SOF_H + +#include +#include + +struct snd_sof_dsp_ops; + +/* + * SOF Platform data. + */ +struct snd_sof_pdata { + const struct firmware *fw; + const char *drv_name; + const char *name; + const char *platform; + + struct device *dev; + + /* + * notification callback used if the hardware initialization + * can take time or is handled in a workqueue. This callback + * can be used by the caller to e.g. enable runtime_pm + * or limit functionality until all low-level inits are + * complete. + */ + void (*sof_probe_complete)(struct device *dev); + + /* descriptor */ + const struct sof_dev_desc *desc; + + /* firmware and topology filenames */ + const char *fw_filename_prefix; + const char *fw_filename; + const char *tplg_filename_prefix; + const char *tplg_filename; + + /* machine */ + struct platform_device *pdev_mach; + const struct snd_soc_acpi_mach *machine; + + void *hw_pdata; +}; + +/* + * Descriptor used for setting up SOF platform data. This is used when + * ACPI/PCI data is missing or mapped differently. + */ +struct sof_dev_desc { + /* list of machines using this configuration */ + struct snd_soc_acpi_mach *machines; + + /* Platform resource indexes in BAR / ACPI resources. */ + /* Must set to -1 if not used - add new items to end */ + int resindex_lpe_base; + int resindex_pcicfg_base; + int resindex_imr_base; + int irqindex_host_ipc; + int resindex_dma_base; + + /* DMA only valid when resindex_dma_base != -1*/ + int dma_engine; + int dma_size; + + /* IPC timeouts in ms */ + int ipc_timeout; + int boot_timeout; + + /* chip information for dsp */ + const void *chip_info; + + /* defaults for no codec mode */ + const char *nocodec_fw_filename; + const char *nocodec_tplg_filename; + + /* defaults paths for firmware and topology files */ + const char *default_fw_path; + const char *default_tplg_path; + + const struct snd_sof_dsp_ops *ops; + const struct sof_arch_ops *arch_ops; +}; + +#endif diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c new file mode 100644 index 00000000000000..39cbd84ff9c8ca --- /dev/null +++ b/sound/soc/sof/core.c @@ -0,0 +1,506 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +#include +#include +#include +#include +#include +#include "sof-priv.h" +#include "ops.h" + +/* SOF defaults if not provided by the platform in ms */ +#define TIMEOUT_DEFAULT_IPC_MS 5 +#define TIMEOUT_DEFAULT_BOOT_MS 100 + +/* + * Generic object lookup APIs. + */ + +struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev, + const char *name) +{ + struct snd_sof_pcm *spcm; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + /* match with PCM dai name */ + if (strcmp(spcm->pcm.dai_name, name) == 0) + return spcm; + + /* match with playback caps name if set */ + if (*spcm->pcm.caps[0].name && + !strcmp(spcm->pcm.caps[0].name, name)) + return spcm; + + /* match with capture caps name if set */ + if (*spcm->pcm.caps[1].name && + !strcmp(spcm->pcm.caps[1].name, name)) + return spcm; + } + + return NULL; +} + +struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev, + unsigned int comp_id, + int *direction) +{ + struct snd_sof_pcm *spcm; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id == comp_id) { + *direction = SNDRV_PCM_STREAM_PLAYBACK; + return spcm; + } + if (spcm->stream[SNDRV_PCM_STREAM_CAPTURE].comp_id == comp_id) { + *direction = SNDRV_PCM_STREAM_CAPTURE; + return spcm; + } + } + + return NULL; +} + +struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev, + unsigned int pcm_id) +{ + struct snd_sof_pcm *spcm; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + if (le32_to_cpu(spcm->pcm.pcm_id) == pcm_id) + return spcm; + } + + return NULL; +} + +struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev, + const char *name) +{ + struct snd_sof_widget *swidget; + + list_for_each_entry(swidget, &sdev->widget_list, list) { + if (strcmp(name, swidget->widget->name) == 0) + return swidget; + } + + return NULL; +} + +/* find widget by stream name and direction */ +struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev, + const char *pcm_name, int dir) +{ + struct snd_sof_widget *swidget; + enum snd_soc_dapm_type type; + + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + type = snd_soc_dapm_aif_in; + else + type = snd_soc_dapm_aif_out; + + list_for_each_entry(swidget, &sdev->widget_list, list) { + if (!strcmp(pcm_name, swidget->widget->sname) && swidget->id == type) + return swidget; + } + + return NULL; +} + +struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev, + const char *name) +{ + struct snd_sof_dai *dai; + + list_for_each_entry(dai, &sdev->dai_list, list) { + if (dai->name && (strcmp(name, dai->name) == 0)) + return dai; + } + + return NULL; +} + +/* + * FW Panic/fault handling. + */ + +struct sof_panic_msg { + u32 id; + const char *msg; +}; + +/* standard FW panic types */ +static const struct sof_panic_msg panic_msg[] = { + {SOF_IPC_PANIC_MEM, "out of memory"}, + {SOF_IPC_PANIC_WORK, "work subsystem init failed"}, + {SOF_IPC_PANIC_IPC, "IPC subsystem init failed"}, + {SOF_IPC_PANIC_ARCH, "arch init failed"}, + {SOF_IPC_PANIC_PLATFORM, "platform init failed"}, + {SOF_IPC_PANIC_TASK, "scheduler init failed"}, + {SOF_IPC_PANIC_EXCEPTION, "runtime exception"}, + {SOF_IPC_PANIC_DEADLOCK, "deadlock"}, + {SOF_IPC_PANIC_STACK, "stack overflow"}, + {SOF_IPC_PANIC_IDLE, "can't enter idle"}, + {SOF_IPC_PANIC_WFI, "invalid wait state"}, + {SOF_IPC_PANIC_ASSERT, "assertion failed"}, +}; + +/* + * helper to be called from .dbg_dump callbacks. No error code is + * provided, it's left as an exercise for the caller of .dbg_dump + * (typically IPC or loader) + */ +void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, + u32 tracep_code, void *oops, + struct sof_ipc_panic_info *panic_info, + void *stack, size_t stack_words) +{ + u32 code; + int i; + + /* is firmware dead ? */ + if ((panic_code & SOF_IPC_PANIC_MAGIC_MASK) != SOF_IPC_PANIC_MAGIC) { + dev_err(sdev->dev, "error: unexpected fault 0x%8.8x trace 0x%8.8x\n", + panic_code, tracep_code); + return; /* no fault ? */ + } + + code = panic_code & (SOF_IPC_PANIC_MAGIC_MASK | SOF_IPC_PANIC_CODE_MASK); + + for (i = 0; i < ARRAY_SIZE(panic_msg); i++) { + if (panic_msg[i].id == code) { + dev_err(sdev->dev, "error: %s\n", panic_msg[i].msg); + dev_err(sdev->dev, "error: trace point %8.8x\n", + tracep_code); + goto out; + } + } + + /* unknown error */ + dev_err(sdev->dev, "error: unknown reason %8.8x\n", panic_code); + dev_err(sdev->dev, "error: trace point %8.8x\n", tracep_code); + +out: + dev_err(sdev->dev, "error: panic at %s:%d\n", + panic_info->filename, panic_info->linenum); + sof_oops(sdev, oops); + sof_stack(sdev, oops, stack, stack_words); +} +EXPORT_SYMBOL(snd_sof_get_status); + +/* + * Generic buffer page table creation. + * Take the each physical page address and drop the least significant unused + * bits from each (based on PAGE_SIZE). Then pack valid page address bits + * into compressed page table. + */ + +int snd_sof_create_page_table(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab, + unsigned char *page_table, size_t size) +{ + int i, pages; + + pages = snd_sgbuf_aligned_pages(size); + + dev_dbg(sdev->dev, "generating page table for %p size 0x%zx pages %d\n", + dmab->area, size, pages); + + for (i = 0; i < pages; i++) { + /* + * The number of valid address bits for each page is 20. + * idx determines the byte position within page_table + * where the current page's address is stored + * in the compressed page_table. + * This can be calculated by multiplying the page number by 2.5. + */ + u32 idx = (5 * i) >> 1; + u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT; + u8 *pg_table; + + dev_vdbg(sdev->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); + + pg_table = (u8 *)(page_table + idx); + + /* + * pagetable compression: + * byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 + * ___________pfn 0__________ __________pfn 1___________ _pfn 2... + * .... .... .... .... .... .... .... .... .... .... .... + * It is created by: + * 1. set current location to 0, PFN index i to 0 + * 2. put pfn[i] at current location in Little Endian byte order + * 3. calculate an intermediate value as + * x = (pfn[i+1] << 4) | (pfn[i] & 0xf) + * 4. put x at offset (current location + 2) in LE byte order + * 5. increment current location by 5 bytes, increment i by 2 + * 6. continue to (2) + */ + if (i & 1) + put_unaligned_le32((pg_table[0] & 0xf) | pfn << 4, + pg_table); + else + put_unaligned_le32(pfn, pg_table); + } + + return pages; +} + +/* + * SOF Driver enumeration. + */ +static int sof_machine_check(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + struct snd_soc_acpi_mach *machine; + int ret; + + if (plat_data->machine) + return 0; + + if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) { + dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); + return -ENODEV; + } + + /* fallback to nocodec mode */ + dev_warn(sdev->dev, "No ASoC machine driver found - using nocodec\n"); + machine = devm_kzalloc(sdev->dev, sizeof(*machine), GFP_KERNEL); + if (!machine) + return -ENOMEM; + + ret = sof_nocodec_setup(sdev->dev, plat_data, machine, + plat_data->desc, plat_data->desc->ops); + if (ret < 0) + return ret; + + plat_data->machine = machine; + + return 0; +} + +static int sof_probe_continue(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + const char *drv_name; + const void *mach; + int size; + int ret; + + /* probe the DSP hardware */ + ret = snd_sof_probe(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret); + return ret; + } + + /* check machine info */ + ret = sof_machine_check(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to get machine info %d\n", + ret); + goto dbg_err; + } + + /* set up platform component driver */ + snd_sof_new_platform_drv(sdev); + + /* register any debug/trace capabilities */ + ret = snd_sof_dbg_init(sdev); + if (ret < 0) { + /* + * debugfs issues are suppressed in snd_sof_dbg_init() since + * we cannot rely on debugfs + * here we trap errors due to memory allocation only. + */ + dev_err(sdev->dev, "error: failed to init DSP trace/debug %d\n", + ret); + goto dbg_err; + } + + /* init the IPC */ + sdev->ipc = snd_sof_ipc_init(sdev); + if (!sdev->ipc) { + dev_err(sdev->dev, "error: failed to init DSP IPC %d\n", ret); + goto ipc_err; + } + + /* load the firmware */ + ret = snd_sof_load_firmware(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to load DSP firmware %d\n", + ret); + goto fw_load_err; + } + + /* boot the firmware */ + ret = snd_sof_run_firmware(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to boot DSP firmware %d\n", + ret); + goto fw_run_err; + } + + /* init DMA trace */ + ret = snd_sof_init_trace(sdev); + if (ret < 0) { + /* non fatal */ + dev_warn(sdev->dev, + "warning: failed to initialize trace %d\n", ret); + } + + /* hereafter all FW boot flows are for PM reasons */ + sdev->first_boot = false; + + /* now register audio DSP platform driver and dai */ + ret = devm_snd_soc_register_component(sdev->dev, &sdev->plat_drv, + sof_ops(sdev)->drv, + sof_ops(sdev)->num_drv); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to register DSP DAI driver %d\n", ret); + goto fw_run_err; + } + + drv_name = plat_data->machine->drv_name; + mach = (const void *)plat_data->machine; + size = sizeof(*plat_data->machine); + + /* register machine driver, pass machine info as pdata */ + plat_data->pdev_mach = + platform_device_register_data(sdev->dev, drv_name, + PLATFORM_DEVID_NONE, mach, size); + + if (IS_ERR(plat_data->pdev_mach)) { + ret = PTR_ERR(plat_data->pdev_mach); + goto comp_err; + } + + dev_dbg(sdev->dev, "created machine %s\n", + dev_name(&plat_data->pdev_mach->dev)); + + if (plat_data->sof_probe_complete) + plat_data->sof_probe_complete(sdev->dev); + + return 0; + +comp_err: + snd_soc_unregister_component(sdev->dev); +fw_run_err: + snd_sof_fw_unload(sdev); +fw_load_err: + snd_sof_ipc_free(sdev); +ipc_err: + snd_sof_free_debug(sdev); +dbg_err: + snd_sof_remove(sdev); + + return ret; +} + +static void sof_probe_work(struct work_struct *work) +{ + struct snd_sof_dev *sdev = + container_of(work, struct snd_sof_dev, probe_work); + int ret; + + ret = sof_probe_continue(sdev); + if (ret < 0) { + /* errors cannot be propagated, log */ + dev_err(sdev->dev, "error: %s failed err: %d\n", __func__, ret); + } +} + +int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) +{ + struct snd_sof_dev *sdev; + + sdev = devm_kzalloc(dev, sizeof(*sdev), GFP_KERNEL); + if (!sdev) + return -ENOMEM; + + /* initialize sof device */ + sdev->dev = dev; + + sdev->pdata = plat_data; + sdev->first_boot = true; + dev_set_drvdata(dev, sdev); + + /* check all mandatory ops */ + if (!sof_ops(sdev) || !sof_ops(sdev)->probe || !sof_ops(sdev)->run || + !sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write || + !sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware || + !sof_ops(sdev)->ipc_msg_data || !sof_ops(sdev)->ipc_pcm_params) + return -EINVAL; + + INIT_LIST_HEAD(&sdev->pcm_list); + INIT_LIST_HEAD(&sdev->kcontrol_list); + INIT_LIST_HEAD(&sdev->widget_list); + INIT_LIST_HEAD(&sdev->dai_list); + INIT_LIST_HEAD(&sdev->route_list); + spin_lock_init(&sdev->ipc_lock); + spin_lock_init(&sdev->hw_lock); + + if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) + INIT_WORK(&sdev->probe_work, sof_probe_work); + + /* set default timeouts if none provided */ + if (plat_data->desc->ipc_timeout == 0) + sdev->ipc_timeout = TIMEOUT_DEFAULT_IPC_MS; + else + sdev->ipc_timeout = plat_data->desc->ipc_timeout; + if (plat_data->desc->boot_timeout == 0) + sdev->boot_timeout = TIMEOUT_DEFAULT_BOOT_MS; + else + sdev->boot_timeout = plat_data->desc->boot_timeout; + + if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) { + schedule_work(&sdev->probe_work); + return 0; + } + + return sof_probe_continue(sdev); +} +EXPORT_SYMBOL(snd_sof_device_probe); + +int snd_sof_device_remove(struct device *dev) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + struct snd_sof_pdata *pdata = sdev->pdata; + + if (IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE)) + cancel_work_sync(&sdev->probe_work); + + snd_sof_fw_unload(sdev); + snd_sof_ipc_free(sdev); + snd_sof_free_debug(sdev); + snd_sof_free_trace(sdev); + snd_sof_remove(sdev); + + /* + * Unregister machine driver. This will unbind the snd_card which + * will remove the component driver and unload the topology + * before freeing the snd_card. + */ + if (!IS_ERR_OR_NULL(pdata->pdev_mach)) + platform_device_unregister(pdata->pdev_mach); + + /* release firmware */ + release_firmware(pdata->fw); + pdata->fw = NULL; + + return 0; +} +EXPORT_SYMBOL(snd_sof_device_remove); + +MODULE_AUTHOR("Liam Girdwood"); +MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("platform:sof-audio"); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h new file mode 100644 index 00000000000000..35e78ffecce2fe --- /dev/null +++ b/sound/soc/sof/sof-priv.h @@ -0,0 +1,632 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __SOUND_SOC_SOF_PRIV_H +#define __SOUND_SOC_SOF_PRIV_H + +#include + +#include +#include + +#include +#include /* needs to be included before control.h */ +#include +#include +#include +#include +#include +#include + +#include + +/* debug flags */ +#define SOF_DBG_REGS BIT(1) +#define SOF_DBG_MBOX BIT(2) +#define SOF_DBG_TEXT BIT(3) +#define SOF_DBG_PCI BIT(4) + +/* max BARs mmaped devices can use */ +#define SND_SOF_BARS 8 + +/* time in ms for runtime suspend delay */ +#define SND_SOF_SUSPEND_DELAY_MS 2000 + +/* DMA buffer size for trace */ +#define DMA_BUF_SIZE_FOR_TRACE (PAGE_SIZE * 16) + +/* max number of FE PCMs before BEs */ +#define SOF_BE_PCM_BASE 16 + +#define SOF_IPC_DSP_REPLY 0 +#define SOF_IPC_HOST_REPLY 1 + +/* convenience constructor for DAI driver streams */ +#define SOF_DAI_STREAM(sname, scmin, scmax, srates, sfmt) \ + {.stream_name = sname, .channels_min = scmin, .channels_max = scmax, \ + .rates = srates, .formats = sfmt} + +#define SOF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_FLOAT) + +struct snd_sof_dev; +struct snd_sof_ipc_msg; +struct snd_sof_ipc; +struct snd_sof_debugfs_map; +struct snd_soc_tplg_ops; +struct snd_soc_component; +struct snd_sof_pdata; + +/* + * SOF DSP HW abstraction operations. + * Used to abstract DSP HW architecture and any IO busses between host CPU + * and DSP device(s). + */ +struct snd_sof_dsp_ops { + + /* probe and remove */ + int (*probe)(struct snd_sof_dev *sof_dev); /* mandatory */ + int (*remove)(struct snd_sof_dev *sof_dev); /* optional */ + + /* DSP core boot / reset */ + int (*run)(struct snd_sof_dev *sof_dev); /* mandatory */ + int (*stall)(struct snd_sof_dev *sof_dev); /* optional */ + int (*reset)(struct snd_sof_dev *sof_dev); /* optional */ + int (*core_power_up)(struct snd_sof_dev *sof_dev, + unsigned int core_mask); /* optional */ + int (*core_power_down)(struct snd_sof_dev *sof_dev, + unsigned int core_mask); /* optional */ + + /* + * Register IO: only used by respective drivers themselves, + * TODO: consider removing these operations and calling respective + * implementations directly + */ + void (*write)(struct snd_sof_dev *sof_dev, void __iomem *addr, + u32 value); /* optional */ + u32 (*read)(struct snd_sof_dev *sof_dev, + void __iomem *addr); /* optional */ + void (*write64)(struct snd_sof_dev *sof_dev, void __iomem *addr, + u64 value); /* optional */ + u64 (*read64)(struct snd_sof_dev *sof_dev, + void __iomem *addr); /* optional */ + + /* memcpy IO */ + void (*block_read)(struct snd_sof_dev *sof_dev, u32 bar, + u32 offset, void *dest, + size_t size); /* mandatory */ + void (*block_write)(struct snd_sof_dev *sof_dev, u32 bar, + u32 offset, void *src, + size_t size); /* mandatory */ + + /* doorbell */ + irqreturn_t (*irq_handler)(int irq, void *context); /* optional */ + irqreturn_t (*irq_thread)(int irq, void *context); /* optional */ + + /* ipc */ + int (*send_msg)(struct snd_sof_dev *sof_dev, + struct snd_sof_ipc_msg *msg); /* mandatory */ + + /* FW loading */ + int (*load_firmware)(struct snd_sof_dev *sof_dev); /* mandatory */ + int (*load_module)(struct snd_sof_dev *sof_dev, + struct snd_sof_mod_hdr *hdr); /* optional */ + /* + * FW ready checks for ABI compatibility and creates + * memory windows at first boot + */ + int (*fw_ready)(struct snd_sof_dev *sdev, u32 msg_id); /* optional */ + + /* connect pcm substream to a host stream */ + int (*pcm_open)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); /* optional */ + /* disconnect pcm substream to a host stream */ + int (*pcm_close)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); /* optional */ + + /* host stream hw params */ + int (*pcm_hw_params)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct sof_ipc_stream_params *ipc_params); /* optional */ + + /* host stream trigger */ + int (*pcm_trigger)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + int cmd); /* optional */ + + /* host stream pointer */ + snd_pcm_uframes_t (*pcm_pointer)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); /* optional */ + + /* host read DSP stream data */ + void (*ipc_msg_data)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz); /* mandatory */ + + /* host configure DSP HW parameters */ + int (*ipc_pcm_params)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply); /* mandatory */ + + /* pre/post firmware run */ + int (*pre_fw_run)(struct snd_sof_dev *sof_dev); /* optional */ + int (*post_fw_run)(struct snd_sof_dev *sof_dev); /* optional */ + + /* DSP PM */ + int (*suspend)(struct snd_sof_dev *sof_dev, int state); /* optional */ + int (*resume)(struct snd_sof_dev *sof_dev); /* optional */ + int (*runtime_suspend)(struct snd_sof_dev *sof_dev, + int state); /* optional */ + int (*runtime_resume)(struct snd_sof_dev *sof_dev); /* optional */ + + /* DSP clocking */ + int (*set_clk)(struct snd_sof_dev *sof_dev, u32 freq); /* optional */ + + /* debug */ + const struct snd_sof_debugfs_map *debug_map; /* optional */ + int debug_map_count; /* optional */ + void (*dbg_dump)(struct snd_sof_dev *sof_dev, + u32 flags); /* optional */ + + /* host DMA trace initialization */ + int (*trace_init)(struct snd_sof_dev *sdev, + u32 *stream_tag); /* optional */ + int (*trace_release)(struct snd_sof_dev *sdev); /* optional */ + int (*trace_trigger)(struct snd_sof_dev *sdev, + int cmd); /* optional */ + + /* DAI ops */ + struct snd_soc_dai_driver *drv; + int num_drv; +}; + +/* DSP architecture specific callbacks for oops and stack dumps */ +struct sof_arch_ops { + void (*dsp_oops)(struct snd_sof_dev *sdev, void *oops); + void (*dsp_stack)(struct snd_sof_dev *sdev, void *oops, + u32 *stack, u32 stack_words); +}; + +#define sof_arch_ops(sdev) ((sdev)->pdata->desc->arch_ops) + +/* DSP device HW descriptor mapping between bus ID and ops */ +struct sof_ops_table { + const struct sof_dev_desc *desc; + const struct snd_sof_dsp_ops *ops; +}; + +enum sof_dfsentry_type { + SOF_DFSENTRY_TYPE_IOMEM = 0, + SOF_DFSENTRY_TYPE_BUF, +}; + +enum sof_debugfs_access_type { + SOF_DEBUGFS_ACCESS_ALWAYS = 0, + SOF_DEBUGFS_ACCESS_D0_ONLY, +}; + +/* FS entry for debug files that can expose DSP memories, registers */ +struct snd_sof_dfsentry { + struct dentry *dfsentry; + size_t size; + enum sof_dfsentry_type type; + /* + * access_type specifies if the + * memory -> DSP resource (memory, register etc) is always accessible + * or if it is accessible only when the DSP is in D0. + */ + enum sof_debugfs_access_type access_type; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) + char *cache_buf; /* buffer to cache the contents of debugfs memory */ +#endif + struct snd_sof_dev *sdev; + struct list_head list; /* list in sdev dfsentry list */ + union { + void __iomem *io_mem; + void *buf; + }; +}; + +/* Debug mapping for any DSP memory or registers that can used for debug */ +struct snd_sof_debugfs_map { + const char *name; + u32 bar; + u32 offset; + u32 size; + /* + * access_type specifies if the memory is always accessible + * or if it is accessible only when the DSP is in D0. + */ + enum sof_debugfs_access_type access_type; +}; + +/* mailbox descriptor, used for host <-> DSP IPC */ +struct snd_sof_mailbox { + u32 offset; + size_t size; +}; + +/* IPC message descriptor for host <-> DSP IO */ +struct snd_sof_ipc_msg { + /* message data */ + u32 header; + void *msg_data; + void *reply_data; + size_t msg_size; + size_t reply_size; + int reply_error; + + wait_queue_head_t waitq; + bool ipc_complete; +}; + +/* PCM stream, mapped to FW component */ +struct snd_sof_pcm_stream { + u32 comp_id; + struct snd_dma_buffer page_table; + struct sof_ipc_stream_posn posn; + struct snd_pcm_substream *substream; +}; + +/* ALSA SOF PCM device */ +struct snd_sof_pcm { + struct snd_sof_dev *sdev; + struct snd_soc_tplg_pcm pcm; + struct snd_sof_pcm_stream stream[2]; + struct list_head list; /* list in sdev pcm list */ + struct snd_pcm_hw_params params[2]; + int hw_params_upon_resume[2]; /* set up hw_params upon resume */ +}; + +/* ALSA SOF Kcontrol device */ +struct snd_sof_control { + struct snd_sof_dev *sdev; + int comp_id; + int num_channels; + u32 readback_offset; /* offset to mmaped data if used */ + struct sof_ipc_ctrl_data *control_data; + u32 size; /* cdata size */ + enum sof_ipc_ctrl_cmd cmd; + u32 *volume_table; /* volume table computed from tlv data*/ + + struct list_head list; /* list in sdev control list */ +}; + +/* ASoC SOF DAPM widget */ +struct snd_sof_widget { + struct snd_sof_dev *sdev; + int comp_id; + int pipeline_id; + int complete; + int id; + + struct snd_soc_dapm_widget *widget; + struct list_head list; /* list in sdev widget list */ + + void *private; /* core does not touch this */ +}; + +/* ASoC SOF DAPM route */ +struct snd_sof_route { + struct snd_sof_dev *sdev; + + struct snd_soc_dapm_route *route; + struct list_head list; /* list in sdev route list */ + + void *private; +}; + +/* ASoC DAI device */ +struct snd_sof_dai { + struct snd_sof_dev *sdev; + const char *name; + + struct sof_ipc_comp_dai comp_dai; + struct sof_ipc_dai_config *dai_config; + struct list_head list; /* list in sdev dai list */ +}; + +/* + * SOF Device Level. + */ +struct snd_sof_dev { + struct device *dev; + spinlock_t ipc_lock; /* lock for IPC users */ + spinlock_t hw_lock; /* lock for HW IO access */ + + /* + * ASoC components. plat_drv fields are set dynamically so + * can't use const + */ + struct snd_soc_component_driver plat_drv; + + /* DSP firmware boot */ + wait_queue_head_t boot_wait; + u32 boot_complete; + u32 first_boot; + + /* work queue in case the probe is implemented in two steps */ + struct work_struct probe_work; + + /* DSP HW differentiation */ + struct snd_sof_pdata *pdata; + + /* IPC */ + struct snd_sof_ipc *ipc; + struct snd_sof_mailbox dsp_box; /* DSP initiated IPC */ + struct snd_sof_mailbox host_box; /* Host initiated IPC */ + struct snd_sof_mailbox stream_box; /* Stream position update */ + struct snd_sof_ipc_msg *msg; + u64 irq_status; + int ipc_irq; + u32 next_comp_id; /* monotonic - reset during S3 */ + + /* memory bases for mmaped DSPs - set by dsp_init() */ + void __iomem *bar[SND_SOF_BARS]; /* DSP base address */ + int mmio_bar; + int mailbox_bar; + size_t dsp_oops_offset; + + /* debug */ + struct dentry *debugfs_root; + struct list_head dfsentry_list; + + /* firmware loader */ + struct snd_dma_buffer dmab; + struct snd_dma_buffer dmab_bdl; + struct sof_ipc_fw_ready fw_ready; + struct sof_ipc_fw_version fw_version; + + /* topology */ + struct snd_soc_tplg_ops *tplg_ops; + struct list_head pcm_list; + struct list_head kcontrol_list; + struct list_head widget_list; + struct list_head dai_list; + struct list_head route_list; + struct snd_soc_component *component; + u32 enabled_cores_mask; /* keep track of enabled cores */ + + /* FW configuration */ + struct sof_ipc_dma_buffer_data *info_buffer; + struct sof_ipc_window *info_window; + + /* IPC timeouts in ms */ + int ipc_timeout; + int boot_timeout; + + /* Wait queue for code loading */ + wait_queue_head_t waitq; + int code_loading; + + /* DMA for Trace */ + struct snd_dma_buffer dmatb; + struct snd_dma_buffer dmatp; + int dma_trace_pages; + wait_queue_head_t trace_sleep; + u32 host_offset; + u32 dtrace_is_enabled; + u32 dtrace_error; + u32 msi_enabled; + + void *private; /* core does not touch this */ +}; + +/* + * Device Level. + */ + +int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data); +int snd_sof_device_remove(struct device *dev); + +int snd_sof_runtime_suspend(struct device *dev); +int snd_sof_runtime_resume(struct device *dev); +int snd_sof_resume(struct device *dev); +int snd_sof_suspend(struct device *dev); + +void snd_sof_new_platform_drv(struct snd_sof_dev *sdev); + +int snd_sof_create_page_table(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab, + unsigned char *page_table, size_t size); + +/* + * Firmware loading. + */ +int snd_sof_load_firmware(struct snd_sof_dev *sdev); +int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev); +int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev); +int snd_sof_run_firmware(struct snd_sof_dev *sdev); +int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, + struct snd_sof_mod_hdr *module); +void snd_sof_fw_unload(struct snd_sof_dev *sdev); +int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset); + +/* + * IPC low level APIs. + */ +struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev); +void snd_sof_ipc_free(struct snd_sof_dev *sdev); +int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id); +void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev); +int snd_sof_ipc_stream_pcm_params(struct snd_sof_dev *sdev, + struct sof_ipc_pcm_params *params); +int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox, + size_t dspbox_size, u32 hostbox, + size_t hostbox_size); +int snd_sof_ipc_valid(struct snd_sof_dev *sdev); +int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, + void *msg_data, size_t msg_bytes, void *reply_data, + size_t reply_bytes); +struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev, + const char *name); +struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev, + const char *pcm_name, + int dir); +struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev, + const char *name); + +static inline +struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_sof_dev *sdev, + struct snd_soc_pcm_runtime *rtd) +{ + struct snd_sof_pcm *spcm = NULL; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + if (le32_to_cpu(spcm->pcm.dai_id) == rtd->dai_link->id) + return spcm; + } + + return NULL; +} + +struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev, + const char *name); +struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev, + unsigned int comp_id, + int *direction); +struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev, + unsigned int pcm_id); + +/* + * Stream IPC + */ +int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev, + struct snd_sof_pcm *spcm, int direction, + struct sof_ipc_stream_posn *posn); + +/* + * Mixer IPC + */ +int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc, + struct snd_sof_control *scontrol, u32 ipc_cmd, + enum sof_ipc_ctrl_type ctrl_type, + enum sof_ipc_ctrl_cmd ctrl_cmd, + bool send); + +/* + * Topology. + * There is no snd_sof_free_topology since topology components will + * be freed by snd_soc_unregister_component, + */ +int snd_sof_init_topology(struct snd_sof_dev *sdev, + struct snd_soc_tplg_ops *ops); +int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file); +int snd_sof_complete_pipeline(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget); + +int sof_load_pipeline_ipc(struct snd_sof_dev *sdev, + struct sof_ipc_pipe_new *pipeline, + struct sof_ipc_comp_reply *r); + +/* + * Trace/debug + */ +int snd_sof_init_trace(struct snd_sof_dev *sdev); +void snd_sof_release_trace(struct snd_sof_dev *sdev); +void snd_sof_free_trace(struct snd_sof_dev *sdev); +int snd_sof_dbg_init(struct snd_sof_dev *sdev); +void snd_sof_free_debug(struct snd_sof_dev *sdev); +int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev, + void __iomem *base, size_t size, + const char *name, + enum sof_debugfs_access_type access_type); +int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, + void *base, size_t size, + const char *name); +int snd_sof_trace_update_pos(struct snd_sof_dev *sdev, + struct sof_ipc_dma_trace_posn *posn); +void snd_sof_trace_notify_for_error(struct snd_sof_dev *sdev); +void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, + u32 tracep_code, void *oops, + struct sof_ipc_panic_info *panic_info, + void *stack, size_t stack_words); +int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev); + +/* + * Platform specific ops. + */ +extern struct snd_compr_ops sof_compressed_ops; + +/* + * Kcontrols. + */ + +int snd_sof_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, + const unsigned int __user *binary_data, + unsigned int size); +int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, + unsigned int __user *binary_data, + unsigned int size); + +/* + * DSP Architectures. + */ +static inline void sof_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack, + u32 stack_words) +{ + if (sof_arch_ops(sdev)->dsp_stack) + sof_arch_ops(sdev)->dsp_stack(sdev, oops, stack, stack_words); +} + +static inline void sof_oops(struct snd_sof_dev *sdev, void *oops) +{ + if (sof_arch_ops(sdev)->dsp_oops) + sof_arch_ops(sdev)->dsp_oops(sdev, oops); +} + +extern const struct sof_arch_ops sof_xtensa_arch_ops; + +/* + * Utilities + */ +void sof_io_write(struct snd_sof_dev *sdev, void __iomem *addr, u32 value); +void sof_io_write64(struct snd_sof_dev *sdev, void __iomem *addr, u64 value); +u32 sof_io_read(struct snd_sof_dev *sdev, void __iomem *addr); +u64 sof_io_read64(struct snd_sof_dev *sdev, void __iomem *addr); +void sof_mailbox_write(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes); +void sof_mailbox_read(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes); +void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, + size_t size); +void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, + size_t size); + +void intel_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz); +int intel_ipc_pcm_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply); + +int intel_pcm_open(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); +int intel_pcm_close(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); + +#endif From efe7efec2c80ed8f1e7580caa586a70fa8a44811 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:05:07 -0500 Subject: [PATCH 1391/1995] ASoC: SOF: Add Sound Open Firmware KControl support SOF exposes regular ALSA Kcontrols that are defined by topology. This patch converts the Kcontrol IO to DSP IPC. The current implementation is aligned with previous Intel solutions, but is not optimal and can be improved: a) for every get/put the host wakes up the DSP and generates an IPC. The kernel should cache the values and generate an IPC only when strictly necessary. b) the firmware can be implemented to only instantiate the pipelines and related control-related parts that are needed at a given time, and power-gate the relevant SRAM blocks. The development tasks for these two improvements has started, once validated they will be provided in an update. Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit c3078f5397046755ddcd0447d202124c398469c5) --- sound/soc/sof/control.c | 552 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 552 insertions(+) create mode 100644 sound/soc/sof/control.c diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c new file mode 100644 index 00000000000000..11762c4580f102 --- /dev/null +++ b/sound/soc/sof/control.c @@ -0,0 +1,552 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +/* Mixer Controls */ + +#include +#include "sof-priv.h" + +static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size) +{ + if (value >= size) + return volume_map[size - 1]; + + return volume_map[value]; +} + +static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (volume_map[i] >= value) + return i; + } + + return i - 1; +} + +int snd_sof_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *sm = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_sof_control *scontrol = sm->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + unsigned int i, channels = scontrol->num_channels; + int err, ret; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err_ratelimited(sdev->dev, + "error: volume get failed to resume %d\n", + ret); + pm_runtime_put_noidle(sdev->dev); + return ret; + } + + /* get all the mixer data from DSP */ + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_GET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_VOLUME, + false); + + /* read back each channel */ + for (i = 0; i < channels; i++) + ucontrol->value.integer.value[i] = + ipc_to_mixer(cdata->chanv[i].value, + scontrol->volume_table, sm->max + 1); + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, + "error: volume get failed to idle %d\n", + err); + return 0; +} + +int snd_sof_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *sm = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_sof_control *scontrol = sm->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + unsigned int i, channels = scontrol->num_channels; + int ret, err; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err_ratelimited(sdev->dev, + "error: volume put failed to resume %d\n", + ret); + pm_runtime_put_noidle(sdev->dev); + return ret; + } + + /* update each channel */ + for (i = 0; i < channels; i++) { + cdata->chanv[i].value = + mixer_to_ipc(ucontrol->value.integer.value[i], + scontrol->volume_table, sm->max + 1); + cdata->chanv[i].channel = i; + } + + /* notify DSP of mixer updates */ + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_VOLUME, + true); + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, + "error: volume put failed to idle %d\n", + err); + return 0; +} + +int snd_sof_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *sm = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_sof_control *scontrol = sm->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + unsigned int i, channels = scontrol->num_channels; + int err, ret; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err_ratelimited(sdev->dev, + "error: switch get failed to resume %d\n", + ret); + pm_runtime_put_noidle(sdev->dev); + return ret; + } + + /* get all the mixer data from DSP */ + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_GET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_SWITCH, + false); + + /* read back each channel */ + for (i = 0; i < channels; i++) + ucontrol->value.integer.value[i] = cdata->chanv[i].value; + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, + "error: switch get failed to idle %d\n", + err); + return 0; +} + +int snd_sof_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *sm = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_sof_control *scontrol = sm->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + unsigned int i, channels = scontrol->num_channels; + int ret, err; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err_ratelimited(sdev->dev, + "error: switch put failed to resume %d\n", + ret); + pm_runtime_put_noidle(sdev->dev); + return ret; + } + + /* update each channel */ + for (i = 0; i < channels; i++) { + cdata->chanv[i].value = ucontrol->value.integer.value[i]; + cdata->chanv[i].channel = i; + } + + /* notify DSP of mixer updates */ + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_SWITCH, + true); + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, + "error: switch put failed to idle %d\n", + err); + return 0; +} + +int snd_sof_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *se = + (struct soc_enum *)kcontrol->private_value; + struct snd_sof_control *scontrol = se->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + unsigned int i, channels = scontrol->num_channels; + int err, ret; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err_ratelimited(sdev->dev, + "error: enum get failed to resume %d\n", + ret); + pm_runtime_put_noidle(sdev->dev); + return ret; + } + + /* get all the enum data from DSP */ + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_GET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_ENUM, + false); + + /* read back each channel */ + for (i = 0; i < channels; i++) + ucontrol->value.enumerated.item[i] = cdata->chanv[i].value; + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, + "error: enum get failed to idle %d\n", + err); + return 0; +} + +int snd_sof_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *se = + (struct soc_enum *)kcontrol->private_value; + struct snd_sof_control *scontrol = se->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + unsigned int i, channels = scontrol->num_channels; + int ret, err; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err_ratelimited(sdev->dev, + "error: enum put failed to resume %d\n", + ret); + pm_runtime_put_noidle(sdev->dev); + return ret; + } + + /* update each channel */ + for (i = 0; i < channels; i++) { + cdata->chanv[i].value = ucontrol->value.enumerated.item[i]; + cdata->chanv[i].channel = i; + } + + /* notify DSP of enum updates */ + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_ENUM, + true); + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, + "error: enum put failed to idle %d\n", + err); + return 0; +} + +int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_bytes_ext *be = + (struct soc_bytes_ext *)kcontrol->private_value; + struct snd_sof_control *scontrol = be->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct sof_abi_hdr *data = cdata->data; + size_t size; + int ret, err; + + if (be->max > sizeof(ucontrol->value.bytes.data)) { + dev_err_ratelimited(sdev->dev, + "error: data max %d exceeds ucontrol data array size\n", + be->max); + return -EINVAL; + } + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err_ratelimited(sdev->dev, + "error: bytes get failed to resume %d\n", + ret); + pm_runtime_put_noidle(sdev->dev); + return ret; + } + + /* get all the binary data from DSP */ + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_GET_DATA, + SOF_CTRL_TYPE_DATA_GET, + scontrol->cmd, + false); + + size = data->size + sizeof(*data); + if (size > be->max) { + dev_err_ratelimited(sdev->dev, + "error: DSP sent %zu bytes max is %d\n", + size, be->max); + ret = -EINVAL; + goto out; + } + + /* copy back to kcontrol */ + memcpy(ucontrol->value.bytes.data, data, size); + +out: + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, + "error: bytes get failed to idle %d\n", + err); + return ret; +} + +int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_bytes_ext *be = + (struct soc_bytes_ext *)kcontrol->private_value; + struct snd_sof_control *scontrol = be->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct sof_abi_hdr *data = cdata->data; + int ret, err; + + if (be->max > sizeof(ucontrol->value.bytes.data)) { + dev_err_ratelimited(sdev->dev, + "error: data max %d exceeds ucontrol data array size\n", + be->max); + return -EINVAL; + } + + if (data->size > be->max) { + dev_err_ratelimited(sdev->dev, + "error: size too big %d bytes max is %d\n", + data->size, be->max); + return -EINVAL; + } + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err_ratelimited(sdev->dev, + "error: bytes put failed to resume %d\n", + ret); + pm_runtime_put_noidle(sdev->dev); + return ret; + } + + /* copy from kcontrol */ + memcpy(data, ucontrol->value.bytes.data, data->size); + + /* notify DSP of byte control updates */ + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_DATA, + SOF_CTRL_TYPE_DATA_SET, + scontrol->cmd, + true); + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, + "error: bytes put failed to idle %d\n", + err); + return ret; +} + +int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, + const unsigned int __user *binary_data, + unsigned int size) +{ + struct soc_bytes_ext *be = + (struct soc_bytes_ext *)kcontrol->private_value; + struct snd_sof_control *scontrol = be->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct snd_ctl_tlv header; + const struct snd_ctl_tlv __user *tlvd = + (const struct snd_ctl_tlv __user *)binary_data; + int ret; + int err; + + /* + * The beginning of bytes data contains a header from where + * the length (as bytes) is needed to know the correct copy + * length of data from tlvd->tlv. + */ + if (copy_from_user(&header, tlvd, sizeof(const struct snd_ctl_tlv))) + return -EFAULT; + + /* be->max is coming from topology */ + if (header.length > be->max) { + dev_err_ratelimited(sdev->dev, "error: Bytes data size %d exceeds max %d.\n", + header.length, be->max); + return -EINVAL; + } + + /* Check that header id matches the command */ + if (header.numid != scontrol->cmd) { + dev_err_ratelimited(sdev->dev, + "error: incorrect numid %d\n", + header.numid); + return -EINVAL; + } + + if (copy_from_user(cdata->data, tlvd->tlv, header.length)) + return -EFAULT; + + if (cdata->data->magic != SOF_ABI_MAGIC) { + dev_err_ratelimited(sdev->dev, + "error: Wrong ABI magic 0x%08x.\n", + cdata->data->magic); + return -EINVAL; + } + + if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { + dev_err_ratelimited(sdev->dev, "error: Incompatible ABI version 0x%08x.\n", + cdata->data->abi); + return -EINVAL; + } + + if (cdata->data->size + sizeof(const struct sof_abi_hdr) > be->max) { + dev_err_ratelimited(sdev->dev, "error: Mismatch in ABI data size (truncated?).\n"); + return -EINVAL; + } + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err_ratelimited(sdev->dev, + "error: bytes_ext put failed to resume %d\n", + ret); + pm_runtime_put_noidle(sdev->dev); + return ret; + } + + /* notify DSP of byte control updates */ + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_DATA, + SOF_CTRL_TYPE_DATA_SET, + scontrol->cmd, + true); + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, + "error: bytes_ext put failed to idle %d\n", + err); + + return ret; +} + +int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, + unsigned int __user *binary_data, + unsigned int size) +{ + struct soc_bytes_ext *be = + (struct soc_bytes_ext *)kcontrol->private_value; + struct snd_sof_control *scontrol = be->dobj.private; + struct snd_sof_dev *sdev = scontrol->sdev; + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct snd_ctl_tlv header; + struct snd_ctl_tlv __user *tlvd = + (struct snd_ctl_tlv __user *)binary_data; + int data_size; + int err; + int ret; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err_ratelimited(sdev->dev, + "error: bytes_ext get failed to resume %d\n", + ret); + pm_runtime_put_noidle(sdev->dev); + return ret; + } + + /* + * Decrement the limit by ext bytes header size to + * ensure the user space buffer is not exceeded. + */ + size -= sizeof(const struct snd_ctl_tlv); + + /* set the ABI header values */ + cdata->data->magic = SOF_ABI_MAGIC; + cdata->data->abi = SOF_ABI_VERSION; + + /* get all the component data from DSP */ + ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_GET_DATA, + SOF_CTRL_TYPE_DATA_GET, + scontrol->cmd, + false); + + /* Prevent read of other kernel data or possibly corrupt response */ + data_size = cdata->data->size + sizeof(const struct sof_abi_hdr); + + /* check data size doesn't exceed max coming from topology */ + if (data_size > be->max) { + dev_err_ratelimited(sdev->dev, "error: user data size %d exceeds max size %d.\n", + data_size, be->max); + ret = -EINVAL; + goto out; + } + + header.numid = scontrol->cmd; + header.length = data_size; + if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv))) { + ret = -EFAULT; + goto out; + } + + if (copy_to_user(tlvd->tlv, cdata->data, data_size)) + ret = -EFAULT; + +out: + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, + "error: bytes_ext get failed to idle %d\n", + err); + return ret; +} From 2d4025655d0927e6bfaad47d36c5e38a24a3af3c Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:05:08 -0500 Subject: [PATCH 1392/1995] ASoC: SOF: Add driver debug support. Add debugFS files that can be used to expose DSP memories and and peripherals to userspace to assist with firmware debugging. Since we cannot rely on debugFS, errors are logged but don't stop execution. When a resource cannot be read in D3, it is optionally cached on suspend. Copying memories from IO will increase the suspend latency, this should only used in engineering builds w/ debug options. This part will have to be enhanced when support for D0ix states is provided, currently only D0 and D3 are supported. Signed-off-by: Pan Xiuli Signed-off-by: Ranjani Sridharan Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 86b02f71ccf320727473448733503e6f9378102d) --- sound/soc/sof/debug.c | 232 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 sound/soc/sof/debug.c diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c new file mode 100644 index 00000000000000..55f1d808dba04f --- /dev/null +++ b/sound/soc/sof/debug.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// +// Generic debug routines used to export DSP MMIO and memories to userspace +// for firmware debugging. +// + +#include +#include +#include +#include "sof-priv.h" +#include "ops.h" + +static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct snd_sof_dfsentry *dfse = file->private_data; + struct snd_sof_dev *sdev = dfse->sdev; + loff_t pos = *ppos; + size_t size_ret; + int skip = 0; + int size; + u8 *buf; + + size = dfse->size; + + /* validate position & count */ + if (pos < 0) + return -EINVAL; + if (pos >= size || !count) + return 0; + /* find the minimum. min() is not used since it adds sparse warnings */ + if (count > size - pos) + count = size - pos; + + /* align io read start to u32 multiple */ + pos = ALIGN_DOWN(pos, 4); + + /* intermediate buffer size must be u32 multiple */ + size = ALIGN(count, 4); + + /* if start position is unaligned, read extra u32 */ + if (unlikely(pos != *ppos)) { + skip = *ppos - pos; + if (pos + size + 4 < dfse->size) + size += 4; + } + + buf = kzalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (dfse->type == SOF_DFSENTRY_TYPE_IOMEM) { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) + /* + * If the DSP is active: copy from IO. + * If the DSP is suspended: + * - Copy from IO if the memory is always accessible. + * - Otherwise, copy from cached buffer. + */ + if (pm_runtime_active(sdev->dev) || + dfse->access_type == SOF_DEBUGFS_ACCESS_ALWAYS) { + memcpy_fromio(buf, dfse->io_mem + pos, size); + } else { + dev_info(sdev->dev, + "Copying cached debugfs data\n"); + memcpy(buf, dfse->cache_buf + pos, size); + } +#else + /* if the DSP is in D3 */ + if (!pm_runtime_active(sdev->dev) && + dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) { + dev_err(sdev->dev, + "error: debugfs entry %s cannot be read in DSP D3\n", + dfse->dfsentry->d_name.name); + kfree(buf); + return -EINVAL; + } + + memcpy_fromio(buf, dfse->io_mem + pos, size); +#endif + } else { + memcpy(buf, ((u8 *)(dfse->buf) + pos), size); + } + + /* copy to userspace */ + size_ret = copy_to_user(buffer, buf + skip, count); + + kfree(buf); + + /* update count & position if copy succeeded */ + if (size_ret) + return -EFAULT; + + *ppos = pos + count; + + return count; +} + +static const struct file_operations sof_dfs_fops = { + .open = simple_open, + .read = sof_dfsentry_read, + .llseek = default_llseek, +}; + +/* create FS entry for debug files that can expose DSP memories, registers */ +int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev, + void __iomem *base, size_t size, + const char *name, + enum sof_debugfs_access_type access_type) +{ + struct snd_sof_dfsentry *dfse; + + if (!sdev) + return -EINVAL; + + dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); + if (!dfse) + return -ENOMEM; + + dfse->type = SOF_DFSENTRY_TYPE_IOMEM; + dfse->io_mem = base; + dfse->size = size; + dfse->sdev = sdev; + dfse->access_type = access_type; + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) + /* + * allocate cache buffer that will be used to save the mem window + * contents prior to suspend + */ + if (access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) { + dfse->cache_buf = devm_kzalloc(sdev->dev, size, GFP_KERNEL); + if (!dfse->cache_buf) + return -ENOMEM; + } +#endif + + dfse->dfsentry = debugfs_create_file(name, 0444, sdev->debugfs_root, + dfse, &sof_dfs_fops); + if (!dfse->dfsentry) { + /* can't rely on debugfs, only log error and keep going */ + dev_err(sdev->dev, "error: cannot create debugfs entry %s\n", + name); + } else { + /* add to dfsentry list */ + list_add(&dfse->list, &sdev->dfsentry_list); + + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_sof_debugfs_io_item); + +/* create FS entry for debug files to expose kernel memory */ +int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, + void *base, size_t size, + const char *name) +{ + struct snd_sof_dfsentry *dfse; + + if (!sdev) + return -EINVAL; + + dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); + if (!dfse) + return -ENOMEM; + + dfse->type = SOF_DFSENTRY_TYPE_BUF; + dfse->buf = base; + dfse->size = size; + dfse->sdev = sdev; + + dfse->dfsentry = debugfs_create_file(name, 0444, sdev->debugfs_root, + dfse, &sof_dfs_fops); + if (!dfse->dfsentry) { + /* can't rely on debugfs, only log error and keep going */ + dev_err(sdev->dev, "error: cannot create debugfs entry %s\n", + name); + } else { + /* add to dfsentry list */ + list_add(&dfse->list, &sdev->dfsentry_list); + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_sof_debugfs_buf_item); + +int snd_sof_dbg_init(struct snd_sof_dev *sdev) +{ + const struct snd_sof_dsp_ops *ops = sof_ops(sdev); + const struct snd_sof_debugfs_map *map; + int i; + int err; + + /* use "sof" as top level debugFS dir */ + sdev->debugfs_root = debugfs_create_dir("sof", NULL); + if (IS_ERR_OR_NULL(sdev->debugfs_root)) { + dev_err(sdev->dev, "error: failed to create debugfs directory\n"); + return 0; + } + + /* init dfsentry list */ + INIT_LIST_HEAD(&sdev->dfsentry_list); + + /* create debugFS files for platform specific MMIO/DSP memories */ + for (i = 0; i < ops->debug_map_count; i++) { + map = &ops->debug_map[i]; + + err = snd_sof_debugfs_io_item(sdev, sdev->bar[map->bar] + + map->offset, map->size, + map->name, map->access_type); + /* errors are only due to memory allocation, not debugfs */ + if (err < 0) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_sof_dbg_init); + +void snd_sof_free_debug(struct snd_sof_dev *sdev) +{ + debugfs_remove_recursive(sdev->debugfs_root); +} +EXPORT_SYMBOL_GPL(snd_sof_free_debug); From a09d3bc269786d9f868d6c564cd0088066f67012 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:05:09 -0500 Subject: [PATCH 1393/1995] ASoC: SOF: Add support for IPC IO between DSP and Host Define an IPC ABI for all host <--> DSP communication. This ABI should be transport agnostic. i.e. it should work on MMIO and SPI/I2C style interfaces. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 53e0c72d98ba3eae314c32476103eac47612aa58) --- include/sound/sof/control.h | 158 +++++++ include/sound/sof/dai-intel.h | 178 ++++++++ include/sound/sof/dai.h | 75 +++ include/sound/sof/header.h | 158 +++++++ include/sound/sof/info.h | 118 +++++ include/sound/sof/pm.h | 48 ++ include/sound/sof/stream.h | 148 ++++++ include/sound/sof/trace.h | 67 +++ sound/soc/sof/ipc.c | 832 ++++++++++++++++++++++++++++++++++ 9 files changed, 1782 insertions(+) create mode 100644 include/sound/sof/control.h create mode 100644 include/sound/sof/dai-intel.h create mode 100644 include/sound/sof/dai.h create mode 100644 include/sound/sof/header.h create mode 100644 include/sound/sof/info.h create mode 100644 include/sound/sof/pm.h create mode 100644 include/sound/sof/stream.h create mode 100644 include/sound/sof/trace.h create mode 100644 sound/soc/sof/ipc.c diff --git a/include/sound/sof/control.h b/include/sound/sof/control.h new file mode 100644 index 00000000000000..bded69e696d4a2 --- /dev/null +++ b/include/sound/sof/control.h @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_CONTROL_H__ +#define __INCLUDE_SOUND_SOF_CONTROL_H__ + +#include +#include + +/* + * Component Mixers and Controls + */ + +/* channel positions - uses same values as ALSA */ +enum sof_ipc_chmap { + SOF_CHMAP_UNKNOWN = 0, + SOF_CHMAP_NA, /**< N/A, silent */ + SOF_CHMAP_MONO, /**< mono stream */ + SOF_CHMAP_FL, /**< front left */ + SOF_CHMAP_FR, /**< front right */ + SOF_CHMAP_RL, /**< rear left */ + SOF_CHMAP_RR, /**< rear right */ + SOF_CHMAP_FC, /**< front centre */ + SOF_CHMAP_LFE, /**< LFE */ + SOF_CHMAP_SL, /**< side left */ + SOF_CHMAP_SR, /**< side right */ + SOF_CHMAP_RC, /**< rear centre */ + SOF_CHMAP_FLC, /**< front left centre */ + SOF_CHMAP_FRC, /**< front right centre */ + SOF_CHMAP_RLC, /**< rear left centre */ + SOF_CHMAP_RRC, /**< rear right centre */ + SOF_CHMAP_FLW, /**< front left wide */ + SOF_CHMAP_FRW, /**< front right wide */ + SOF_CHMAP_FLH, /**< front left high */ + SOF_CHMAP_FCH, /**< front centre high */ + SOF_CHMAP_FRH, /**< front right high */ + SOF_CHMAP_TC, /**< top centre */ + SOF_CHMAP_TFL, /**< top front left */ + SOF_CHMAP_TFR, /**< top front right */ + SOF_CHMAP_TFC, /**< top front centre */ + SOF_CHMAP_TRL, /**< top rear left */ + SOF_CHMAP_TRR, /**< top rear right */ + SOF_CHMAP_TRC, /**< top rear centre */ + SOF_CHMAP_TFLC, /**< top front left centre */ + SOF_CHMAP_TFRC, /**< top front right centre */ + SOF_CHMAP_TSL, /**< top side left */ + SOF_CHMAP_TSR, /**< top side right */ + SOF_CHMAP_LLFE, /**< left LFE */ + SOF_CHMAP_RLFE, /**< right LFE */ + SOF_CHMAP_BC, /**< bottom centre */ + SOF_CHMAP_BLC, /**< bottom left centre */ + SOF_CHMAP_BRC, /**< bottom right centre */ + SOF_CHMAP_LAST = SOF_CHMAP_BRC, +}; + +/* control data type and direction */ +enum sof_ipc_ctrl_type { + /* per channel data - uses struct sof_ipc_ctrl_value_chan */ + SOF_CTRL_TYPE_VALUE_CHAN_GET = 0, + SOF_CTRL_TYPE_VALUE_CHAN_SET, + /* component data - uses struct sof_ipc_ctrl_value_comp */ + SOF_CTRL_TYPE_VALUE_COMP_GET, + SOF_CTRL_TYPE_VALUE_COMP_SET, + /* bespoke data - uses struct sof_abi_hdr */ + SOF_CTRL_TYPE_DATA_GET, + SOF_CTRL_TYPE_DATA_SET, +}; + +/* control command type */ +enum sof_ipc_ctrl_cmd { + SOF_CTRL_CMD_VOLUME = 0, /**< maps to ALSA volume style controls */ + SOF_CTRL_CMD_ENUM, /**< maps to ALSA enum style controls */ + SOF_CTRL_CMD_SWITCH, /**< maps to ALSA switch style controls */ + SOF_CTRL_CMD_BINARY, /**< maps to ALSA binary style controls */ +}; + +/* generic channel mapped value data */ +struct sof_ipc_ctrl_value_chan { + uint32_t channel; /**< channel map - enum sof_ipc_chmap */ + uint32_t value; +} __packed; + +/* generic component mapped value data */ +struct sof_ipc_ctrl_value_comp { + uint32_t index; /**< component source/sink/control index in control */ + union { + uint32_t uvalue; + int32_t svalue; + }; +} __packed; + +/* generic control data */ +struct sof_ipc_ctrl_data { + struct sof_ipc_reply rhdr; + uint32_t comp_id; + + /* control access and data type */ + uint32_t type; /**< enum sof_ipc_ctrl_type */ + uint32_t cmd; /**< enum sof_ipc_ctrl_cmd */ + uint32_t index; /**< control index for comps > 1 control */ + + /* control data - can either be appended or DMAed from host */ + struct sof_ipc_host_buffer buffer; + uint32_t num_elems; /**< in array elems or bytes for data type */ + uint32_t elems_remaining; /**< elems remaining if sent in parts */ + + uint32_t msg_index; /**< for large messages sent in parts */ + + /* reserved for future use */ + uint32_t reserved[6]; + + /* control data - add new types if needed */ + union { + /* channel values can be used by volume type controls */ + struct sof_ipc_ctrl_value_chan chanv[0]; + /* component values used by routing controls like mux, mixer */ + struct sof_ipc_ctrl_value_comp compv[0]; + /* data can be used by binary controls */ + struct sof_abi_hdr data[0]; + }; +} __packed; + +/** Event type */ +enum sof_ipc_ctrl_event_type { + SOF_CTRL_EVENT_GENERIC = 0, /**< generic event */ + SOF_CTRL_EVENT_GENERIC_METADATA, /**< generic event with metadata */ + SOF_CTRL_EVENT_KD, /**< keyword detection event */ + SOF_CTRL_EVENT_VAD, /**< voice activity detection event */ +}; + +/** + * Generic notification data. + */ +struct sof_ipc_comp_event { + struct sof_ipc_reply rhdr; + uint16_t src_comp_type; /**< COMP_TYPE_ */ + uint32_t src_comp_id; /**< source component id */ + uint32_t event_type; /**< event type - SOF_CTRL_EVENT_* */ + uint32_t num_elems; /**< in array elems or bytes for data type */ + + /* reserved for future use */ + uint32_t reserved[8]; + + /* control data - add new types if needed */ + union { + /* data can be used by binary controls */ + struct sof_abi_hdr data[0]; + /* event specific values */ + uint32_t event_value; + }; +} __packed; + +#endif diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h new file mode 100644 index 00000000000000..4bd83f7adddf65 --- /dev/null +++ b/include/sound/sof/dai-intel.h @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_DAI_INTEL_H__ +#define __INCLUDE_SOUND_SOF_DAI_INTEL_H__ + +#include + + /* ssc1: TINTE */ +#define SOF_DAI_INTEL_SSP_QUIRK_TINTE (1 << 0) + /* ssc1: PINTE */ +#define SOF_DAI_INTEL_SSP_QUIRK_PINTE (1 << 1) + /* ssc2: SMTATF */ +#define SOF_DAI_INTEL_SSP_QUIRK_SMTATF (1 << 2) + /* ssc2: MMRATF */ +#define SOF_DAI_INTEL_SSP_QUIRK_MMRATF (1 << 3) + /* ssc2: PSPSTWFDFD */ +#define SOF_DAI_INTEL_SSP_QUIRK_PSPSTWFDFD (1 << 4) + /* ssc2: PSPSRWFDFD */ +#define SOF_DAI_INTEL_SSP_QUIRK_PSPSRWFDFD (1 << 5) +/* ssc1: LBM */ +#define SOF_DAI_INTEL_SSP_QUIRK_LBM (1 << 6) + + /* here is the possibility to define others aux macros */ + +#define SOF_DAI_INTEL_SSP_FRAME_PULSE_WIDTH_MAX 38 +#define SOF_DAI_INTEL_SSP_SLOT_PADDING_MAX 31 + +/* SSP clocks control settings + * + * Macros for clks_control field in sof_ipc_dai_ssp_params struct. + */ + +/* mclk 0 disable */ +#define SOF_DAI_INTEL_SSP_MCLK_0_DISABLE BIT(0) +/* mclk 1 disable */ +#define SOF_DAI_INTEL_SSP_MCLK_1_DISABLE BIT(1) +/* mclk keep active */ +#define SOF_DAI_INTEL_SSP_CLKCTRL_MCLK_KA BIT(2) +/* bclk keep active */ +#define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_KA BIT(3) +/* fs keep active */ +#define SOF_DAI_INTEL_SSP_CLKCTRL_FS_KA BIT(4) +/* bclk idle */ +#define SOF_DAI_INTEL_SSP_CLKCTRL_BCLK_IDLE_HIGH BIT(5) + +/* SSP Configuration Request - SOF_IPC_DAI_SSP_CONFIG */ +struct sof_ipc_dai_ssp_params { + struct sof_ipc_hdr hdr; + uint16_t reserved1; + uint16_t mclk_id; + + uint32_t mclk_rate; /* mclk frequency in Hz */ + uint32_t fsync_rate; /* fsync frequency in Hz */ + uint32_t bclk_rate; /* bclk frequency in Hz */ + + /* TDM */ + uint32_t tdm_slots; + uint32_t rx_slots; + uint32_t tx_slots; + + /* data */ + uint32_t sample_valid_bits; + uint16_t tdm_slot_width; + uint16_t reserved2; /* alignment */ + + /* MCLK */ + uint32_t mclk_direction; + + uint16_t frame_pulse_width; + uint16_t tdm_per_slot_padding_flag; + uint32_t clks_control; + uint32_t quirks; +} __packed; + +/* HDA Configuration Request - SOF_IPC_DAI_HDA_CONFIG */ +struct sof_ipc_dai_hda_params { + struct sof_ipc_hdr hdr; + uint32_t link_dma_ch; +} __packed; + +/* DMIC Configuration Request - SOF_IPC_DAI_DMIC_CONFIG */ + +/* This struct is defined per 2ch PDM controller available in the platform. + * Normally it is sufficient to set the used microphone specific enables to 1 + * and keep other parameters as zero. The customizations are: + * + * 1. If a device mixes different microphones types with different polarity + * and/or the absolute polarity matters the PCM signal from a microphone + * can be inverted with the controls. + * + * 2. If the microphones in a stereo pair do not appear in captured stream + * in desired order due to board schematics choises they can be swapped with + * the clk_edge parameter. + * + * 3. If PDM bit errors are seen in capture (poor quality) the skew parameter + * that delays the sampling time of data by half cycles of DMIC source clock + * can be tried for improvement. However there is no guarantee for this to fix + * data integrity problems. + */ +struct sof_ipc_dai_dmic_pdm_ctrl { + struct sof_ipc_hdr hdr; + uint16_t id; /**< PDM controller ID */ + + uint16_t enable_mic_a; /**< Use A (left) channel mic (0 or 1)*/ + uint16_t enable_mic_b; /**< Use B (right) channel mic (0 or 1)*/ + + uint16_t polarity_mic_a; /**< Optionally invert mic A signal (0 or 1) */ + uint16_t polarity_mic_b; /**< Optionally invert mic B signal (0 or 1) */ + + uint16_t clk_edge; /**< Optionally swap data clock edge (0 or 1) */ + uint16_t skew; /**< Adjust PDM data sampling vs. clock (0..15) */ + + uint16_t reserved[3]; /**< Make sure the total size is 4 bytes aligned */ +} __packed; + +/* This struct contains the global settings for all 2ch PDM controllers. The + * version number used in configuration data is checked vs. version used by + * device driver src/drivers/dmic.c need to match. It is incremented from + * initial value 1 if updates done for the to driver would alter the operation + * of the microhone. + * + * Note: The microphone clock (pdmclk_min, pdmclk_max, duty_min, duty_max) + * parameters need to be set as defined in microphone data sheet. E.g. clock + * range 1.0 - 3.2 MHz is usually supported microphones. Some microphones are + * multi-mode capable and there may be denied mic clock frequencies between + * the modes. In such case set the clock range limits of the desired mode to + * avoid the driver to set clock to an illegal rate. + * + * The duty cycle could be set to 48-52% if not known. Generally these + * parameters can be altered within data sheet specified limits to match + * required audio application performance power. + * + * The microphone clock needs to be usually about 50-80 times the used audio + * sample rate. With highest sample rates above 48 kHz this can relaxed + * somewhat. + * + * The parameter wake_up_time describes how long time the microphone needs + * for the data line to produce valid output from mic clock start. The driver + * will mute the captured audio for the given time. The min_clock_on_time + * parameter is used to prevent too short clock bursts to happen. The driver + * will keep the clock active after capture stop if this time is not yet + * met. The unit for both is microseconds (us). Exceed of 100 ms will be + * treated as an error. + */ +struct sof_ipc_dai_dmic_params { + struct sof_ipc_hdr hdr; + uint32_t driver_ipc_version; /**< Version (1..N) */ + + uint32_t pdmclk_min; /**< Minimum microphone clock in Hz (100000..N) */ + uint32_t pdmclk_max; /**< Maximum microphone clock in Hz (min...N) */ + + uint32_t fifo_fs; /**< FIFO sample rate in Hz (8000..96000) */ + uint32_t reserved_1; /**< Reserved */ + uint16_t fifo_bits; /**< FIFO word length (16 or 32) */ + uint16_t reserved_2; /**< Reserved */ + + uint16_t duty_min; /**< Min. mic clock duty cycle in % (20..80) */ + uint16_t duty_max; /**< Max. mic clock duty cycle in % (min..80) */ + + uint32_t num_pdm_active; /**< Number of active pdm controllers */ + + uint32_t wake_up_time; /**< Time from clock start to data (us) */ + uint32_t min_clock_on_time; /**< Min. time that clk is kept on (us) */ + + /* reserved for future use */ + uint32_t reserved[6]; + + /**< variable number of pdm controller config */ + struct sof_ipc_dai_dmic_pdm_ctrl pdm[0]; +} __packed; + +#endif diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h new file mode 100644 index 00000000000000..3b67c93ff101b5 --- /dev/null +++ b/include/sound/sof/dai.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_DAI_H__ +#define __INCLUDE_SOUND_SOF_DAI_H__ + +#include +#include + +/* + * DAI Configuration. + * + * Each different DAI type will have it's own structure and IPC cmd. + */ + +#define SOF_DAI_FMT_I2S 1 /**< I2S mode */ +#define SOF_DAI_FMT_RIGHT_J 2 /**< Right Justified mode */ +#define SOF_DAI_FMT_LEFT_J 3 /**< Left Justified mode */ +#define SOF_DAI_FMT_DSP_A 4 /**< L data MSB after FRM LRC */ +#define SOF_DAI_FMT_DSP_B 5 /**< L data MSB during FRM LRC */ +#define SOF_DAI_FMT_PDM 6 /**< Pulse density modulation */ + +#define SOF_DAI_FMT_CONT (1 << 4) /**< continuous clock */ +#define SOF_DAI_FMT_GATED (0 << 4) /**< clock is gated */ + +#define SOF_DAI_FMT_NB_NF (0 << 8) /**< normal bit clock + frame */ +#define SOF_DAI_FMT_NB_IF (2 << 8) /**< normal BCLK + inv FRM */ +#define SOF_DAI_FMT_IB_NF (3 << 8) /**< invert BCLK + nor FRM */ +#define SOF_DAI_FMT_IB_IF (4 << 8) /**< invert BCLK + FRM */ + +#define SOF_DAI_FMT_CBM_CFM (0 << 12) /**< codec clk & FRM master */ +#define SOF_DAI_FMT_CBS_CFM (2 << 12) /**< codec clk slave & FRM master */ +#define SOF_DAI_FMT_CBM_CFS (3 << 12) /**< codec clk master & frame slave */ +#define SOF_DAI_FMT_CBS_CFS (4 << 12) /**< codec clk & FRM slave */ + +#define SOF_DAI_FMT_FORMAT_MASK 0x000f +#define SOF_DAI_FMT_CLOCK_MASK 0x00f0 +#define SOF_DAI_FMT_INV_MASK 0x0f00 +#define SOF_DAI_FMT_MASTER_MASK 0xf000 + +/** \brief Types of DAI */ +enum sof_ipc_dai_type { + SOF_DAI_INTEL_NONE = 0, /**< None */ + SOF_DAI_INTEL_SSP, /**< Intel SSP */ + SOF_DAI_INTEL_DMIC, /**< Intel DMIC */ + SOF_DAI_INTEL_HDA, /**< Intel HD/A */ +}; + +/* general purpose DAI configuration */ +struct sof_ipc_dai_config { + struct sof_ipc_cmd_hdr hdr; + uint32_t type; /**< DAI type - enum sof_ipc_dai_type */ + uint32_t dai_index; /**< index of this type dai */ + + /* physical protocol and clocking */ + uint16_t format; /**< SOF_DAI_FMT_ */ + uint16_t reserved16; /**< alignment */ + + /* reserved for future use */ + uint32_t reserved[8]; + + /* HW specific data */ + union { + struct sof_ipc_dai_ssp_params ssp; + struct sof_ipc_dai_dmic_params dmic; + struct sof_ipc_dai_hda_params hda; + }; +} __packed; + +#endif diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h new file mode 100644 index 00000000000000..ccb6a004b37b78 --- /dev/null +++ b/include/sound/sof/header.h @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_HEADER_H__ +#define __INCLUDE_SOUND_SOF_HEADER_H__ + +#include + +/** \addtogroup sof_uapi uAPI + * SOF uAPI specification. + * @{ + */ + +/* + * IPC messages have a prefixed 32 bit identifier made up as follows :- + * + * 0xGCCCNNNN where + * G is global cmd type (4 bits) + * C is command type (12 bits) + * I is the ID number (16 bits) - monotonic and overflows + * + * This is sent at the start of the IPM message in the mailbox. Messages should + * not be sent in the doorbell (special exceptions for firmware . + */ + +/* Global Message - Generic */ +#define SOF_GLB_TYPE_SHIFT 28 +#define SOF_GLB_TYPE_MASK (0xf << SOF_GLB_TYPE_SHIFT) +#define SOF_GLB_TYPE(x) ((x) << SOF_GLB_TYPE_SHIFT) + +/* Command Message - Generic */ +#define SOF_CMD_TYPE_SHIFT 16 +#define SOF_CMD_TYPE_MASK (0xfff << SOF_CMD_TYPE_SHIFT) +#define SOF_CMD_TYPE(x) ((x) << SOF_CMD_TYPE_SHIFT) + +/* Global Message Types */ +#define SOF_IPC_GLB_REPLY SOF_GLB_TYPE(0x1U) +#define SOF_IPC_GLB_COMPOUND SOF_GLB_TYPE(0x2U) +#define SOF_IPC_GLB_TPLG_MSG SOF_GLB_TYPE(0x3U) +#define SOF_IPC_GLB_PM_MSG SOF_GLB_TYPE(0x4U) +#define SOF_IPC_GLB_COMP_MSG SOF_GLB_TYPE(0x5U) +#define SOF_IPC_GLB_STREAM_MSG SOF_GLB_TYPE(0x6U) +#define SOF_IPC_FW_READY SOF_GLB_TYPE(0x7U) +#define SOF_IPC_GLB_DAI_MSG SOF_GLB_TYPE(0x8U) +#define SOF_IPC_GLB_TRACE_MSG SOF_GLB_TYPE(0x9U) + +/* + * DSP Command Message Types + */ + +/* topology */ +#define SOF_IPC_TPLG_COMP_NEW SOF_CMD_TYPE(0x001) +#define SOF_IPC_TPLG_COMP_FREE SOF_CMD_TYPE(0x002) +#define SOF_IPC_TPLG_COMP_CONNECT SOF_CMD_TYPE(0x003) +#define SOF_IPC_TPLG_PIPE_NEW SOF_CMD_TYPE(0x010) +#define SOF_IPC_TPLG_PIPE_FREE SOF_CMD_TYPE(0x011) +#define SOF_IPC_TPLG_PIPE_CONNECT SOF_CMD_TYPE(0x012) +#define SOF_IPC_TPLG_PIPE_COMPLETE SOF_CMD_TYPE(0x013) +#define SOF_IPC_TPLG_BUFFER_NEW SOF_CMD_TYPE(0x020) +#define SOF_IPC_TPLG_BUFFER_FREE SOF_CMD_TYPE(0x021) + +/* PM */ +#define SOF_IPC_PM_CTX_SAVE SOF_CMD_TYPE(0x001) +#define SOF_IPC_PM_CTX_RESTORE SOF_CMD_TYPE(0x002) +#define SOF_IPC_PM_CTX_SIZE SOF_CMD_TYPE(0x003) +#define SOF_IPC_PM_CLK_SET SOF_CMD_TYPE(0x004) +#define SOF_IPC_PM_CLK_GET SOF_CMD_TYPE(0x005) +#define SOF_IPC_PM_CLK_REQ SOF_CMD_TYPE(0x006) +#define SOF_IPC_PM_CORE_ENABLE SOF_CMD_TYPE(0x007) + +/* component runtime config - multiple different types */ +#define SOF_IPC_COMP_SET_VALUE SOF_CMD_TYPE(0x001) +#define SOF_IPC_COMP_GET_VALUE SOF_CMD_TYPE(0x002) +#define SOF_IPC_COMP_SET_DATA SOF_CMD_TYPE(0x003) +#define SOF_IPC_COMP_GET_DATA SOF_CMD_TYPE(0x004) + +/* DAI messages */ +#define SOF_IPC_DAI_CONFIG SOF_CMD_TYPE(0x001) +#define SOF_IPC_DAI_LOOPBACK SOF_CMD_TYPE(0x002) + +/* stream */ +#define SOF_IPC_STREAM_PCM_PARAMS SOF_CMD_TYPE(0x001) +#define SOF_IPC_STREAM_PCM_PARAMS_REPLY SOF_CMD_TYPE(0x002) +#define SOF_IPC_STREAM_PCM_FREE SOF_CMD_TYPE(0x003) +#define SOF_IPC_STREAM_TRIG_START SOF_CMD_TYPE(0x004) +#define SOF_IPC_STREAM_TRIG_STOP SOF_CMD_TYPE(0x005) +#define SOF_IPC_STREAM_TRIG_PAUSE SOF_CMD_TYPE(0x006) +#define SOF_IPC_STREAM_TRIG_RELEASE SOF_CMD_TYPE(0x007) +#define SOF_IPC_STREAM_TRIG_DRAIN SOF_CMD_TYPE(0x008) +#define SOF_IPC_STREAM_TRIG_XRUN SOF_CMD_TYPE(0x009) +#define SOF_IPC_STREAM_POSITION SOF_CMD_TYPE(0x00a) +#define SOF_IPC_STREAM_VORBIS_PARAMS SOF_CMD_TYPE(0x010) +#define SOF_IPC_STREAM_VORBIS_FREE SOF_CMD_TYPE(0x011) + +/* trace and debug */ +#define SOF_IPC_TRACE_DMA_PARAMS SOF_CMD_TYPE(0x001) +#define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002) + +/* Get message component id */ +#define SOF_IPC_MESSAGE_ID(x) ((x) & 0xffff) + +/* maximum message size for mailbox Tx/Rx */ +#define SOF_IPC_MSG_MAX_SIZE 384 + +/* + * Structure Header - Header for all IPC structures except command structs. + * The size can be greater than the structure size and that means there is + * extended bespoke data beyond the end of the structure including variable + * arrays. + */ + +struct sof_ipc_hdr { + uint32_t size; /**< size of structure */ +} __packed; + +/* + * Command Header - Header for all IPC commands. Identifies IPC message. + * The size can be greater than the structure size and that means there is + * extended bespoke data beyond the end of the structure including variable + * arrays. + */ + +struct sof_ipc_cmd_hdr { + uint32_t size; /**< size of structure */ + uint32_t cmd; /**< SOF_IPC_GLB_ + cmd */ +} __packed; + +/* + * Generic reply message. Some commands override this with their own reply + * types that must include this at start. + */ +struct sof_ipc_reply { + struct sof_ipc_cmd_hdr hdr; + int32_t error; /**< negative error numbers */ +} __packed; + +/* + * Compound commands - SOF_IPC_GLB_COMPOUND. + * + * Compound commands are sent to the DSP as a single IPC operation. The + * commands are split into blocks and each block has a header. This header + * identifies the command type and the number of commands before the next + * header. + */ + +struct sof_ipc_compound_hdr { + struct sof_ipc_cmd_hdr hdr; + uint32_t count; /**< count of 0 means end of compound sequence */ +} __packed; + +/** @}*/ + +#endif diff --git a/include/sound/sof/info.h b/include/sound/sof/info.h new file mode 100644 index 00000000000000..21dae04d818398 --- /dev/null +++ b/include/sound/sof/info.h @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_INFO_H__ +#define __INCLUDE_SOUND_SOF_INFO_H__ + +#include +#include + +/* + * Firmware boot and version + */ + +#define SOF_IPC_MAX_ELEMS 16 + +/* extended data types that can be appended onto end of sof_ipc_fw_ready */ +enum sof_ipc_ext_data { + SOF_IPC_EXT_DMA_BUFFER = 0, + SOF_IPC_EXT_WINDOW, +}; + +/* FW version - SOF_IPC_GLB_VERSION */ +struct sof_ipc_fw_version { + struct sof_ipc_hdr hdr; + uint16_t major; + uint16_t minor; + uint16_t micro; + uint16_t build; + uint8_t date[12]; + uint8_t time[10]; + uint8_t tag[6]; + uint32_t abi_version; + + /* reserved for future use */ + uint32_t reserved[4]; +} __packed; + +/* FW ready Message - sent by firmware when boot has completed */ +struct sof_ipc_fw_ready { + struct sof_ipc_cmd_hdr hdr; + uint32_t dspbox_offset; /* dsp initiated IPC mailbox */ + uint32_t hostbox_offset; /* host initiated IPC mailbox */ + uint32_t dspbox_size; + uint32_t hostbox_size; + struct sof_ipc_fw_version version; + + /* Miscellaneous debug flags showing build/debug features enabled */ + union { + uint64_t reserved; + struct { + uint64_t build:1; + uint64_t locks:1; + uint64_t locks_verbose:1; + uint64_t gdb:1; + } bits; + } debug; + + /* reserved for future use */ + uint32_t reserved[4]; +} __packed; + +/* + * Extended Firmware data. All optional, depends on platform/arch. + */ +enum sof_ipc_region { + SOF_IPC_REGION_DOWNBOX = 0, + SOF_IPC_REGION_UPBOX, + SOF_IPC_REGION_TRACE, + SOF_IPC_REGION_DEBUG, + SOF_IPC_REGION_STREAM, + SOF_IPC_REGION_REGS, + SOF_IPC_REGION_EXCEPTION, +}; + +struct sof_ipc_ext_data_hdr { + struct sof_ipc_cmd_hdr hdr; + uint32_t type; /**< SOF_IPC_EXT_ */ +} __packed; + +struct sof_ipc_dma_buffer_elem { + struct sof_ipc_hdr hdr; + uint32_t type; /**< SOF_IPC_REGION_ */ + uint32_t id; /**< platform specific - used to map to host memory */ + struct sof_ipc_host_buffer buffer; +} __packed; + +/* extended data DMA buffers for IPC, trace and debug */ +struct sof_ipc_dma_buffer_data { + struct sof_ipc_ext_data_hdr ext_hdr; + uint32_t num_buffers; + + /* host files in buffer[n].buffer */ + struct sof_ipc_dma_buffer_elem buffer[]; +} __packed; + +struct sof_ipc_window_elem { + struct sof_ipc_hdr hdr; + uint32_t type; /**< SOF_IPC_REGION_ */ + uint32_t id; /**< platform specific - used to map to host memory */ + uint32_t flags; /**< R, W, RW, etc - to define */ + uint32_t size; /**< size of region in bytes */ + /* offset in window region as windows can be partitioned */ + uint32_t offset; +} __packed; + +/* extended data memory windows for IPC, trace and debug */ +struct sof_ipc_window { + struct sof_ipc_ext_data_hdr ext_hdr; + uint32_t num_windows; + struct sof_ipc_window_elem window[]; +} __packed; + +#endif diff --git a/include/sound/sof/pm.h b/include/sound/sof/pm.h new file mode 100644 index 00000000000000..8ae3ad45bdf7ca --- /dev/null +++ b/include/sound/sof/pm.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_PM_H__ +#define __INCLUDE_SOUND_SOF_PM_H__ + +#include + +/* + * PM + */ + +/* PM context element */ +struct sof_ipc_pm_ctx_elem { + struct sof_ipc_hdr hdr; + uint32_t type; + uint32_t size; + uint64_t addr; +} __packed; + +/* + * PM context - SOF_IPC_PM_CTX_SAVE, SOF_IPC_PM_CTX_RESTORE, + * SOF_IPC_PM_CTX_SIZE + */ +struct sof_ipc_pm_ctx { + struct sof_ipc_cmd_hdr hdr; + struct sof_ipc_host_buffer buffer; + uint32_t num_elems; + uint32_t size; + + /* reserved for future use */ + uint32_t reserved[8]; + + struct sof_ipc_pm_ctx_elem elems[]; +} __packed; + +/* enable or disable cores - SOF_IPC_PM_CORE_ENABLE */ +struct sof_ipc_pm_core_config { + struct sof_ipc_cmd_hdr hdr; + uint32_t enable_mask; +} __packed; + +#endif diff --git a/include/sound/sof/stream.h b/include/sound/sof/stream.h new file mode 100644 index 00000000000000..643f175cb479a4 --- /dev/null +++ b/include/sound/sof/stream.h @@ -0,0 +1,148 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_STREAM_H__ +#define __INCLUDE_SOUND_SOF_STREAM_H__ + +#include + +/* + * Stream configuration. + */ + +#define SOF_IPC_MAX_CHANNELS 8 + +/* common sample rates for use in masks */ +#define SOF_RATE_8000 (1 << 0) /**< 8000Hz */ +#define SOF_RATE_11025 (1 << 1) /**< 11025Hz */ +#define SOF_RATE_12000 (1 << 2) /**< 12000Hz */ +#define SOF_RATE_16000 (1 << 3) /**< 16000Hz */ +#define SOF_RATE_22050 (1 << 4) /**< 22050Hz */ +#define SOF_RATE_24000 (1 << 5) /**< 24000Hz */ +#define SOF_RATE_32000 (1 << 6) /**< 32000Hz */ +#define SOF_RATE_44100 (1 << 7) /**< 44100Hz */ +#define SOF_RATE_48000 (1 << 8) /**< 48000Hz */ +#define SOF_RATE_64000 (1 << 9) /**< 64000Hz */ +#define SOF_RATE_88200 (1 << 10) /**< 88200Hz */ +#define SOF_RATE_96000 (1 << 11) /**< 96000Hz */ +#define SOF_RATE_176400 (1 << 12) /**< 176400Hz */ +#define SOF_RATE_192000 (1 << 13) /**< 192000Hz */ + +/* continuous and non-standard rates for flexibility */ +#define SOF_RATE_CONTINUOUS (1 << 30) /**< range */ +#define SOF_RATE_KNOT (1 << 31) /**< non-continuous */ + +/* generic PCM flags for runtime settings */ +#define SOF_PCM_FLAG_XRUN_STOP (1 << 0) /**< Stop on any XRUN */ + +/* stream PCM frame format */ +enum sof_ipc_frame { + SOF_IPC_FRAME_S16_LE = 0, + SOF_IPC_FRAME_S24_4LE, + SOF_IPC_FRAME_S32_LE, + SOF_IPC_FRAME_FLOAT, + /* other formats here */ +}; + +/* stream buffer format */ +enum sof_ipc_buffer_format { + SOF_IPC_BUFFER_INTERLEAVED, + SOF_IPC_BUFFER_NONINTERLEAVED, + /* other formats here */ +}; + +/* stream direction */ +enum sof_ipc_stream_direction { + SOF_IPC_STREAM_PLAYBACK = 0, + SOF_IPC_STREAM_CAPTURE, +}; + +/* stream ring info */ +struct sof_ipc_host_buffer { + struct sof_ipc_hdr hdr; + uint32_t phy_addr; + uint32_t pages; + uint32_t size; + uint32_t reserved[3]; +} __packed; + +struct sof_ipc_stream_params { + struct sof_ipc_hdr hdr; + struct sof_ipc_host_buffer buffer; + uint32_t direction; /**< enum sof_ipc_stream_direction */ + uint32_t frame_fmt; /**< enum sof_ipc_frame */ + uint32_t buffer_fmt; /**< enum sof_ipc_buffer_format */ + uint32_t rate; + uint16_t stream_tag; + uint16_t channels; + uint16_t sample_valid_bytes; + uint16_t sample_container_bytes; + + /* for notifying host period has completed - 0 means no period IRQ */ + uint32_t host_period_bytes; + + uint32_t reserved[2]; + uint16_t chmap[SOF_IPC_MAX_CHANNELS]; /**< channel map - SOF_CHMAP_ */ +} __packed; + +/* PCM params info - SOF_IPC_STREAM_PCM_PARAMS */ +struct sof_ipc_pcm_params { + struct sof_ipc_cmd_hdr hdr; + uint32_t comp_id; + uint32_t flags; /**< generic PCM flags - SOF_PCM_FLAG_ */ + uint32_t reserved[2]; + struct sof_ipc_stream_params params; +} __packed; + +/* PCM params info reply - SOF_IPC_STREAM_PCM_PARAMS_REPLY */ +struct sof_ipc_pcm_params_reply { + struct sof_ipc_reply rhdr; + uint32_t comp_id; + uint32_t posn_offset; +} __packed; + +/* free stream - SOF_IPC_STREAM_PCM_PARAMS */ +struct sof_ipc_stream { + struct sof_ipc_cmd_hdr hdr; + uint32_t comp_id; +} __packed; + +/* flags indicating which time stamps are in sync with each other */ +#define SOF_TIME_HOST_SYNC (1 << 0) +#define SOF_TIME_DAI_SYNC (1 << 1) +#define SOF_TIME_WALL_SYNC (1 << 2) +#define SOF_TIME_STAMP_SYNC (1 << 3) + +/* flags indicating which time stamps are valid */ +#define SOF_TIME_HOST_VALID (1 << 8) +#define SOF_TIME_DAI_VALID (1 << 9) +#define SOF_TIME_WALL_VALID (1 << 10) +#define SOF_TIME_STAMP_VALID (1 << 11) + +/* flags indicating time stamps are 64bit else 3use low 32bit */ +#define SOF_TIME_HOST_64 (1 << 16) +#define SOF_TIME_DAI_64 (1 << 17) +#define SOF_TIME_WALL_64 (1 << 18) +#define SOF_TIME_STAMP_64 (1 << 19) + +struct sof_ipc_stream_posn { + struct sof_ipc_reply rhdr; + uint32_t comp_id; /**< host component ID */ + uint32_t flags; /**< SOF_TIME_ */ + uint32_t wallclock_hz; /**< frequency of wallclock in Hz */ + uint32_t timestamp_ns; /**< resolution of timestamp in ns */ + uint64_t host_posn; /**< host DMA position in bytes */ + uint64_t dai_posn; /**< DAI DMA position in bytes */ + uint64_t comp_posn; /**< comp position in bytes */ + uint64_t wallclock; /**< audio wall clock */ + uint64_t timestamp; /**< system time stamp */ + uint32_t xrun_comp_id; /**< comp ID of XRUN component */ + int32_t xrun_size; /**< XRUN size in bytes */ +} __packed; + +#endif diff --git a/include/sound/sof/trace.h b/include/sound/sof/trace.h new file mode 100644 index 00000000000000..7d211f319a92e2 --- /dev/null +++ b/include/sound/sof/trace.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_TRACE_H__ +#define __INCLUDE_SOUND_SOF_TRACE_H__ + +#include +#include + +/* + * DMA for Trace + */ + +#define SOF_TRACE_FILENAME_SIZE 32 + +/* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS */ +struct sof_ipc_dma_trace_params { + struct sof_ipc_cmd_hdr hdr; + struct sof_ipc_host_buffer buffer; + uint32_t stream_tag; +} __packed; + +/* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS */ +struct sof_ipc_dma_trace_posn { + struct sof_ipc_reply rhdr; + uint32_t host_offset; /* Offset of DMA host buffer */ + uint32_t overflow; /* overflow bytes if any */ + uint32_t messages; /* total trace messages */ +} __packed; + +/* + * Commom debug + */ + +/* + * SOF panic codes + */ +#define SOF_IPC_PANIC_MAGIC 0x0dead000 +#define SOF_IPC_PANIC_MAGIC_MASK 0x0ffff000 +#define SOF_IPC_PANIC_CODE_MASK 0x00000fff +#define SOF_IPC_PANIC_MEM (SOF_IPC_PANIC_MAGIC | 0x0) +#define SOF_IPC_PANIC_WORK (SOF_IPC_PANIC_MAGIC | 0x1) +#define SOF_IPC_PANIC_IPC (SOF_IPC_PANIC_MAGIC | 0x2) +#define SOF_IPC_PANIC_ARCH (SOF_IPC_PANIC_MAGIC | 0x3) +#define SOF_IPC_PANIC_PLATFORM (SOF_IPC_PANIC_MAGIC | 0x4) +#define SOF_IPC_PANIC_TASK (SOF_IPC_PANIC_MAGIC | 0x5) +#define SOF_IPC_PANIC_EXCEPTION (SOF_IPC_PANIC_MAGIC | 0x6) +#define SOF_IPC_PANIC_DEADLOCK (SOF_IPC_PANIC_MAGIC | 0x7) +#define SOF_IPC_PANIC_STACK (SOF_IPC_PANIC_MAGIC | 0x8) +#define SOF_IPC_PANIC_IDLE (SOF_IPC_PANIC_MAGIC | 0x9) +#define SOF_IPC_PANIC_WFI (SOF_IPC_PANIC_MAGIC | 0xa) +#define SOF_IPC_PANIC_ASSERT (SOF_IPC_PANIC_MAGIC | 0xb) + +/* panic info include filename and line number */ +struct sof_ipc_panic_info { + struct sof_ipc_hdr hdr; + uint32_t code; /* SOF_IPC_PANIC_ */ + char filename[SOF_TRACE_FILENAME_SIZE]; + uint32_t linenum; +} __packed; + +#endif diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c new file mode 100644 index 00000000000000..d00373ceca12a3 --- /dev/null +++ b/sound/soc/sof/ipc.c @@ -0,0 +1,832 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// +// Generic IPC layer that can work over MMIO and SPI/I2C. PHY layer provided +// by platform driver code. +// + +#include +#include + +#include "sof-priv.h" +#include "ops.h" + +/* + * IPC message default size and timeout (ms). + * TODO: allow platforms to set size and timeout. + */ +#define IPC_TIMEOUT_MS 300 + +static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id); +static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd); + +/* + * IPC message Tx/Rx message handling. + */ + +/* SOF generic IPC data */ +struct snd_sof_ipc { + struct snd_sof_dev *sdev; + + /* protects messages and the disable flag */ + struct mutex tx_mutex; + /* disables further sending of ipc's */ + bool disable_ipc_tx; + + struct snd_sof_ipc_msg msg; +}; + +struct sof_ipc_ctrl_data_params { + size_t msg_bytes; + size_t hdr_bytes; + size_t pl_size; + size_t elems; + u32 num_msg; + u8 *src; + u8 *dst; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_VERBOSE_IPC) +static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) +{ + u8 *str; + u8 *str2 = NULL; + u32 glb; + u32 type; + + glb = cmd & SOF_GLB_TYPE_MASK; + type = cmd & SOF_CMD_TYPE_MASK; + + switch (glb) { + case SOF_IPC_GLB_REPLY: + str = "GLB_REPLY"; break; + case SOF_IPC_GLB_COMPOUND: + str = "GLB_COMPOUND"; break; + case SOF_IPC_GLB_TPLG_MSG: + str = "GLB_TPLG_MSG"; + switch (type) { + case SOF_IPC_TPLG_COMP_NEW: + str2 = "COMP_NEW"; break; + case SOF_IPC_TPLG_COMP_FREE: + str2 = "COMP_FREE"; break; + case SOF_IPC_TPLG_COMP_CONNECT: + str2 = "COMP_CONNECT"; break; + case SOF_IPC_TPLG_PIPE_NEW: + str2 = "PIPE_NEW"; break; + case SOF_IPC_TPLG_PIPE_FREE: + str2 = "PIPE_FREE"; break; + case SOF_IPC_TPLG_PIPE_CONNECT: + str2 = "PIPE_CONNECT"; break; + case SOF_IPC_TPLG_PIPE_COMPLETE: + str2 = "PIPE_COMPLETE"; break; + case SOF_IPC_TPLG_BUFFER_NEW: + str2 = "BUFFER_NEW"; break; + case SOF_IPC_TPLG_BUFFER_FREE: + str2 = "BUFFER_FREE"; break; + default: + str2 = "unknown type"; break; + } + break; + case SOF_IPC_GLB_PM_MSG: + str = "GLB_PM_MSG"; + switch (type) { + case SOF_IPC_PM_CTX_SAVE: + str2 = "CTX_SAVE"; break; + case SOF_IPC_PM_CTX_RESTORE: + str2 = "CTX_RESTORE"; break; + case SOF_IPC_PM_CTX_SIZE: + str2 = "CTX_SIZE"; break; + case SOF_IPC_PM_CLK_SET: + str2 = "CLK_SET"; break; + case SOF_IPC_PM_CLK_GET: + str2 = "CLK_GET"; break; + case SOF_IPC_PM_CLK_REQ: + str2 = "CLK_REQ"; break; + case SOF_IPC_PM_CORE_ENABLE: + str2 = "CORE_ENABLE"; break; + default: + str2 = "unknown type"; break; + } + break; + case SOF_IPC_GLB_COMP_MSG: + str = "GLB_COMP_MSG: SET_VALUE"; + switch (type) { + case SOF_IPC_COMP_SET_VALUE: + str2 = "SET_VALUE"; break; + case SOF_IPC_COMP_GET_VALUE: + str2 = "GET_VALUE"; break; + case SOF_IPC_COMP_SET_DATA: + str2 = "SET_DATA"; break; + case SOF_IPC_COMP_GET_DATA: + str2 = "GET_DATA"; break; + default: + str2 = "unknown type"; break; + } + break; + case SOF_IPC_GLB_STREAM_MSG: + str = "GLB_STREAM_MSG"; + switch (type) { + case SOF_IPC_STREAM_PCM_PARAMS: + str2 = "PCM_PARAMS"; break; + case SOF_IPC_STREAM_PCM_PARAMS_REPLY: + str2 = "PCM_REPLY"; break; + case SOF_IPC_STREAM_PCM_FREE: + str2 = "PCM_FREE"; break; + case SOF_IPC_STREAM_TRIG_START: + str2 = "TRIG_START"; break; + case SOF_IPC_STREAM_TRIG_STOP: + str2 = "TRIG_STOP"; break; + case SOF_IPC_STREAM_TRIG_PAUSE: + str2 = "TRIG_PAUSE"; break; + case SOF_IPC_STREAM_TRIG_RELEASE: + str2 = "TRIG_RELEASE"; break; + case SOF_IPC_STREAM_TRIG_DRAIN: + str2 = "TRIG_DRAIN"; break; + case SOF_IPC_STREAM_TRIG_XRUN: + str2 = "TRIG_XRUN"; break; + case SOF_IPC_STREAM_POSITION: + str2 = "POSITION"; break; + case SOF_IPC_STREAM_VORBIS_PARAMS: + str2 = "VORBIS_PARAMS"; break; + case SOF_IPC_STREAM_VORBIS_FREE: + str2 = "VORBIS_FREE"; break; + default: + str2 = "unknown type"; break; + } + break; + case SOF_IPC_FW_READY: + str = "FW_READY"; break; + case SOF_IPC_GLB_DAI_MSG: + str = "GLB_DAI_MSG"; + switch (type) { + case SOF_IPC_DAI_CONFIG: + str2 = "CONFIG"; break; + case SOF_IPC_DAI_LOOPBACK: + str2 = "LOOPBACK"; break; + default: + str2 = "unknown type"; break; + } + break; + case SOF_IPC_GLB_TRACE_MSG: + str = "GLB_TRACE_MSG"; break; + default: + str = "unknown GLB command"; break; + } + + if (str2) + dev_dbg(dev, "%s: 0x%x: %s: %s\n", text, cmd, str, str2); + else + dev_dbg(dev, "%s: 0x%x: %s\n", text, cmd, str); +} +#else +static inline void ipc_log_header(struct device *dev, u8 *text, u32 cmd) +{ + dev_dbg(dev, "%s: 0x%x\n", text, cmd); +} +#endif + +/* wait for IPC message reply */ +static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, + void *reply_data) +{ + struct snd_sof_dev *sdev = ipc->sdev; + struct sof_ipc_cmd_hdr *hdr = msg->msg_data; + int ret; + + /* wait for DSP IPC completion */ + ret = wait_event_timeout(msg->waitq, msg->ipc_complete, + msecs_to_jiffies(IPC_TIMEOUT_MS)); + + if (ret == 0) { + dev_err(sdev->dev, "error: ipc timed out for 0x%x size %d\n", + hdr->cmd, hdr->size); + snd_sof_dsp_dbg_dump(ipc->sdev, SOF_DBG_REGS | SOF_DBG_MBOX); + snd_sof_trace_notify_for_error(ipc->sdev); + ret = -ETIMEDOUT; + } else { + /* copy the data returned from DSP */ + ret = msg->reply_error; + if (msg->reply_size) + memcpy(reply_data, msg->reply_data, msg->reply_size); + if (ret < 0) + dev_err(sdev->dev, "error: ipc error for 0x%x size %zu\n", + hdr->cmd, msg->reply_size); + else + ipc_log_header(sdev->dev, "ipc tx succeeded", hdr->cmd); + } + + return ret; +} + +/* send IPC message from host to DSP */ +static int sof_ipc_tx_message_unlocked(struct snd_sof_ipc *ipc, u32 header, + void *msg_data, size_t msg_bytes, + void *reply_data, size_t reply_bytes) +{ + struct snd_sof_dev *sdev = ipc->sdev; + struct snd_sof_ipc_msg *msg; + int ret; + + if (ipc->disable_ipc_tx) + return -ENODEV; + + /* + * The spin-lock is also still needed to protect message objects against + * other atomic contexts. + */ + spin_lock_irq(&sdev->ipc_lock); + + /* initialise the message */ + msg = &ipc->msg; + + msg->header = header; + msg->msg_size = msg_bytes; + msg->reply_size = reply_bytes; + msg->reply_error = 0; + + /* attach any data */ + if (msg_bytes) + memcpy(msg->msg_data, msg_data, msg_bytes); + + sdev->msg = msg; + + ret = snd_sof_dsp_send_msg(sdev, msg); + /* Next reply that we receive will be related to this message */ + if (!ret) + msg->ipc_complete = false; + + spin_unlock_irq(&sdev->ipc_lock); + + if (ret < 0) { + /* So far IPC TX never fails, consider making the above void */ + dev_err_ratelimited(sdev->dev, + "error: ipc tx failed with error %d\n", + ret); + return ret; + } + + ipc_log_header(sdev->dev, "ipc tx", msg->header); + + /* now wait for completion */ + if (!ret) + ret = tx_wait_done(ipc, msg, reply_data); + + return ret; +} + +/* send IPC message from host to DSP */ +int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, + void *msg_data, size_t msg_bytes, void *reply_data, + size_t reply_bytes) +{ + int ret; + + if (msg_bytes > SOF_IPC_MSG_MAX_SIZE || + reply_bytes > SOF_IPC_MSG_MAX_SIZE) + return -ENOBUFS; + + /* Serialise IPC TX */ + mutex_lock(&ipc->tx_mutex); + + ret = sof_ipc_tx_message_unlocked(ipc, header, msg_data, msg_bytes, + reply_data, reply_bytes); + + mutex_unlock(&ipc->tx_mutex); + + return ret; +} +EXPORT_SYMBOL(sof_ipc_tx_message); + +/* handle reply message from DSP */ +int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct snd_sof_ipc_msg *msg = &sdev->ipc->msg; + unsigned long flags; + + /* + * Protect against a theoretical race with sof_ipc_tx_message(): if the + * DSP is fast enough to receive an IPC message, reply to it, and the + * host interrupt processing calls this function on a different core + * from the one, where the sending is taking place, the message might + * not yet be marked as expecting a reply. + */ + spin_lock_irqsave(&sdev->ipc_lock, flags); + + if (msg->ipc_complete) { + spin_unlock_irqrestore(&sdev->ipc_lock, flags); + dev_err(sdev->dev, "error: no reply expected, received 0x%x", + msg_id); + return -EINVAL; + } + + /* wake up and return the error if we have waiters on this message ? */ + msg->ipc_complete = true; + wake_up(&msg->waitq); + + spin_unlock_irqrestore(&sdev->ipc_lock, flags); + + return 0; +} +EXPORT_SYMBOL(snd_sof_ipc_reply); + +/* DSP firmware has sent host a message */ +void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) +{ + struct sof_ipc_cmd_hdr hdr; + u32 cmd, type; + int err = 0; + + /* read back header */ + snd_sof_ipc_msg_data(sdev, NULL, &hdr, sizeof(hdr)); + ipc_log_header(sdev->dev, "ipc rx", hdr.cmd); + + cmd = hdr.cmd & SOF_GLB_TYPE_MASK; + type = hdr.cmd & SOF_CMD_TYPE_MASK; + + /* check message type */ + switch (cmd) { + case SOF_IPC_GLB_REPLY: + dev_err(sdev->dev, "error: ipc reply unknown\n"); + break; + case SOF_IPC_FW_READY: + /* check for FW boot completion */ + if (!sdev->boot_complete) { + err = sof_ops(sdev)->fw_ready(sdev, cmd); + if (err < 0) { + /* + * this indicates a mismatch in ABI + * between the driver and fw + */ + dev_err(sdev->dev, "error: ABI mismatch %d\n", + err); + } else { + /* firmware boot completed OK */ + sdev->boot_complete = true; + } + + /* wake up firmware loader */ + wake_up(&sdev->boot_wait); + } + break; + case SOF_IPC_GLB_COMPOUND: + case SOF_IPC_GLB_TPLG_MSG: + case SOF_IPC_GLB_PM_MSG: + case SOF_IPC_GLB_COMP_MSG: + break; + case SOF_IPC_GLB_STREAM_MSG: + /* need to pass msg id into the function */ + ipc_stream_message(sdev, hdr.cmd); + break; + case SOF_IPC_GLB_TRACE_MSG: + ipc_trace_message(sdev, type); + break; + default: + dev_err(sdev->dev, "error: unknown DSP message 0x%x\n", cmd); + break; + } + + ipc_log_header(sdev->dev, "ipc rx done", hdr.cmd); +} +EXPORT_SYMBOL(snd_sof_ipc_msgs_rx); + +/* + * IPC trace mechanism. + */ + +static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct sof_ipc_dma_trace_posn posn; + + switch (msg_id) { + case SOF_IPC_TRACE_DMA_POSITION: + /* read back full message */ + snd_sof_ipc_msg_data(sdev, NULL, &posn, sizeof(posn)); + snd_sof_trace_update_pos(sdev, &posn); + break; + default: + dev_err(sdev->dev, "error: unhandled trace message %x\n", + msg_id); + break; + } +} + +/* + * IPC stream position. + */ + +static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct snd_sof_pcm_stream *stream; + struct sof_ipc_stream_posn posn; + struct snd_sof_pcm *spcm; + int direction; + + spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction); + if (!spcm) { + dev_err(sdev->dev, + "error: period elapsed for unknown stream, msg_id %d\n", + msg_id); + return; + } + + stream = &spcm->stream[direction]; + snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); + + dev_dbg(sdev->dev, "posn : host 0x%llx dai 0x%llx wall 0x%llx\n", + posn.host_posn, posn.dai_posn, posn.wallclock); + + memcpy(&stream->posn, &posn, sizeof(posn)); + + /* only inform ALSA for period_wakeup mode */ + if (!stream->substream->runtime->no_period_wakeup) + snd_pcm_period_elapsed(stream->substream); +} + +/* DSP notifies host of an XRUN within FW */ +static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct snd_sof_pcm_stream *stream; + struct sof_ipc_stream_posn posn; + struct snd_sof_pcm *spcm; + int direction; + + spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction); + if (!spcm) { + dev_err(sdev->dev, "error: XRUN for unknown stream, msg_id %d\n", + msg_id); + return; + } + + stream = &spcm->stream[direction]; + snd_sof_ipc_msg_data(sdev, stream->substream, &posn, sizeof(posn)); + + dev_dbg(sdev->dev, "posn XRUN: host %llx comp %d size %d\n", + posn.host_posn, posn.xrun_comp_id, posn.xrun_size); + +#if defined(CONFIG_SND_SOC_SOF_DEBUG_XRUN_STOP) + /* stop PCM on XRUN - used for pipeline debug */ + memcpy(&stream->posn, &posn, sizeof(posn)); + snd_pcm_stop_xrun(stream->substream); +#endif +} + +/* stream notifications from DSP FW */ +static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd) +{ + /* get msg cmd type and msd id */ + u32 msg_type = msg_cmd & SOF_CMD_TYPE_MASK; + u32 msg_id = SOF_IPC_MESSAGE_ID(msg_cmd); + + switch (msg_type) { + case SOF_IPC_STREAM_POSITION: + ipc_period_elapsed(sdev, msg_id); + break; + case SOF_IPC_STREAM_TRIG_XRUN: + ipc_xrun(sdev, msg_id); + break; + default: + dev_err(sdev->dev, "error: unhandled stream message %x\n", + msg_id); + break; + } +} + +/* get stream position IPC - use faster MMIO method if available on platform */ +int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev, + struct snd_sof_pcm *spcm, int direction, + struct sof_ipc_stream_posn *posn) +{ + struct sof_ipc_stream stream; + int err; + + /* read position via slower IPC */ + stream.hdr.size = sizeof(stream); + stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_POSITION; + stream.comp_id = spcm->stream[direction].comp_id; + + /* send IPC to the DSP */ + err = sof_ipc_tx_message(sdev->ipc, + stream.hdr.cmd, &stream, sizeof(stream), &posn, + sizeof(*posn)); + if (err < 0) { + dev_err(sdev->dev, "error: failed to get stream %d position\n", + stream.comp_id); + return err; + } + + return 0; +} +EXPORT_SYMBOL(snd_sof_ipc_stream_posn); + +static int sof_get_ctrl_copy_params(enum sof_ipc_ctrl_type ctrl_type, + struct sof_ipc_ctrl_data *src, + struct sof_ipc_ctrl_data *dst, + struct sof_ipc_ctrl_data_params *sparams) +{ + switch (ctrl_type) { + case SOF_CTRL_TYPE_VALUE_CHAN_GET: + case SOF_CTRL_TYPE_VALUE_CHAN_SET: + sparams->src = (u8 *)src->chanv; + sparams->dst = (u8 *)dst->chanv; + break; + case SOF_CTRL_TYPE_VALUE_COMP_GET: + case SOF_CTRL_TYPE_VALUE_COMP_SET: + sparams->src = (u8 *)src->compv; + sparams->dst = (u8 *)dst->compv; + break; + case SOF_CTRL_TYPE_DATA_GET: + case SOF_CTRL_TYPE_DATA_SET: + sparams->src = (u8 *)src->data->data; + sparams->dst = (u8 *)dst->data->data; + break; + default: + return -EINVAL; + } + + /* calculate payload size and number of messages */ + sparams->pl_size = SOF_IPC_MSG_MAX_SIZE - sparams->hdr_bytes; + sparams->num_msg = DIV_ROUND_UP(sparams->msg_bytes, sparams->pl_size); + + return 0; +} + +static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev, + struct sof_ipc_ctrl_data *cdata, + struct sof_ipc_ctrl_data_params *sparams, + bool send) +{ + struct sof_ipc_ctrl_data *partdata; + size_t send_bytes; + size_t offset = 0; + size_t msg_bytes; + size_t pl_size; + int err = 0; + int i; + + /* allocate max ipc size because we have at least one */ + partdata = kzalloc(SOF_IPC_MSG_MAX_SIZE, GFP_KERNEL); + if (!partdata) + return -ENOMEM; + + if (send) + sof_get_ctrl_copy_params(cdata->type, cdata, partdata, sparams); + else + sof_get_ctrl_copy_params(cdata->type, partdata, cdata, sparams); + + msg_bytes = sparams->msg_bytes; + pl_size = sparams->pl_size; + + /* copy the header data */ + memcpy(partdata, cdata, sparams->hdr_bytes); + + /* Serialise IPC TX */ + mutex_lock(&sdev->ipc->tx_mutex); + + /* copy the payload data in a loop */ + for (i = 0; i < sparams->num_msg; i++) { + send_bytes = min(msg_bytes, pl_size); + partdata->num_elems = send_bytes; + partdata->rhdr.hdr.size = sparams->hdr_bytes + send_bytes; + partdata->msg_index = i; + msg_bytes -= send_bytes; + partdata->elems_remaining = msg_bytes; + + if (send) + memcpy(sparams->dst, sparams->src + offset, send_bytes); + + err = sof_ipc_tx_message_unlocked(sdev->ipc, + partdata->rhdr.hdr.cmd, + partdata, + partdata->rhdr.hdr.size, + partdata, + partdata->rhdr.hdr.size); + if (err < 0) + break; + + if (!send) + memcpy(sparams->dst + offset, sparams->src, send_bytes); + + offset += pl_size; + } + + mutex_unlock(&sdev->ipc->tx_mutex); + + kfree(partdata); + return err; +} + +/* + * IPC get()/set() for kcontrols. + */ +int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc, + struct snd_sof_control *scontrol, + u32 ipc_cmd, + enum sof_ipc_ctrl_type ctrl_type, + enum sof_ipc_ctrl_cmd ctrl_cmd, + bool send) +{ + struct sof_ipc_ctrl_data *cdata = scontrol->control_data; + struct snd_sof_dev *sdev = ipc->sdev; + struct sof_ipc_fw_ready *ready = &sdev->fw_ready; + struct sof_ipc_fw_version *v = &ready->version; + struct sof_ipc_ctrl_data_params sparams; + size_t send_bytes; + int err; + + /* read or write firmware volume */ + if (scontrol->readback_offset != 0) { + /* write/read value header via mmaped region */ + send_bytes = sizeof(struct sof_ipc_ctrl_value_chan) * + cdata->num_elems; + if (send) + snd_sof_dsp_block_write(sdev, sdev->mmio_bar, + scontrol->readback_offset, + cdata->chanv, send_bytes); + + else + snd_sof_dsp_block_read(sdev, sdev->mmio_bar, + scontrol->readback_offset, + cdata->chanv, send_bytes); + return 0; + } + + cdata->rhdr.hdr.cmd = SOF_IPC_GLB_COMP_MSG | ipc_cmd; + cdata->cmd = ctrl_cmd; + cdata->type = ctrl_type; + cdata->comp_id = scontrol->comp_id; + cdata->msg_index = 0; + + /* calculate header and data size */ + switch (cdata->type) { + case SOF_CTRL_TYPE_VALUE_CHAN_GET: + case SOF_CTRL_TYPE_VALUE_CHAN_SET: + sparams.msg_bytes = scontrol->num_channels * + sizeof(struct sof_ipc_ctrl_value_chan); + sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data); + sparams.elems = scontrol->num_channels; + break; + case SOF_CTRL_TYPE_VALUE_COMP_GET: + case SOF_CTRL_TYPE_VALUE_COMP_SET: + sparams.msg_bytes = scontrol->num_channels * + sizeof(struct sof_ipc_ctrl_value_comp); + sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data); + sparams.elems = scontrol->num_channels; + break; + case SOF_CTRL_TYPE_DATA_GET: + case SOF_CTRL_TYPE_DATA_SET: + sparams.msg_bytes = cdata->data->size; + sparams.hdr_bytes = sizeof(struct sof_ipc_ctrl_data) + + sizeof(struct sof_abi_hdr); + sparams.elems = cdata->data->size; + break; + default: + return -EINVAL; + } + + cdata->rhdr.hdr.size = sparams.msg_bytes + sparams.hdr_bytes; + cdata->num_elems = sparams.elems; + cdata->elems_remaining = 0; + + /* send normal size ipc in one part */ + if (cdata->rhdr.hdr.size <= SOF_IPC_MSG_MAX_SIZE) { + err = sof_ipc_tx_message(sdev->ipc, cdata->rhdr.hdr.cmd, cdata, + cdata->rhdr.hdr.size, cdata, + cdata->rhdr.hdr.size); + + if (err < 0) + dev_err(sdev->dev, "error: set/get ctrl ipc comp %d\n", + cdata->comp_id); + + return err; + } + + /* data is bigger than max ipc size, chop into smaller pieces */ + dev_dbg(sdev->dev, "large ipc size %u, control size %u\n", + cdata->rhdr.hdr.size, scontrol->size); + + /* large messages is only supported from ABI 3.3.0 onwards */ + if (v->abi_version < SOF_ABI_VER(3, 3, 0)) { + dev_err(sdev->dev, "error: incompatible FW ABI version\n"); + return -EINVAL; + } + + err = sof_set_get_large_ctrl_data(sdev, cdata, &sparams, send); + + if (err < 0) + dev_err(sdev->dev, "error: set/get large ctrl ipc comp %d\n", + cdata->comp_id); + + return err; +} +EXPORT_SYMBOL(snd_sof_ipc_set_get_comp_data); + +/* + * IPC layer enumeration. + */ + +int snd_sof_dsp_mailbox_init(struct snd_sof_dev *sdev, u32 dspbox, + size_t dspbox_size, u32 hostbox, + size_t hostbox_size) +{ + sdev->dsp_box.offset = dspbox; + sdev->dsp_box.size = dspbox_size; + sdev->host_box.offset = hostbox; + sdev->host_box.size = hostbox_size; + return 0; +} +EXPORT_SYMBOL(snd_sof_dsp_mailbox_init); + +int snd_sof_ipc_valid(struct snd_sof_dev *sdev) +{ + struct sof_ipc_fw_ready *ready = &sdev->fw_ready; + struct sof_ipc_fw_version *v = &ready->version; + + dev_info(sdev->dev, + "Firmware info: version %d:%d:%d-%s\n", v->major, v->minor, + v->micro, v->tag); + dev_info(sdev->dev, + "Firmware: ABI %d:%d:%d Kernel ABI %d:%d:%d\n", + SOF_ABI_VERSION_MAJOR(v->abi_version), + SOF_ABI_VERSION_MINOR(v->abi_version), + SOF_ABI_VERSION_PATCH(v->abi_version), + SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH); + + if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, v->abi_version)) { + dev_err(sdev->dev, "error: incompatible FW ABI version\n"); + return -EINVAL; + } + + if (ready->debug.bits.build) { + dev_info(sdev->dev, + "Firmware debug build %d on %s-%s - options:\n" + " GDB: %s\n" + " lock debug: %s\n" + " lock vdebug: %s\n", + v->build, v->date, v->time, + ready->debug.bits.gdb ? "enabled" : "disabled", + ready->debug.bits.locks ? "enabled" : "disabled", + ready->debug.bits.locks_verbose ? "enabled" : "disabled"); + } + + /* copy the fw_version into debugfs at first boot */ + memcpy(&sdev->fw_version, v, sizeof(*v)); + + return 0; +} +EXPORT_SYMBOL(snd_sof_ipc_valid); + +struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) +{ + struct snd_sof_ipc *ipc; + struct snd_sof_ipc_msg *msg; + + /* check if mandatory ops required for ipc are defined */ + if (!sof_ops(sdev)->fw_ready) { + dev_err(sdev->dev, "error: ipc mandatory ops not defined\n"); + return NULL; + } + + ipc = devm_kzalloc(sdev->dev, sizeof(*ipc), GFP_KERNEL); + if (!ipc) + return NULL; + + mutex_init(&ipc->tx_mutex); + ipc->sdev = sdev; + msg = &ipc->msg; + + /* indicate that we aren't sending a message ATM */ + msg->ipc_complete = true; + + /* pre-allocate message data */ + msg->msg_data = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, + GFP_KERNEL); + if (!msg->msg_data) + return NULL; + + msg->reply_data = devm_kzalloc(sdev->dev, SOF_IPC_MSG_MAX_SIZE, + GFP_KERNEL); + if (!msg->reply_data) + return NULL; + + init_waitqueue_head(&msg->waitq); + + return ipc; +} +EXPORT_SYMBOL(snd_sof_ipc_init); + +void snd_sof_ipc_free(struct snd_sof_dev *sdev) +{ + struct snd_sof_ipc *ipc = sdev->ipc; + + /* disable sending of ipc's */ + mutex_lock(&ipc->tx_mutex); + ipc->disable_ipc_tx = true; + mutex_unlock(&ipc->tx_mutex); +} +EXPORT_SYMBOL(snd_sof_ipc_free); From 204b38893d5d96fe66e3cbb410abb80d6afb0690 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:05:10 -0500 Subject: [PATCH 1394/1995] ASoC: SOF: Add PCM operations support Add support for exposing PCMs to userspace. PCMs are defined by topology and the operations in this patch map to SOF IPC calls. The .get_module_upon_open field is set to allow for module load/unload tests. There is no risk of the sof-pci/acpi-dev module being removed while the platform components are in use. This may need to be revisited when DT platforms are supported. Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 868bd00f495514630a52161052d2fe155af599fe) --- sound/soc/sof/pcm.c | 719 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 719 insertions(+) create mode 100644 sound/soc/sof/pcm.c diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c new file mode 100644 index 00000000000000..be4984c4da4eb8 --- /dev/null +++ b/sound/soc/sof/pcm.c @@ -0,0 +1,719 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// +// PCM Layer, interface between ALSA and IPC. +// + +#include +#include +#include +#include "sof-priv.h" +#include "ops.h" + +#define DRV_NAME "sof-audio-component" + +/* Create DMA buffer page table for DSP */ +static int create_page_table(struct snd_pcm_substream *substream, + unsigned char *dma_area, size_t size) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm; + struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream); + int stream = substream->stream; + + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + + return snd_sof_create_page_table(sdev, dmab, + spcm->stream[stream].page_table.area, size); +} + +static int sof_pcm_dsp_params(struct snd_sof_pcm *spcm, struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply) +{ + struct snd_sof_dev *sdev = spcm->sdev; + /* validate offset */ + int ret = snd_sof_ipc_pcm_params(sdev, substream, reply); + + if (ret < 0) + dev_err(sdev->dev, "error: got wrong reply for PCM %d\n", + spcm->pcm.pcm_id); + + return ret; +} + +/* this may get called several times by oss emulation */ +static int sof_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm; + struct sof_ipc_pcm_params pcm; + struct sof_ipc_pcm_params_reply ipc_params_reply; + int ret; + + /* nothing to do for BE */ + if (rtd->dai_link->no_pcm) + return 0; + + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + + dev_dbg(sdev->dev, "pcm: hw params stream %d dir %d\n", + spcm->pcm.pcm_id, substream->stream); + + memset(&pcm, 0, sizeof(pcm)); + + /* allocate audio buffer pages */ + ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); + if (ret < 0) { + dev_err(sdev->dev, "error: could not allocate %d bytes for PCM %d\n", + params_buffer_bytes(params), spcm->pcm.pcm_id); + return ret; + } + if (ret) { + /* + * ret == 1 means the buffer is changed + * create compressed page table for audio firmware + * ret == 0 means the buffer is not changed + * so no need to regenerate the page table + */ + ret = create_page_table(substream, runtime->dma_area, + runtime->dma_bytes); + if (ret < 0) + return ret; + } + + /* number of pages should be rounded up */ + pcm.params.buffer.pages = PFN_UP(runtime->dma_bytes); + + /* set IPC PCM parameters */ + pcm.hdr.size = sizeof(pcm); + pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS; + pcm.comp_id = spcm->stream[substream->stream].comp_id; + pcm.params.hdr.size = sizeof(pcm.params); + pcm.params.buffer.phy_addr = + spcm->stream[substream->stream].page_table.addr; + pcm.params.buffer.size = runtime->dma_bytes; + pcm.params.direction = substream->stream; + pcm.params.sample_valid_bytes = params_width(params) >> 3; + pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED; + pcm.params.rate = params_rate(params); + pcm.params.channels = params_channels(params); + pcm.params.host_period_bytes = params_period_bytes(params); + + /* container size */ + ret = snd_pcm_format_physical_width(params_format(params)); + if (ret < 0) + return ret; + pcm.params.sample_container_bytes = ret >> 3; + + /* format */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16: + pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE; + break; + case SNDRV_PCM_FORMAT_S24: + pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE; + break; + case SNDRV_PCM_FORMAT_S32: + pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE; + break; + case SNDRV_PCM_FORMAT_FLOAT: + pcm.params.frame_fmt = SOF_IPC_FRAME_FLOAT; + break; + default: + return -EINVAL; + } + + /* firmware already configured host stream */ + ret = snd_sof_pcm_platform_hw_params(sdev, + substream, + params, + &pcm.params); + if (ret < 0) { + dev_err(sdev->dev, "error: platform hw params failed\n"); + return ret; + } + + dev_dbg(sdev->dev, "stream_tag %d", pcm.params.stream_tag); + + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm), + &ipc_params_reply, sizeof(ipc_params_reply)); + if (ret < 0) { + dev_err(sdev->dev, "error: hw params ipc failed for stream %d\n", + pcm.params.stream_tag); + return ret; + } + + ret = sof_pcm_dsp_params(spcm, substream, &ipc_params_reply); + if (ret < 0) + return ret; + + /* save pcm hw_params */ + memcpy(&spcm->params[substream->stream], params, sizeof(*params)); + + return ret; +} + +static int sof_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm; + struct sof_ipc_stream stream; + struct sof_ipc_reply reply; + int ret; + + /* nothing to do for BE */ + if (rtd->dai_link->no_pcm) + return 0; + + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + + dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id, + substream->stream); + + stream.hdr.size = sizeof(stream); + stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE; + stream.comp_id = spcm->stream[substream->stream].comp_id; + + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, + sizeof(stream), &reply, sizeof(reply)); + + snd_pcm_lib_free_pages(substream); + return ret; +} + +static int sof_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm; + int ret; + + /* nothing to do for BE */ + if (rtd->dai_link->no_pcm) + return 0; + + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + + /* + * check if hw_params needs to be set-up again. + * This is only needed when resuming from system sleep. + */ + if (!spcm->hw_params_upon_resume[substream->stream]) + return 0; + + dev_dbg(sdev->dev, "pcm: prepare stream %d dir %d\n", spcm->pcm.pcm_id, + substream->stream); + + /* set hw_params */ + ret = sof_pcm_hw_params(substream, &spcm->params[substream->stream]); + if (ret < 0) { + dev_err(sdev->dev, "error: set pcm hw_params after resume\n"); + return ret; + } + + return 0; +} + +/* + * FE dai link trigger actions are always executed in non-atomic context because + * they involve IPC's. + */ +static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm; + struct sof_ipc_stream stream; + struct sof_ipc_reply reply; + int ret; + + /* nothing to do for BE */ + if (rtd->dai_link->no_pcm) + return 0; + + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + + dev_dbg(sdev->dev, "pcm: trigger stream %d dir %d cmd %d\n", + spcm->pcm.pcm_id, substream->stream, cmd); + + stream.hdr.size = sizeof(stream); + stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG; + stream.comp_id = spcm->stream[substream->stream].comp_id; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_PAUSE; + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE; + break; + case SNDRV_PCM_TRIGGER_RESUME: + /* set up hw_params */ + ret = sof_pcm_prepare(substream); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to set up hw_params upon resume\n"); + return ret; + } + + /* fallthrough */ + case SNDRV_PCM_TRIGGER_START: + stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_START; + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; + break; + default: + dev_err(sdev->dev, "error: unhandled trigger cmd %d\n", cmd); + return -EINVAL; + } + + snd_sof_pcm_platform_trigger(sdev, substream, cmd); + + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, + sizeof(stream), &reply, sizeof(reply)); + + if (ret < 0 || cmd != SNDRV_PCM_TRIGGER_SUSPEND) + return ret; + + /* + * The hw_free op is usually called when the pcm stream is closed. + * Since the stream is not closed during suspend, the DSP needs to be + * notified explicitly to free pcm to prevent errors upon resume. + */ + stream.hdr.size = sizeof(stream); + stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE; + stream.comp_id = spcm->stream[substream->stream].comp_id; + + /* send IPC to the DSP */ + return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, + sizeof(stream), &reply, sizeof(reply)); +} + +static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm; + snd_pcm_uframes_t host, dai; + + /* nothing to do for BE */ + if (rtd->dai_link->no_pcm) + return 0; + + /* use dsp ops pointer callback directly if set */ + if (sof_ops(sdev)->pcm_pointer) + return sof_ops(sdev)->pcm_pointer(sdev, substream); + + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + + /* read position from DSP */ + host = bytes_to_frames(substream->runtime, + spcm->stream[substream->stream].posn.host_posn); + dai = bytes_to_frames(substream->runtime, + spcm->stream[substream->stream].posn.dai_posn); + + dev_dbg(sdev->dev, "PCM: stream %d dir %d DMA position %lu DAI position %lu\n", + spcm->pcm.pcm_id, substream->stream, host, dai); + + return host; +} + +static int sof_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm; + struct snd_soc_tplg_stream_caps *caps; + int ret; + int err; + + /* nothing to do for BE */ + if (rtd->dai_link->no_pcm) + return 0; + + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + + dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id, + substream->stream); + + /* clear hw_params_upon_resume flag */ + spcm->hw_params_upon_resume[substream->stream] = 0; + + caps = &spcm->pcm.caps[substream->stream]; + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "error: pcm open failed to resume %d\n", + ret); + pm_runtime_put_noidle(sdev->dev); + return ret; + } + + /* set any runtime constraints based on topology */ + snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + le32_to_cpu(caps->period_size_min)); + snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, + le32_to_cpu(caps->period_size_min)); + + /* set runtime config */ + runtime->hw.info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP; + runtime->hw.formats = le64_to_cpu(caps->formats); + runtime->hw.period_bytes_min = le32_to_cpu(caps->period_size_min); + runtime->hw.period_bytes_max = le32_to_cpu(caps->period_size_max); + runtime->hw.periods_min = le32_to_cpu(caps->periods_min); + runtime->hw.periods_max = le32_to_cpu(caps->periods_max); + + /* + * caps->buffer_size_min is not used since the + * snd_pcm_hardware structure only defines buffer_bytes_max + */ + runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max); + + dev_dbg(sdev->dev, "period min %zd max %zd bytes\n", + runtime->hw.period_bytes_min, + runtime->hw.period_bytes_max); + dev_dbg(sdev->dev, "period count %d max %d\n", + runtime->hw.periods_min, + runtime->hw.periods_max); + dev_dbg(sdev->dev, "buffer max %zd bytes\n", + runtime->hw.buffer_bytes_max); + + /* set wait time - TODO: come from topology */ + substream->wait_time = 500; + + spcm->stream[substream->stream].posn.host_posn = 0; + spcm->stream[substream->stream].posn.dai_posn = 0; + spcm->stream[substream->stream].substream = substream; + + ret = snd_sof_pcm_platform_open(sdev, substream); + if (ret < 0) { + dev_err(sdev->dev, "error: pcm open failed %d\n", + ret); + + pm_runtime_mark_last_busy(sdev->dev); + + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err(sdev->dev, "error: pcm close failed to idle %d\n", + err); + } + + return ret; +} + +static int sof_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm; + int err; + + /* nothing to do for BE */ + if (rtd->dai_link->no_pcm) + return 0; + + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + + dev_dbg(sdev->dev, "pcm: close stream %d dir %d\n", spcm->pcm.pcm_id, + substream->stream); + + err = snd_sof_pcm_platform_close(sdev, substream); + if (err < 0) { + dev_err(sdev->dev, "error: pcm close failed %d\n", + err); + /* + * keep going, no point in preventing the close + * from happening + */ + } + + pm_runtime_mark_last_busy(sdev->dev); + + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err(sdev->dev, "error: pcm close failed to idle %d\n", + err); + + return 0; +} + +static struct snd_pcm_ops sof_pcm_ops = { + .open = sof_pcm_open, + .close = sof_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = sof_pcm_hw_params, + .prepare = sof_pcm_prepare, + .hw_free = sof_pcm_hw_free, + .trigger = sof_pcm_trigger, + .pointer = sof_pcm_pointer, + .page = snd_pcm_sgbuf_ops_page, +}; + +/* + * Pre-allocate playback/capture audio buffer pages. + * no need to explicitly release memory preallocated by sof_pcm_new in pcm_free + * snd_pcm_lib_preallocate_free_for_all() is called by the core. + */ +static int sof_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_pcm *spcm; + struct snd_pcm *pcm = rtd->pcm; + struct snd_soc_tplg_stream_caps *caps; + int stream = SNDRV_PCM_STREAM_PLAYBACK; + + /* find SOF PCM for this RTD */ + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) { + dev_warn(sdev->dev, "warn: can't find PCM with DAI ID %d\n", + rtd->dai_link->id); + return 0; + } + + dev_dbg(sdev->dev, "creating new PCM %s\n", spcm->pcm.pcm_name); + + /* do we need to pre-allocate playback audio buffer pages */ + if (!spcm->pcm.playback) + goto capture; + + caps = &spcm->pcm.caps[stream]; + + /* pre-allocate playback audio buffer pages */ + dev_dbg(sdev->dev, "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n", + caps->name, caps->buffer_size_min, caps->buffer_size_max); + + snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream, + SNDRV_DMA_TYPE_DEV_SG, sdev->dev, + le32_to_cpu(caps->buffer_size_min), + le32_to_cpu(caps->buffer_size_max)); +capture: + stream = SNDRV_PCM_STREAM_CAPTURE; + + /* do we need to pre-allocate capture audio buffer pages */ + if (!spcm->pcm.capture) + return 0; + + caps = &spcm->pcm.caps[stream]; + + /* pre-allocate capture audio buffer pages */ + dev_dbg(sdev->dev, "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n", + caps->name, caps->buffer_size_min, caps->buffer_size_max); + + snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream, + SNDRV_DMA_TYPE_DEV_SG, sdev->dev, + le32_to_cpu(caps->buffer_size_min), + le32_to_cpu(caps->buffer_size_max)); + + return 0; +} + +/* fixup the BE DAI link to match any values from topology */ +static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_dai *dai = + snd_sof_find_dai(sdev, (char *)rtd->dai_link->name); + + /* no topology exists for this BE, try a common configuration */ + if (!dai) { + dev_warn(sdev->dev, "warning: no topology found for BE DAI %s config\n", + rtd->dai_link->name); + + /* set 48k, stereo, 16bits by default */ + rate->min = 48000; + rate->max = 48000; + + channels->min = 2; + channels->max = 2; + + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); + + return 0; + } + + /* read format from topology */ + snd_mask_none(fmt); + + switch (dai->comp_dai.config.frame_fmt) { + case SOF_IPC_FRAME_S16_LE: + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); + break; + case SOF_IPC_FRAME_S24_4LE: + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + break; + case SOF_IPC_FRAME_S32_LE: + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); + break; + default: + dev_err(sdev->dev, "error: No available DAI format!\n"); + return -EINVAL; + } + + /* read rate and channels from topology */ + switch (dai->dai_config->type) { + case SOF_DAI_INTEL_SSP: + rate->min = dai->dai_config->ssp.fsync_rate; + rate->max = dai->dai_config->ssp.fsync_rate; + channels->min = dai->dai_config->ssp.tdm_slots; + channels->max = dai->dai_config->ssp.tdm_slots; + + dev_dbg(sdev->dev, + "rate_min: %d rate_max: %d\n", rate->min, rate->max); + dev_dbg(sdev->dev, + "channels_min: %d channels_max: %d\n", + channels->min, channels->max); + + break; + case SOF_DAI_INTEL_DMIC: + /* DMIC only supports 16 or 32 bit formats */ + if (dai->comp_dai.config.frame_fmt == SOF_IPC_FRAME_S24_4LE) { + dev_err(sdev->dev, + "error: invalid fmt %d for DAI type %d\n", + dai->comp_dai.config.frame_fmt, + dai->dai_config->type); + } + break; + case SOF_DAI_INTEL_HDA: + /* do nothing for HDA dai_link */ + break; + default: + dev_err(sdev->dev, "error: invalid DAI type %d\n", + dai->dai_config->type); + break; + } + + return 0; +} + +static int sof_pcm_probe(struct snd_soc_component *component) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + struct snd_sof_pdata *plat_data = sdev->pdata; + const char *tplg_filename; + int ret; + + /* load the default topology */ + sdev->component = component; + + tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, + "%s/%s", + plat_data->tplg_filename_prefix, + plat_data->tplg_filename); + if (!tplg_filename) + return -ENOMEM; + + ret = snd_sof_load_topology(sdev, tplg_filename); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to load DSP topology %d\n", + ret); + return ret; + } + + /* + * Some platforms in SOF, ex: BYT, may not have their platform PM + * callbacks set. Increment the usage count so as to + * prevent the device from entering runtime suspend. + */ + if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume) + pm_runtime_get_noresume(sdev->dev); + + return ret; +} + +static void sof_pcm_remove(struct snd_soc_component *component) +{ + /* remove topology */ + snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); +} + +void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) +{ + struct snd_soc_component_driver *pd = &sdev->plat_drv; + struct snd_sof_pdata *plat_data = sdev->pdata; + const char *drv_name; + + drv_name = plat_data->machine->drv_name; + + pd->name = "sof-audio-component"; + pd->probe = sof_pcm_probe; + pd->remove = sof_pcm_remove; + pd->ops = &sof_pcm_ops; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) + pd->compr_ops = &sof_compressed_ops; +#endif + pd->pcm_new = sof_pcm_new; + pd->ignore_machine = drv_name; + pd->be_hw_params_fixup = sof_pcm_dai_link_fixup; + pd->be_pcm_base = SOF_BE_PCM_BASE; + pd->use_dai_pcm_id = true; + pd->topology_name_prefix = "sof"; + + /* increment module refcount when a pcm is opened */ + pd->module_get_upon_open = 1; +} From 4f9a0b7edb7f9a35a2f45d9c8403f00ae08bb0af Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:05:11 -0500 Subject: [PATCH 1395/1995] ASoC: SOF: Add support for loading topologies SOF uses topology to define the DAPM graphs and widgets, DAIs, PCMs and set parameters for init and run time usage. This patch loads topology and maps it to IPC commands that are build the topology on the DSP. Signed-off-by: Ranjani Sridharan Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 311ce4fe7637d96608b6e57bf9ebbd8aabcf429e) --- include/sound/sof/topology.h | 256 +++ sound/soc/sof/topology.c | 3164 ++++++++++++++++++++++++++++++++++ 2 files changed, 3420 insertions(+) create mode 100644 include/sound/sof/topology.h create mode 100644 sound/soc/sof/topology.c diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h new file mode 100644 index 00000000000000..46b2a7e63167bb --- /dev/null +++ b/include/sound/sof/topology.h @@ -0,0 +1,256 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_TOPOLOGY_H__ +#define __INCLUDE_SOUND_SOF_TOPOLOGY_H__ + +#include + +/* + * Component + */ + +/* types of component */ +enum sof_comp_type { + SOF_COMP_NONE = 0, + SOF_COMP_HOST, + SOF_COMP_DAI, + SOF_COMP_SG_HOST, /**< scatter gather variant */ + SOF_COMP_SG_DAI, /**< scatter gather variant */ + SOF_COMP_VOLUME, + SOF_COMP_MIXER, + SOF_COMP_MUX, + SOF_COMP_SRC, + SOF_COMP_SPLITTER, + SOF_COMP_TONE, + SOF_COMP_SWITCH, + SOF_COMP_BUFFER, + SOF_COMP_EQ_IIR, + SOF_COMP_EQ_FIR, + SOF_COMP_KEYWORD_DETECT, + SOF_COMP_KPB, /* A key phrase buffer component */ + SOF_COMP_SELECTOR, /**< channel selector component */ + /* keep FILEREAD/FILEWRITE as the last ones */ + SOF_COMP_FILEREAD = 10000, /**< host test based file IO */ + SOF_COMP_FILEWRITE = 10001, /**< host test based file IO */ +}; + +/* XRUN action for component */ +#define SOF_XRUN_STOP 1 /**< stop stream */ +#define SOF_XRUN_UNDER_ZERO 2 /**< send 0s to sink */ +#define SOF_XRUN_OVER_NULL 4 /**< send data to NULL */ + +/* create new generic component - SOF_IPC_TPLG_COMP_NEW */ +struct sof_ipc_comp { + struct sof_ipc_cmd_hdr hdr; + uint32_t id; + enum sof_comp_type type; + uint32_t pipeline_id; + + /* reserved for future use */ + uint32_t reserved[2]; +} __packed; + +/* + * Component Buffers + */ + +/* + * SOF memory capabilities, add new ones at the end + */ +#define SOF_MEM_CAPS_RAM (1 << 0) +#define SOF_MEM_CAPS_ROM (1 << 1) +#define SOF_MEM_CAPS_EXT (1 << 2) /**< external */ +#define SOF_MEM_CAPS_LP (1 << 3) /**< low power */ +#define SOF_MEM_CAPS_HP (1 << 4) /**< high performance */ +#define SOF_MEM_CAPS_DMA (1 << 5) /**< DMA'able */ +#define SOF_MEM_CAPS_CACHE (1 << 6) /**< cacheable */ +#define SOF_MEM_CAPS_EXEC (1 << 7) /**< executable */ + +/* create new component buffer - SOF_IPC_TPLG_BUFFER_NEW */ +struct sof_ipc_buffer { + struct sof_ipc_comp comp; + uint32_t size; /**< buffer size in bytes */ + uint32_t caps; /**< SOF_MEM_CAPS_ */ +} __packed; + +/* generic component config data - must always be after struct sof_ipc_comp */ +struct sof_ipc_comp_config { + struct sof_ipc_cmd_hdr hdr; + uint32_t periods_sink; /**< 0 means variable */ + uint32_t periods_source; /**< 0 means variable */ + uint32_t reserved1; /**< reserved */ + uint32_t frame_fmt; /**< SOF_IPC_FRAME_ */ + uint32_t xrun_action; + + /* reserved for future use */ + uint32_t reserved[2]; +} __packed; + +/* generic host component */ +struct sof_ipc_comp_host { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + uint32_t direction; /**< SOF_IPC_STREAM_ */ + uint32_t no_irq; /**< don't send periodic IRQ to host/DSP */ + uint32_t dmac_config; /**< DMA engine specific */ +} __packed; + +/* generic DAI component */ +struct sof_ipc_comp_dai { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + uint32_t direction; /**< SOF_IPC_STREAM_ */ + uint32_t dai_index; /**< index of this type dai */ + uint32_t type; /**< DAI type - SOF_DAI_ */ + uint32_t reserved; /**< reserved */ +} __packed; + +/* generic mixer component */ +struct sof_ipc_comp_mixer { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; +} __packed; + +/* volume ramping types */ +enum sof_volume_ramp { + SOF_VOLUME_LINEAR = 0, + SOF_VOLUME_LOG, + SOF_VOLUME_LINEAR_ZC, + SOF_VOLUME_LOG_ZC, +}; + +/* generic volume component */ +struct sof_ipc_comp_volume { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + uint32_t channels; + uint32_t min_value; + uint32_t max_value; + uint32_t ramp; /**< SOF_VOLUME_ */ + uint32_t initial_ramp; /**< ramp space in ms */ +} __packed; + +/* generic SRC component */ +struct sof_ipc_comp_src { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + /* either source or sink rate must be non zero */ + uint32_t source_rate; /**< source rate or 0 for variable */ + uint32_t sink_rate; /**< sink rate or 0 for variable */ + uint32_t rate_mask; /**< SOF_RATE_ supported rates */ +} __packed; + +/* generic MUX component */ +struct sof_ipc_comp_mux { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; +} __packed; + +/* generic tone generator component */ +struct sof_ipc_comp_tone { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + int32_t sample_rate; + int32_t frequency; + int32_t amplitude; + int32_t freq_mult; + int32_t ampl_mult; + int32_t length; + int32_t period; + int32_t repeats; + int32_t ramp_step; +} __packed; + +/** \brief Types of processing components */ +enum sof_ipc_process_type { + SOF_PROCESS_NONE = 0, /**< None */ + SOF_PROCESS_EQFIR, /**< Intel FIR */ + SOF_PROCESS_EQIIR, /**< Intel IIR */ + SOF_PROCESS_KEYWORD_DETECT, /**< Keyword Detection */ + SOF_PROCESS_KPB, /**< KeyPhrase Buffer Manager */ + SOF_PROCESS_CHAN_SELECTOR, /**< Channel Selector */ +}; + +/* generic "effect", "codec" or proprietary processing component */ +struct sof_ipc_comp_process { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + uint32_t size; /**< size of bespoke data section in bytes */ + uint32_t type; /**< sof_ipc_process_type */ + + /* reserved for future use */ + uint32_t reserved[7]; + + unsigned char data[0]; +} __packed; + +/* frees components, buffers and pipelines + * SOF_IPC_TPLG_COMP_FREE, SOF_IPC_TPLG_PIPE_FREE, SOF_IPC_TPLG_BUFFER_FREE + */ +struct sof_ipc_free { + struct sof_ipc_cmd_hdr hdr; + uint32_t id; +} __packed; + +struct sof_ipc_comp_reply { + struct sof_ipc_reply rhdr; + uint32_t id; + uint32_t offset; +} __packed; + +/* + * Pipeline + */ + +/** \brief Types of pipeline scheduling time domains */ +enum sof_ipc_pipe_sched_time_domain { + SOF_TIME_DOMAIN_DMA = 0, /**< DMA interrupt */ + SOF_TIME_DOMAIN_TIMER, /**< Timer interrupt */ +}; + +/* new pipeline - SOF_IPC_TPLG_PIPE_NEW */ +struct sof_ipc_pipe_new { + struct sof_ipc_cmd_hdr hdr; + uint32_t comp_id; /**< component id for pipeline */ + uint32_t pipeline_id; /**< pipeline id */ + uint32_t sched_id; /**< Scheduling component id */ + uint32_t core; /**< core we run on */ + uint32_t period; /**< execution period in us*/ + uint32_t priority; /**< priority level 0 (low) to 10 (max) */ + uint32_t period_mips; /**< worst case instruction count per period */ + uint32_t frames_per_sched;/**< output frames of pipeline, 0 is variable */ + uint32_t xrun_limit_usecs; /**< report xruns greater than limit */ + uint32_t time_domain; /**< scheduling time domain */ +} __packed; + +/* pipeline construction complete - SOF_IPC_TPLG_PIPE_COMPLETE */ +struct sof_ipc_pipe_ready { + struct sof_ipc_cmd_hdr hdr; + uint32_t comp_id; +} __packed; + +struct sof_ipc_pipe_free { + struct sof_ipc_cmd_hdr hdr; + uint32_t comp_id; +} __packed; + +/* connect two components in pipeline - SOF_IPC_TPLG_COMP_CONNECT */ +struct sof_ipc_pipe_comp_connect { + struct sof_ipc_cmd_hdr hdr; + uint32_t source_id; + uint32_t sink_id; +} __packed; + +/* external events */ +enum sof_event_types { + SOF_EVENT_NONE = 0, + SOF_KEYWORD_DETECT_DAPM_EVENT, +}; + +#endif diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c new file mode 100644 index 00000000000000..2b9de1b97447b7 --- /dev/null +++ b/sound/soc/sof/topology.c @@ -0,0 +1,3164 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +#include +#include +#include +#include +#include "sof-priv.h" +#include "ops.h" + +#define COMP_ID_UNASSIGNED 0xffffffff +/* + * Constants used in the computation of linear volume gain + * from dB gain 20th root of 10 in Q1.16 fixed-point notation + */ +#define VOL_TWENTIETH_ROOT_OF_TEN 73533 +/* 40th root of 10 in Q1.16 fixed-point notation*/ +#define VOL_FORTIETH_ROOT_OF_TEN 69419 +/* + * Volume fractional word length define to 16 sets + * the volume linear gain value to use Qx.16 format + */ +#define VOLUME_FWL 16 +/* 0.5 dB step value in topology TLV */ +#define VOL_HALF_DB_STEP 50 +/* Full volume for default values */ +#define VOL_ZERO_DB BIT(VOLUME_FWL) + +/* TLV data items */ +#define TLV_ITEMS 3 +#define TLV_MIN 0 +#define TLV_STEP 1 +#define TLV_MUTE 2 + +/* size of tplg abi in byte */ +#define SOF_TPLG_ABI_SIZE 3 + +/* send pcm params ipc */ +static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir) +{ + struct sof_ipc_pcm_params_reply ipc_params_reply; + struct snd_sof_dev *sdev = swidget->sdev; + struct sof_ipc_pcm_params pcm; + struct snd_pcm_hw_params *params; + struct snd_sof_pcm *spcm; + int ret = 0; + + memset(&pcm, 0, sizeof(pcm)); + + /* get runtime PCM params using widget's stream name */ + spcm = snd_sof_find_spcm_name(sdev, swidget->widget->sname); + if (!spcm) { + dev_err(sdev->dev, "error: cannot find PCM for %s\n", + swidget->widget->name); + return -EINVAL; + } + + params = &spcm->params[dir]; + + /* set IPC PCM params */ + pcm.hdr.size = sizeof(pcm); + pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS; + pcm.comp_id = swidget->comp_id; + pcm.params.hdr.size = sizeof(pcm.params); + pcm.params.direction = dir; + pcm.params.sample_valid_bytes = params_width(params) >> 3; + pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED; + pcm.params.rate = params_rate(params); + pcm.params.channels = params_channels(params); + pcm.params.host_period_bytes = params_period_bytes(params); + + /* set format */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16: + pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE; + break; + case SNDRV_PCM_FORMAT_S24: + pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE; + break; + case SNDRV_PCM_FORMAT_S32: + pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE; + break; + default: + return -EINVAL; + } + + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm), + &ipc_params_reply, sizeof(ipc_params_reply)); + if (ret < 0) + dev_err(sdev->dev, "error: pcm params failed for %s\n", + swidget->widget->name); + + return ret; +} + + /* send stream trigger ipc */ +static int ipc_trigger(struct snd_sof_widget *swidget, int cmd) +{ + struct snd_sof_dev *sdev = swidget->sdev; + struct sof_ipc_stream stream; + struct sof_ipc_reply reply; + int ret = 0; + + /* set IPC stream params */ + stream.hdr.size = sizeof(stream); + stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | cmd; + stream.comp_id = swidget->comp_id; + + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, + sizeof(stream), &reply, sizeof(reply)); + if (ret < 0) + dev_err(sdev->dev, "error: failed to trigger %s\n", + swidget->widget->name); + + return ret; +} + +static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_sof_widget *swidget = w->dobj.private; + struct snd_sof_dev *sdev; + int ret = 0; + + if (!swidget) + return 0; + + sdev = swidget->sdev; + + dev_dbg(sdev->dev, "received event %d for widget %s\n", + event, w->name); + + /* process events */ + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* set pcm params */ + ret = ipc_pcm_params(swidget, SOF_IPC_STREAM_CAPTURE); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to set pcm params for widget %s\n", + swidget->widget->name); + break; + } + + /* start trigger */ + ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_START); + if (ret < 0) + dev_err(sdev->dev, + "error: failed to trigger widget %s\n", + swidget->widget->name); + break; + case SND_SOC_DAPM_POST_PMD: + /* stop trigger */ + ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP); + if (ret < 0) + dev_err(sdev->dev, + "error: failed to trigger widget %s\n", + swidget->widget->name); + + /* pcm free */ + ret = ipc_trigger(swidget, SOF_IPC_STREAM_PCM_FREE); + if (ret < 0) + dev_err(sdev->dev, + "error: failed to trigger widget %s\n", + swidget->widget->name); + break; + default: + break; + } + + return ret; +} + +/* event handlers for keyword detect component */ +static const struct snd_soc_tplg_widget_events sof_kwd_events[] = { + {SOF_KEYWORD_DETECT_DAPM_EVENT, sof_keyword_dapm_event}, +}; + +static inline int get_tlv_data(const int *p, int tlv[TLV_ITEMS]) +{ + /* we only support dB scale TLV type at the moment */ + if ((int)p[SNDRV_CTL_TLVO_TYPE] != SNDRV_CTL_TLVT_DB_SCALE) + return -EINVAL; + + /* min value in topology tlv data is multiplied by 100 */ + tlv[TLV_MIN] = (int)p[SNDRV_CTL_TLVO_DB_SCALE_MIN] / 100; + + /* volume steps */ + tlv[TLV_STEP] = (int)(p[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] & + TLV_DB_SCALE_MASK); + + /* mute ON/OFF */ + if ((p[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] & + TLV_DB_SCALE_MUTE) == 0) + tlv[TLV_MUTE] = 0; + else + tlv[TLV_MUTE] = 1; + + return 0; +} + +/* + * Function to truncate an unsigned 64-bit number + * by x bits and return 32-bit unsigned number. This + * function also takes care of rounding while truncating + */ +static inline u32 vol_shift_64(u64 i, u32 x) +{ + /* do not truncate more than 32 bits */ + if (x > 32) + x = 32; + + if (x == 0) + return (u32)i; + + return (u32)(((i >> (x - 1)) + 1) >> 1); +} + +/* + * Function to compute a ^ exp where, + * a is a fractional number represented by a fixed-point + * integer with a fractional world length of "fwl" + * exp is an integer + * fwl is the fractional word length + * Return value is a fractional number represented by a + * fixed-point integer with a fractional word length of "fwl" + */ +static u32 vol_pow32(u32 a, int exp, u32 fwl) +{ + int i, iter; + u32 power = 1 << fwl; + u64 numerator; + + /* if exponent is 0, return 1 */ + if (exp == 0) + return power; + + /* determine the number of iterations based on the exponent */ + if (exp < 0) + iter = exp * -1; + else + iter = exp; + + /* mutiply a "iter" times to compute power */ + for (i = 0; i < iter; i++) { + /* + * Product of 2 Qx.fwl fixed-point numbers yields a Q2*x.2*fwl + * Truncate product back to fwl fractional bits with rounding + */ + power = vol_shift_64((u64)power * a, fwl); + } + + if (exp > 0) { + /* if exp is positive, return the result */ + return power; + } + + /* if exp is negative, return the multiplicative inverse */ + numerator = (u64)1 << (fwl << 1); + do_div(numerator, power); + + return (u32)numerator; +} + +/* + * Function to calculate volume gain from TLV data. + * This function can only handle gain steps that are multiples of 0.5 dB + */ +static u32 vol_compute_gain(u32 value, int *tlv) +{ + int dB_gain; + u32 linear_gain; + int f_step; + + /* mute volume */ + if (value == 0 && tlv[TLV_MUTE]) + return 0; + + /* + * compute dB gain from tlv. tlv_step + * in topology is multiplied by 100 + */ + dB_gain = tlv[TLV_MIN] + (value * tlv[TLV_STEP]) / 100; + + /* + * compute linear gain represented by fixed-point + * int with VOLUME_FWL fractional bits + */ + linear_gain = vol_pow32(VOL_TWENTIETH_ROOT_OF_TEN, dB_gain, VOLUME_FWL); + + /* extract the fractional part of volume step */ + f_step = tlv[TLV_STEP] - (tlv[TLV_STEP] / 100); + + /* if volume step is an odd multiple of 0.5 dB */ + if (f_step == VOL_HALF_DB_STEP && (value & 1)) + linear_gain = vol_shift_64((u64)linear_gain * + VOL_FORTIETH_ROOT_OF_TEN, + VOLUME_FWL); + + return linear_gain; +} + +/* + * Set up volume table for kcontrols from tlv data + * "size" specifies the number of entries in the table + */ +static int set_up_volume_table(struct snd_sof_control *scontrol, + int tlv[TLV_ITEMS], int size) +{ + int j; + + /* init the volume table */ + scontrol->volume_table = kcalloc(size, sizeof(u32), GFP_KERNEL); + if (!scontrol->volume_table) + return -ENOMEM; + + /* populate the volume table */ + for (j = 0; j < size ; j++) + scontrol->volume_table[j] = vol_compute_gain(j, tlv); + + return 0; +} + +struct sof_dai_types { + const char *name; + enum sof_ipc_dai_type type; +}; + +static const struct sof_dai_types sof_dais[] = { + {"SSP", SOF_DAI_INTEL_SSP}, + {"HDA", SOF_DAI_INTEL_HDA}, + {"DMIC", SOF_DAI_INTEL_DMIC}, +}; + +static enum sof_ipc_dai_type find_dai(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sof_dais); i++) { + if (strcmp(name, sof_dais[i].name) == 0) + return sof_dais[i].type; + } + + return SOF_DAI_INTEL_NONE; +} + +/* + * Supported Frame format types and lookup, add new ones to end of list. + */ + +struct sof_frame_types { + const char *name; + enum sof_ipc_frame frame; +}; + +static const struct sof_frame_types sof_frames[] = { + {"s16le", SOF_IPC_FRAME_S16_LE}, + {"s24le", SOF_IPC_FRAME_S24_4LE}, + {"s32le", SOF_IPC_FRAME_S32_LE}, + {"float", SOF_IPC_FRAME_FLOAT}, +}; + +static enum sof_ipc_frame find_format(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sof_frames); i++) { + if (strcmp(name, sof_frames[i].name) == 0) + return sof_frames[i].frame; + } + + /* use s32le if nothing is specified */ + return SOF_IPC_FRAME_S32_LE; +} + +struct sof_process_types { + const char *name; + enum sof_ipc_process_type type; + enum sof_comp_type comp_type; +}; + +static const struct sof_process_types sof_process[] = { + {"EQFIR", SOF_PROCESS_EQFIR, SOF_COMP_EQ_FIR}, + {"EQIIR", SOF_PROCESS_EQIIR, SOF_COMP_EQ_IIR}, + {"KEYWORD_DETECT", SOF_PROCESS_KEYWORD_DETECT, SOF_COMP_KEYWORD_DETECT}, + {"KPB", SOF_PROCESS_KPB, SOF_COMP_KPB}, + {"CHAN_SELECTOR", SOF_PROCESS_CHAN_SELECTOR, SOF_COMP_SELECTOR}, +}; + +static enum sof_ipc_process_type find_process(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sof_process); i++) { + if (strcmp(name, sof_process[i].name) == 0) + return sof_process[i].type; + } + + return SOF_PROCESS_NONE; +} + +static enum sof_comp_type find_process_comp_type(enum sof_ipc_process_type type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sof_process); i++) { + if (sof_process[i].type == type) + return sof_process[i].comp_type; + } + + return SOF_COMP_NONE; +} + +/* + * Standard Kcontrols. + */ + +static int sof_control_load_volume(struct snd_soc_component *scomp, + struct snd_sof_control *scontrol, + struct snd_kcontrol_new *kc, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_mixer_control *mc = + container_of(hdr, struct snd_soc_tplg_mixer_control, hdr); + struct sof_ipc_ctrl_data *cdata; + int tlv[TLV_ITEMS]; + unsigned int i; + int ret; + + /* validate topology data */ + if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN) + return -EINVAL; + + /* init the volume get/put data */ + scontrol->size = sizeof(struct sof_ipc_ctrl_data) + + sizeof(struct sof_ipc_ctrl_value_chan) * + le32_to_cpu(mc->num_channels); + scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); + if (!scontrol->control_data) + return -ENOMEM; + + scontrol->comp_id = sdev->next_comp_id; + scontrol->num_channels = le32_to_cpu(mc->num_channels); + + /* set cmd for mixer control */ + if (le32_to_cpu(mc->max) == 1) { + scontrol->cmd = SOF_CTRL_CMD_SWITCH; + goto out; + } + + scontrol->cmd = SOF_CTRL_CMD_VOLUME; + + /* extract tlv data */ + if (get_tlv_data(kc->tlv.p, tlv) < 0) { + dev_err(sdev->dev, "error: invalid TLV data\n"); + return -EINVAL; + } + + /* set up volume table */ + ret = set_up_volume_table(scontrol, tlv, le32_to_cpu(mc->max) + 1); + if (ret < 0) { + dev_err(sdev->dev, "error: setting up volume table\n"); + return ret; + } + + /* set default volume values to 0dB in control */ + cdata = scontrol->control_data; + for (i = 0; i < scontrol->num_channels; i++) { + cdata->chanv[i].channel = i; + cdata->chanv[i].value = VOL_ZERO_DB; + } + +out: + dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", + scontrol->comp_id, scontrol->num_channels); + + return 0; +} + +static int sof_control_load_enum(struct snd_soc_component *scomp, + struct snd_sof_control *scontrol, + struct snd_kcontrol_new *kc, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_enum_control *ec = + container_of(hdr, struct snd_soc_tplg_enum_control, hdr); + + /* validate topology data */ + if (le32_to_cpu(ec->num_channels) > SND_SOC_TPLG_MAX_CHAN) + return -EINVAL; + + /* init the enum get/put data */ + scontrol->size = sizeof(struct sof_ipc_ctrl_data) + + sizeof(struct sof_ipc_ctrl_value_chan) * + le32_to_cpu(ec->num_channels); + scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); + if (!scontrol->control_data) + return -ENOMEM; + + scontrol->comp_id = sdev->next_comp_id; + scontrol->num_channels = le32_to_cpu(ec->num_channels); + + scontrol->cmd = SOF_CTRL_CMD_ENUM; + + dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d comp_id %d\n", + scontrol->comp_id, scontrol->num_channels, scontrol->comp_id); + + return 0; +} + +static int sof_control_load_bytes(struct snd_soc_component *scomp, + struct snd_sof_control *scontrol, + struct snd_kcontrol_new *kc, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc_ctrl_data *cdata; + struct snd_soc_tplg_bytes_control *control = + container_of(hdr, struct snd_soc_tplg_bytes_control, hdr); + struct soc_bytes_ext *sbe = (struct soc_bytes_ext *)kc->private_value; + int max_size = sbe->max; + + if (le32_to_cpu(control->priv.size) > max_size) { + dev_err(sdev->dev, "err: bytes data size %d exceeds max %d.\n", + control->priv.size, max_size); + return -EINVAL; + } + + /* init the get/put bytes data */ + scontrol->size = sizeof(struct sof_ipc_ctrl_data) + + le32_to_cpu(control->priv.size); + scontrol->control_data = kzalloc(max_size, GFP_KERNEL); + cdata = scontrol->control_data; + if (!scontrol->control_data) + return -ENOMEM; + + scontrol->comp_id = sdev->next_comp_id; + scontrol->cmd = SOF_CTRL_CMD_BINARY; + + dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", + scontrol->comp_id, scontrol->num_channels); + + if (le32_to_cpu(control->priv.size) > 0) { + memcpy(cdata->data, control->priv.data, + le32_to_cpu(control->priv.size)); + + if (cdata->data->magic != SOF_ABI_MAGIC) { + dev_err(sdev->dev, "error: Wrong ABI magic 0x%08x.\n", + cdata->data->magic); + return -EINVAL; + } + if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, + cdata->data->abi)) { + dev_err(sdev->dev, + "error: Incompatible ABI version 0x%08x.\n", + cdata->data->abi); + return -EINVAL; + } + if (cdata->data->size + sizeof(const struct sof_abi_hdr) != + le32_to_cpu(control->priv.size)) { + dev_err(sdev->dev, + "error: Conflict in bytes vs. priv size.\n"); + return -EINVAL; + } + } + return 0; +} + +/* + * Topology Token Parsing. + * New tokens should be added to headers and parsing tables below. + */ + +struct sof_topology_token { + u32 token; + u32 type; + int (*get_token)(void *elem, void *object, u32 offset, u32 size); + u32 offset; + u32 size; +}; + +static int get_token_u32(void *elem, void *object, u32 offset, u32 size) +{ + struct snd_soc_tplg_vendor_value_elem *velem = elem; + u32 *val = (u32 *)((u8 *)object + offset); + + *val = le32_to_cpu(velem->value); + return 0; +} + +static int get_token_u16(void *elem, void *object, u32 offset, u32 size) +{ + struct snd_soc_tplg_vendor_value_elem *velem = elem; + u16 *val = (u16 *)((u8 *)object + offset); + + *val = (u16)le32_to_cpu(velem->value); + return 0; +} + +static int get_token_comp_format(void *elem, void *object, u32 offset, u32 size) +{ + struct snd_soc_tplg_vendor_string_elem *velem = elem; + u32 *val = (u32 *)((u8 *)object + offset); + + *val = find_format(velem->string); + return 0; +} + +static int get_token_dai_type(void *elem, void *object, u32 offset, u32 size) +{ + struct snd_soc_tplg_vendor_string_elem *velem = elem; + u32 *val = (u32 *)((u8 *)object + offset); + + *val = find_dai(velem->string); + return 0; +} + +static int get_token_process_type(void *elem, void *object, u32 offset, + u32 size) +{ + struct snd_soc_tplg_vendor_string_elem *velem = elem; + u32 *val = (u32 *)((u8 *)object + offset); + + *val = find_process(velem->string); + return 0; +} + +/* Buffers */ +static const struct sof_topology_token buffer_tokens[] = { + {SOF_TKN_BUF_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_buffer, size), 0}, + {SOF_TKN_BUF_CAPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_buffer, caps), 0}, +}; + +/* DAI */ +static const struct sof_topology_token dai_tokens[] = { + {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, + offsetof(struct sof_ipc_comp_dai, type), 0}, + {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_dai, dai_index), 0}, + {SOF_TKN_DAI_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_dai, direction), 0}, +}; + +/* BE DAI link */ +static const struct sof_topology_token dai_link_tokens[] = { + {SOF_TKN_DAI_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_dai_type, + offsetof(struct sof_ipc_dai_config, type), 0}, + {SOF_TKN_DAI_INDEX, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_config, dai_index), 0}, +}; + +/* scheduling */ +static const struct sof_topology_token sched_tokens[] = { + {SOF_TKN_SCHED_PERIOD, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, period), 0}, + {SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, priority), 0}, + {SOF_TKN_SCHED_MIPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, period_mips), 0}, + {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, core), 0}, + {SOF_TKN_SCHED_FRAMES, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, frames_per_sched), 0}, + {SOF_TKN_SCHED_TIME_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_pipe_new, time_domain), 0}, +}; + +/* volume */ +static const struct sof_topology_token volume_tokens[] = { + {SOF_TKN_VOLUME_RAMP_STEP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, offsetof(struct sof_ipc_comp_volume, ramp), 0}, + {SOF_TKN_VOLUME_RAMP_STEP_MS, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_volume, initial_ramp), 0}, +}; + +/* SRC */ +static const struct sof_topology_token src_tokens[] = { + {SOF_TKN_SRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_src, source_rate), 0}, + {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_src, sink_rate), 0}, +}; + +/* Tone */ +static const struct sof_topology_token tone_tokens[] = { +}; + +/* EFFECT */ +static const struct sof_topology_token process_tokens[] = { + {SOF_TKN_PROCESS_TYPE, SND_SOC_TPLG_TUPLE_TYPE_STRING, + get_token_process_type, + offsetof(struct sof_ipc_comp_process, type), 0}, +}; + +/* PCM */ +static const struct sof_topology_token pcm_tokens[] = { + {SOF_TKN_PCM_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_host, dmac_config), 0}, +}; + +/* Generic components */ +static const struct sof_topology_token comp_tokens[] = { + {SOF_TKN_COMP_PERIOD_SINK_COUNT, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_config, periods_sink), 0}, + {SOF_TKN_COMP_PERIOD_SOURCE_COUNT, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_config, periods_source), 0}, + {SOF_TKN_COMP_FORMAT, + SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format, + offsetof(struct sof_ipc_comp_config, frame_fmt), 0}, +}; + +/* SSP */ +static const struct sof_topology_token ssp_tokens[] = { + {SOF_TKN_INTEL_SSP_CLKS_CONTROL, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_ssp_params, clks_control), 0}, + {SOF_TKN_INTEL_SSP_MCLK_ID, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_ssp_params, mclk_id), 0}, + {SOF_TKN_INTEL_SSP_SAMPLE_BITS, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, + offsetof(struct sof_ipc_dai_ssp_params, sample_valid_bits), 0}, + {SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT, + get_token_u16, + offsetof(struct sof_ipc_dai_ssp_params, frame_pulse_width), 0}, + {SOF_TKN_INTEL_SSP_QUIRKS, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, + offsetof(struct sof_ipc_dai_ssp_params, quirks), 0}, + {SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT, SND_SOC_TPLG_TUPLE_TYPE_BOOL, + get_token_u16, + offsetof(struct sof_ipc_dai_ssp_params, + tdm_per_slot_padding_flag), 0}, + +}; + +/* DMIC */ +static const struct sof_topology_token dmic_tokens[] = { + {SOF_TKN_INTEL_DMIC_DRIVER_VERSION, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, driver_ipc_version), + 0}, + {SOF_TKN_INTEL_DMIC_CLK_MIN, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, pdmclk_min), 0}, + {SOF_TKN_INTEL_DMIC_CLK_MAX, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, pdmclk_max), 0}, + {SOF_TKN_INTEL_DMIC_SAMPLE_RATE, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, fifo_fs), 0}, + {SOF_TKN_INTEL_DMIC_DUTY_MIN, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_params, duty_min), 0}, + {SOF_TKN_INTEL_DMIC_DUTY_MAX, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_params, duty_max), 0}, + {SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, + num_pdm_active), 0}, + {SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_params, fifo_bits), 0}, +}; + +/* + * DMIC PDM Tokens + * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token + * as it increments the index while parsing the array of pdm tokens + * and determines the correct offset + */ +static const struct sof_topology_token dmic_pdm_tokens[] = { + {SOF_TKN_INTEL_DMIC_PDM_CTRL_ID, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, id), + 0}, + {SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_a), + 0}, + {SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, enable_mic_b), + 0}, + {SOF_TKN_INTEL_DMIC_PDM_POLARITY_A, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_a), + 0}, + {SOF_TKN_INTEL_DMIC_PDM_POLARITY_B, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, polarity_mic_b), + 0}, + {SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, clk_edge), + 0}, + {SOF_TKN_INTEL_DMIC_PDM_SKEW, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_dmic_pdm_ctrl, skew), + 0}, +}; + +/* HDA */ +static const struct sof_topology_token hda_tokens[] = { +}; + +static void sof_parse_uuid_tokens(struct snd_soc_component *scomp, + void *object, + const struct sof_topology_token *tokens, + int count, + struct snd_soc_tplg_vendor_array *array) +{ + struct snd_soc_tplg_vendor_uuid_elem *elem; + int i, j; + + /* parse element by element */ + for (i = 0; i < le32_to_cpu(array->num_elems); i++) { + elem = &array->uuid[i]; + + /* search for token */ + for (j = 0; j < count; j++) { + /* match token type */ + if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_UUID) + continue; + + /* match token id */ + if (tokens[j].token != le32_to_cpu(elem->token)) + continue; + + /* matched - now load token */ + tokens[j].get_token(elem, object, tokens[j].offset, + tokens[j].size); + } + } +} + +static void sof_parse_string_tokens(struct snd_soc_component *scomp, + void *object, + const struct sof_topology_token *tokens, + int count, + struct snd_soc_tplg_vendor_array *array) +{ + struct snd_soc_tplg_vendor_string_elem *elem; + int i, j; + + /* parse element by element */ + for (i = 0; i < le32_to_cpu(array->num_elems); i++) { + elem = &array->string[i]; + + /* search for token */ + for (j = 0; j < count; j++) { + /* match token type */ + if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_STRING) + continue; + + /* match token id */ + if (tokens[j].token != le32_to_cpu(elem->token)) + continue; + + /* matched - now load token */ + tokens[j].get_token(elem, object, tokens[j].offset, + tokens[j].size); + } + } +} + +static void sof_parse_word_tokens(struct snd_soc_component *scomp, + void *object, + const struct sof_topology_token *tokens, + int count, + struct snd_soc_tplg_vendor_array *array) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_vendor_value_elem *elem; + size_t size = sizeof(struct sof_ipc_dai_dmic_pdm_ctrl); + int i, j; + u32 offset; + u32 *index = NULL; + + /* parse element by element */ + for (i = 0; i < le32_to_cpu(array->num_elems); i++) { + elem = &array->value[i]; + + /* search for token */ + for (j = 0; j < count; j++) { + /* match token type */ + if (!(tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_WORD || + tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_SHORT)) + continue; + + /* match token id */ + if (tokens[j].token != le32_to_cpu(elem->token)) + continue; + + /* pdm config array index */ + if (sdev->private) + index = sdev->private; + + /* matched - determine offset */ + switch (tokens[j].token) { + case SOF_TKN_INTEL_DMIC_PDM_CTRL_ID: + + /* inc number of pdm array index */ + if (index) + (*index)++; + /* fallthrough */ + case SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable: + case SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable: + case SOF_TKN_INTEL_DMIC_PDM_POLARITY_A: + case SOF_TKN_INTEL_DMIC_PDM_POLARITY_B: + case SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE: + case SOF_TKN_INTEL_DMIC_PDM_SKEW: + + /* check if array index is valid */ + if (!index || *index == 0) { + dev_err(sdev->dev, + "error: invalid array offset\n"); + continue; + } else { + /* offset within the pdm config array */ + offset = size * (*index - 1); + } + break; + default: + offset = 0; + break; + } + + /* load token */ + tokens[j].get_token(elem, object, + offset + tokens[j].offset, + tokens[j].size); + } + } +} + +static int sof_parse_tokens(struct snd_soc_component *scomp, + void *object, + const struct sof_topology_token *tokens, + int count, + struct snd_soc_tplg_vendor_array *array, + int priv_size) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + int asize; + + while (priv_size > 0) { + asize = le32_to_cpu(array->size); + + /* validate asize */ + if (asize < 0) { /* FIXME: A zero-size array makes no sense */ + dev_err(sdev->dev, "error: invalid array size 0x%x\n", + asize); + return -EINVAL; + } + + /* make sure there is enough data before parsing */ + priv_size -= asize; + if (priv_size < 0) { + dev_err(sdev->dev, "error: invalid array size 0x%x\n", + asize); + return -EINVAL; + } + + /* call correct parser depending on type */ + switch (le32_to_cpu(array->type)) { + case SND_SOC_TPLG_TUPLE_TYPE_UUID: + sof_parse_uuid_tokens(scomp, object, tokens, count, + array); + break; + case SND_SOC_TPLG_TUPLE_TYPE_STRING: + sof_parse_string_tokens(scomp, object, tokens, count, + array); + break; + case SND_SOC_TPLG_TUPLE_TYPE_BOOL: + case SND_SOC_TPLG_TUPLE_TYPE_BYTE: + case SND_SOC_TPLG_TUPLE_TYPE_WORD: + case SND_SOC_TPLG_TUPLE_TYPE_SHORT: + sof_parse_word_tokens(scomp, object, tokens, count, + array); + break; + default: + dev_err(sdev->dev, "error: unknown token type %d\n", + array->type); + return -EINVAL; + } + + /* next array */ + array = (struct snd_soc_tplg_vendor_array *)((u8 *)array + + asize); + } + return 0; +} + +static void sof_dbg_comp_config(struct snd_soc_component *scomp, + struct sof_ipc_comp_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + + dev_dbg(sdev->dev, " config: periods snk %d src %d fmt %d\n", + config->periods_sink, config->periods_source, + config->frame_fmt); +} + +/* external kcontrol init - used for any driver specific init */ +static int sof_control_load(struct snd_soc_component *scomp, int index, + struct snd_kcontrol_new *kc, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct soc_mixer_control *sm; + struct soc_bytes_ext *sbe; + struct soc_enum *se; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_dobj *dobj; + struct snd_sof_control *scontrol; + int ret = -EINVAL; + + dev_dbg(sdev->dev, "tplg: load control type %d name : %s\n", + hdr->type, hdr->name); + + scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL); + if (!scontrol) + return -ENOMEM; + + scontrol->sdev = sdev; + + switch (le32_to_cpu(hdr->ops.info)) { + case SND_SOC_TPLG_CTL_VOLSW: + case SND_SOC_TPLG_CTL_VOLSW_SX: + case SND_SOC_TPLG_CTL_VOLSW_XR_SX: + sm = (struct soc_mixer_control *)kc->private_value; + dobj = &sm->dobj; + ret = sof_control_load_volume(scomp, scontrol, kc, hdr); + break; + case SND_SOC_TPLG_CTL_BYTES: + sbe = (struct soc_bytes_ext *)kc->private_value; + dobj = &sbe->dobj; + ret = sof_control_load_bytes(scomp, scontrol, kc, hdr); + break; + case SND_SOC_TPLG_CTL_ENUM: + case SND_SOC_TPLG_CTL_ENUM_VALUE: + se = (struct soc_enum *)kc->private_value; + dobj = &se->dobj; + ret = sof_control_load_enum(scomp, scontrol, kc, hdr); + break; + case SND_SOC_TPLG_CTL_RANGE: + case SND_SOC_TPLG_CTL_STROBE: + case SND_SOC_TPLG_DAPM_CTL_VOLSW: + case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: + case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: + case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: + case SND_SOC_TPLG_DAPM_CTL_PIN: + default: + dev_warn(sdev->dev, "control type not supported %d:%d:%d\n", + hdr->ops.get, hdr->ops.put, hdr->ops.info); + kfree(scontrol); + return 0; + } + + dobj->private = scontrol; + list_add(&scontrol->list, &sdev->kcontrol_list); + return ret; +} + +static int sof_control_unload(struct snd_soc_component *scomp, + struct snd_soc_dobj *dobj) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc_free fcomp; + struct snd_sof_control *scontrol = dobj->private; + + dev_dbg(sdev->dev, "tplg: unload control name : %s\n", scomp->name); + + fcomp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_FREE; + fcomp.hdr.size = sizeof(fcomp); + fcomp.id = scontrol->comp_id; + + kfree(scontrol->control_data); + list_del(&scontrol->list); + kfree(scontrol); + /* send IPC to the DSP */ + return sof_ipc_tx_message(sdev->ipc, + fcomp.hdr.cmd, &fcomp, sizeof(fcomp), + NULL, 0); +} + +/* + * DAI Topology + */ + +static int sof_connect_dai_widget(struct snd_soc_component *scomp, + struct snd_soc_dapm_widget *w, + struct snd_soc_tplg_dapm_widget *tw, + struct snd_sof_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_card *card = scomp->card; + struct snd_soc_pcm_runtime *rtd; + + list_for_each_entry(rtd, &card->rtd_list, list) { + dev_vdbg(sdev->dev, "tplg: check widget: %s stream: %s dai stream: %s\n", + w->name, w->sname, rtd->dai_link->stream_name); + + if (!w->sname || !rtd->dai_link->stream_name) + continue; + + /* does stream match DAI link ? */ + if (strcmp(w->sname, rtd->dai_link->stream_name)) + continue; + + switch (w->id) { + case snd_soc_dapm_dai_out: + rtd->cpu_dai->capture_widget = w; + if (dai) + dai->name = rtd->dai_link->name; + dev_dbg(sdev->dev, "tplg: connected widget %s -> DAI link %s\n", + w->name, rtd->dai_link->name); + break; + case snd_soc_dapm_dai_in: + rtd->cpu_dai->playback_widget = w; + if (dai) + dai->name = rtd->dai_link->name; + dev_dbg(sdev->dev, "tplg: connected widget %s -> DAI link %s\n", + w->name, rtd->dai_link->name); + break; + default: + break; + } + } + + /* check we have a connection */ + if (!dai->name) { + dev_err(sdev->dev, "error: can't connect DAI %s stream %s\n", + w->name, w->sname); + return -EINVAL; + } + + return 0; +} + +static int sof_widget_load_dai(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r, + struct snd_sof_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_dai comp_dai; + int ret; + + /* configure dai IPC message */ + memset(&comp_dai, 0, sizeof(comp_dai)); + comp_dai.comp.hdr.size = sizeof(comp_dai); + comp_dai.comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + comp_dai.comp.id = swidget->comp_id; + comp_dai.comp.type = SOF_COMP_DAI; + comp_dai.comp.pipeline_id = index; + comp_dai.config.hdr.size = sizeof(comp_dai.config); + + ret = sof_parse_tokens(scomp, &comp_dai, dai_tokens, + ARRAY_SIZE(dai_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse dai tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + + ret = sof_parse_tokens(scomp, &comp_dai.config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse dai.cfg tokens failed %d\n", + private->size); + return ret; + } + + dev_dbg(sdev->dev, "dai %s: type %d index %d\n", + swidget->widget->name, comp_dai.type, comp_dai.dai_index); + sof_dbg_comp_config(scomp, &comp_dai.config); + + ret = sof_ipc_tx_message(sdev->ipc, comp_dai.comp.hdr.cmd, + &comp_dai, sizeof(comp_dai), r, sizeof(*r)); + + if (ret == 0 && dai) { + dai->sdev = sdev; + memcpy(&dai->comp_dai, &comp_dai, sizeof(comp_dai)); + } + + return ret; +} + +/* + * Buffer topology + */ + +static int sof_widget_load_buffer(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_buffer *buffer; + int ret; + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + /* configure dai IPC message */ + buffer->comp.hdr.size = sizeof(*buffer); + buffer->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_BUFFER_NEW; + buffer->comp.id = swidget->comp_id; + buffer->comp.type = SOF_COMP_BUFFER; + buffer->comp.pipeline_id = index; + + ret = sof_parse_tokens(scomp, buffer, buffer_tokens, + ARRAY_SIZE(buffer_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse buffer tokens failed %d\n", + private->size); + kfree(buffer); + return ret; + } + + dev_dbg(sdev->dev, "buffer %s: size %d caps 0x%x\n", + swidget->widget->name, buffer->size, buffer->caps); + + swidget->private = buffer; + + ret = sof_ipc_tx_message(sdev->ipc, buffer->comp.hdr.cmd, buffer, + sizeof(*buffer), r, sizeof(*r)); + if (ret < 0) { + dev_err(sdev->dev, "error: buffer %s load failed\n", + swidget->widget->name); + kfree(buffer); + } + + return ret; +} + +/* bind PCM ID to host component ID */ +static int spcm_bind(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, + int dir) +{ + struct snd_sof_widget *host_widget; + + host_widget = snd_sof_find_swidget_sname(sdev, + spcm->pcm.caps[dir].name, + dir); + if (!host_widget) { + dev_err(sdev->dev, "can't find host comp to bind pcm\n"); + return -EINVAL; + } + + spcm->stream[dir].comp_id = host_widget->comp_id; + + return 0; +} + +/* + * PCM Topology + */ + +static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + enum sof_ipc_stream_direction dir, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_host *host; + int ret; + + host = kzalloc(sizeof(*host), GFP_KERNEL); + if (!host) + return -ENOMEM; + + /* configure host comp IPC message */ + host->comp.hdr.size = sizeof(*host); + host->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + host->comp.id = swidget->comp_id; + host->comp.type = SOF_COMP_HOST; + host->comp.pipeline_id = index; + host->direction = dir; + host->config.hdr.size = sizeof(host->config); + + ret = sof_parse_tokens(scomp, host, pcm_tokens, + ARRAY_SIZE(pcm_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse host tokens failed %d\n", + private->size); + goto err; + } + + ret = sof_parse_tokens(scomp, &host->config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse host.cfg tokens failed %d\n", + le32_to_cpu(private->size)); + goto err; + } + + dev_dbg(sdev->dev, "loaded host %s\n", swidget->widget->name); + sof_dbg_comp_config(scomp, &host->config); + + swidget->private = host; + + ret = sof_ipc_tx_message(sdev->ipc, host->comp.hdr.cmd, host, + sizeof(*host), r, sizeof(*r)); + if (ret >= 0) + return ret; +err: + kfree(host); + return ret; +} + +/* + * Pipeline Topology + */ +int sof_load_pipeline_ipc(struct snd_sof_dev *sdev, + struct sof_ipc_pipe_new *pipeline, + struct sof_ipc_comp_reply *r) +{ + struct sof_ipc_pm_core_config pm_core_config; + int ret; + + ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline, + sizeof(*pipeline), r, sizeof(*r)); + if (ret < 0) { + dev_err(sdev->dev, "error: load pipeline ipc failure\n"); + return ret; + } + + /* power up the core that this pipeline is scheduled on */ + ret = snd_sof_dsp_core_power_up(sdev, 1 << pipeline->core); + if (ret < 0) { + dev_err(sdev->dev, "error: powering up pipeline schedule core %d\n", + pipeline->core); + return ret; + } + + /* update enabled cores mask */ + sdev->enabled_cores_mask |= 1 << pipeline->core; + + /* + * Now notify DSP that the core that this pipeline is scheduled on + * has been powered up + */ + memset(&pm_core_config, 0, sizeof(pm_core_config)); + pm_core_config.enable_mask = sdev->enabled_cores_mask; + + /* configure CORE_ENABLE ipc message */ + pm_core_config.hdr.size = sizeof(pm_core_config); + pm_core_config.hdr.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CORE_ENABLE; + + /* send ipc */ + ret = sof_ipc_tx_message(sdev->ipc, pm_core_config.hdr.cmd, + &pm_core_config, sizeof(pm_core_config), + &pm_core_config, sizeof(pm_core_config)); + if (ret < 0) + dev_err(sdev->dev, "error: core enable ipc failure\n"); + + return ret; +} + +static int sof_widget_load_pipeline(struct snd_soc_component *scomp, + int index, struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_pipe_new *pipeline; + struct snd_sof_widget *comp_swidget; + int ret; + + pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL); + if (!pipeline) + return -ENOMEM; + + /* configure dai IPC message */ + pipeline->hdr.size = sizeof(*pipeline); + pipeline->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_NEW; + pipeline->pipeline_id = index; + pipeline->comp_id = swidget->comp_id; + + /* component at start of pipeline is our stream id */ + comp_swidget = snd_sof_find_swidget(sdev, tw->sname); + if (!comp_swidget) { + dev_err(sdev->dev, "error: widget %s refers to non existent widget %s\n", + tw->name, tw->sname); + ret = -EINVAL; + goto err; + } + + pipeline->sched_id = comp_swidget->comp_id; + + dev_dbg(sdev->dev, "tplg: pipeline id %d comp %d scheduling comp id %d\n", + pipeline->pipeline_id, pipeline->comp_id, pipeline->sched_id); + + ret = sof_parse_tokens(scomp, pipeline, sched_tokens, + ARRAY_SIZE(sched_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse pipeline tokens failed %d\n", + private->size); + goto err; + } + + dev_dbg(sdev->dev, "pipeline %s: period %d pri %d mips %d core %d frames %d\n", + swidget->widget->name, pipeline->period, pipeline->priority, + pipeline->period_mips, pipeline->core, pipeline->frames_per_sched); + + swidget->private = pipeline; + + /* send ipc's to create pipeline comp and power up schedule core */ + ret = sof_load_pipeline_ipc(sdev, pipeline, r); + if (ret >= 0) + return ret; +err: + kfree(pipeline); + return ret; +} + +/* + * Mixer topology + */ + +static int sof_widget_load_mixer(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_mixer *mixer; + int ret; + + mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); + if (!mixer) + return -ENOMEM; + + /* configure mixer IPC message */ + mixer->comp.hdr.size = sizeof(*mixer); + mixer->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + mixer->comp.id = swidget->comp_id; + mixer->comp.type = SOF_COMP_MIXER; + mixer->comp.pipeline_id = index; + mixer->config.hdr.size = sizeof(mixer->config); + + ret = sof_parse_tokens(scomp, &mixer->config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse mixer.cfg tokens failed %d\n", + private->size); + kfree(mixer); + return ret; + } + + sof_dbg_comp_config(scomp, &mixer->config); + + swidget->private = mixer; + + ret = sof_ipc_tx_message(sdev->ipc, mixer->comp.hdr.cmd, mixer, + sizeof(*mixer), r, sizeof(*r)); + if (ret < 0) + kfree(mixer); + + return ret; +} + +/* + * Mux topology + */ +static int sof_widget_load_mux(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_mux *mux; + int ret; + + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return -ENOMEM; + + /* configure mux IPC message */ + mux->comp.hdr.size = sizeof(*mux); + mux->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + mux->comp.id = swidget->comp_id; + mux->comp.type = SOF_COMP_MUX; + mux->comp.pipeline_id = index; + mux->config.hdr.size = sizeof(mux->config); + + ret = sof_parse_tokens(scomp, &mux->config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse mux.cfg tokens failed %d\n", + private->size); + kfree(mux); + return ret; + } + + sof_dbg_comp_config(scomp, &mux->config); + + swidget->private = mux; + + ret = sof_ipc_tx_message(sdev->ipc, mux->comp.hdr.cmd, mux, + sizeof(*mux), r, sizeof(*r)); + if (ret < 0) + kfree(mux); + + return ret; +} + +/* + * PGA Topology + */ + +static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_volume *volume; + int ret; + + volume = kzalloc(sizeof(*volume), GFP_KERNEL); + if (!volume) + return -ENOMEM; + + if (le32_to_cpu(tw->num_kcontrols) != 1) { + dev_err(sdev->dev, "error: invalid kcontrol count %d for volume\n", + tw->num_kcontrols); + ret = -EINVAL; + goto err; + } + + /* configure volume IPC message */ + volume->comp.hdr.size = sizeof(*volume); + volume->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + volume->comp.id = swidget->comp_id; + volume->comp.type = SOF_COMP_VOLUME; + volume->comp.pipeline_id = index; + volume->config.hdr.size = sizeof(volume->config); + + ret = sof_parse_tokens(scomp, volume, volume_tokens, + ARRAY_SIZE(volume_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse volume tokens failed %d\n", + private->size); + goto err; + } + ret = sof_parse_tokens(scomp, &volume->config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse volume.cfg tokens failed %d\n", + le32_to_cpu(private->size)); + goto err; + } + + sof_dbg_comp_config(scomp, &volume->config); + + swidget->private = volume; + + ret = sof_ipc_tx_message(sdev->ipc, volume->comp.hdr.cmd, volume, + sizeof(*volume), r, sizeof(*r)); + if (ret >= 0) + return ret; +err: + kfree(volume); + return ret; +} + +/* + * SRC Topology + */ + +static int sof_widget_load_src(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_src *src; + int ret; + + src = kzalloc(sizeof(*src), GFP_KERNEL); + if (!src) + return -ENOMEM; + + /* configure src IPC message */ + src->comp.hdr.size = sizeof(*src); + src->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + src->comp.id = swidget->comp_id; + src->comp.type = SOF_COMP_SRC; + src->comp.pipeline_id = index; + src->config.hdr.size = sizeof(src->config); + + ret = sof_parse_tokens(scomp, src, src_tokens, + ARRAY_SIZE(src_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse src tokens failed %d\n", + private->size); + goto err; + } + + ret = sof_parse_tokens(scomp, &src->config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse src.cfg tokens failed %d\n", + le32_to_cpu(private->size)); + goto err; + } + + dev_dbg(sdev->dev, "src %s: source rate %d sink rate %d\n", + swidget->widget->name, src->source_rate, src->sink_rate); + sof_dbg_comp_config(scomp, &src->config); + + swidget->private = src; + + ret = sof_ipc_tx_message(sdev->ipc, src->comp.hdr.cmd, src, + sizeof(*src), r, sizeof(*r)); + if (ret >= 0) + return ret; +err: + kfree(src); + return ret; +} + +/* + * Signal Generator Topology + */ + +static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_tone *tone; + int ret; + + tone = kzalloc(sizeof(*tone), GFP_KERNEL); + if (!tone) + return -ENOMEM; + + /* configure siggen IPC message */ + tone->comp.hdr.size = sizeof(*tone); + tone->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + tone->comp.id = swidget->comp_id; + tone->comp.type = SOF_COMP_TONE; + tone->comp.pipeline_id = index; + tone->config.hdr.size = sizeof(tone->config); + + ret = sof_parse_tokens(scomp, tone, tone_tokens, + ARRAY_SIZE(tone_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse tone tokens failed %d\n", + le32_to_cpu(private->size)); + goto err; + } + + ret = sof_parse_tokens(scomp, &tone->config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse tone.cfg tokens failed %d\n", + le32_to_cpu(private->size)); + goto err; + } + + dev_dbg(sdev->dev, "tone %s: frequency %d amplitude %d\n", + swidget->widget->name, tone->frequency, tone->amplitude); + sof_dbg_comp_config(scomp, &tone->config); + + swidget->private = tone; + + ret = sof_ipc_tx_message(sdev->ipc, tone->comp.hdr.cmd, tone, + sizeof(*tone), r, sizeof(*r)); + if (ret >= 0) + return ret; +err: + kfree(tone); + return ret; +} + +static int sof_process_load(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r, + int type) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct snd_soc_dapm_widget *widget = swidget->widget; + const struct snd_kcontrol_new *kc; + struct soc_bytes_ext *sbe; + struct soc_mixer_control *sm; + struct soc_enum *se; + struct snd_sof_control *scontrol = NULL; + struct sof_abi_hdr *pdata = NULL; + struct sof_ipc_comp_process *process; + size_t ipc_size, ipc_data_size = 0; + int ret, i, offset = 0; + + if (type == SOF_COMP_NONE) { + dev_err(sdev->dev, "error: invalid process comp type %d\n", + type); + return -EINVAL; + } + + /* + * get possible component controls - get size of all pdata, + * then memcpy with headers + */ + for (i = 0; i < widget->num_kcontrols; i++) { + + kc = &widget->kcontrol_news[i]; + + switch (widget->dobj.widget.kcontrol_type) { + case SND_SOC_TPLG_TYPE_MIXER: + sm = (struct soc_mixer_control *)kc->private_value; + scontrol = sm->dobj.private; + break; + case SND_SOC_TPLG_TYPE_BYTES: + sbe = (struct soc_bytes_ext *)kc->private_value; + scontrol = sbe->dobj.private; + break; + case SND_SOC_TPLG_TYPE_ENUM: + se = (struct soc_enum *)kc->private_value; + scontrol = se->dobj.private; + break; + default: + dev_err(sdev->dev, "error: unknown kcontrol type %d in widget %s\n", + widget->dobj.widget.kcontrol_type, + widget->name); + return -EINVAL; + } + + if (!scontrol) { + dev_err(sdev->dev, "error: no scontrol for widget %s\n", + widget->name); + return -EINVAL; + } + + /* don't include if no private data */ + pdata = scontrol->control_data->data; + if (!pdata) + continue; + + /* make sure data is valid - data can be updated at runtime */ + if (pdata->magic != SOF_ABI_MAGIC) + continue; + + ipc_data_size += pdata->size; + } + + ipc_size = sizeof(struct sof_ipc_comp_process) + + le32_to_cpu(private->size) + + ipc_data_size; + + process = kzalloc(ipc_size, GFP_KERNEL); + if (!process) + return -ENOMEM; + + /* configure iir IPC message */ + process->comp.hdr.size = ipc_size; + process->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + process->comp.id = swidget->comp_id; + process->comp.type = type; + process->comp.pipeline_id = index; + process->config.hdr.size = sizeof(process->config); + + ret = sof_parse_tokens(scomp, &process->config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse process.cfg tokens failed %d\n", + le32_to_cpu(private->size)); + goto err; + } + + sof_dbg_comp_config(scomp, &process->config); + + /* + * found private data in control, so copy it. + * get possible component controls - get size of all pdata, + * then memcpy with headers + */ + for (i = 0; i < widget->num_kcontrols; i++) { + kc = &widget->kcontrol_news[i]; + + switch (widget->dobj.widget.kcontrol_type) { + case SND_SOC_TPLG_TYPE_MIXER: + sm = (struct soc_mixer_control *)kc->private_value; + scontrol = sm->dobj.private; + break; + case SND_SOC_TPLG_TYPE_BYTES: + sbe = (struct soc_bytes_ext *)kc->private_value; + scontrol = sbe->dobj.private; + break; + case SND_SOC_TPLG_TYPE_ENUM: + se = (struct soc_enum *)kc->private_value; + scontrol = se->dobj.private; + break; + default: + dev_err(sdev->dev, "error: unknown kcontrol type %d in widget %s\n", + widget->dobj.widget.kcontrol_type, + widget->name); + return -EINVAL; + } + + /* don't include if no private data */ + pdata = scontrol->control_data->data; + if (!pdata) + continue; + + /* make sure data is valid - data can be updated at runtime */ + if (pdata->magic != SOF_ABI_MAGIC) + continue; + + memcpy(&process->data + offset, pdata->data, pdata->size); + offset += pdata->size; + } + + process->size = ipc_data_size; + swidget->private = process; + + ret = sof_ipc_tx_message(sdev->ipc, process->comp.hdr.cmd, process, + ipc_size, r, sizeof(*r)); + if (ret >= 0) + return ret; +err: + kfree(process); + return ret; +} + +/* + * Processing Component Topology - can be "effect", "codec", or general + * "processing". + */ + +static int sof_widget_load_process(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_process config; + int ret; + + /* check we have some tokens - we need at least process type */ + if (le32_to_cpu(private->size) == 0) { + dev_err(sdev->dev, "error: process tokens not found\n"); + return -EINVAL; + } + + memset(&config, 0, sizeof(config)); + + /* get the process token */ + ret = sof_parse_tokens(scomp, &config, process_tokens, + ARRAY_SIZE(process_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse process tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + + /* now load process specific data and send IPC */ + ret = sof_process_load(scomp, index, swidget, tw, r, + find_process_comp_type(config.type)); + if (ret < 0) { + dev_err(sdev->dev, "error: process loading failed\n"); + return ret; + } + + return 0; +} + +static int sof_widget_bind_event(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget, + u16 event_type) +{ + struct sof_ipc_comp *ipc_comp; + + /* validate widget event type */ + switch (event_type) { + case SOF_KEYWORD_DETECT_DAPM_EVENT: + /* only KEYWORD_DETECT comps should handle this */ + if (swidget->id != snd_soc_dapm_effect) + break; + + ipc_comp = swidget->private; + if (ipc_comp && ipc_comp->type != SOF_COMP_KEYWORD_DETECT) + break; + + /* bind event to keyword detect comp */ + return snd_soc_tplg_widget_bind_event(swidget->widget, + sof_kwd_events, + ARRAY_SIZE(sof_kwd_events), + event_type); + default: + break; + } + + dev_err(sdev->dev, + "error: invalid event type %d for widget %s\n", + event_type, swidget->widget->name); + return -EINVAL; +} + +/* external widget init - used for any driver specific init */ +static int sof_widget_ready(struct snd_soc_component *scomp, int index, + struct snd_soc_dapm_widget *w, + struct snd_soc_tplg_dapm_widget *tw) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_widget *swidget; + struct snd_sof_dai *dai; + struct sof_ipc_comp_reply reply; + struct snd_sof_control *scontrol; + int ret = 0; + + swidget = kzalloc(sizeof(*swidget), GFP_KERNEL); + if (!swidget) + return -ENOMEM; + + swidget->sdev = sdev; + swidget->widget = w; + swidget->comp_id = sdev->next_comp_id++; + swidget->complete = 0; + swidget->id = w->id; + swidget->pipeline_id = index; + swidget->private = NULL; + memset(&reply, 0, sizeof(reply)); + + dev_dbg(sdev->dev, "tplg: ready widget id %d pipe %d type %d name : %s stream %s\n", + swidget->comp_id, index, swidget->id, tw->name, + strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 + ? tw->sname : "none"); + + /* handle any special case widgets */ + switch (w->id) { + case snd_soc_dapm_dai_in: + case snd_soc_dapm_dai_out: + dai = kzalloc(sizeof(*dai), GFP_KERNEL); + if (!dai) { + kfree(swidget); + return -ENOMEM; + } + + ret = sof_widget_load_dai(scomp, index, swidget, tw, &reply, + dai); + if (ret == 0) { + sof_connect_dai_widget(scomp, w, tw, dai); + list_add(&dai->list, &sdev->dai_list); + swidget->private = dai; + } else { + kfree(dai); + } + break; + case snd_soc_dapm_mixer: + ret = sof_widget_load_mixer(scomp, index, swidget, tw, &reply); + break; + case snd_soc_dapm_pga: + ret = sof_widget_load_pga(scomp, index, swidget, tw, &reply); + /* Find scontrol for this pga and set readback offset*/ + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + if (scontrol->comp_id == swidget->comp_id) { + scontrol->readback_offset = reply.offset; + break; + } + } + break; + case snd_soc_dapm_buffer: + ret = sof_widget_load_buffer(scomp, index, swidget, tw, &reply); + break; + case snd_soc_dapm_scheduler: + ret = sof_widget_load_pipeline(scomp, index, swidget, tw, + &reply); + break; + case snd_soc_dapm_aif_out: + ret = sof_widget_load_pcm(scomp, index, swidget, + SOF_IPC_STREAM_CAPTURE, tw, &reply); + break; + case snd_soc_dapm_aif_in: + ret = sof_widget_load_pcm(scomp, index, swidget, + SOF_IPC_STREAM_PLAYBACK, tw, &reply); + break; + case snd_soc_dapm_src: + ret = sof_widget_load_src(scomp, index, swidget, tw, &reply); + break; + case snd_soc_dapm_siggen: + ret = sof_widget_load_siggen(scomp, index, swidget, tw, &reply); + break; + case snd_soc_dapm_effect: + ret = sof_widget_load_process(scomp, index, swidget, tw, + &reply); + break; + case snd_soc_dapm_mux: + case snd_soc_dapm_demux: + ret = sof_widget_load_mux(scomp, index, swidget, tw, &reply); + break; + case snd_soc_dapm_switch: + case snd_soc_dapm_dai_link: + case snd_soc_dapm_kcontrol: + default: + dev_warn(sdev->dev, "warning: widget type %d name %s not handled\n", + swidget->id, tw->name); + break; + } + + /* check IPC reply */ + if (ret < 0 || reply.rhdr.error < 0) { + dev_err(sdev->dev, + "error: DSP failed to add widget id %d type %d name : %s stream %s reply %d\n", + tw->shift, swidget->id, tw->name, + strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 + ? tw->sname : "none", reply.rhdr.error); + kfree(swidget); + return ret; + } + + /* bind widget to external event */ + if (tw->event_type) { + ret = sof_widget_bind_event(sdev, swidget, + le16_to_cpu(tw->event_type)); + if (ret) { + dev_err(sdev->dev, "error: widget event binding failed\n"); + kfree(swidget->private); + kfree(swidget); + return ret; + } + } + + w->dobj.private = swidget; + list_add(&swidget->list, &sdev->widget_list); + return ret; +} + +static int sof_route_unload(struct snd_soc_component *scomp, + struct snd_soc_dobj *dobj) +{ + struct snd_sof_route *sroute; + + sroute = dobj->private; + if (!sroute) + return 0; + + /* free sroute and its private data */ + kfree(sroute->private); + list_del(&sroute->list); + kfree(sroute); + + return 0; +} + +static int sof_widget_unload(struct snd_soc_component *scomp, + struct snd_soc_dobj *dobj) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct snd_kcontrol_new *kc; + struct snd_soc_dapm_widget *widget; + struct sof_ipc_pipe_new *pipeline; + struct snd_sof_control *scontrol; + struct snd_sof_widget *swidget; + struct soc_mixer_control *sm; + struct soc_bytes_ext *sbe; + struct snd_sof_dai *dai; + struct soc_enum *se; + int ret = 0; + int i; + + swidget = dobj->private; + if (!swidget) + return 0; + + widget = swidget->widget; + + switch (swidget->id) { + case snd_soc_dapm_dai_in: + case snd_soc_dapm_dai_out: + dai = swidget->private; + + if (dai) { + /* free dai config */ + kfree(dai->dai_config); + list_del(&dai->list); + } + break; + case snd_soc_dapm_scheduler: + + /* power down the pipeline schedule core */ + pipeline = swidget->private; + ret = snd_sof_dsp_core_power_down(sdev, 1 << pipeline->core); + if (ret < 0) + dev_err(sdev->dev, "error: powering down pipeline schedule core %d\n", + pipeline->core); + + /* update enabled cores mask */ + sdev->enabled_cores_mask &= ~(1 << pipeline->core); + + break; + default: + break; + } + for (i = 0; i < widget->num_kcontrols; i++) { + kc = &widget->kcontrol_news[i]; + switch (dobj->widget.kcontrol_type) { + case SND_SOC_TPLG_TYPE_MIXER: + sm = (struct soc_mixer_control *)kc->private_value; + scontrol = sm->dobj.private; + if (sm->max > 1) + kfree(scontrol->volume_table); + break; + case SND_SOC_TPLG_TYPE_ENUM: + se = (struct soc_enum *)kc->private_value; + scontrol = se->dobj.private; + break; + case SND_SOC_TPLG_TYPE_BYTES: + sbe = (struct soc_bytes_ext *)kc->private_value; + scontrol = sbe->dobj.private; + break; + default: + dev_warn(sdev->dev, "unsupported kcontrol_type\n"); + goto out; + } + kfree(scontrol->control_data); + list_del(&scontrol->list); + kfree(scontrol); + } + +out: + /* free private value */ + kfree(swidget->private); + + /* remove and free swidget object */ + list_del(&swidget->list); + kfree(swidget); + + return ret; +} + +/* + * DAI HW configuration. + */ + +/* FE DAI - used for any driver specific init */ +static int sof_dai_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_driver *dai_drv, + struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_stream_caps *caps; + struct snd_sof_pcm *spcm; + int stream = SNDRV_PCM_STREAM_PLAYBACK; + int ret = 0; + + /* nothing to do for BEs atm */ + if (!pcm) + return 0; + + spcm = kzalloc(sizeof(*spcm), GFP_KERNEL); + if (!spcm) + return -ENOMEM; + + spcm->sdev = sdev; + spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id = COMP_ID_UNASSIGNED; + spcm->stream[SNDRV_PCM_STREAM_CAPTURE].comp_id = COMP_ID_UNASSIGNED; + + if (pcm) { + spcm->pcm = *pcm; + dev_dbg(sdev->dev, "tplg: load pcm %s\n", pcm->dai_name); + } + dai_drv->dobj.private = spcm; + list_add(&spcm->list, &sdev->pcm_list); + + /* do we need to allocate playback PCM DMA pages */ + if (!spcm->pcm.playback) + goto capture; + + caps = &spcm->pcm.caps[stream]; + + /* allocate playback page table buffer */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev, + PAGE_SIZE, &spcm->stream[stream].page_table); + if (ret < 0) { + dev_err(sdev->dev, "error: can't alloc page table for %s %d\n", + caps->name, ret); + + return ret; + } + + /* bind pcm to host comp */ + ret = spcm_bind(sdev, spcm, stream); + if (ret) { + dev_err(sdev->dev, + "error: can't bind pcm to host\n"); + goto free_playback_tables; + } + +capture: + stream = SNDRV_PCM_STREAM_CAPTURE; + + /* do we need to allocate capture PCM DMA pages */ + if (!spcm->pcm.capture) + return ret; + + caps = &spcm->pcm.caps[stream]; + + /* allocate capture page table buffer */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev, + PAGE_SIZE, &spcm->stream[stream].page_table); + if (ret < 0) { + dev_err(sdev->dev, "error: can't alloc page table for %s %d\n", + caps->name, ret); + goto free_playback_tables; + } + + /* bind pcm to host comp */ + ret = spcm_bind(sdev, spcm, stream); + if (ret) { + dev_err(sdev->dev, + "error: can't bind pcm to host\n"); + snd_dma_free_pages(&spcm->stream[stream].page_table); + goto free_playback_tables; + } + + return ret; + +free_playback_tables: + if (spcm->pcm.playback) + snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].page_table); + + return ret; +} + +static int sof_dai_unload(struct snd_soc_component *scomp, + struct snd_soc_dobj *dobj) +{ + struct snd_sof_pcm *spcm = dobj->private; + + /* free PCM DMA pages */ + if (spcm->pcm.playback) + snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].page_table); + + if (spcm->pcm.capture) + snd_dma_free_pages(&spcm->stream[SNDRV_PCM_STREAM_CAPTURE].page_table); + + /* remove from list and free spcm */ + list_del(&spcm->list); + kfree(spcm); + + return 0; +} + +static void sof_dai_set_format(struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + /* clock directions wrt codec */ + if (hw_config->bclk_master == SND_SOC_TPLG_BCLK_CM) { + /* codec is bclk master */ + if (hw_config->fsync_master == SND_SOC_TPLG_FSYNC_CM) + config->format |= SOF_DAI_FMT_CBM_CFM; + else + config->format |= SOF_DAI_FMT_CBM_CFS; + } else { + /* codec is bclk slave */ + if (hw_config->fsync_master == SND_SOC_TPLG_FSYNC_CM) + config->format |= SOF_DAI_FMT_CBS_CFM; + else + config->format |= SOF_DAI_FMT_CBS_CFS; + } + + /* inverted clocks ? */ + if (hw_config->invert_bclk) { + if (hw_config->invert_fsync) + config->format |= SOF_DAI_FMT_IB_IF; + else + config->format |= SOF_DAI_FMT_IB_NF; + } else { + if (hw_config->invert_fsync) + config->format |= SOF_DAI_FMT_NB_IF; + else + config->format |= SOF_DAI_FMT_NB_NF; + } +} + +/* set config for all DAI's with name matching the link name */ +static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size, + struct snd_soc_dai_link *link, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dai *dai; + int found = 0; + + list_for_each_entry(dai, &sdev->dai_list, list) { + if (!dai->name) + continue; + + if (strcmp(link->name, dai->name) == 0) { + dai->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!dai->dai_config) + return -ENOMEM; + + found = 1; + } + } + + /* + * machine driver may define a dai link with playback and capture + * dai enabled, but the dai link in topology would support both, one + * or none of them. Here print a warning message to notify user + */ + if (!found) { + dev_warn(sdev->dev, "warning: failed to find dai for dai link %s", + link->name); + } + + return 0; +} + +static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &cfg->priv; + struct sof_ipc_reply reply; + u32 size = sizeof(*config); + int ret; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->ssp, 0, sizeof(struct sof_ipc_dai_ssp_params)); + config->hdr.size = size; + + ret = sof_parse_tokens(scomp, &config->ssp, ssp_tokens, + ARRAY_SIZE(ssp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse ssp tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + + config->ssp.mclk_rate = le32_to_cpu(hw_config->mclk_rate); + config->ssp.bclk_rate = le32_to_cpu(hw_config->bclk_rate); + config->ssp.fsync_rate = le32_to_cpu(hw_config->fsync_rate); + config->ssp.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + config->ssp.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width); + config->ssp.mclk_direction = hw_config->mclk_direction; + config->ssp.rx_slots = le32_to_cpu(hw_config->rx_slots); + config->ssp.tx_slots = le32_to_cpu(hw_config->tx_slots); + + dev_dbg(sdev->dev, "tplg: config SSP%d fmt 0x%x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d quirks %d\n", + config->dai_index, config->format, + config->ssp.mclk_rate, config->ssp.bclk_rate, + config->ssp.fsync_rate, config->ssp.sample_valid_bits, + config->ssp.tdm_slot_width, config->ssp.tdm_slots, + config->ssp.mclk_id, config->ssp.quirks); + + /* validate SSP fsync rate and channel count */ + if (config->ssp.fsync_rate < 8000 || config->ssp.fsync_rate > 192000) { + dev_err(sdev->dev, "error: invalid fsync rate for SSP%d\n", + config->dai_index); + return -EINVAL; + } + + if (config->ssp.tdm_slots < 1 || config->ssp.tdm_slots > 8) { + dev_err(sdev->dev, "error: invalid channel count for SSP%d\n", + config->dai_index); + return -EINVAL; + } + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + config->hdr.cmd, config, size, &reply, + sizeof(reply)); + + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DAI config for SSP%d\n", + config->dai_index); + return ret; + } + + /* set config for all DAI's with name matching the link name */ + ret = sof_set_dai_config(sdev, size, link, config); + if (ret < 0) + dev_err(sdev->dev, "error: failed to save DAI config for SSP%d\n", + config->dai_index); + + return ret; +} + +static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &cfg->priv; + struct sof_ipc_dai_config *ipc_config; + struct sof_ipc_reply reply; + struct sof_ipc_fw_ready *ready = &sdev->fw_ready; + struct sof_ipc_fw_version *v = &ready->version; + u32 size; + int ret, j; + + /* + * config is only used for the common params in dmic_params structure + * that does not include the PDM controller config array + * Set the common params to 0. + */ + memset(&config->dmic, 0, sizeof(struct sof_ipc_dai_dmic_params)); + + /* get DMIC tokens */ + ret = sof_parse_tokens(scomp, &config->dmic, dmic_tokens, + ARRAY_SIZE(dmic_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse dmic tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + + /* + * allocate memory for dmic dai config accounting for the + * variable number of active pdm controllers + * This will be the ipc payload for setting dai config + */ + size = sizeof(*config) + sizeof(struct sof_ipc_dai_dmic_pdm_ctrl) * + config->dmic.num_pdm_active; + + ipc_config = kzalloc(size, GFP_KERNEL); + if (!ipc_config) + return -ENOMEM; + + /* copy the common dai config and dmic params */ + memcpy(ipc_config, config, sizeof(*config)); + + /* + * alloc memory for private member + * Used to track the pdm config array index currently being parsed + */ + sdev->private = kzalloc(sizeof(u32), GFP_KERNEL); + if (!sdev->private) { + kfree(ipc_config); + return -ENOMEM; + } + + /* get DMIC PDM tokens */ + ret = sof_parse_tokens(scomp, &ipc_config->dmic.pdm[0], dmic_pdm_tokens, + ARRAY_SIZE(dmic_pdm_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse dmic pdm tokens failed %d\n", + le32_to_cpu(private->size)); + goto err; + } + + /* set IPC header size */ + ipc_config->hdr.size = size; + + /* debug messages */ + dev_dbg(sdev->dev, "tplg: config DMIC%d driver version %d\n", + ipc_config->dai_index, ipc_config->dmic.driver_ipc_version); + dev_dbg(sdev->dev, "pdmclk_min %d pdm_clkmax %d duty_min %hd\n", + ipc_config->dmic.pdmclk_min, ipc_config->dmic.pdmclk_max, + ipc_config->dmic.duty_min); + dev_dbg(sdev->dev, "duty_max %hd fifo_fs %d num_pdms active %d\n", + ipc_config->dmic.duty_max, ipc_config->dmic.fifo_fs, + ipc_config->dmic.num_pdm_active); + dev_dbg(sdev->dev, "fifo word length %hd\n", + ipc_config->dmic.fifo_bits); + + for (j = 0; j < ipc_config->dmic.num_pdm_active; j++) { + dev_dbg(sdev->dev, "pdm %hd mic a %hd mic b %hd\n", + ipc_config->dmic.pdm[j].id, + ipc_config->dmic.pdm[j].enable_mic_a, + ipc_config->dmic.pdm[j].enable_mic_b); + dev_dbg(sdev->dev, "pdm %hd polarity a %hd polarity b %hd\n", + ipc_config->dmic.pdm[j].id, + ipc_config->dmic.pdm[j].polarity_mic_a, + ipc_config->dmic.pdm[j].polarity_mic_b); + dev_dbg(sdev->dev, "pdm %hd clk_edge %hd skew %hd\n", + ipc_config->dmic.pdm[j].id, + ipc_config->dmic.pdm[j].clk_edge, + ipc_config->dmic.pdm[j].skew); + } + + if (SOF_ABI_VER(v->major, v->minor, v->micro) < SOF_ABI_VER(3, 0, 1)) { + /* this takes care of backwards compatible handling of fifo_bits_b */ + ipc_config->dmic.reserved_2 = ipc_config->dmic.fifo_bits; + } + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + ipc_config->hdr.cmd, ipc_config, size, &reply, + sizeof(reply)); + + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to set DAI config for DMIC%d\n", + config->dai_index); + goto err; + } + + /* set config for all DAI's with name matching the link name */ + ret = sof_set_dai_config(sdev, size, link, ipc_config); + if (ret < 0) + dev_err(sdev->dev, "error: failed to save DAI config for DMIC%d\n", + config->dai_index); + +err: + kfree(sdev->private); + kfree(ipc_config); + + return ret; +} + +/* + * for hda link, playback and capture are supported by different dai + * in FW. Here get the dai_index, set dma channel of each dai + * and send config to FW. In FW, each dai sets config by dai_index + */ +static int sof_link_hda_process(struct snd_sof_dev *sdev, + struct snd_soc_dai_link *link, + struct sof_ipc_dai_config *config, + int tx_slot, + int rx_slot) +{ + struct sof_ipc_reply reply; + u32 size = sizeof(*config); + struct snd_sof_dai *sof_dai; + int found = 0; + int ret; + + list_for_each_entry(sof_dai, &sdev->dai_list, list) { + if (!sof_dai->name) + continue; + + if (strcmp(link->name, sof_dai->name) == 0) { + if (sof_dai->comp_dai.direction == + SNDRV_PCM_STREAM_PLAYBACK) { + if (!link->dpcm_playback) + return -EINVAL; + + config->hda.link_dma_ch = tx_slot; + } else { + if (!link->dpcm_capture) + return -EINVAL; + + config->hda.link_dma_ch = rx_slot; + } + + config->dai_index = sof_dai->comp_dai.dai_index; + found = 1; + + /* save config in dai component */ + sof_dai->dai_config = kmemdup(config, size, GFP_KERNEL); + if (!sof_dai->dai_config) + return -ENOMEM; + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + config->hdr.cmd, config, size, + &reply, sizeof(reply)); + + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DAI config for direction:%d of HDA dai %d\n", + sof_dai->comp_dai.direction, + config->dai_index); + + return ret; + } + } + } + + /* + * machine driver may define a dai link with playback and capture + * dai enabled, but the dai link in topology would support both, one + * or none of them. Here print a warning message to notify user + */ + if (!found) { + dev_warn(sdev->dev, "warning: failed to find dai for dai link %s", + link->name); + } + + return 0; +} + +static int sof_link_hda_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_dai_link_component dai_component; + struct snd_soc_tplg_private *private = &cfg->priv; + struct snd_soc_dai *dai; + u32 size = sizeof(*config); + u32 tx_num = 0; + u32 tx_slot = 0; + u32 rx_num = 0; + u32 rx_slot = 0; + int ret; + + /* init IPC */ + memset(&dai_component, 0, sizeof(dai_component)); + memset(&config->hda, 0, sizeof(struct sof_ipc_dai_hda_params)); + config->hdr.size = size; + + /* get any bespoke DAI tokens */ + ret = sof_parse_tokens(scomp, config, hda_tokens, + ARRAY_SIZE(hda_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse hda tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + + dai_component.dai_name = link->cpu_dai_name; + dai = snd_soc_find_dai(&dai_component); + if (!dai) { + dev_err(sdev->dev, "error: failed to find dai %s in %s", + dai_component.dai_name, __func__); + return -EINVAL; + } + + if (link->dpcm_playback) + tx_num = 1; + + if (link->dpcm_capture) + rx_num = 1; + + ret = snd_soc_dai_get_channel_map(dai, &tx_num, &tx_slot, + &rx_num, &rx_slot); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to get dma channel for HDA%d\n", + config->dai_index); + + return ret; + } + + ret = sof_link_hda_process(sdev, link, config, tx_slot, rx_slot); + if (ret < 0) + dev_err(sdev->dev, "error: failed to process hda dai link %s", + link->name); + + return ret; +} + +/* DAI link - used for any driver specific init */ +static int sof_link_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &cfg->priv; + struct sof_ipc_dai_config config; + struct snd_soc_tplg_hw_config *hw_config; + int num_hw_configs; + int ret; + int i = 0; + + link->platform_name = dev_name(sdev->dev); + + /* + * Set nonatomic property for FE dai links as their trigger action + * involves IPC's. + */ + if (!link->no_pcm) { + link->nonatomic = true; + + /* nothing more to do for FE dai links */ + return 0; + } + + /* check we have some tokens - we need at least DAI type */ + if (le32_to_cpu(private->size) == 0) { + dev_err(sdev->dev, "error: expected tokens for DAI, none found\n"); + return -EINVAL; + } + + /* Send BE DAI link configurations to DSP */ + memset(&config, 0, sizeof(config)); + + /* get any common DAI tokens */ + ret = sof_parse_tokens(scomp, &config, dai_link_tokens, + ARRAY_SIZE(dai_link_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse link tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + + /* + * DAI links are expected to have at least 1 hw_config. + * But some older topologies might have no hw_config for HDA dai links. + */ + num_hw_configs = le32_to_cpu(cfg->num_hw_configs); + if (!num_hw_configs) { + if (config.type != SOF_DAI_INTEL_HDA) { + dev_err(sdev->dev, "error: unexpected DAI config count %d!\n", + le32_to_cpu(cfg->num_hw_configs)); + return -EINVAL; + } + } else { + dev_dbg(sdev->dev, "tplg: %d hw_configs found, default id: %d!\n", + cfg->num_hw_configs, le32_to_cpu(cfg->default_hw_config_id)); + + for (i = 0; i < num_hw_configs; i++) { + if (cfg->hw_config[i].id == cfg->default_hw_config_id) + break; + } + + if (i == num_hw_configs) { + dev_err(sdev->dev, "error: default hw_config id: %d not found!\n", + le32_to_cpu(cfg->default_hw_config_id)); + return -EINVAL; + } + } + + /* configure dai IPC message */ + hw_config = &cfg->hw_config[i]; + + config.hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG; + config.format = le32_to_cpu(hw_config->fmt); + + /* now load DAI specific data and send IPC - type comes from token */ + switch (config.type) { + case SOF_DAI_INTEL_SSP: + ret = sof_link_ssp_load(scomp, index, link, cfg, hw_config, + &config); + break; + case SOF_DAI_INTEL_DMIC: + ret = sof_link_dmic_load(scomp, index, link, cfg, hw_config, + &config); + break; + case SOF_DAI_INTEL_HDA: + ret = sof_link_hda_load(scomp, index, link, cfg, hw_config, + &config); + break; + default: + dev_err(sdev->dev, "error: invalid DAI type %d\n", config.type); + ret = -EINVAL; + break; + } + if (ret < 0) + return ret; + + return 0; +} + +static int sof_link_hda_unload(struct snd_sof_dev *sdev, + struct snd_soc_dai_link *link) +{ + struct snd_soc_dai_link_component dai_component; + struct snd_soc_dai *dai; + int ret = 0; + + memset(&dai_component, 0, sizeof(dai_component)); + dai_component.dai_name = link->cpu_dai_name; + dai = snd_soc_find_dai(&dai_component); + if (!dai) { + dev_err(sdev->dev, "error: failed to find dai %s in %s", + dai_component.dai_name, __func__); + return -EINVAL; + } + + /* + * FIXME: this call to hw_free is mainly to release the link DMA ID. + * This is abusing the API and handling SOC internals is not + * recommended. This part will be reworked. + */ + if (dai->driver->ops->hw_free) + ret = dai->driver->ops->hw_free(NULL, dai); + if (ret < 0) + dev_err(sdev->dev, "error: failed to free hda resource for %s\n", + link->name); + + return ret; +} + +static int sof_link_unload(struct snd_soc_component *scomp, + struct snd_soc_dobj *dobj) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_dai_link *link = + container_of(dobj, struct snd_soc_dai_link, dobj); + + struct snd_sof_dai *sof_dai; + int ret = 0; + + /* only BE link is loaded by sof */ + if (!link->no_pcm) + return 0; + + list_for_each_entry(sof_dai, &sdev->dai_list, list) { + if (!sof_dai->name) + continue; + + if (strcmp(link->name, sof_dai->name) == 0) + goto found; + } + + dev_err(sdev->dev, "error: failed to find dai %s in %s", + link->name, __func__); + return -EINVAL; +found: + + switch (sof_dai->dai_config->type) { + case SOF_DAI_INTEL_SSP: + case SOF_DAI_INTEL_DMIC: + /* no resource needs to be released for SSP and DMIC */ + break; + case SOF_DAI_INTEL_HDA: + ret = sof_link_hda_unload(sdev, link); + break; + default: + dev_err(sdev->dev, "error: invalid DAI type %d\n", + sof_dai->dai_config->type); + ret = -EINVAL; + break; + } + + return ret; +} + +/* DAI link - used for any driver specific init */ +static int sof_route_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dapm_route *route) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc_pipe_comp_connect *connect; + struct snd_sof_widget *source_swidget, *sink_swidget; + struct snd_soc_dobj *dobj = &route->dobj; + struct snd_sof_route *sroute; + struct sof_ipc_reply reply; + int ret = 0; + + /* allocate memory for sroute and connect */ + sroute = kzalloc(sizeof(*sroute), GFP_KERNEL); + if (!sroute) + return -ENOMEM; + + sroute->sdev = sdev; + + connect = kzalloc(sizeof(*connect), GFP_KERNEL); + if (!connect) { + kfree(sroute); + return -ENOMEM; + } + + connect->hdr.size = sizeof(*connect); + connect->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_CONNECT; + + dev_dbg(sdev->dev, "sink %s control %s source %s\n", + route->sink, route->control ? route->control : "none", + route->source); + + /* source component */ + source_swidget = snd_sof_find_swidget(sdev, (char *)route->source); + if (!source_swidget) { + dev_err(sdev->dev, "error: source %s not found\n", + route->source); + ret = -EINVAL; + goto err; + } + + /* + * Virtual widgets of type output/out_drv may be added in topology + * for compatibility. These are not handled by the FW. + * So, don't send routes whose source/sink widget is of such types + * to the DSP. + */ + if (source_swidget->id == snd_soc_dapm_out_drv || + source_swidget->id == snd_soc_dapm_output) + goto err; + + connect->source_id = source_swidget->comp_id; + + /* sink component */ + sink_swidget = snd_sof_find_swidget(sdev, (char *)route->sink); + if (!sink_swidget) { + dev_err(sdev->dev, "error: sink %s not found\n", + route->sink); + ret = -EINVAL; + goto err; + } + + /* + * Don't send routes whose sink widget is of type + * output or out_drv to the DSP + */ + if (sink_swidget->id == snd_soc_dapm_out_drv || + sink_swidget->id == snd_soc_dapm_output) + goto err; + + connect->sink_id = sink_swidget->comp_id; + + /* + * For virtual routes, both sink and source are not + * buffer. Since only buffer linked to component is supported by + * FW, others are reported as error, add check in route function, + * do not send it to FW when both source and sink are not buffer + */ + if (source_swidget->id != snd_soc_dapm_buffer && + sink_swidget->id != snd_soc_dapm_buffer) { + dev_dbg(sdev->dev, "warning: neither Linked source component %s nor sink component %s is of buffer type, ignoring link\n", + route->source, route->sink); + ret = 0; + goto err; + } else { + ret = sof_ipc_tx_message(sdev->ipc, + connect->hdr.cmd, + connect, sizeof(*connect), + &reply, sizeof(reply)); + + /* check IPC return value */ + if (ret < 0) { + dev_err(sdev->dev, "error: failed to add route sink %s control %s source %s\n", + route->sink, + route->control ? route->control : "none", + route->source); + goto err; + } + + /* check IPC reply */ + if (reply.error < 0) { + dev_err(sdev->dev, "error: DSP failed to add route sink %s control %s source %s result %d\n", + route->sink, + route->control ? route->control : "none", + route->source, reply.error); + ret = reply.error; + goto err; + } + + sroute->route = route; + dobj->private = sroute; + sroute->private = connect; + + /* add route to route list */ + list_add(&sroute->list, &sdev->route_list); + + return ret; + } + +err: + kfree(connect); + kfree(sroute); + return ret; +} + +int snd_sof_complete_pipeline(struct snd_sof_dev *sdev, + struct snd_sof_widget *swidget) +{ + struct sof_ipc_pipe_ready ready; + struct sof_ipc_reply reply; + int ret; + + dev_dbg(sdev->dev, "tplg: complete pipeline %s id %d\n", + swidget->widget->name, swidget->comp_id); + + memset(&ready, 0, sizeof(ready)); + ready.hdr.size = sizeof(ready); + ready.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_PIPE_COMPLETE; + ready.comp_id = swidget->comp_id; + + ret = sof_ipc_tx_message(sdev->ipc, + ready.hdr.cmd, &ready, sizeof(ready), &reply, + sizeof(reply)); + if (ret < 0) + return ret; + return 1; +} + +/* completion - called at completion of firmware loading */ +static void sof_complete(struct snd_soc_component *scomp) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_widget *swidget; + + /* some widget types require completion notificattion */ + list_for_each_entry(swidget, &sdev->widget_list, list) { + if (swidget->complete) + continue; + + switch (swidget->id) { + case snd_soc_dapm_scheduler: + swidget->complete = + snd_sof_complete_pipeline(sdev, swidget); + break; + default: + break; + } + } +} + +/* manifest - optional to inform component of manifest */ +static int sof_manifest(struct snd_soc_component *scomp, int index, + struct snd_soc_tplg_manifest *man) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + u32 size; + + size = le32_to_cpu(man->priv.size); + + /* backward compatible with tplg without ABI info */ + if (!size) { + dev_dbg(sdev->dev, "No topology ABI info\n"); + return 0; + } + + if (size == SOF_TPLG_ABI_SIZE) { + dev_info(sdev->dev, + "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n", + man->priv.data[0], man->priv.data[1], + man->priv.data[2], SOF_ABI_MAJOR, SOF_ABI_MINOR, + SOF_ABI_PATCH); + if (SOF_ABI_VER(man->priv.data[0], man->priv.data[1], + man->priv.data[2]) <= SOF_ABI_VERSION) + return 0; + } + dev_err(sdev->dev, + "error: Incompatible ABI version %d:%d:%d\n", + man->priv.data[0], man->priv.data[1], man->priv.data[2]); + return -EINVAL; +} + +/* vendor specific kcontrol handlers available for binding */ +static const struct snd_soc_tplg_kcontrol_ops sof_io_ops[] = { + {SOF_TPLG_KCTL_VOL_ID, snd_sof_volume_get, snd_sof_volume_put}, + {SOF_TPLG_KCTL_BYTES_ID, snd_sof_bytes_get, snd_sof_bytes_put}, + {SOF_TPLG_KCTL_ENUM_ID, snd_sof_enum_get, snd_sof_enum_put}, + {SOF_TPLG_KCTL_SWITCH_ID, snd_sof_switch_get, snd_sof_switch_put}, +}; + +/* vendor specific bytes ext handlers available for binding */ +static const struct snd_soc_tplg_bytes_ext_ops sof_bytes_ext_ops[] = { + {SOF_TPLG_KCTL_BYTES_ID, snd_sof_bytes_ext_get, snd_sof_bytes_ext_put}, +}; + +static struct snd_soc_tplg_ops sof_tplg_ops = { + /* external kcontrol init - used for any driver specific init */ + .control_load = sof_control_load, + .control_unload = sof_control_unload, + + /* external kcontrol init - used for any driver specific init */ + .dapm_route_load = sof_route_load, + .dapm_route_unload = sof_route_unload, + + /* external widget init - used for any driver specific init */ + /* .widget_load is not currently used */ + .widget_ready = sof_widget_ready, + .widget_unload = sof_widget_unload, + + /* FE DAI - used for any driver specific init */ + .dai_load = sof_dai_load, + .dai_unload = sof_dai_unload, + + /* DAI link - used for any driver specific init */ + .link_load = sof_link_load, + .link_unload = sof_link_unload, + + /* completion - called at completion of firmware loading */ + .complete = sof_complete, + + /* manifest - optional to inform component of manifest */ + .manifest = sof_manifest, + + /* vendor specific kcontrol handlers available for binding */ + .io_ops = sof_io_ops, + .io_ops_count = ARRAY_SIZE(sof_io_ops), + + /* vendor specific bytes ext handlers available for binding */ + .bytes_ext_ops = sof_bytes_ext_ops, + .bytes_ext_ops_count = ARRAY_SIZE(sof_bytes_ext_ops), +}; + +int snd_sof_init_topology(struct snd_sof_dev *sdev, + struct snd_soc_tplg_ops *ops) +{ + /* TODO: support linked list of topologies */ + sdev->tplg_ops = ops; + return 0; +} +EXPORT_SYMBOL(snd_sof_init_topology); + +int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file) +{ + const struct firmware *fw; + int ret; + + dev_dbg(sdev->dev, "loading topology:%s\n", file); + + ret = request_firmware(&fw, file, sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "error: tplg request firmware %s failed err: %d\n", + file, ret); + return ret; + } + + ret = snd_soc_tplg_component_load(sdev->component, + &sof_tplg_ops, fw, + SND_SOC_TPLG_INDEX_ALL); + if (ret < 0) { + dev_err(sdev->dev, "error: tplg component load failed %d\n", + ret); + ret = -EINVAL; + } + + release_firmware(fw); + return ret; +} +EXPORT_SYMBOL(snd_sof_load_topology); From 59e4e8e04820ff65029c661a865198a7ccc9f94a Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:05:12 -0500 Subject: [PATCH 1396/1995] ASoC: SOF: Add DSP firmware logger support This patch adds support for real-time DSP logging (timestamped events and bespoke binary data) for firmware debug. The current solution relies on DMA transfers to system memory that is then accessed by userspace tools such as sof-logger. For Intel platforms, two types of DMAs are currently used (GP-DMA for Baytrail/CherryTrail and HDaudio DMA for SKL+) Due to historical reasons, the driver code follows the DSP firmware conventions and refers to 'traces', but it is currently unrelated to the Linux trace subsystem. Future solutions will include support for more advanced hardware (e.g. MIPI Sys-T), additional formats and the ability to enable/disable specific traces dynamically. Signed-off-by: Pan Xiuli Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit fd51c47b352b7da0e78fc88b9e4da7f298bfdd70) --- sound/soc/sof/trace.c | 297 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 sound/soc/sof/trace.c diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c new file mode 100644 index 00000000000000..d588e4b70fad3e --- /dev/null +++ b/sound/soc/sof/trace.c @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +#include +#include +#include "sof-priv.h" +#include "ops.h" + +static size_t sof_wait_trace_avail(struct snd_sof_dev *sdev, + loff_t pos, size_t buffer_size) +{ + wait_queue_entry_t wait; + loff_t host_offset = READ_ONCE(sdev->host_offset); + + /* + * If host offset is less than local pos, it means write pointer of + * host DMA buffer has been wrapped. We should output the trace data + * at the end of host DMA buffer at first. + */ + if (host_offset < pos) + return buffer_size - pos; + + /* If there is available trace data now, it is unnecessary to wait. */ + if (host_offset > pos) + return host_offset - pos; + + /* wait for available trace data from FW */ + init_waitqueue_entry(&wait, current); + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&sdev->trace_sleep, &wait); + + if (!signal_pending(current)) { + /* set timeout to max value, no error code */ + schedule_timeout(MAX_SCHEDULE_TIMEOUT); + } + remove_wait_queue(&sdev->trace_sleep, &wait); + + /* return bytes available for copy */ + host_offset = READ_ONCE(sdev->host_offset); + if (host_offset < pos) + return buffer_size - pos; + + return host_offset - pos; +} + +static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct snd_sof_dfsentry *dfse = file->private_data; + struct snd_sof_dev *sdev = dfse->sdev; + unsigned long rem; + loff_t lpos = *ppos; + size_t avail, buffer_size = dfse->size; + u64 lpos_64; + + /* make sure we know about any failures on the DSP side */ + sdev->dtrace_error = false; + + /* check pos and count */ + if (lpos < 0) + return -EINVAL; + if (!count) + return 0; + + /* check for buffer wrap and count overflow */ + lpos_64 = lpos; + lpos = do_div(lpos_64, buffer_size); + + if (count > buffer_size - lpos) /* min() not used to avoid sparse warnings */ + count = buffer_size - lpos; + + /* get available count based on current host offset */ + avail = sof_wait_trace_avail(sdev, lpos, buffer_size); + if (sdev->dtrace_error) { + dev_err(sdev->dev, "error: trace IO error\n"); + return -EIO; + } + + /* make sure count is <= avail */ + count = avail > count ? count : avail; + + /* copy available trace data to debugfs */ + rem = copy_to_user(buffer, ((u8 *)(dfse->buf) + lpos), count); + if (rem) + return -EFAULT; + + *ppos += count; + + /* move debugfs reading position */ + return count; +} + +static const struct file_operations sof_dfs_trace_fops = { + .open = simple_open, + .read = sof_dfsentry_trace_read, + .llseek = default_llseek, +}; + +static int trace_debugfs_create(struct snd_sof_dev *sdev) +{ + struct snd_sof_dfsentry *dfse; + + if (!sdev) + return -EINVAL; + + dfse = devm_kzalloc(sdev->dev, sizeof(*dfse), GFP_KERNEL); + if (!dfse) + return -ENOMEM; + + dfse->type = SOF_DFSENTRY_TYPE_BUF; + dfse->buf = sdev->dmatb.area; + dfse->size = sdev->dmatb.bytes; + dfse->sdev = sdev; + + dfse->dfsentry = debugfs_create_file("trace", 0444, sdev->debugfs_root, + dfse, &sof_dfs_trace_fops); + if (!dfse->dfsentry) { + /* can't rely on debugfs, only log error and keep going */ + dev_err(sdev->dev, + "error: cannot create debugfs entry for trace\n"); + } + + return 0; +} + +int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) +{ + struct sof_ipc_dma_trace_params params; + struct sof_ipc_reply ipc_reply; + int ret; + + if (sdev->dtrace_is_enabled || !sdev->dma_trace_pages) + return -EINVAL; + + /* set IPC parameters */ + params.hdr.size = sizeof(params); + params.hdr.cmd = SOF_IPC_GLB_TRACE_MSG | SOF_IPC_TRACE_DMA_PARAMS; + params.buffer.phy_addr = sdev->dmatp.addr; + params.buffer.size = sdev->dmatb.bytes; + params.buffer.pages = sdev->dma_trace_pages; + params.stream_tag = 0; + + sdev->host_offset = 0; + + ret = snd_sof_dma_trace_init(sdev, ¶ms.stream_tag); + if (ret < 0) { + dev_err(sdev->dev, + "error: fail in snd_sof_dma_trace_init %d\n", ret); + return ret; + } + dev_dbg(sdev->dev, "stream_tag: %d\n", params.stream_tag); + + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + params.hdr.cmd, ¶ms, sizeof(params), + &ipc_reply, sizeof(ipc_reply)); + if (ret < 0) { + dev_err(sdev->dev, + "error: can't set params for DMA for trace %d\n", ret); + goto trace_release; + } + + ret = snd_sof_dma_trace_trigger(sdev, SNDRV_PCM_TRIGGER_START); + if (ret < 0) { + dev_err(sdev->dev, + "error: snd_sof_dma_trace_trigger: start: %d\n", ret); + goto trace_release; + } + + sdev->dtrace_is_enabled = true; + + return 0; + +trace_release: + snd_sof_dma_trace_release(sdev); + return ret; +} + +int snd_sof_init_trace(struct snd_sof_dev *sdev) +{ + int ret; + + /* set false before start initialization */ + sdev->dtrace_is_enabled = false; + + /* allocate trace page table buffer */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev, + PAGE_SIZE, &sdev->dmatp); + if (ret < 0) { + dev_err(sdev->dev, + "error: can't alloc page table for trace %d\n", ret); + return ret; + } + + /* allocate trace data buffer */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, sdev->dev, + DMA_BUF_SIZE_FOR_TRACE, &sdev->dmatb); + if (ret < 0) { + dev_err(sdev->dev, + "error: can't alloc buffer for trace %d\n", ret); + goto page_err; + } + + /* create compressed page table for audio firmware */ + ret = snd_sof_create_page_table(sdev, &sdev->dmatb, sdev->dmatp.area, + sdev->dmatb.bytes); + if (ret < 0) + goto table_err; + + sdev->dma_trace_pages = ret; + dev_dbg(sdev->dev, "dma_trace_pages: %d\n", sdev->dma_trace_pages); + + if (sdev->first_boot) { + ret = trace_debugfs_create(sdev); + if (ret < 0) + goto table_err; + } + + init_waitqueue_head(&sdev->trace_sleep); + + ret = snd_sof_init_trace_ipc(sdev); + if (ret < 0) + goto table_err; + + return 0; +table_err: + sdev->dma_trace_pages = 0; + snd_dma_free_pages(&sdev->dmatb); +page_err: + snd_dma_free_pages(&sdev->dmatp); + return ret; +} +EXPORT_SYMBOL(snd_sof_init_trace); + +int snd_sof_trace_update_pos(struct snd_sof_dev *sdev, + struct sof_ipc_dma_trace_posn *posn) +{ + if (sdev->dtrace_is_enabled && sdev->host_offset != posn->host_offset) { + sdev->host_offset = posn->host_offset; + wake_up(&sdev->trace_sleep); + } + + if (posn->overflow != 0) + dev_err(sdev->dev, + "error: DSP trace buffer overflow %u bytes. Total messages %d\n", + posn->overflow, posn->messages); + + return 0; +} + +/* an error has occurred within the DSP that prevents further trace */ +void snd_sof_trace_notify_for_error(struct snd_sof_dev *sdev) +{ + if (sdev->dtrace_is_enabled) { + dev_err(sdev->dev, "error: waking up any trace sleepers\n"); + sdev->dtrace_error = true; + wake_up(&sdev->trace_sleep); + } +} +EXPORT_SYMBOL(snd_sof_trace_notify_for_error); + +void snd_sof_release_trace(struct snd_sof_dev *sdev) +{ + int ret; + + if (!sdev->dtrace_is_enabled) + return; + + ret = snd_sof_dma_trace_trigger(sdev, SNDRV_PCM_TRIGGER_STOP); + if (ret < 0) + dev_err(sdev->dev, + "error: snd_sof_dma_trace_trigger: stop: %d\n", ret); + + ret = snd_sof_dma_trace_release(sdev); + if (ret < 0) + dev_err(sdev->dev, + "error: fail in snd_sof_dma_trace_release %d\n", ret); + + sdev->dtrace_is_enabled = false; +} +EXPORT_SYMBOL(snd_sof_release_trace); + +void snd_sof_free_trace(struct snd_sof_dev *sdev) +{ + snd_sof_release_trace(sdev); + + snd_dma_free_pages(&sdev->dmatb); + snd_dma_free_pages(&sdev->dmatp); +} +EXPORT_SYMBOL(snd_sof_free_trace); From 891db3657de818bdfe0857548ac1e8343bb5265a Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:05:13 -0500 Subject: [PATCH 1397/1995] ASoC: SOF: Add DSP HW abstraction operations Add operation pointers that can be called by core to control a wide variety of DSP targets. The DSP HW drivers will fill in these operations. Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit d1d95fcb63e3b83245ad06484b6905ab6c21afc3) --- sound/soc/sof/ops.c | 163 ++++++++++++++++++ sound/soc/sof/ops.h | 399 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 562 insertions(+) create mode 100644 sound/soc/sof/ops.c create mode 100644 sound/soc/sof/ops.h diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c new file mode 100644 index 00000000000000..80f907740b82ce --- /dev/null +++ b/sound/soc/sof/ops.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +#include +#include "ops.h" + +static +bool snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset, + u32 mask, u32 value) +{ + struct pci_dev *pci = to_pci_dev(sdev->dev); + unsigned int old, new; + u32 ret; + + pci_read_config_dword(pci, offset, &ret); + old = ret; + dev_dbg(sdev->dev, "Debug PCIR: %8.8x at %8.8x\n", old & mask, offset); + + new = (old & ~mask) | (value & mask); + + if (old == new) + return false; + + pci_write_config_dword(pci, offset, new); + dev_dbg(sdev->dev, "Debug PCIW: %8.8x at %8.8x\n", value, + offset); + + return true; +} + +bool snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset, + u32 mask, u32 value) +{ + unsigned long flags; + bool change; + + spin_lock_irqsave(&sdev->hw_lock, flags); + change = snd_sof_pci_update_bits_unlocked(sdev, offset, mask, value); + spin_unlock_irqrestore(&sdev->hw_lock, flags); + return change; +} +EXPORT_SYMBOL(snd_sof_pci_update_bits); + +bool snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u32 mask, u32 value) +{ + unsigned int old, new; + u32 ret; + + ret = snd_sof_dsp_read(sdev, bar, offset); + + old = ret; + new = (old & ~mask) | (value & mask); + + if (old == new) + return false; + + snd_sof_dsp_write(sdev, bar, offset, new); + + return true; +} +EXPORT_SYMBOL(snd_sof_dsp_update_bits_unlocked); + +bool snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u64 mask, u64 value) +{ + u64 old, new; + + old = snd_sof_dsp_read64(sdev, bar, offset); + + new = (old & ~mask) | (value & mask); + + if (old == new) + return false; + + snd_sof_dsp_write64(sdev, bar, offset, new); + + return true; +} +EXPORT_SYMBOL(snd_sof_dsp_update_bits64_unlocked); + +/* This is for registers bits with attribute RWC */ +bool snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset, + u32 mask, u32 value) +{ + unsigned long flags; + bool change; + + spin_lock_irqsave(&sdev->hw_lock, flags); + change = snd_sof_dsp_update_bits_unlocked(sdev, bar, offset, mask, + value); + spin_unlock_irqrestore(&sdev->hw_lock, flags); + return change; +} +EXPORT_SYMBOL(snd_sof_dsp_update_bits); + +bool snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, u32 offset, + u64 mask, u64 value) +{ + unsigned long flags; + bool change; + + spin_lock_irqsave(&sdev->hw_lock, flags); + change = snd_sof_dsp_update_bits64_unlocked(sdev, bar, offset, mask, + value); + spin_unlock_irqrestore(&sdev->hw_lock, flags); + return change; +} +EXPORT_SYMBOL(snd_sof_dsp_update_bits64); + +static +void snd_sof_dsp_update_bits_forced_unlocked(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u32 mask, u32 value) +{ + unsigned int old, new; + u32 ret; + + ret = snd_sof_dsp_read(sdev, bar, offset); + + old = ret; + new = (old & ~mask) | (value & mask); + + snd_sof_dsp_write(sdev, bar, offset, new); +} + +/* This is for registers bits with attribute RWC */ +void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u32 mask, u32 value) +{ + unsigned long flags; + + spin_lock_irqsave(&sdev->hw_lock, flags); + snd_sof_dsp_update_bits_forced_unlocked(sdev, bar, offset, mask, value); + spin_unlock_irqrestore(&sdev->hw_lock, flags); +} +EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced); + +void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset) +{ + dev_err(sdev->dev, "error : DSP panic!\n"); + + /* + * check if DSP is not ready and did not set the dsp_oops_offset. + * if the dsp_oops_offset is not set, set it from the panic message. + * Also add a check to memory window setting with panic message. + */ + if (!sdev->dsp_oops_offset) + sdev->dsp_oops_offset = offset; + else + dev_dbg(sdev->dev, "panic: dsp_oops_offset %zu offset %d\n", + sdev->dsp_oops_offset, offset); + + snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX); + snd_sof_trace_notify_for_error(sdev); +} +EXPORT_SYMBOL(snd_sof_dsp_panic); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h new file mode 100644 index 00000000000000..2a5d4c63f160f8 --- /dev/null +++ b/sound/soc/sof/ops.h @@ -0,0 +1,399 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __SOUND_SOC_SOF_IO_H +#define __SOUND_SOC_SOF_IO_H + +#include +#include +#include +#include +#include +#include "sof-priv.h" + +#define sof_ops(sdev) \ + ((sdev)->pdata->desc->ops) + +/* Mandatory operations are verified during probing */ + +/* init */ +static inline int snd_sof_probe(struct snd_sof_dev *sdev) +{ + return sof_ops(sdev)->probe(sdev); +} + +static inline int snd_sof_remove(struct snd_sof_dev *sdev) +{ + if (sof_ops(sdev)->remove) + return sof_ops(sdev)->remove(sdev); + + return 0; +} + +/* control */ + +/* + * snd_sof_dsp_run returns the core mask of the cores that are available + * after successful fw boot + */ +static inline int snd_sof_dsp_run(struct snd_sof_dev *sdev) +{ + return sof_ops(sdev)->run(sdev); +} + +static inline int snd_sof_dsp_stall(struct snd_sof_dev *sdev) +{ + if (sof_ops(sdev)->stall) + return sof_ops(sdev)->stall(sdev); + + return 0; +} + +static inline int snd_sof_dsp_reset(struct snd_sof_dev *sdev) +{ + if (sof_ops(sdev)->reset) + return sof_ops(sdev)->reset(sdev); + + return 0; +} + +/* dsp core power up/power down */ +static inline int snd_sof_dsp_core_power_up(struct snd_sof_dev *sdev, + unsigned int core_mask) +{ + if (sof_ops(sdev)->core_power_up) + return sof_ops(sdev)->core_power_up(sdev, core_mask); + + return 0; +} + +static inline int snd_sof_dsp_core_power_down(struct snd_sof_dev *sdev, + unsigned int core_mask) +{ + if (sof_ops(sdev)->core_power_down) + return sof_ops(sdev)->core_power_down(sdev, core_mask); + + return 0; +} + +/* pre/post fw load */ +static inline int snd_sof_dsp_pre_fw_run(struct snd_sof_dev *sdev) +{ + if (sof_ops(sdev)->pre_fw_run) + return sof_ops(sdev)->pre_fw_run(sdev); + + return 0; +} + +static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev) +{ + if (sof_ops(sdev)->post_fw_run) + return sof_ops(sdev)->post_fw_run(sdev); + + return 0; +} + +/* power management */ +static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev) +{ + if (sof_ops(sdev)->resume) + return sof_ops(sdev)->resume(sdev); + + return 0; +} + +static inline int snd_sof_dsp_suspend(struct snd_sof_dev *sdev, int state) +{ + if (sof_ops(sdev)->suspend) + return sof_ops(sdev)->suspend(sdev, state); + + return 0; +} + +static inline int snd_sof_dsp_runtime_resume(struct snd_sof_dev *sdev) +{ + if (sof_ops(sdev)->runtime_resume) + return sof_ops(sdev)->runtime_resume(sdev); + + return 0; +} + +static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev, + int state) +{ + if (sof_ops(sdev)->runtime_suspend) + return sof_ops(sdev)->runtime_suspend(sdev, state); + + return 0; +} + +static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq) +{ + if (sof_ops(sdev)->set_clk) + return sof_ops(sdev)->set_clk(sdev, freq); + + return 0; +} + +/* debug */ +static inline void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, u32 flags) +{ + if (sof_ops(sdev)->dbg_dump) + return sof_ops(sdev)->dbg_dump(sdev, flags); +} + +/* register IO */ +static inline void snd_sof_dsp_write(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u32 value) +{ + if (sof_ops(sdev)->write) { + sof_ops(sdev)->write(sdev, sdev->bar[bar] + offset, value); + return; + } + + dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__); +} + +static inline void snd_sof_dsp_write64(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u64 value) +{ + if (sof_ops(sdev)->write64) { + sof_ops(sdev)->write64(sdev, sdev->bar[bar] + offset, value); + return; + } + + dev_err_ratelimited(sdev->dev, "error: %s not defined\n", __func__); +} + +static inline u32 snd_sof_dsp_read(struct snd_sof_dev *sdev, u32 bar, + u32 offset) +{ + if (sof_ops(sdev)->read) + return sof_ops(sdev)->read(sdev, sdev->bar[bar] + offset); + + dev_err(sdev->dev, "error: %s not defined\n", __func__); + return -ENOTSUPP; +} + +static inline u64 snd_sof_dsp_read64(struct snd_sof_dev *sdev, u32 bar, + u32 offset) +{ + if (sof_ops(sdev)->read64) + return sof_ops(sdev)->read64(sdev, sdev->bar[bar] + offset); + + dev_err(sdev->dev, "error: %s not defined\n", __func__); + return -ENOTSUPP; +} + +/* block IO */ +static inline void snd_sof_dsp_block_read(struct snd_sof_dev *sdev, u32 bar, + u32 offset, void *dest, size_t bytes) +{ + sof_ops(sdev)->block_read(sdev, bar, offset, dest, bytes); +} + +static inline void snd_sof_dsp_block_write(struct snd_sof_dev *sdev, u32 bar, + u32 offset, void *src, size_t bytes) +{ + sof_ops(sdev)->block_write(sdev, bar, offset, src, bytes); +} + +/* ipc */ +static inline int snd_sof_dsp_send_msg(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg) +{ + return sof_ops(sdev)->send_msg(sdev, msg); +} + +/* host DMA trace */ +static inline int snd_sof_dma_trace_init(struct snd_sof_dev *sdev, + u32 *stream_tag) +{ + if (sof_ops(sdev)->trace_init) + return sof_ops(sdev)->trace_init(sdev, stream_tag); + + return 0; +} + +static inline int snd_sof_dma_trace_release(struct snd_sof_dev *sdev) +{ + if (sof_ops(sdev)->trace_release) + return sof_ops(sdev)->trace_release(sdev); + + return 0; +} + +static inline int snd_sof_dma_trace_trigger(struct snd_sof_dev *sdev, int cmd) +{ + if (sof_ops(sdev)->trace_trigger) + return sof_ops(sdev)->trace_trigger(sdev, cmd); + + return 0; +} + +/* host PCM ops */ +static inline int +snd_sof_pcm_platform_open(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + if (sof_ops(sdev) && sof_ops(sdev)->pcm_open) + return sof_ops(sdev)->pcm_open(sdev, substream); + + return 0; +} + +/* disconnect pcm substream to a host stream */ +static inline int +snd_sof_pcm_platform_close(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + if (sof_ops(sdev) && sof_ops(sdev)->pcm_close) + return sof_ops(sdev)->pcm_close(sdev, substream); + + return 0; +} + +/* host stream hw params */ +static inline int +snd_sof_pcm_platform_hw_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct sof_ipc_stream_params *ipc_params) +{ + if (sof_ops(sdev) && sof_ops(sdev)->pcm_hw_params) + return sof_ops(sdev)->pcm_hw_params(sdev, substream, + params, ipc_params); + + return 0; +} + +/* host stream trigger */ +static inline int +snd_sof_pcm_platform_trigger(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, int cmd) +{ + if (sof_ops(sdev) && sof_ops(sdev)->pcm_trigger) + return sof_ops(sdev)->pcm_trigger(sdev, substream, cmd); + + return 0; +} + +/* host DSP message data */ +static inline void snd_sof_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz) +{ + sof_ops(sdev)->ipc_msg_data(sdev, substream, p, sz); +} + +/* host configure DSP HW parameters */ +static inline int +snd_sof_ipc_pcm_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply) +{ + return sof_ops(sdev)->ipc_pcm_params(sdev, substream, reply); +} + +/* host stream pointer */ +static inline snd_pcm_uframes_t +snd_sof_pcm_platform_pointer(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + if (sof_ops(sdev) && sof_ops(sdev)->pcm_pointer) + return sof_ops(sdev)->pcm_pointer(sdev, substream); + + return 0; +} + +static inline const struct snd_sof_dsp_ops +*sof_get_ops(const struct sof_dev_desc *d, + const struct sof_ops_table mach_ops[], int asize) +{ + int i; + + for (i = 0; i < asize; i++) { + if (d == mach_ops[i].desc) + return mach_ops[i].ops; + } + + /* not found */ + return NULL; +} + +/** + * snd_sof_dsp_register_poll_timeout - Periodically poll an address + * until a condition is met or a timeout occurs + * @op: accessor function (takes @addr as its only argument) + * @addr: Address to poll + * @val: Variable to read the value into + * @cond: Break condition (usually involving @val) + * @sleep_us: Maximum time to sleep between reads in us (0 + * tight-loops). Should be less than ~20ms since usleep_range + * is used (see Documentation/timers/timers-howto.txt). + * @timeout_us: Timeout in us, 0 means never timeout + * + * Returns 0 on success and -ETIMEDOUT upon a timeout. In either + * case, the last read value at @addr is stored in @val. Must not + * be called from atomic context if sleep_us or timeout_us are used. + * + * This is modelled after the readx_poll_timeout macros in linux/iopoll.h. + */ +#define snd_sof_dsp_read_poll_timeout(sdev, bar, offset, val, cond, sleep_us, timeout_us) \ +({ \ + u64 __timeout_us = (timeout_us); \ + unsigned long __sleep_us = (sleep_us); \ + ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \ + might_sleep_if((__sleep_us) != 0); \ + for (;;) { \ + (val) = snd_sof_dsp_read(sdev, bar, offset); \ + if (cond) { \ + dev_dbg(sdev->dev, \ + "FW Poll Status: reg=%#x successful\n", (val)); \ + break; \ + } \ + if (__timeout_us && \ + ktime_compare(ktime_get(), __timeout) > 0) { \ + (val) = snd_sof_dsp_read(sdev, bar, offset); \ + dev_dbg(sdev->dev, \ + "FW Poll Status: reg=%#x timedout\n", (val)); \ + break; \ + } \ + if (__sleep_us) \ + usleep_range((__sleep_us >> 2) + 1, __sleep_us); \ + } \ + (cond) ? 0 : -ETIMEDOUT; \ +}) + +/* This is for registers bits with attribute RWC */ +bool snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset, + u32 mask, u32 value); + +bool snd_sof_dsp_update_bits_unlocked(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u32 mask, u32 value); + +bool snd_sof_dsp_update_bits64_unlocked(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u64 mask, u64 value); + +bool snd_sof_dsp_update_bits(struct snd_sof_dev *sdev, u32 bar, u32 offset, + u32 mask, u32 value); + +bool snd_sof_dsp_update_bits64(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u64 mask, u64 value); + +void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar, + u32 offset, u32 mask, u32 value); + +int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset, + u32 mask, u32 target, u32 timeout_ms, + u32 interval_us); + +void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset); +#endif From 0bdf7e9184831afa566a7942f981ea7e040d7de1 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:05:14 -0500 Subject: [PATCH 1398/1995] ASoC: SOF: Add firmware loader support The firmware loader exports APIs that can be called by core to load and process multiple different file formats. Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 70cd52544b95d02f8b20fadccb7400ce68a2cb84) --- sound/soc/sof/loader.c | 400 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 400 insertions(+) create mode 100644 sound/soc/sof/loader.c diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c new file mode 100644 index 00000000000000..81c7452aae1718 --- /dev/null +++ b/sound/soc/sof/loader.c @@ -0,0 +1,400 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// +// Generic firmware loader. +// + +#include +#include +#include "ops.h" + +static int get_ext_windows(struct snd_sof_dev *sdev, + struct sof_ipc_ext_data_hdr *ext_hdr) +{ + struct sof_ipc_window *w = + container_of(ext_hdr, struct sof_ipc_window, ext_hdr); + size_t size; + + if (w->num_windows == 0 || w->num_windows > SOF_IPC_MAX_ELEMS) + return -EINVAL; + + size = sizeof(*w) + sizeof(struct sof_ipc_window_elem) * w->num_windows; + + /* keep a local copy of the data */ + sdev->info_window = kmemdup(w, size, GFP_KERNEL); + if (!sdev->info_window) + return -ENOMEM; + + return 0; +} + +/* parse the extended FW boot data structures from FW boot message */ +int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) +{ + struct sof_ipc_ext_data_hdr *ext_hdr; + void *ext_data; + int ret = 0; + + ext_data = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!ext_data) + return -ENOMEM; + + /* get first header */ + snd_sof_dsp_block_read(sdev, bar, offset, ext_data, + sizeof(*ext_hdr)); + ext_hdr = ext_data; + + while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) { + /* read in ext structure */ + offset += sizeof(*ext_hdr); + snd_sof_dsp_block_read(sdev, bar, offset, + (void *)((u8 *)ext_data + sizeof(*ext_hdr)), + ext_hdr->hdr.size - sizeof(*ext_hdr)); + + dev_dbg(sdev->dev, "found ext header type %d size 0x%x\n", + ext_hdr->type, ext_hdr->hdr.size); + + /* process structure data */ + switch (ext_hdr->type) { + case SOF_IPC_EXT_DMA_BUFFER: + break; + case SOF_IPC_EXT_WINDOW: + ret = get_ext_windows(sdev, ext_hdr); + break; + default: + break; + } + + if (ret < 0) { + dev_err(sdev->dev, "error: failed to parse ext data type %d\n", + ext_hdr->type); + break; + } + + /* move to next header */ + offset += ext_hdr->hdr.size; + snd_sof_dsp_block_read(sdev, bar, offset, ext_data, + sizeof(*ext_hdr)); + ext_hdr = ext_data; + } + + kfree(ext_data); + return ret; +} +EXPORT_SYMBOL(snd_sof_fw_parse_ext_data); + +/* generic module parser for mmaped DSPs */ +int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, + struct snd_sof_mod_hdr *module) +{ + struct snd_sof_blk_hdr *block; + int count; + u32 offset; + size_t remaining; + + dev_dbg(sdev->dev, "new module size 0x%x blocks 0x%x type 0x%x\n", + module->size, module->num_blocks, module->type); + + block = (struct snd_sof_blk_hdr *)((u8 *)module + sizeof(*module)); + + /* module->size doesn't include header size */ + remaining = module->size; + for (count = 0; count < module->num_blocks; count++) { + /* check for wrap */ + if (remaining < sizeof(*block)) { + dev_err(sdev->dev, "error: not enough data remaining\n"); + return -EINVAL; + } + + /* minus header size of block */ + remaining -= sizeof(*block); + + if (block->size == 0) { + dev_warn(sdev->dev, + "warning: block %d size zero\n", count); + dev_warn(sdev->dev, " type 0x%x offset 0x%x\n", + block->type, block->offset); + continue; + } + + switch (block->type) { + case SOF_FW_BLK_TYPE_RSRVD0: + case SOF_FW_BLK_TYPE_SRAM...SOF_FW_BLK_TYPE_RSRVD14: + continue; /* not handled atm */ + case SOF_FW_BLK_TYPE_IRAM: + case SOF_FW_BLK_TYPE_DRAM: + offset = block->offset; + break; + default: + dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n", + block->type, count); + return -EINVAL; + } + + dev_dbg(sdev->dev, + "block %d type 0x%x size 0x%x ==> offset 0x%x\n", + count, block->type, block->size, offset); + + /* checking block->size to avoid unaligned access */ + if (block->size % sizeof(u32)) { + dev_err(sdev->dev, "error: invalid block size 0x%x\n", + block->size); + return -EINVAL; + } + snd_sof_dsp_block_write(sdev, sdev->mmio_bar, offset, + block + 1, block->size); + + if (remaining < block->size) { + dev_err(sdev->dev, "error: not enough data remaining\n"); + return -EINVAL; + } + + /* minus body size of block */ + remaining -= block->size; + /* next block */ + block = (struct snd_sof_blk_hdr *)((u8 *)block + sizeof(*block) + + block->size); + } + + return 0; +} +EXPORT_SYMBOL(snd_sof_parse_module_memcpy); + +static int check_header(struct snd_sof_dev *sdev, const struct firmware *fw) +{ + struct snd_sof_fw_header *header; + + /* Read the header information from the data pointer */ + header = (struct snd_sof_fw_header *)fw->data; + + /* verify FW sig */ + if (strncmp(header->sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE) != 0) { + dev_err(sdev->dev, "error: invalid firmware signature\n"); + return -EINVAL; + } + + /* check size is valid */ + if (fw->size != header->file_size + sizeof(*header)) { + dev_err(sdev->dev, "error: invalid filesize mismatch got 0x%zx expected 0x%zx\n", + fw->size, header->file_size + sizeof(*header)); + return -EINVAL; + } + + dev_dbg(sdev->dev, "header size=0x%x modules=0x%x abi=0x%x size=%zu\n", + header->file_size, header->num_modules, + header->abi, sizeof(*header)); + + return 0; +} + +static int load_modules(struct snd_sof_dev *sdev, const struct firmware *fw) +{ + struct snd_sof_fw_header *header; + struct snd_sof_mod_hdr *module; + int (*load_module)(struct snd_sof_dev *sof_dev, + struct snd_sof_mod_hdr *hdr); + int ret, count; + size_t remaining; + + header = (struct snd_sof_fw_header *)fw->data; + load_module = sof_ops(sdev)->load_module; + if (!load_module) + return -EINVAL; + + /* parse each module */ + module = (struct snd_sof_mod_hdr *)((u8 *)(fw->data) + sizeof(*header)); + remaining = fw->size - sizeof(*header); + /* check for wrap */ + if (remaining > fw->size) { + dev_err(sdev->dev, "error: fw size smaller than header size\n"); + return -EINVAL; + } + + for (count = 0; count < header->num_modules; count++) { + /* check for wrap */ + if (remaining < sizeof(*module)) { + dev_err(sdev->dev, "error: not enough data remaining\n"); + return -EINVAL; + } + + /* minus header size of module */ + remaining -= sizeof(*module); + + /* module */ + ret = load_module(sdev, module); + if (ret < 0) { + dev_err(sdev->dev, "error: invalid module %d\n", count); + return ret; + } + + if (remaining < module->size) { + dev_err(sdev->dev, "error: not enough data remaining\n"); + return -EINVAL; + } + + /* minus body size of module */ + remaining -= module->size; + module = (struct snd_sof_mod_hdr *)((u8 *)module + + sizeof(*module) + module->size); + } + + return 0; +} + +int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + const char *fw_filename; + int ret; + + /* set code loading condition to true */ + sdev->code_loading = 1; + + /* Don't request firmware again if firmware is already requested */ + if (plat_data->fw) + return 0; + + fw_filename = kasprintf(GFP_KERNEL, "%s/%s", + plat_data->fw_filename_prefix, + plat_data->fw_filename); + if (!fw_filename) + return -ENOMEM; + + ret = request_firmware(&plat_data->fw, fw_filename, sdev->dev); + + if (ret < 0) { + dev_err(sdev->dev, "error: request firmware %s failed err: %d\n", + fw_filename, ret); + } + + kfree(fw_filename); + + return ret; +} +EXPORT_SYMBOL(snd_sof_load_firmware_raw); + +int snd_sof_load_firmware_memcpy(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + int ret; + + ret = snd_sof_load_firmware_raw(sdev); + if (ret < 0) + return ret; + + /* make sure the FW header and file is valid */ + ret = check_header(sdev, plat_data->fw); + if (ret < 0) { + dev_err(sdev->dev, "error: invalid FW header\n"); + goto error; + } + + /* prepare the DSP for FW loading */ + ret = snd_sof_dsp_reset(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to reset DSP\n"); + goto error; + } + + /* parse and load firmware modules to DSP */ + ret = load_modules(sdev, plat_data->fw); + if (ret < 0) { + dev_err(sdev->dev, "error: invalid FW modules\n"); + goto error; + } + + return 0; + +error: + release_firmware(plat_data->fw); + plat_data->fw = NULL; + return ret; + +} +EXPORT_SYMBOL(snd_sof_load_firmware_memcpy); + +int snd_sof_load_firmware(struct snd_sof_dev *sdev) +{ + dev_dbg(sdev->dev, "loading firmware\n"); + + if (sof_ops(sdev)->load_firmware) + return sof_ops(sdev)->load_firmware(sdev); + return 0; +} +EXPORT_SYMBOL(snd_sof_load_firmware); + +int snd_sof_run_firmware(struct snd_sof_dev *sdev) +{ + int ret; + int init_core_mask; + + init_waitqueue_head(&sdev->boot_wait); + sdev->boot_complete = false; + + /* create fw_version debugfs to store boot version info */ + if (sdev->first_boot) { + ret = snd_sof_debugfs_buf_item(sdev, &sdev->fw_version, + sizeof(sdev->fw_version), + "fw_version"); + /* errors are only due to memory allocation, not debugfs */ + if (ret < 0) { + dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n"); + return ret; + } + } + + /* perform pre fw run operations */ + ret = snd_sof_dsp_pre_fw_run(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed pre fw run op\n"); + return ret; + } + + dev_dbg(sdev->dev, "booting DSP firmware\n"); + + /* boot the firmware on the DSP */ + ret = snd_sof_dsp_run(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to reset DSP\n"); + return ret; + } + + init_core_mask = ret; + + /* now wait for the DSP to boot */ + ret = wait_event_timeout(sdev->boot_wait, sdev->boot_complete, + msecs_to_jiffies(sdev->boot_timeout)); + if (ret == 0) { + dev_err(sdev->dev, "error: firmware boot failure\n"); + snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX | + SOF_DBG_TEXT | SOF_DBG_PCI); + return -EIO; + } + + dev_info(sdev->dev, "firmware boot complete\n"); + + /* perform post fw run operations */ + ret = snd_sof_dsp_post_fw_run(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed post fw run op\n"); + return ret; + } + + /* fw boot is complete. Update the active cores mask */ + sdev->enabled_cores_mask = init_core_mask; + + return 0; +} +EXPORT_SYMBOL(snd_sof_run_firmware); + +void snd_sof_fw_unload(struct snd_sof_dev *sdev) +{ + /* TODO: support module unloading at runtime */ +} +EXPORT_SYMBOL(snd_sof_fw_unload); From 0db2ff1406ae4d96e16d6dbac26d8a01b72cc89e Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:05:15 -0500 Subject: [PATCH 1399/1995] ASoC: SOF: Add userspace ABI support Add userspace ABI for audio userspace application IO outside of regular ALSA PCM and kcontrols. This is intended to be used to format coefficients and data for custom processing components. Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 4483151e765b5a7ffb823fe9bb11128101410427) --- include/uapi/sound/sof/abi.h | 62 ++++++++++ include/uapi/sound/sof/eq.h | 172 +++++++++++++++++++++++++++ include/uapi/sound/sof/fw.h | 78 +++++++++++++ include/uapi/sound/sof/header.h | 27 +++++ include/uapi/sound/sof/manifest.h | 188 ++++++++++++++++++++++++++++++ include/uapi/sound/sof/tokens.h | 107 +++++++++++++++++ include/uapi/sound/sof/tone.h | 21 ++++ include/uapi/sound/sof/trace.h | 66 +++++++++++ 8 files changed, 721 insertions(+) create mode 100644 include/uapi/sound/sof/abi.h create mode 100644 include/uapi/sound/sof/eq.h create mode 100644 include/uapi/sound/sof/fw.h create mode 100644 include/uapi/sound/sof/header.h create mode 100644 include/uapi/sound/sof/manifest.h create mode 100644 include/uapi/sound/sof/tokens.h create mode 100644 include/uapi/sound/sof/tone.h create mode 100644 include/uapi/sound/sof/trace.h diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h new file mode 100644 index 00000000000000..37e0a90dc9e6c3 --- /dev/null +++ b/include/uapi/sound/sof/abi.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +/** + * SOF ABI versioning is based on Semantic Versioning where we have a given + * MAJOR.MINOR.PATCH version number. See https://semver.org/ + * + * Rules for incrementing or changing version :- + * + * 1) Increment MAJOR version if you make incompatible API changes. MINOR and + * PATCH should be reset to 0. + * + * 2) Increment MINOR version if you add backwards compatible features or + * changes. PATCH should be reset to 0. + * + * 3) Increment PATCH version if you add backwards compatible bug fixes. + */ + +#ifndef __INCLUDE_UAPI_SOUND_SOF_ABI_H__ +#define __INCLUDE_UAPI_SOUND_SOF_ABI_H__ + +/* SOF ABI version major, minor and patch numbers */ +#define SOF_ABI_MAJOR 3 +#define SOF_ABI_MINOR 4 +#define SOF_ABI_PATCH 0 + +/* SOF ABI version number. Format within 32bit word is MMmmmppp */ +#define SOF_ABI_MAJOR_SHIFT 24 +#define SOF_ABI_MAJOR_MASK 0xff +#define SOF_ABI_MINOR_SHIFT 12 +#define SOF_ABI_MINOR_MASK 0xfff +#define SOF_ABI_PATCH_SHIFT 0 +#define SOF_ABI_PATCH_MASK 0xfff + +#define SOF_ABI_VER(major, minor, patch) \ + (((major) << SOF_ABI_MAJOR_SHIFT) | \ + ((minor) << SOF_ABI_MINOR_SHIFT) | \ + ((patch) << SOF_ABI_PATCH_SHIFT)) + +#define SOF_ABI_VERSION_MAJOR(version) \ + (((version) >> SOF_ABI_MAJOR_SHIFT) & SOF_ABI_MAJOR_MASK) +#define SOF_ABI_VERSION_MINOR(version) \ + (((version) >> SOF_ABI_MINOR_SHIFT) & SOF_ABI_MINOR_MASK) +#define SOF_ABI_VERSION_PATCH(version) \ + (((version) >> SOF_ABI_PATCH_SHIFT) & SOF_ABI_PATCH_MASK) + +#define SOF_ABI_VERSION_INCOMPATIBLE(sof_ver, client_ver) \ + (SOF_ABI_VERSION_MAJOR((sof_ver)) != \ + SOF_ABI_VERSION_MAJOR((client_ver)) \ + ) + +#define SOF_ABI_VERSION SOF_ABI_VER(SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_PATCH) + +/* SOF ABI magic number "SOF\0". */ +#define SOF_ABI_MAGIC 0x00464F53 + +#endif diff --git a/include/uapi/sound/sof/eq.h b/include/uapi/sound/sof/eq.h new file mode 100644 index 00000000000000..666c2b6a3229d1 --- /dev/null +++ b/include/uapi/sound/sof/eq.h @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_EQ_H__ +#define __INCLUDE_UAPI_SOUND_SOF_USER_EQ_H__ + +/* FIR EQ type */ + +#define SOF_EQ_FIR_IDX_SWITCH 0 + +#define SOF_EQ_FIR_MAX_SIZE 4096 /* Max size allowed for coef data in bytes */ + +#define SOF_EQ_FIR_MAX_LENGTH 192 /* Max length for individual filter */ + +#define SOF_EQ_FIR_MAX_RESPONSES 8 /* A blob can define max 8 FIR EQs */ + +/* + * eq_fir_configuration data structure contains this information + * uint32_t size + * This is the number of bytes need to store the received EQ + * configuration. + * uint16_t channels_in_config + * This describes the number of channels in this EQ config data. It + * can be different from PLATFORM_MAX_CHANNELS. + * uint16_t number_of_responses + * 0=no responses, 1=one response defined, 2=two responses defined, etc. + * int16_t data[] + * assign_response[channels_in_config] + * 0 = use first response, 1 = use 2nd response, etc. + * E.g. {0, 0, 0, 0, 1, 1, 1, 1} would apply to channels 0-3 the + * same first defined response and for to channels 4-7 the second. + * coef_data[] + * Repeated data + * { filter_length, output_shift, h[] } + * for every EQ response defined where vector h has filter_length + * number of coefficients. Coefficients in h[] are in Q1.15 format. + * E.g. 16384 (Q1.15) = 0.5. The shifts are number of right shifts. + * + * NOTE: The channels_in_config must be even to have coef_data aligned to + * 32 bit word in RAM. Therefore a mono EQ assign must be duplicated to 2ch + * even if it would never used. Similarly a 5ch EQ assign must be increased + * to 6ch. EQ init will return an error if this is not met. + * + * NOTE: The filter_length must be multiple of four. Therefore the filter must + * be padded from the end with zeros have this condition met. + */ + +struct sof_eq_fir_config { + uint32_t size; + uint16_t channels_in_config; + uint16_t number_of_responses; + + /* reserved */ + uint32_t reserved[4]; + + int16_t data[]; +} __packed; + +struct sof_eq_fir_coef_data { + int16_t length; /* Number of FIR taps */ + int16_t out_shift; /* Amount of right shifts at output */ + + /* reserved */ + uint32_t reserved[4]; + + int16_t coef[]; /* FIR coefficients */ +} __packed; + +/* In the struct above there's two 16 bit words (length, shift) and four + * reserved 32 bit words before the actual FIR coefficients. This information + * is used in parsing of the configuration blob. + */ +#define SOF_EQ_FIR_COEF_NHEADER \ + (sizeof(struct sof_eq_fir_coef_data) / sizeof(int16_t)) + +/* IIR EQ type */ + +#define SOF_EQ_IIR_IDX_SWITCH 0 + +#define SOF_EQ_IIR_MAX_SIZE 1024 /* Max size allowed for coef data in bytes */ + +#define SOF_EQ_IIR_MAX_RESPONSES 8 /* A blob can define max 8 IIR EQs */ + +/* eq_iir_configuration + * uint32_t channels_in_config + * This describes the number of channels in this EQ config data. It + * can be different from PLATFORM_MAX_CHANNELS. + * uint32_t number_of_responses_defined + * 0=no responses, 1=one response defined, 2=two responses defined, etc. + * int32_t data[] + * Data consist of two parts. First is the response assign vector that + * has length of channels_in_config. The latter part is coefficient + * data. + * uint32_t assign_response[channels_in_config] + * -1 = not defined, 0 = use first response, 1 = use 2nd, etc. + * E.g. {0, 0, 0, 0, -1, -1, -1, -1} would apply to channels 0-3 the + * same first defined response and leave channels 4-7 unequalized. + * coefficient_data[] + * <1st EQ> + * uint32_t num_biquads + * uint32_t num_biquads_in_series + * <1st biquad> + * int32_t coef_a2 Q2.30 format + * int32_t coef_a1 Q2.30 format + * int32_t coef_b2 Q2.30 format + * int32_t coef_b1 Q2.30 format + * int32_t coef_b0 Q2.30 format + * int32_t output_shift number of shifts right, shift left is negative + * int32_t output_gain Q2.14 format + * <2nd biquad> + * ... + * <2nd EQ> + * + * Note: A flat response biquad can be made with a section set to + * b0 = 1.0, gain = 1.0, and other parameters set to 0 + * {0, 0, 0, 0, 1073741824, 0, 16484} + */ + +struct sof_eq_iir_config { + uint32_t size; + uint32_t channels_in_config; + uint32_t number_of_responses; + + /* reserved */ + uint32_t reserved[4]; + + int32_t data[]; /* eq_assign[channels], eq 0, eq 1, ... */ +} __packed; + +struct sof_eq_iir_header_df2t { + uint32_t num_sections; + uint32_t num_sections_in_series; + + /* reserved */ + uint32_t reserved[4]; + + int32_t biquads[]; /* Repeated biquad coefficients */ +} __packed; + +struct sof_eq_iir_biquad_df2t { + int32_t a2; /* Q2.30 */ + int32_t a1; /* Q2.30 */ + int32_t b2; /* Q2.30 */ + int32_t b1; /* Q2.30 */ + int32_t b0; /* Q2.30 */ + int32_t output_shift; /* Number of right shifts */ + int32_t output_gain; /* Q2.14 */ +} __packed; + +/* A full 22th order equalizer with 11 biquads cover octave bands 1-11 in + * in the 0 - 20 kHz bandwidth. + */ +#define SOF_EQ_IIR_DF2T_BIQUADS_MAX 11 + +/* The number of int32_t words in sof_eq_iir_header_df2t: + * num_sections, num_sections_in_series, reserved[4] + */ +#define SOF_EQ_IIR_NHEADER_DF2T \ + (sizeof(struct sof_eq_iir_header_df2t) / sizeof(int32_t)) + +/* The number of int32_t words in sof_eq_iir_biquad_df2t: + * a2, a1, b2, b1, b0, output_shift, output_gain + */ +#define SOF_EQ_IIR_NBIQUAD_DF2T \ + (sizeof(struct sof_eq_iir_biquad_df2t) / sizeof(int32_t)) + +#endif diff --git a/include/uapi/sound/sof/fw.h b/include/uapi/sound/sof/fw.h new file mode 100644 index 00000000000000..1afca973eb0972 --- /dev/null +++ b/include/uapi/sound/sof/fw.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +/* + * Firmware file format . + */ + +#ifndef __INCLUDE_UAPI_SOF_FW_H__ +#define __INCLUDE_UAPI_SOF_FW_H__ + +#define SND_SOF_FW_SIG_SIZE 4 +#define SND_SOF_FW_ABI 1 +#define SND_SOF_FW_SIG "Reef" + +/* + * Firmware module is made up of 1 . N blocks of different types. The + * Block header is used to determine where and how block is to be copied in the + * DSP/host memory space. + */ +enum snd_sof_fw_blk_type { + SOF_FW_BLK_TYPE_INVALID = -1, + SOF_FW_BLK_TYPE_START = 0, + SOF_FW_BLK_TYPE_RSRVD0 = SOF_FW_BLK_TYPE_START, + SOF_FW_BLK_TYPE_IRAM = 1, /* local instruction RAM */ + SOF_FW_BLK_TYPE_DRAM = 2, /* local data RAM */ + SOF_FW_BLK_TYPE_SRAM = 3, /* system RAM */ + SOF_FW_BLK_TYPE_ROM = 4, + SOF_FW_BLK_TYPE_IMR = 5, + SOF_FW_BLK_TYPE_RSRVD6 = 6, + SOF_FW_BLK_TYPE_RSRVD7 = 7, + SOF_FW_BLK_TYPE_RSRVD8 = 8, + SOF_FW_BLK_TYPE_RSRVD9 = 9, + SOF_FW_BLK_TYPE_RSRVD10 = 10, + SOF_FW_BLK_TYPE_RSRVD11 = 11, + SOF_FW_BLK_TYPE_RSRVD12 = 12, + SOF_FW_BLK_TYPE_RSRVD13 = 13, + SOF_FW_BLK_TYPE_RSRVD14 = 14, + /* use SOF_FW_BLK_TYPE_RSVRDX for new block types */ + SOF_FW_BLK_TYPE_NUM +}; + +struct snd_sof_blk_hdr { + enum snd_sof_fw_blk_type type; + uint32_t size; /* bytes minus this header */ + uint32_t offset; /* offset from base */ +} __packed; + +/* + * Firmware file is made up of 1 .. N different modules types. The module + * type is used to determine how to load and parse the module. + */ +enum snd_sof_fw_mod_type { + SOF_FW_BASE = 0, /* base firmware image */ + SOF_FW_MODULE = 1, /* firmware module */ +}; + +struct snd_sof_mod_hdr { + enum snd_sof_fw_mod_type type; + uint32_t size; /* bytes minus this header */ + uint32_t num_blocks; /* number of blocks */ +} __packed; + +/* + * Firmware file header. + */ +struct snd_sof_fw_header { + unsigned char sig[SND_SOF_FW_SIG_SIZE]; /* "Reef" */ + uint32_t file_size; /* size of file minus this header */ + uint32_t num_modules; /* number of modules */ + uint32_t abi; /* version of header format */ +} __packed; + +#endif diff --git a/include/uapi/sound/sof/header.h b/include/uapi/sound/sof/header.h new file mode 100644 index 00000000000000..7868990b0d6f34 --- /dev/null +++ b/include/uapi/sound/sof/header.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_HEADER_H__ +#define __INCLUDE_UAPI_SOUND_SOF_USER_HEADER_H__ + +/* + * Header for all non IPC ABI data. + * + * Identifies data type, size and ABI. + * Used by any bespoke component data structures or binary blobs. + */ +struct sof_abi_hdr { + uint32_t magic; /**< 'S', 'O', 'F', '\0' */ + uint32_t type; /**< component specific type */ + uint32_t size; /**< size in bytes of data excl. this struct */ + uint32_t abi; /**< SOF ABI version */ + uint32_t reserved[4]; /**< reserved for future use */ + uint32_t data[0]; /**< Component data - opaque to core */ +} __packed; + +#endif diff --git a/include/uapi/sound/sof/manifest.h b/include/uapi/sound/sof/manifest.h new file mode 100644 index 00000000000000..2009ee30fad022 --- /dev/null +++ b/include/uapi/sound/sof/manifest.h @@ -0,0 +1,188 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_MANIFEST_H__ +#define __INCLUDE_UAPI_SOUND_SOF_USER_MANIFEST_H__ + +/* start offset for base FW module */ +#define SOF_MAN_ELF_TEXT_OFFSET 0x2000 + +/* FW Extended Manifest Header id = $AE1 */ +#define SOF_MAN_EXT_HEADER_MAGIC 0x31454124 + +/* module type load type */ +#define SOF_MAN_MOD_TYPE_BUILTIN 0 +#define SOF_MAN_MOD_TYPE_MODULE 1 + +struct sof_man_module_type { + uint32_t load_type:4; /* SOF_MAN_MOD_TYPE_ */ + uint32_t auto_start:1; + uint32_t domain_ll:1; + uint32_t domain_dp:1; + uint32_t rsvd_:25; +}; + +/* segment flags.type */ +#define SOF_MAN_SEGMENT_TEXT 0 +#define SOF_MAN_SEGMENT_RODATA 1 +#define SOF_MAN_SEGMENT_DATA 1 +#define SOF_MAN_SEGMENT_BSS 2 +#define SOF_MAN_SEGMENT_EMPTY 15 + +union sof_man_segment_flags { + uint32_t ul; + struct { + uint32_t contents:1; + uint32_t alloc:1; + uint32_t load:1; + uint32_t readonly:1; + uint32_t code:1; + uint32_t data:1; + uint32_t _rsvd0:2; + uint32_t type:4; /* MAN_SEGMENT_ */ + uint32_t _rsvd1:4; + uint32_t length:16; /* of segment in pages */ + } r; +} __packed; + +/* + * Module segment descriptor. Used by ROM - Immutable. + */ +struct sof_man_segment_desc { + union sof_man_segment_flags flags; + uint32_t v_base_addr; + uint32_t file_offset; +} __packed; + +/* + * The firmware binary can be split into several modules. + */ + +#define SOF_MAN_MOD_ID_LEN 4 +#define SOF_MAN_MOD_NAME_LEN 8 +#define SOF_MAN_MOD_SHA256_LEN 32 +#define SOF_MAN_MOD_ID {'$', 'A', 'M', 'E'} + +/* + * Each module has an entry in the FW header. Used by ROM - Immutable. + */ +struct sof_man_module { + uint8_t struct_id[SOF_MAN_MOD_ID_LEN]; /* SOF_MAN_MOD_ID */ + uint8_t name[SOF_MAN_MOD_NAME_LEN]; + uint8_t uuid[16]; + struct sof_man_module_type type; + uint8_t hash[SOF_MAN_MOD_SHA256_LEN]; + uint32_t entry_point; + uint16_t cfg_offset; + uint16_t cfg_count; + uint32_t affinity_mask; + uint16_t instance_max_count; /* max number of instances */ + uint16_t instance_bss_size; /* instance (pages) */ + struct sof_man_segment_desc segment[3]; +} __packed; + +/* + * Each module has a configuration in the FW header. Used by ROM - Immutable. + */ +struct sof_man_mod_config { + uint32_t par[4]; /* module parameters */ + uint32_t is_pages; /* actual size of instance .bss (pages) */ + uint32_t cps; /* cycles per second */ + uint32_t ibs; /* input buffer size (bytes) */ + uint32_t obs; /* output buffer size (bytes) */ + uint32_t module_flags; /* flags, reserved for future use */ + uint32_t cpc; /* cycles per single run */ + uint32_t obls; /* output block size, reserved for future use */ +} __packed; + +/* + * FW Manifest Header + */ + +#define SOF_MAN_FW_HDR_FW_NAME_LEN 8 +#define SOF_MAN_FW_HDR_ID {'$', 'A', 'M', '1'} +#define SOF_MAN_FW_HDR_NAME "ADSPFW" +#define SOF_MAN_FW_HDR_FLAGS 0x0 +#define SOF_MAN_FW_HDR_FEATURES 0xff + +/* + * The firmware has a standard header that is checked by the ROM on firmware + * loading. preload_page_count is used by DMA code loader and is entire + * image size on CNL. i.e. CNL: total size of the binary’s .text and .rodata + * Used by ROM - Immutable. + */ +struct sof_man_fw_header { + uint8_t header_id[4]; + uint32_t header_len; + uint8_t name[SOF_MAN_FW_HDR_FW_NAME_LEN]; + /* number of pages of preloaded image loaded by driver */ + uint32_t preload_page_count; + uint32_t fw_image_flags; + uint32_t feature_mask; + uint16_t major_version; + uint16_t minor_version; + uint16_t hotfix_version; + uint16_t build_version; + uint32_t num_module_entries; + uint32_t hw_buf_base_addr; + uint32_t hw_buf_length; + /* target address for binary loading as offset in IMR - must be == base offset */ + uint32_t load_offset; +} __packed; + +/* + * Firmware manifest descriptor. This can contain N modules and N module + * configs. Used by ROM - Immutable. + */ +struct sof_man_fw_desc { + struct sof_man_fw_header header; + + /* Warning - hack for module arrays. For some unknown reason the we + * have a variable size array of struct man_module followed by a + * variable size array of struct mod_config. These should have been + * merged into a variable array of a parent structure. We have to hack + * around this in many places.... + * + * struct sof_man_module man_module[]; + * struct sof_man_mod_config mod_config[]; + */ + +} __packed; + +/* + * Component Descriptor. Used by ROM - Immutable. + */ +struct sof_man_component_desc { + uint32_t reserved[2]; /* all 0 */ + uint32_t version; + uint8_t hash[SOF_MAN_MOD_SHA256_LEN]; + uint32_t base_offset; + uint32_t limit_offset; + uint32_t attributes[4]; +} __packed; + +/* + * Audio DSP extended metadata. Used by ROM - Immutable. + */ +struct sof_man_adsp_meta_file_ext { + uint32_t ext_type; /* always 17 for ADSP extension */ + uint32_t ext_len; + uint32_t imr_type; + uint8_t reserved[16]; /* all 0 */ + struct sof_man_component_desc comp_desc[1]; +} __packed; + +/* + * Module Manifest for rimage module metadata. Not used by ROM. + */ +struct sof_man_module_manifest { + struct sof_man_module module; + uint32_t text_size; +} __packed; + +#endif diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h new file mode 100644 index 00000000000000..53ea94bf1c08d3 --- /dev/null +++ b/include/uapi/sound/sof/tokens.h @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * Author: Liam Girdwood + * Keyon Jie + */ + +/* + * Topology IDs and tokens. + * + * ** MUST BE ALIGNED WITH TOPOLOGY CONFIGURATION TOKEN VALUES ** + */ + +#ifndef __INCLUDE_UAPI_SOF_TOPOLOGY_H__ +#define __INCLUDE_UAPI_SOF_TOPOLOGY_H__ + +/* + * Kcontrol IDs + */ +#define SOF_TPLG_KCTL_VOL_ID 256 +#define SOF_TPLG_KCTL_ENUM_ID 257 +#define SOF_TPLG_KCTL_BYTES_ID 258 +#define SOF_TPLG_KCTL_SWITCH_ID 259 + +/* + * Tokens - must match values in topology configurations + */ + +/* buffers */ +#define SOF_TKN_BUF_SIZE 100 +#define SOF_TKN_BUF_CAPS 101 + +/* DAI */ +/* Token retired with ABI 3.2, do not use for new capabilities + * #define SOF_TKN_DAI_DMAC_CONFIG 153 + */ +#define SOF_TKN_DAI_TYPE 154 +#define SOF_TKN_DAI_INDEX 155 +#define SOF_TKN_DAI_DIRECTION 156 + +/* scheduling */ +#define SOF_TKN_SCHED_PERIOD 200 +#define SOF_TKN_SCHED_PRIORITY 201 +#define SOF_TKN_SCHED_MIPS 202 +#define SOF_TKN_SCHED_CORE 203 +#define SOF_TKN_SCHED_FRAMES 204 +#define SOF_TKN_SCHED_TIME_DOMAIN 205 + +/* volume */ +#define SOF_TKN_VOLUME_RAMP_STEP_TYPE 250 +#define SOF_TKN_VOLUME_RAMP_STEP_MS 251 + +/* SRC */ +#define SOF_TKN_SRC_RATE_IN 300 +#define SOF_TKN_SRC_RATE_OUT 301 + +/* PCM */ +#define SOF_TKN_PCM_DMAC_CONFIG 353 + +/* Generic components */ +#define SOF_TKN_COMP_PERIOD_SINK_COUNT 400 +#define SOF_TKN_COMP_PERIOD_SOURCE_COUNT 401 +#define SOF_TKN_COMP_FORMAT 402 +/* Token retired with ABI 3.2, do not use for new capabilities + * #define SOF_TKN_COMP_PRELOAD_COUNT 403 + */ + +/* SSP */ +#define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500 +#define SOF_TKN_INTEL_SSP_MCLK_ID 501 +#define SOF_TKN_INTEL_SSP_SAMPLE_BITS 502 +#define SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH 503 +#define SOF_TKN_INTEL_SSP_QUIRKS 504 +#define SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT 505 + +/* DMIC */ +#define SOF_TKN_INTEL_DMIC_DRIVER_VERSION 600 +#define SOF_TKN_INTEL_DMIC_CLK_MIN 601 +#define SOF_TKN_INTEL_DMIC_CLK_MAX 602 +#define SOF_TKN_INTEL_DMIC_DUTY_MIN 603 +#define SOF_TKN_INTEL_DMIC_DUTY_MAX 604 +#define SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE 605 +#define SOF_TKN_INTEL_DMIC_SAMPLE_RATE 608 +#define SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH 609 + +/* DMIC PDM */ +#define SOF_TKN_INTEL_DMIC_PDM_CTRL_ID 700 +#define SOF_TKN_INTEL_DMIC_PDM_MIC_A_Enable 701 +#define SOF_TKN_INTEL_DMIC_PDM_MIC_B_Enable 702 +#define SOF_TKN_INTEL_DMIC_PDM_POLARITY_A 703 +#define SOF_TKN_INTEL_DMIC_PDM_POLARITY_B 704 +#define SOF_TKN_INTEL_DMIC_PDM_CLK_EDGE 705 +#define SOF_TKN_INTEL_DMIC_PDM_SKEW 706 + +/* Tone */ +#define SOF_TKN_TONE_SAMPLE_RATE 800 + +/* Processing Components */ +#define SOF_TKN_PROCESS_TYPE 900 + +/* for backward compatibility */ +#define SOF_TKN_EFFECT_TYPE SOF_TKN_PROCESS_TYPE + +#endif diff --git a/include/uapi/sound/sof/tone.h b/include/uapi/sound/sof/tone.h new file mode 100644 index 00000000000000..d7c6e5d8317ebb --- /dev/null +++ b/include/uapi/sound/sof/tone.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* +* This file is provided under a dual BSD/GPLv2 license. When using or +* redistributing this file, you may do so under either license. +* +* Copyright(c) 2018 Intel Corporation. All rights reserved. +*/ + +#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_TONE_H__ +#define __INCLUDE_UAPI_SOUND_SOF_USER_TONE_H__ + +#define SOF_TONE_IDX_FREQUENCY 0 +#define SOF_TONE_IDX_AMPLITUDE 1 +#define SOF_TONE_IDX_FREQ_MULT 2 +#define SOF_TONE_IDX_AMPL_MULT 3 +#define SOF_TONE_IDX_LENGTH 4 +#define SOF_TONE_IDX_PERIOD 5 +#define SOF_TONE_IDX_REPEATS 6 +#define SOF_TONE_IDX_LIN_RAMP_STEP 7 + +#endif diff --git a/include/uapi/sound/sof/trace.h b/include/uapi/sound/sof/trace.h new file mode 100644 index 00000000000000..ffa7288a0f16f0 --- /dev/null +++ b/include/uapi/sound/sof/trace.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_TRACE_H__ +#define __INCLUDE_UAPI_SOUND_SOF_USER_TRACE_H__ + +/* + * Host system time. + * + * This property is used by the driver to pass down information about + * current system time. It is expressed in us. + * FW translates timestamps (in log entries, probe pockets) to this time + * domain. + * + * (cavs: SystemTime). + */ +struct system_time { + uint32_t val_l; /* Lower dword of current host time value */ + uint32_t val_u; /* Upper dword of current host time value */ +} __packed; + +#define LOG_ENABLE 1 /* Enable logging */ +#define LOG_DISABLE 0 /* Disable logging */ + +#define LOG_LEVEL_CRITICAL 1 /* (FDK fatal) */ +#define LOG_LEVEL_VERBOSE 2 + +/* + * Layout of a log fifo. + */ +struct log_buffer_layout { + uint32_t read_ptr; /*read pointer */ + uint32_t write_ptr; /* write pointer */ + uint32_t buffer[0]; /* buffer */ +} __packed; + +/* + * Log buffer status reported by FW. + */ +struct log_buffer_status { + uint32_t core_id; /* ID of core that logged to other half */ +} __packed; + +#define TRACE_ID_LENGTH 12 + +/* + * Log entry header. + * + * The header is followed by an array of arguments (uint32_t[]). + * Number of arguments is specified by the params_num field of log_entry + */ +struct log_entry_header { + uint32_t id_0 : TRACE_ID_LENGTH; /* e.g. Pipeline ID */ + uint32_t id_1 : TRACE_ID_LENGTH; /* e.g. Component ID */ + uint32_t core_id : 8; /* Reporting core's id */ + + uint64_t timestamp; /* Timestamp (in dsp ticks) */ + uint32_t log_entry_address; /* Address of log entry in ELF */ +} __packed; + +#endif From 0610e99fca733a6da81701ef6a3825f7e99bf1d8 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:05:16 -0500 Subject: [PATCH 1400/1995] ASoC: SOF: Add PM support Add support for saving and restoring DSP context in D3 to host DDR. The suspend callback includes: suspend all pcm's stream that are running, send CTX_SAVE ipc, drop all ipc's, release trace dma and then power off the DSP. And the resume callback performs the following steps: load FW, run FW, re-initialize trace, restore pipeline, restore the kcontrol values and finally send the ctx restore ipc to the dsp. The streams that are suspended are resumed by the ALSA resume trigger. If the streams are paused during system suspend, they are marked explicitly so they can be restored during PAUSE_RELEASE. Signed-off-by: Ranjani Sridharan Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 8920153c6461da69e49014a35275dc80cbf6ba14) --- sound/soc/sof/pm.c | 385 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 385 insertions(+) create mode 100644 sound/soc/sof/pm.c diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c new file mode 100644 index 00000000000000..fc599e1b6f65e6 --- /dev/null +++ b/sound/soc/sof/pm.c @@ -0,0 +1,385 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +#include "ops.h" +#include "sof-priv.h" + +static int sof_restore_kcontrols(struct snd_sof_dev *sdev) +{ + struct snd_sof_control *scontrol; + int ipc_cmd, ctrl_type; + int ret = 0; + + /* restore kcontrol values */ + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + /* reset readback offset for scontrol after resuming */ + scontrol->readback_offset = 0; + + /* notify DSP of kcontrol values */ + switch (scontrol->cmd) { + case SOF_CTRL_CMD_VOLUME: + case SOF_CTRL_CMD_ENUM: + case SOF_CTRL_CMD_SWITCH: + ipc_cmd = SOF_IPC_COMP_SET_VALUE; + ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET; + ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + ipc_cmd, ctrl_type, + scontrol->cmd, + true); + break; + case SOF_CTRL_CMD_BINARY: + ipc_cmd = SOF_IPC_COMP_SET_DATA; + ctrl_type = SOF_CTRL_TYPE_DATA_SET; + ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + ipc_cmd, ctrl_type, + scontrol->cmd, + true); + break; + + default: + break; + } + + if (ret < 0) { + dev_err(sdev->dev, + "error: failed kcontrol value set for widget: %d\n", + scontrol->comp_id); + + return ret; + } + } + + return 0; +} + +static int sof_restore_pipelines(struct snd_sof_dev *sdev) +{ + struct snd_sof_widget *swidget; + struct snd_sof_route *sroute; + struct sof_ipc_pipe_new *pipeline; + struct snd_sof_dai *dai; + struct sof_ipc_comp_dai *comp_dai; + struct sof_ipc_cmd_hdr *hdr; + int ret; + + /* restore pipeline components */ + list_for_each_entry_reverse(swidget, &sdev->widget_list, list) { + struct sof_ipc_comp_reply r; + + /* skip if there is no private data */ + if (!swidget->private) + continue; + + switch (swidget->id) { + case snd_soc_dapm_dai_in: + case snd_soc_dapm_dai_out: + dai = swidget->private; + comp_dai = &dai->comp_dai; + ret = sof_ipc_tx_message(sdev->ipc, + comp_dai->comp.hdr.cmd, + comp_dai, sizeof(*comp_dai), + &r, sizeof(r)); + break; + case snd_soc_dapm_scheduler: + + /* + * During suspend, all DSP cores are powered off. + * Therefore upon resume, create the pipeline comp + * and power up the core that the pipeline is + * scheduled on. + */ + pipeline = swidget->private; + ret = sof_load_pipeline_ipc(sdev, pipeline, &r); + break; + default: + hdr = swidget->private; + ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, + swidget->private, hdr->size, + &r, sizeof(r)); + break; + } + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to load widget type %d with ID: %d\n", + swidget->widget->id, swidget->comp_id); + + return ret; + } + } + + /* restore pipeline connections */ + list_for_each_entry_reverse(sroute, &sdev->route_list, list) { + struct sof_ipc_pipe_comp_connect *connect; + struct sof_ipc_reply reply; + + /* skip if there's no private data */ + if (!sroute->private) + continue; + + connect = sroute->private; + + /* send ipc */ + ret = sof_ipc_tx_message(sdev->ipc, + connect->hdr.cmd, + connect, sizeof(*connect), + &reply, sizeof(reply)); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to load route sink %s control %s source %s\n", + sroute->route->sink, + sroute->route->control ? sroute->route->control + : "none", + sroute->route->source); + + return ret; + } + } + + /* restore dai links */ + list_for_each_entry_reverse(dai, &sdev->dai_list, list) { + struct sof_ipc_reply reply; + struct sof_ipc_dai_config *config = dai->dai_config; + + if (!config) { + dev_err(sdev->dev, "error: no config for DAI %s\n", + dai->name); + continue; + } + + ret = sof_ipc_tx_message(sdev->ipc, + config->hdr.cmd, config, + config->hdr.size, + &reply, sizeof(reply)); + + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to set dai config for %s\n", + dai->name); + + return ret; + } + } + + /* complete pipeline */ + list_for_each_entry(swidget, &sdev->widget_list, list) { + switch (swidget->id) { + case snd_soc_dapm_scheduler: + swidget->complete = + snd_sof_complete_pipeline(sdev, swidget); + break; + default: + break; + } + } + + /* restore pipeline kcontrols */ + ret = sof_restore_kcontrols(sdev); + if (ret < 0) + dev_err(sdev->dev, + "error: restoring kcontrols after resume\n"); + + return ret; +} + +static int sof_send_pm_ipc(struct snd_sof_dev *sdev, int cmd) +{ + struct sof_ipc_pm_ctx pm_ctx; + struct sof_ipc_reply reply; + + memset(&pm_ctx, 0, sizeof(pm_ctx)); + + /* configure ctx save ipc message */ + pm_ctx.hdr.size = sizeof(pm_ctx); + pm_ctx.hdr.cmd = SOF_IPC_GLB_PM_MSG | cmd; + + /* send ctx save ipc to dsp */ + return sof_ipc_tx_message(sdev->ipc, pm_ctx.hdr.cmd, &pm_ctx, + sizeof(pm_ctx), &reply, sizeof(reply)); +} + +static void sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev) +{ + struct snd_pcm_substream *substream; + struct snd_sof_pcm *spcm; + snd_pcm_state_t state; + int dir; + + /* + * SOF requires hw_params to be set-up internally upon resume. + * So, set the flag to indicate this for those streams that + * have been suspended. + */ + list_for_each_entry(spcm, &sdev->pcm_list, list) { + for (dir = 0; dir <= SNDRV_PCM_STREAM_CAPTURE; dir++) { + substream = spcm->stream[dir].substream; + if (!substream || !substream->runtime) + continue; + + state = substream->runtime->status->state; + if (state == SNDRV_PCM_STATE_SUSPENDED) + spcm->hw_params_upon_resume[dir] = 1; + } + } +} + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) +static void sof_cache_debugfs(struct snd_sof_dev *sdev) +{ + struct snd_sof_dfsentry *dfse; + + list_for_each_entry(dfse, &sdev->dfsentry_list, list) { + + /* nothing to do if debugfs buffer is not IO mem */ + if (dfse->type == SOF_DFSENTRY_TYPE_BUF) + continue; + + /* cache memory that is only accessible in D0 */ + if (dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY) + memcpy_fromio(dfse->cache_buf, dfse->io_mem, + dfse->size); + } +} +#endif + +static int sof_resume(struct device *dev, bool runtime_resume) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + int ret; + + /* do nothing if dsp resume callbacks are not set */ + if (!sof_ops(sdev)->resume || !sof_ops(sdev)->runtime_resume) + return 0; + + /* + * if the runtime_resume flag is set, call the runtime_resume routine + * or else call the system resume routine + */ + if (runtime_resume) + ret = snd_sof_dsp_runtime_resume(sdev); + else + ret = snd_sof_dsp_resume(sdev); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to power up DSP after resume\n"); + return ret; + } + + /* load the firmware */ + ret = snd_sof_load_firmware(sdev); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to load DSP firmware after resume %d\n", + ret); + return ret; + } + + /* boot the firmware */ + ret = snd_sof_run_firmware(sdev); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to boot DSP firmware after resume %d\n", + ret); + return ret; + } + + /* resume DMA trace, only need send ipc */ + ret = snd_sof_init_trace_ipc(sdev); + if (ret < 0) { + /* non fatal */ + dev_warn(sdev->dev, + "warning: failed to init trace after resume %d\n", + ret); + } + + /* restore pipelines */ + ret = sof_restore_pipelines(sdev); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to restore pipeline after resume %d\n", + ret); + return ret; + } + + /* notify DSP of system resume */ + ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_RESTORE); + if (ret < 0) + dev_err(sdev->dev, + "error: ctx_restore ipc error during resume %d\n", + ret); + + return ret; +} + +static int sof_suspend(struct device *dev, bool runtime_suspend) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + int ret; + + /* do nothing if dsp suspend callback is not set */ + if (!sof_ops(sdev)->suspend) + return 0; + + /* release trace */ + snd_sof_release_trace(sdev); + + /* set restore_stream for all streams during system suspend */ + if (!runtime_suspend) + sof_set_hw_params_upon_resume(sdev); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) + /* cache debugfs contents during runtime suspend */ + if (runtime_suspend) + sof_cache_debugfs(sdev); +#endif + /* notify DSP of upcoming power down */ + ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_SAVE); + if (ret < 0) { + dev_err(sdev->dev, + "error: ctx_save ipc error during suspend %d\n", + ret); + return ret; + } + + /* power down all DSP cores */ + if (runtime_suspend) + ret = snd_sof_dsp_runtime_suspend(sdev, 0); + else + ret = snd_sof_dsp_suspend(sdev, 0); + if (ret < 0) + dev_err(sdev->dev, + "error: failed to power down DSP during suspend %d\n", + ret); + + return ret; +} + +int snd_sof_runtime_suspend(struct device *dev) +{ + return sof_suspend(dev, true); +} +EXPORT_SYMBOL(snd_sof_runtime_suspend); + +int snd_sof_runtime_resume(struct device *dev) +{ + return sof_resume(dev, true); +} +EXPORT_SYMBOL(snd_sof_runtime_resume); + +int snd_sof_resume(struct device *dev) +{ + return sof_resume(dev, false); +} +EXPORT_SYMBOL(snd_sof_resume); + +int snd_sof_suspend(struct device *dev) +{ + return sof_suspend(dev, false); +} +EXPORT_SYMBOL(snd_sof_suspend); From a3476c1ba1832038f32b1d537ff52ae79242a2b9 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:05:17 -0500 Subject: [PATCH 1401/1995] ASoC: SOF: Add Nocodec machine driver support Add a simple "fallback" machine driver that can be used to enable SOF on boards with no codec device. This machine driver can also be forced for debug/development. Signed-off-by: Keyon Jie Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 8017b8fd37bf5ed4e9c0596f83295b019ff1c287) --- include/sound/sof.h | 6 +++ sound/soc/sof/nocodec.c | 109 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 sound/soc/sof/nocodec.c diff --git a/include/sound/sof.h b/include/sound/sof.h index 54f65ec33a6c3f..4640566b54fe90 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -12,6 +12,7 @@ #define __INCLUDE_SOUND_SOF_H #include +#include #include struct snd_sof_dsp_ops; @@ -91,4 +92,9 @@ struct sof_dev_desc { const struct sof_arch_ops *arch_ops; }; +int sof_nocodec_setup(struct device *dev, + struct snd_sof_pdata *sof_pdata, + struct snd_soc_acpi_mach *mach, + const struct sof_dev_desc *desc, + const struct snd_sof_dsp_ops *ops); #endif diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c new file mode 100644 index 00000000000000..f84b4344dcc3e9 --- /dev/null +++ b/sound/soc/sof/nocodec.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +#include +#include +#include "sof-priv.h" + +static struct snd_soc_card sof_nocodec_card = { + .name = "nocodec", /* the sof- prefix is added by the core */ +}; + +static int sof_nocodec_bes_setup(struct device *dev, + const struct snd_sof_dsp_ops *ops, + struct snd_soc_dai_link *links, + int link_num, struct snd_soc_card *card) +{ + int i; + + if (!ops || !links || !card) + return -EINVAL; + + /* set up BE dai_links */ + for (i = 0; i < link_num; i++) { + links[i].name = devm_kasprintf(dev, GFP_KERNEL, + "NoCodec-%d", i); + if (!links[i].name) + return -ENOMEM; + + links[i].id = i; + links[i].no_pcm = 1; + links[i].cpu_dai_name = ops->drv[i].name; + links[i].platform_name = dev_name(dev); + links[i].codec_dai_name = "snd-soc-dummy-dai"; + links[i].codec_name = "snd-soc-dummy"; + links[i].dpcm_playback = 1; + links[i].dpcm_capture = 1; + } + + card->dai_link = links; + card->num_links = link_num; + + return 0; +} + +int sof_nocodec_setup(struct device *dev, + struct snd_sof_pdata *sof_pdata, + struct snd_soc_acpi_mach *mach, + const struct sof_dev_desc *desc, + const struct snd_sof_dsp_ops *ops) +{ + struct snd_soc_dai_link *links; + int ret; + + if (!mach) + return -EINVAL; + + sof_pdata->drv_name = "sof-nocodec"; + + mach->drv_name = "sof-nocodec"; + sof_pdata->fw_filename = desc->nocodec_fw_filename; + sof_pdata->tplg_filename = desc->nocodec_tplg_filename; + + /* create dummy BE dai_links */ + links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * + ops->num_drv, GFP_KERNEL); + if (!links) + return -ENOMEM; + + ret = sof_nocodec_bes_setup(dev, ops, links, ops->num_drv, + &sof_nocodec_card); + return ret; +} +EXPORT_SYMBOL(sof_nocodec_setup); + +static int sof_nocodec_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &sof_nocodec_card; + + card->dev = &pdev->dev; + + return devm_snd_soc_register_card(&pdev->dev, card); +} + +static int sof_nocodec_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver sof_nocodec_audio = { + .probe = sof_nocodec_probe, + .remove = sof_nocodec_remove, + .driver = { + .name = "sof-nocodec", + .pm = &snd_soc_pm_ops, + }, +}; +module_platform_driver(sof_nocodec_audio) + +MODULE_DESCRIPTION("ASoC sof nocodec"); +MODULE_AUTHOR("Liam Girdwood"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("platform:sof-nocodec"); From fa4ffd45a4cd86e745e785de6380c1fa705da0f1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Apr 2019 11:05:18 -0500 Subject: [PATCH 1402/1995] ASoC: SOF: Add xtensa support Add common directory for xtensa architecture Signed-off-by: Pan Xiuli Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit e657c18a01c85d2c4ec0e96d52be8ba42b956593) --- include/sound/sof/xtensa.h | 44 +++++++++++ sound/soc/sof/xtensa/Kconfig | 2 + sound/soc/sof/xtensa/Makefile | 5 ++ sound/soc/sof/xtensa/core.c | 138 ++++++++++++++++++++++++++++++++++ 4 files changed, 189 insertions(+) create mode 100644 include/sound/sof/xtensa.h create mode 100644 sound/soc/sof/xtensa/Kconfig create mode 100644 sound/soc/sof/xtensa/Makefile create mode 100644 sound/soc/sof/xtensa/core.c diff --git a/include/sound/sof/xtensa.h b/include/sound/sof/xtensa.h new file mode 100644 index 00000000000000..a7189984000d5d --- /dev/null +++ b/include/sound/sof/xtensa.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + */ + +#ifndef __INCLUDE_SOUND_SOF_XTENSA_H__ +#define __INCLUDE_SOUND_SOF_XTENSA_H__ + +#include + +/* + * Architecture specific debug + */ + +/* Xtensa Firmware Oops data */ +struct sof_ipc_dsp_oops_xtensa { + struct sof_ipc_hdr hdr; + uint32_t exccause; + uint32_t excvaddr; + uint32_t ps; + uint32_t epc1; + uint32_t epc2; + uint32_t epc3; + uint32_t epc4; + uint32_t epc5; + uint32_t epc6; + uint32_t epc7; + uint32_t eps2; + uint32_t eps3; + uint32_t eps4; + uint32_t eps5; + uint32_t eps6; + uint32_t eps7; + uint32_t depc; + uint32_t intenable; + uint32_t interrupt; + uint32_t sar; + uint32_t stack; +} __packed; + +#endif diff --git a/sound/soc/sof/xtensa/Kconfig b/sound/soc/sof/xtensa/Kconfig new file mode 100644 index 00000000000000..8a9343b8514673 --- /dev/null +++ b/sound/soc/sof/xtensa/Kconfig @@ -0,0 +1,2 @@ +config SND_SOC_SOF_XTENSA + tristate diff --git a/sound/soc/sof/xtensa/Makefile b/sound/soc/sof/xtensa/Makefile new file mode 100644 index 00000000000000..cc89c7472a3802 --- /dev/null +++ b/sound/soc/sof/xtensa/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) + +snd-sof-xtensa-dsp-objs := core.o + +obj-$(CONFIG_SND_SOC_SOF_XTENSA) += snd-sof-xtensa-dsp.o diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c new file mode 100644 index 00000000000000..c3ad23a85b99fe --- /dev/null +++ b/sound/soc/sof/xtensa/core.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Pan Xiuli +// + +#include +#include +#include +#include "../sof-priv.h" + +struct xtensa_exception_cause { + u32 id; + const char *msg; + const char *description; +}; + +/* + * From 4.4.1.5 table 4-64 Exception Causes of Xtensa + * Instruction Set Architecture (ISA) Reference Manual + */ +static const struct xtensa_exception_cause xtensa_exception_causes[] = { + {0, "IllegalInstructionCause", "Illegal instruction"}, + {1, "SyscallCause", "SYSCALL instruction"}, + {2, "InstructionFetchErrorCause", + "Processor internal physical address or data error during instruction fetch"}, + {3, "LoadStoreErrorCause", + "Processor internal physical address or data error during load or store"}, + {4, "Level1InterruptCause", + "Level-1 interrupt as indicated by set level-1 bits in the INTERRUPT register"}, + {5, "AllocaCause", + "MOVSP instruction, if caller’s registers are not in the register file"}, + {6, "IntegerDivideByZeroCause", + "QUOS, QUOU, REMS, or REMU divisor operand is zero"}, + {8, "PrivilegedCause", + "Attempt to execute a privileged operation when CRING ? 0"}, + {9, "LoadStoreAlignmentCause", "Load or store to an unaligned address"}, + {12, "InstrPIFDataErrorCause", + "PIF data error during instruction fetch"}, + {13, "LoadStorePIFDataErrorCause", + "Synchronous PIF data error during LoadStore access"}, + {14, "InstrPIFAddrErrorCause", + "PIF address error during instruction fetch"}, + {15, "LoadStorePIFAddrErrorCause", + "Synchronous PIF address error during LoadStore access"}, + {16, "InstTLBMissCause", "Error during Instruction TLB refill"}, + {17, "InstTLBMultiHitCause", + "Multiple instruction TLB entries matched"}, + {18, "InstFetchPrivilegeCause", + "An instruction fetch referenced a virtual address at a ring level less than CRING"}, + {20, "InstFetchProhibitedCause", + "An instruction fetch referenced a page mapped with an attribute that does not permit instruction fetch"}, + {24, "LoadStoreTLBMissCause", + "Error during TLB refill for a load or store"}, + {25, "LoadStoreTLBMultiHitCause", + "Multiple TLB entries matched for a load or store"}, + {26, "LoadStorePrivilegeCause", + "A load or store referenced a virtual address at a ring level less than CRING"}, + {28, "LoadProhibitedCause", + "A load referenced a page mapped with an attribute that does not permit loads"}, + {32, "Coprocessor0Disabled", + "Coprocessor 0 instruction when cp0 disabled"}, + {33, "Coprocessor1Disabled", + "Coprocessor 1 instruction when cp1 disabled"}, + {34, "Coprocessor2Disabled", + "Coprocessor 2 instruction when cp2 disabled"}, + {35, "Coprocessor3Disabled", + "Coprocessor 3 instruction when cp3 disabled"}, + {36, "Coprocessor4Disabled", + "Coprocessor 4 instruction when cp4 disabled"}, + {37, "Coprocessor5Disabled", + "Coprocessor 5 instruction when cp5 disabled"}, + {38, "Coprocessor6Disabled", + "Coprocessor 6 instruction when cp6 disabled"}, + {39, "Coprocessor7Disabled", + "Coprocessor 7 instruction when cp7 disabled"}, +}; + +/* only need xtensa atm */ +static void xtensa_dsp_oops(struct snd_sof_dev *sdev, void *oops) +{ + struct sof_ipc_dsp_oops_xtensa *xoops = oops; + int i; + + dev_err(sdev->dev, "error: DSP Firmware Oops\n"); + for (i = 0; i < ARRAY_SIZE(xtensa_exception_causes); i++) { + if (xtensa_exception_causes[i].id == xoops->exccause) { + dev_err(sdev->dev, "error: Exception Cause: %s, %s\n", + xtensa_exception_causes[i].msg, + xtensa_exception_causes[i].description); + } + } + dev_err(sdev->dev, "EXCCAUSE 0x%8.8x EXCVADDR 0x%8.8x PS 0x%8.8x SAR 0x%8.8x\n", + xoops->exccause, xoops->excvaddr, xoops->ps, xoops->sar); + dev_err(sdev->dev, "EPC1 0x%8.8x EPC2 0x%8.8x EPC3 0x%8.8x EPC4 0x%8.8x", + xoops->epc1, xoops->epc2, xoops->epc3, xoops->epc4); + dev_err(sdev->dev, "EPC5 0x%8.8x EPC6 0x%8.8x EPC7 0x%8.8x DEPC 0x%8.8x", + xoops->epc5, xoops->epc6, xoops->epc7, xoops->depc); + dev_err(sdev->dev, "EPS2 0x%8.8x EPS3 0x%8.8x EPS4 0x%8.8x EPS5 0x%8.8x", + xoops->eps2, xoops->eps3, xoops->eps4, xoops->eps5); + dev_err(sdev->dev, "EPS6 0x%8.8x EPS7 0x%8.8x INTENABL 0x%8.8x INTERRU 0x%8.8x", + xoops->eps6, xoops->eps7, xoops->intenable, xoops->interrupt); +} + +static void xtensa_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack, + u32 stack_words) +{ + struct sof_ipc_dsp_oops_xtensa *xoops = oops; + u32 stack_ptr = xoops->stack; + /* 4 * 8chars + 3 ws + 1 terminating NUL */ + unsigned char buf[4 * 8 + 3 + 1]; + int i; + + dev_err(sdev->dev, "stack dump from 0x%8.8x\n", stack_ptr); + + /* + * example output: + * 0x0049fbb0: 8000f2d0 0049fc00 6f6c6c61 00632e63 + */ + for (i = 0; i < stack_words; i += 4) { + hex_dump_to_buffer(stack + i * 4, 16, 16, 4, + buf, sizeof(buf), false); + dev_err(sdev->dev, "0x%08x: %s\n", stack_ptr + i, buf); + } +} + +const struct sof_arch_ops sof_xtensa_arch_ops = { + .dsp_oops = xtensa_dsp_oops, + .dsp_stack = xtensa_stack, +}; +EXPORT_SYMBOL(sof_xtensa_arch_ops); + +MODULE_DESCRIPTION("SOF Xtensa DSP support"); +MODULE_LICENSE("Dual BSD/GPL"); From c8f0894bf7c5fa02dd2ab5c597b949ab4ba4b8e9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Apr 2019 11:05:19 -0500 Subject: [PATCH 1403/1995] ASoC: SOF: Add utils Helpers to set-up back-ends, create platform devices and common IO/block read/write operations Signed-off-by: Keyon Jie Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 3bafac46065eb7ea6f3e3fcbdb8b70b66f6c71b4) --- sound/soc/sof/utils.c | 112 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 sound/soc/sof/utils.c diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c new file mode 100644 index 00000000000000..2ac4c3da03206d --- /dev/null +++ b/sound/soc/sof/utils.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Keyon Jie +// + +#include +#include +#include +#include +#include "sof-priv.h" + +/* + * Register IO + * + * The sof_io_xyz() wrappers are typically referenced in snd_sof_dsp_ops + * structures and cannot be inlined. + */ + +void sof_io_write(struct snd_sof_dev *sdev, void __iomem *addr, u32 value) +{ + writel(value, addr); +} +EXPORT_SYMBOL(sof_io_write); + +u32 sof_io_read(struct snd_sof_dev *sdev, void __iomem *addr) +{ + return readl(addr); +} +EXPORT_SYMBOL(sof_io_read); + +void sof_io_write64(struct snd_sof_dev *sdev, void __iomem *addr, u64 value) +{ + writeq(value, addr); +} +EXPORT_SYMBOL(sof_io_write64); + +u64 sof_io_read64(struct snd_sof_dev *sdev, void __iomem *addr) +{ + return readq(addr); +} +EXPORT_SYMBOL(sof_io_read64); + +/* + * IPC Mailbox IO + */ + +void sof_mailbox_write(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes) +{ + void __iomem *dest = sdev->bar[sdev->mailbox_bar] + offset; + + memcpy_toio(dest, message, bytes); +} +EXPORT_SYMBOL(sof_mailbox_write); + +void sof_mailbox_read(struct snd_sof_dev *sdev, u32 offset, + void *message, size_t bytes) +{ + void __iomem *src = sdev->bar[sdev->mailbox_bar] + offset; + + memcpy_fromio(message, src, bytes); +} +EXPORT_SYMBOL(sof_mailbox_read); + +/* + * Memory copy. + */ + +void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, + size_t size) +{ + void __iomem *dest = sdev->bar[bar] + offset; + const u8 *src_byte = src; + u32 affected_mask; + u32 tmp; + int m, n; + + m = size / 4; + n = size % 4; + + /* __iowrite32_copy use 32bit size values so divide by 4 */ + __iowrite32_copy(dest, src, m); + + if (n) { + affected_mask = (1 << (8 * n)) - 1; + + /* first read the 32bit data of dest, then change affected + * bytes, and write back to dest. For unaffected bytes, it + * should not be changed + */ + tmp = ioread32(dest + m * 4); + tmp &= ~affected_mask; + + tmp |= *(u32 *)(src_byte + m * 4) & affected_mask; + iowrite32(tmp, dest + m * 4); + } +} +EXPORT_SYMBOL(sof_block_write); + +void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, + size_t size) +{ + void __iomem *src = sdev->bar[bar] + offset; + + memcpy_fromio(dest, src, size); +} +EXPORT_SYMBOL(sof_block_read); From 573ca9eb9cacf6017a41ea086c16225814d4740c Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:08:44 -0500 Subject: [PATCH 1404/1995] ASoC: SOF: Intel: Add BYT, CHT and BSW DSP HW support. Add support for the audio DSP hardware found on Intel Baytrail, Cherrytrail and Braswell based devices. Signed-off-by: Rander Wang Signed-off-by: Pan Xiuli Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 9e42c5ca4a276a668b11116704f5f0d66ab80608) --- sound/soc/sof/intel/byt.c | 874 +++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/shim.h | 183 ++++++++ 2 files changed, 1057 insertions(+) create mode 100644 sound/soc/sof/intel/byt.c create mode 100644 sound/soc/sof/intel/shim.h diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c new file mode 100644 index 00000000000000..7bf9143d310673 --- /dev/null +++ b/sound/soc/sof/intel/byt.c @@ -0,0 +1,874 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +/* + * Hardware interface for audio DSP on Baytrail, Braswell and Cherrytrail. + */ + +#include +#include +#include +#include "../ops.h" +#include "shim.h" + +/* DSP memories */ +#define IRAM_OFFSET 0x0C0000 +#define IRAM_SIZE (80 * 1024) +#define DRAM_OFFSET 0x100000 +#define DRAM_SIZE (160 * 1024) +#define SHIM_OFFSET 0x140000 +#define SHIM_SIZE 0x100 +#define MBOX_OFFSET 0x144000 +#define MBOX_SIZE 0x1000 +#define EXCEPT_OFFSET 0x800 + +/* DSP peripherals */ +#define DMAC0_OFFSET 0x098000 +#define DMAC1_OFFSET 0x09c000 +#define DMAC2_OFFSET 0x094000 +#define DMAC_SIZE 0x420 +#define SSP0_OFFSET 0x0a0000 +#define SSP1_OFFSET 0x0a1000 +#define SSP2_OFFSET 0x0a2000 +#define SSP3_OFFSET 0x0a4000 +#define SSP4_OFFSET 0x0a5000 +#define SSP5_OFFSET 0x0a6000 +#define SSP_SIZE 0x100 + +#define BYT_STACK_DUMP_SIZE 32 + +#define BYT_PCI_BAR_SIZE 0x200000 + +#define BYT_PANIC_OFFSET(x) (((x) & GENMASK_ULL(47, 32)) >> 32) + +/* + * Debug + */ + +#define MBOX_DUMP_SIZE 0x30 + +/* BARs */ +#define BYT_DSP_BAR 0 +#define BYT_PCI_BAR 1 +#define BYT_IMR_BAR 2 + +static const struct snd_sof_debugfs_map byt_debugfs[] = { + {"dmac0", BYT_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dmac1", BYT_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp0", BYT_DSP_BAR, SSP0_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp1", BYT_DSP_BAR, SSP1_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp2", BYT_DSP_BAR, SSP2_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"iram", BYT_DSP_BAR, IRAM_OFFSET, IRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, +}; + +static const struct snd_sof_debugfs_map cht_debugfs[] = { + {"dmac0", BYT_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dmac1", BYT_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dmac2", BYT_DSP_BAR, DMAC2_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp0", BYT_DSP_BAR, SSP0_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp1", BYT_DSP_BAR, SSP1_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp2", BYT_DSP_BAR, SSP2_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp3", BYT_DSP_BAR, SSP3_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp4", BYT_DSP_BAR, SSP4_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp5", BYT_DSP_BAR, SSP5_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"iram", BYT_DSP_BAR, IRAM_OFFSET, IRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, +}; + +static void byt_host_done(struct snd_sof_dev *sdev); +static void byt_dsp_done(struct snd_sof_dev *sdev); +static void byt_get_reply(struct snd_sof_dev *sdev); + +/* + * IPC Firmware ready. + */ +static void byt_get_windows(struct snd_sof_dev *sdev) +{ + struct sof_ipc_window_elem *elem; + u32 outbox_offset = 0; + u32 stream_offset = 0; + u32 inbox_offset = 0; + u32 outbox_size = 0; + u32 stream_size = 0; + u32 inbox_size = 0; + int i; + + if (!sdev->info_window) { + dev_err(sdev->dev, "error: have no window info\n"); + return; + } + + for (i = 0; i < sdev->info_window->num_windows; i++) { + elem = &sdev->info_window->window[i]; + + switch (elem->type) { + case SOF_IPC_REGION_UPBOX: + inbox_offset = elem->offset + MBOX_OFFSET; + inbox_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[BYT_DSP_BAR] + + inbox_offset, + elem->size, "inbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_DOWNBOX: + outbox_offset = elem->offset + MBOX_OFFSET; + outbox_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[BYT_DSP_BAR] + + outbox_offset, + elem->size, "outbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_TRACE: + snd_sof_debugfs_io_item(sdev, + sdev->bar[BYT_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "etrace", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_DEBUG: + snd_sof_debugfs_io_item(sdev, + sdev->bar[BYT_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "debug", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_STREAM: + stream_offset = elem->offset + MBOX_OFFSET; + stream_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[BYT_DSP_BAR] + + stream_offset, + elem->size, "stream", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_REGS: + snd_sof_debugfs_io_item(sdev, + sdev->bar[BYT_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "regs", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_EXCEPTION: + sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; + snd_sof_debugfs_io_item(sdev, + sdev->bar[BYT_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "exception", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + default: + dev_err(sdev->dev, "error: get illegal window info\n"); + return; + } + } + + if (outbox_size == 0 || inbox_size == 0) { + dev_err(sdev->dev, "error: get illegal mailbox window\n"); + return; + } + + snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, + outbox_offset, outbox_size); + sdev->stream_box.offset = stream_offset; + sdev->stream_box.size = stream_size; + + dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", + inbox_offset, inbox_size); + dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", + outbox_offset, outbox_size); + dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", + stream_offset, stream_size); +} + +/* check for ABI compatibility and create memory windows on first boot */ +static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; + u32 offset; + int ret; + + /* mailbox must be on 4k boundary */ + offset = MBOX_OFFSET; + + dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n", + msg_id, offset); + + /* no need to re-check version/ABI for subsequent boots */ + if (!sdev->first_boot) + return 0; + + /* copy data from the DSP FW ready offset */ + sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, + sizeof(*fw_ready)); + + snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, + fw_ready->dspbox_size, + fw_ready->hostbox_offset, + fw_ready->hostbox_size); + + /* make sure ABI version is compatible */ + ret = snd_sof_ipc_valid(sdev); + if (ret < 0) + return ret; + + /* now check for extended data */ + snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + + sizeof(struct sof_ipc_fw_ready)); + + byt_get_windows(sdev); + + return 0; +} + +/* + * Debug + */ + +static void byt_get_registers(struct snd_sof_dev *sdev, + struct sof_ipc_dsp_oops_xtensa *xoops, + struct sof_ipc_panic_info *panic_info, + u32 *stack, size_t stack_words) +{ + /* first read regsisters */ + sof_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); + + /* then get panic info */ + sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), + panic_info, sizeof(*panic_info)); + + /* then get the stack */ + sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + + sizeof(*panic_info), stack, + stack_words * sizeof(u32)); +} + +static void byt_dump(struct snd_sof_dev *sdev, u32 flags) +{ + struct sof_ipc_dsp_oops_xtensa xoops; + struct sof_ipc_panic_info panic_info; + u32 stack[BYT_STACK_DUMP_SIZE]; + u32 status, panic; + + /* now try generic SOF status messages */ + status = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IPCD); + panic = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IPCX); + byt_get_registers(sdev, &xoops, &panic_info, stack, + BYT_STACK_DUMP_SIZE); + snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, + BYT_STACK_DUMP_SIZE); +} + +/* + * IPC Doorbell IRQ handler and thread. + */ + +static irqreturn_t byt_irq_handler(int irq, void *context) +{ + struct snd_sof_dev *sdev = context; + u64 isr; + int ret = IRQ_NONE; + + /* Interrupt arrived, check src */ + isr = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_ISRX); + if (isr & (SHIM_ISRX_DONE | SHIM_ISRX_BUSY)) + ret = IRQ_WAKE_THREAD; + + return ret; +} + +static irqreturn_t byt_irq_thread(int irq, void *context) +{ + struct snd_sof_dev *sdev = context; + u64 ipcx, ipcd; + u64 imrx; + + imrx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IMRX); + ipcx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCX); + + /* reply message from DSP */ + if (ipcx & SHIM_BYT_IPCX_DONE && + !(imrx & SHIM_IMRX_DONE)) { + /* Mask Done interrupt before first */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, + SHIM_IMRX, + SHIM_IMRX_DONE, + SHIM_IMRX_DONE); + /* + * handle immediate reply from DSP core. If the msg is + * found, set done bit in cmd_done which is called at the + * end of message processing function, else set it here + * because the done bit can't be set in cmd_done function + * which is triggered by msg + */ + byt_get_reply(sdev); + snd_sof_ipc_reply(sdev, ipcx); + + byt_dsp_done(sdev); + } + + /* new message from DSP */ + ipcd = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCD); + if (ipcd & SHIM_BYT_IPCD_BUSY && + !(imrx & SHIM_IMRX_BUSY)) { + /* Mask Busy interrupt before return */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, + SHIM_IMRX, + SHIM_IMRX_BUSY, + SHIM_IMRX_BUSY); + + /* Handle messages from DSP Core */ + if ((ipcd & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { + snd_sof_dsp_panic(sdev, BYT_PANIC_OFFSET(ipcd) + + MBOX_OFFSET); + } else { + snd_sof_ipc_msgs_rx(sdev); + } + + byt_host_done(sdev); + } + + return IRQ_HANDLED; +} + +static int byt_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + u64 cmd = msg->header; + + /* send the message */ + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + snd_sof_dsp_write64(sdev, BYT_DSP_BAR, SHIM_IPCX, + cmd | SHIM_BYT_IPCX_BUSY); + + return 0; +} + +static void byt_get_reply(struct snd_sof_dev *sdev) +{ + struct snd_sof_ipc_msg *msg = sdev->msg; + struct sof_ipc_reply reply; + unsigned long flags; + int ret = 0; + + /* + * Sometimes, there is unexpected reply ipc arriving. The reply + * ipc belongs to none of the ipcs sent from driver. + * In this case, the driver must ignore the ipc. + */ + if (!msg) { + dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); + return; + } + + /* get reply */ + sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); + + spin_lock_irqsave(&sdev->ipc_lock, flags); + + if (reply.error < 0) { + memcpy(msg->reply_data, &reply, sizeof(reply)); + ret = reply.error; + } else { + /* reply correct size ? */ + if (reply.hdr.size != msg->reply_size) { + dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", + msg->reply_size, reply.hdr.size); + ret = -EINVAL; + } + + /* read the message */ + if (msg->reply_size > 0) + sof_mailbox_read(sdev, sdev->host_box.offset, + msg->reply_data, msg->reply_size); + } + + msg->reply_error = ret; + + spin_unlock_irqrestore(&sdev->ipc_lock, flags); +} + +static void byt_host_done(struct snd_sof_dev *sdev) +{ + /* clear BUSY bit and set DONE bit - accept new messages */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCD, + SHIM_BYT_IPCD_BUSY | + SHIM_BYT_IPCD_DONE, + SHIM_BYT_IPCD_DONE); + + /* unmask busy interrupt */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_BUSY, 0); +} + +static void byt_dsp_done(struct snd_sof_dev *sdev) +{ + /* clear DONE bit - tell DSP we have completed */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IPCX, + SHIM_BYT_IPCX_DONE, 0); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_DONE, 0); +} + +/* + * DSP control. + */ + +static int byt_run(struct snd_sof_dev *sdev) +{ + int tries = 10; + + /* release stall and wait to unstall */ + snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_CSR, + SHIM_BYT_CSR_STALL, 0x0); + while (tries--) { + if (!(snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_CSR) & + SHIM_BYT_CSR_PWAITMODE)) + break; + msleep(100); + } + if (tries < 0) { + dev_err(sdev->dev, "error: unable to run DSP firmware\n"); + byt_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX); + return -ENODEV; + } + + /* return init core mask */ + return 1; +} + +static int byt_reset(struct snd_sof_dev *sdev) +{ + /* put DSP into reset, set reset vector and stall */ + snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_CSR, + SHIM_BYT_CSR_RST | SHIM_BYT_CSR_VECTOR_SEL | + SHIM_BYT_CSR_STALL, + SHIM_BYT_CSR_RST | SHIM_BYT_CSR_VECTOR_SEL | + SHIM_BYT_CSR_STALL); + + usleep_range(10, 15); + + /* take DSP out of reset and keep stalled for FW loading */ + snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_CSR, + SHIM_BYT_CSR_RST, 0); + + return 0; +} + +/* Baytrail DAIs */ +static struct snd_soc_dai_driver byt_dai[] = { +{ + .name = "ssp0-port", +}, +{ + .name = "ssp1-port", +}, +{ + .name = "ssp2-port", +}, +{ + .name = "ssp3-port", +}, +{ + .name = "ssp4-port", +}, +{ + .name = "ssp5-port", +}, +}; + +/* + * Probe and remove. + */ + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) + +static int tangier_pci_probe(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *pdata = sdev->pdata; + const struct sof_dev_desc *desc = pdata->desc; + struct pci_dev *pci = to_pci_dev(sdev->dev); + u32 base, size; + int ret; + + /* DSP DMA can only access low 31 bits of host memory */ + ret = dma_coerce_mask_and_coherent(&pci->dev, DMA_BIT_MASK(31)); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DMA mask %d\n", ret); + return ret; + } + + /* LPE base */ + base = pci_resource_start(pci, desc->resindex_lpe_base) - IRAM_OFFSET; + size = BYT_PCI_BAR_SIZE; + + dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); + sdev->bar[BYT_DSP_BAR] = devm_ioremap(sdev->dev, base, size); + if (!sdev->bar[BYT_DSP_BAR]) { + dev_err(sdev->dev, "error: failed to ioremap LPE base 0x%x size 0x%x\n", + base, size); + return -ENODEV; + } + dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[BYT_DSP_BAR]); + + /* IMR base - optional */ + if (desc->resindex_imr_base == -1) + goto irq; + + base = pci_resource_start(pci, desc->resindex_imr_base); + size = pci_resource_len(pci, desc->resindex_imr_base); + + /* some BIOSes don't map IMR */ + if (base == 0x55aa55aa || base == 0x0) { + dev_info(sdev->dev, "IMR not set by BIOS. Ignoring\n"); + goto irq; + } + + dev_dbg(sdev->dev, "IMR base at 0x%x size 0x%x", base, size); + sdev->bar[BYT_IMR_BAR] = devm_ioremap(sdev->dev, base, size); + if (!sdev->bar[BYT_IMR_BAR]) { + dev_err(sdev->dev, "error: failed to ioremap IMR base 0x%x size 0x%x\n", + base, size); + return -ENODEV; + } + dev_dbg(sdev->dev, "IMR VADDR %p\n", sdev->bar[BYT_IMR_BAR]); + +irq: + /* register our IRQ */ + sdev->ipc_irq = pci->irq; + dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); + ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, + byt_irq_handler, byt_irq_thread, + 0, "AudioDSP", sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to register IRQ %d\n", + sdev->ipc_irq); + return ret; + } + + /* enable Interrupt from both sides */ + snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRX, 0x3, 0x0); + snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRD, 0x3, 0x0); + + /* set default mailbox offset for FW ready message */ + sdev->dsp_box.offset = MBOX_OFFSET; + + return ret; +} + +const struct snd_sof_dsp_ops sof_tng_ops = { + /* device init */ + .probe = tangier_pci_probe, + + /* DSP core boot / reset */ + .run = byt_run, + .reset = byt_reset, + + /* Register IO */ + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* doorbell */ + .irq_handler = byt_irq_handler, + .irq_thread = byt_irq_thread, + + /* ipc */ + .send_msg = byt_send_msg, + .fw_ready = byt_fw_ready, + + .ipc_msg_data = intel_ipc_msg_data, + .ipc_pcm_params = intel_ipc_pcm_params, + + /* debug */ + .debug_map = byt_debugfs, + .debug_map_count = ARRAY_SIZE(byt_debugfs), + .dbg_dump = byt_dump, + + /* stream callbacks */ + .pcm_open = intel_pcm_open, + .pcm_close = intel_pcm_close, + + /* module loading */ + .load_module = snd_sof_parse_module_memcpy, + + /*Firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + + /* DAI drivers */ + .drv = byt_dai, + .num_drv = 3, /* we have only 3 SSPs on byt*/ +}; +EXPORT_SYMBOL(sof_tng_ops); + +const struct sof_intel_dsp_desc tng_chip_info = { + .cores_num = 1, + .cores_mask = 1, +}; +EXPORT_SYMBOL(tng_chip_info); + +#endif /* CONFIG_SND_SOC_SOF_MERRIFIELD */ + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) + +static int byt_acpi_probe(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *pdata = sdev->pdata; + const struct sof_dev_desc *desc = pdata->desc; + struct platform_device *pdev = + container_of(sdev->dev, struct platform_device, dev); + struct resource *mmio; + u32 base, size; + int ret; + + /* DSP DMA can only access low 31 bits of host memory */ + ret = dma_coerce_mask_and_coherent(sdev->dev, DMA_BIT_MASK(31)); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DMA mask %d\n", ret); + return ret; + } + + /* LPE base */ + mmio = platform_get_resource(pdev, IORESOURCE_MEM, + desc->resindex_lpe_base); + if (mmio) { + base = mmio->start; + size = resource_size(mmio); + } else { + dev_err(sdev->dev, "error: failed to get LPE base at idx %d\n", + desc->resindex_lpe_base); + return -EINVAL; + } + + dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); + sdev->bar[BYT_DSP_BAR] = devm_ioremap(sdev->dev, base, size); + if (!sdev->bar[BYT_DSP_BAR]) { + dev_err(sdev->dev, "error: failed to ioremap LPE base 0x%x size 0x%x\n", + base, size); + return -ENODEV; + } + dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[BYT_DSP_BAR]); + + /* TODO: add offsets */ + sdev->mmio_bar = BYT_DSP_BAR; + sdev->mailbox_bar = BYT_DSP_BAR; + + /* IMR base - optional */ + if (desc->resindex_imr_base == -1) + goto irq; + + mmio = platform_get_resource(pdev, IORESOURCE_MEM, + desc->resindex_imr_base); + if (mmio) { + base = mmio->start; + size = resource_size(mmio); + } else { + dev_err(sdev->dev, "error: failed to get IMR base at idx %d\n", + desc->resindex_imr_base); + return -ENODEV; + } + + /* some BIOSes don't map IMR */ + if (base == 0x55aa55aa || base == 0x0) { + dev_info(sdev->dev, "IMR not set by BIOS. Ignoring\n"); + goto irq; + } + + dev_dbg(sdev->dev, "IMR base at 0x%x size 0x%x", base, size); + sdev->bar[BYT_IMR_BAR] = devm_ioremap(sdev->dev, base, size); + if (!sdev->bar[BYT_IMR_BAR]) { + dev_err(sdev->dev, "error: failed to ioremap IMR base 0x%x size 0x%x\n", + base, size); + return -ENODEV; + } + dev_dbg(sdev->dev, "IMR VADDR %p\n", sdev->bar[BYT_IMR_BAR]); + +irq: + /* register our IRQ */ + sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc); + if (sdev->ipc_irq < 0) { + dev_err(sdev->dev, "error: failed to get IRQ at index %d\n", + desc->irqindex_host_ipc); + return sdev->ipc_irq; + } + + dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); + ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, + byt_irq_handler, byt_irq_thread, + IRQF_SHARED, "AudioDSP", sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to register IRQ %d\n", + sdev->ipc_irq); + return ret; + } + + /* enable Interrupt from both sides */ + snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRX, 0x3, 0x0); + snd_sof_dsp_update_bits64(sdev, BYT_DSP_BAR, SHIM_IMRD, 0x3, 0x0); + + /* set default mailbox offset for FW ready message */ + sdev->dsp_box.offset = MBOX_OFFSET; + + return ret; +} + +/* baytrail ops */ +const struct snd_sof_dsp_ops sof_byt_ops = { + /* device init */ + .probe = byt_acpi_probe, + + /* DSP core boot / reset */ + .run = byt_run, + .reset = byt_reset, + + /* Register IO */ + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* doorbell */ + .irq_handler = byt_irq_handler, + .irq_thread = byt_irq_thread, + + /* ipc */ + .send_msg = byt_send_msg, + .fw_ready = byt_fw_ready, + + .ipc_msg_data = intel_ipc_msg_data, + .ipc_pcm_params = intel_ipc_pcm_params, + + /* debug */ + .debug_map = byt_debugfs, + .debug_map_count = ARRAY_SIZE(byt_debugfs), + .dbg_dump = byt_dump, + + /* stream callbacks */ + .pcm_open = intel_pcm_open, + .pcm_close = intel_pcm_close, + + /* module loading */ + .load_module = snd_sof_parse_module_memcpy, + + /*Firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + + /* DAI drivers */ + .drv = byt_dai, + .num_drv = 3, /* we have only 3 SSPs on byt*/ +}; +EXPORT_SYMBOL(sof_byt_ops); + +const struct sof_intel_dsp_desc byt_chip_info = { + .cores_num = 1, + .cores_mask = 1, +}; +EXPORT_SYMBOL(byt_chip_info); + +/* cherrytrail and braswell ops */ +const struct snd_sof_dsp_ops sof_cht_ops = { + /* device init */ + .probe = byt_acpi_probe, + + /* DSP core boot / reset */ + .run = byt_run, + .reset = byt_reset, + + /* Register IO */ + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* doorbell */ + .irq_handler = byt_irq_handler, + .irq_thread = byt_irq_thread, + + /* ipc */ + .send_msg = byt_send_msg, + .fw_ready = byt_fw_ready, + + .ipc_msg_data = intel_ipc_msg_data, + .ipc_pcm_params = intel_ipc_pcm_params, + + /* debug */ + .debug_map = cht_debugfs, + .debug_map_count = ARRAY_SIZE(cht_debugfs), + .dbg_dump = byt_dump, + + /* stream callbacks */ + .pcm_open = intel_pcm_open, + .pcm_close = intel_pcm_close, + + /* module loading */ + .load_module = snd_sof_parse_module_memcpy, + + /*Firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + + /* DAI drivers */ + .drv = byt_dai, + /* all 6 SSPs may be available for cherrytrail */ + .num_drv = ARRAY_SIZE(byt_dai), +}; +EXPORT_SYMBOL(sof_cht_ops); + +const struct sof_intel_dsp_desc cht_chip_info = { + .cores_num = 1, + .cores_mask = 1, +}; +EXPORT_SYMBOL(cht_chip_info); + +#endif /* CONFIG_SND_SOC_SOF_BAYTRAIL */ + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h new file mode 100644 index 00000000000000..11fd77cb4e6d0b --- /dev/null +++ b/sound/soc/sof/intel/shim.h @@ -0,0 +1,183 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __SOF_INTEL_SHIM_H +#define __SOF_INTEL_SHIM_H + +/* + * SHIM registers for BYT, BSW, CHT, HSW, BDW + */ + +#define SHIM_CSR (SHIM_OFFSET + 0x00) +#define SHIM_PISR (SHIM_OFFSET + 0x08) +#define SHIM_PIMR (SHIM_OFFSET + 0x10) +#define SHIM_ISRX (SHIM_OFFSET + 0x18) +#define SHIM_ISRD (SHIM_OFFSET + 0x20) +#define SHIM_IMRX (SHIM_OFFSET + 0x28) +#define SHIM_IMRD (SHIM_OFFSET + 0x30) +#define SHIM_IPCX (SHIM_OFFSET + 0x38) +#define SHIM_IPCD (SHIM_OFFSET + 0x40) +#define SHIM_ISRSC (SHIM_OFFSET + 0x48) +#define SHIM_ISRLPESC (SHIM_OFFSET + 0x50) +#define SHIM_IMRSC (SHIM_OFFSET + 0x58) +#define SHIM_IMRLPESC (SHIM_OFFSET + 0x60) +#define SHIM_IPCSC (SHIM_OFFSET + 0x68) +#define SHIM_IPCLPESC (SHIM_OFFSET + 0x70) +#define SHIM_CLKCTL (SHIM_OFFSET + 0x78) +#define SHIM_CSR2 (SHIM_OFFSET + 0x80) +#define SHIM_LTRC (SHIM_OFFSET + 0xE0) +#define SHIM_HMDC (SHIM_OFFSET + 0xE8) + +#define SHIM_PWMCTRL 0x1000 + +/* + * SST SHIM register bits for BYT, BSW, CHT HSW, BDW + * Register bit naming and functionaility can differ between devices. + */ + +/* CSR / CS */ +#define SHIM_CSR_RST BIT(1) +#define SHIM_CSR_SBCS0 BIT(2) +#define SHIM_CSR_SBCS1 BIT(3) +#define SHIM_CSR_DCS(x) ((x) << 4) +#define SHIM_CSR_DCS_MASK (0x7 << 4) +#define SHIM_CSR_STALL BIT(10) +#define SHIM_CSR_S0IOCS BIT(21) +#define SHIM_CSR_S1IOCS BIT(23) +#define SHIM_CSR_LPCS BIT(31) +#define SHIM_CSR_24MHZ_LPCS \ + (SHIM_CSR_SBCS0 | SHIM_CSR_SBCS1 | SHIM_CSR_LPCS) +#define SHIM_CSR_24MHZ_NO_LPCS (SHIM_CSR_SBCS0 | SHIM_CSR_SBCS1) +#define SHIM_BYT_CSR_RST BIT(0) +#define SHIM_BYT_CSR_VECTOR_SEL BIT(1) +#define SHIM_BYT_CSR_STALL BIT(2) +#define SHIM_BYT_CSR_PWAITMODE BIT(3) + +/* ISRX / ISC */ +#define SHIM_ISRX_BUSY BIT(1) +#define SHIM_ISRX_DONE BIT(0) +#define SHIM_BYT_ISRX_REQUEST BIT(1) + +/* ISRD / ISD */ +#define SHIM_ISRD_BUSY BIT(1) +#define SHIM_ISRD_DONE BIT(0) + +/* IMRX / IMC */ +#define SHIM_IMRX_BUSY BIT(1) +#define SHIM_IMRX_DONE BIT(0) +#define SHIM_BYT_IMRX_REQUEST BIT(1) + +/* IMRD / IMD */ +#define SHIM_IMRD_DONE BIT(0) +#define SHIM_IMRD_BUSY BIT(1) +#define SHIM_IMRD_SSP0 BIT(16) +#define SHIM_IMRD_DMAC0 BIT(21) +#define SHIM_IMRD_DMAC1 BIT(22) +#define SHIM_IMRD_DMAC (SHIM_IMRD_DMAC0 | SHIM_IMRD_DMAC1) + +/* IPCX / IPCC */ +#define SHIM_IPCX_DONE BIT(30) +#define SHIM_IPCX_BUSY BIT(31) +#define SHIM_BYT_IPCX_DONE BIT_ULL(62) +#define SHIM_BYT_IPCX_BUSY BIT_ULL(63) + +/* IPCD */ +#define SHIM_IPCD_DONE BIT(30) +#define SHIM_IPCD_BUSY BIT(31) +#define SHIM_BYT_IPCD_DONE BIT_ULL(62) +#define SHIM_BYT_IPCD_BUSY BIT_ULL(63) + +/* CLKCTL */ +#define SHIM_CLKCTL_SMOS(x) ((x) << 24) +#define SHIM_CLKCTL_MASK (3 << 24) +#define SHIM_CLKCTL_DCPLCG BIT(18) +#define SHIM_CLKCTL_SCOE1 BIT(17) +#define SHIM_CLKCTL_SCOE0 BIT(16) + +/* CSR2 / CS2 */ +#define SHIM_CSR2_SDFD_SSP0 BIT(1) +#define SHIM_CSR2_SDFD_SSP1 BIT(2) + +/* LTRC */ +#define SHIM_LTRC_VAL(x) ((x) << 0) + +/* HMDC */ +#define SHIM_HMDC_HDDA0(x) ((x) << 0) +#define SHIM_HMDC_HDDA1(x) ((x) << 7) +#define SHIM_HMDC_HDDA_E0_CH0 1 +#define SHIM_HMDC_HDDA_E0_CH1 2 +#define SHIM_HMDC_HDDA_E0_CH2 4 +#define SHIM_HMDC_HDDA_E0_CH3 8 +#define SHIM_HMDC_HDDA_E1_CH0 SHIM_HMDC_HDDA1(SHIM_HMDC_HDDA_E0_CH0) +#define SHIM_HMDC_HDDA_E1_CH1 SHIM_HMDC_HDDA1(SHIM_HMDC_HDDA_E0_CH1) +#define SHIM_HMDC_HDDA_E1_CH2 SHIM_HMDC_HDDA1(SHIM_HMDC_HDDA_E0_CH2) +#define SHIM_HMDC_HDDA_E1_CH3 SHIM_HMDC_HDDA1(SHIM_HMDC_HDDA_E0_CH3) +#define SHIM_HMDC_HDDA_E0_ALLCH \ + (SHIM_HMDC_HDDA_E0_CH0 | SHIM_HMDC_HDDA_E0_CH1 | \ + SHIM_HMDC_HDDA_E0_CH2 | SHIM_HMDC_HDDA_E0_CH3) +#define SHIM_HMDC_HDDA_E1_ALLCH \ + (SHIM_HMDC_HDDA_E1_CH0 | SHIM_HMDC_HDDA_E1_CH1 | \ + SHIM_HMDC_HDDA_E1_CH2 | SHIM_HMDC_HDDA_E1_CH3) + +/* Audio DSP PCI registers */ +#define PCI_VDRTCTL0 0xa0 +#define PCI_VDRTCTL1 0xa4 +#define PCI_VDRTCTL2 0xa8 +#define PCI_VDRTCTL3 0xaC + +/* VDRTCTL0 */ +#define PCI_VDRTCL0_D3PGD BIT(0) +#define PCI_VDRTCL0_D3SRAMPGD BIT(1) +#define PCI_VDRTCL0_DSRAMPGE_SHIFT 12 +#define PCI_VDRTCL0_DSRAMPGE_MASK GENMASK(PCI_VDRTCL0_DSRAMPGE_SHIFT + 19,\ + PCI_VDRTCL0_DSRAMPGE_SHIFT) +#define PCI_VDRTCL0_ISRAMPGE_SHIFT 2 +#define PCI_VDRTCL0_ISRAMPGE_MASK GENMASK(PCI_VDRTCL0_ISRAMPGE_SHIFT + 9,\ + PCI_VDRTCL0_ISRAMPGE_SHIFT) + +/* VDRTCTL2 */ +#define PCI_VDRTCL2_DCLCGE BIT(1) +#define PCI_VDRTCL2_DTCGE BIT(10) +#define PCI_VDRTCL2_APLLSE_MASK BIT(31) + +/* PMCS */ +#define PCI_PMCS 0x84 +#define PCI_PMCS_PS_MASK 0x3 + +/* DSP hardware descriptor */ +struct sof_intel_dsp_desc { + int cores_num; + int cores_mask; + int init_core_mask; /* cores available after fw boot */ + int ipc_req; + int ipc_req_mask; + int ipc_ack; + int ipc_ack_mask; + int ipc_ctl; + int rom_init_timeout; +}; + +extern const struct snd_sof_dsp_ops sof_tng_ops; +extern const struct snd_sof_dsp_ops sof_byt_ops; +extern const struct snd_sof_dsp_ops sof_cht_ops; +extern const struct snd_sof_dsp_ops sof_hsw_ops; +extern const struct snd_sof_dsp_ops sof_bdw_ops; + +extern const struct sof_intel_dsp_desc byt_chip_info; +extern const struct sof_intel_dsp_desc cht_chip_info; +extern const struct sof_intel_dsp_desc bdw_chip_info; +extern const struct sof_intel_dsp_desc hsw_chip_info; +extern const struct sof_intel_dsp_desc tng_chip_info; + +struct sof_intel_stream { + size_t posn_offset; +}; + +#endif From 2af4dc762bdf9940418cb9b368c6e3f53fa8e3ee Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:08:45 -0500 Subject: [PATCH 1405/1995] ASoC: SOF: Intel: Add BDW HW DSP support Add SOF support for Intel Broadwell based devices. Signed-off-by: Rander Wang Signed-off-by: Pan Xiuli Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 458bc7296184729b5462f704fb0792b6f1676f0d) --- sound/soc/sof/intel/bdw.c | 713 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 713 insertions(+) create mode 100644 sound/soc/sof/intel/bdw.c diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c new file mode 100644 index 00000000000000..065cb868bdface --- /dev/null +++ b/sound/soc/sof/intel/bdw.c @@ -0,0 +1,713 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +/* + * Hardware interface for audio DSP on Broadwell + */ + +#include +#include +#include +#include "../ops.h" +#include "shim.h" + +/* BARs */ +#define BDW_DSP_BAR 0 +#define BDW_PCI_BAR 1 + +/* + * Debug + */ + +/* DSP memories for BDW */ +#define IRAM_OFFSET 0xA0000 +#define BDW_IRAM_SIZE (10 * 32 * 1024) +#define DRAM_OFFSET 0x00000 +#define BDW_DRAM_SIZE (20 * 32 * 1024) +#define SHIM_OFFSET 0xFB000 +#define SHIM_SIZE 0x100 +#define MBOX_OFFSET 0x9E000 +#define MBOX_SIZE 0x1000 +#define MBOX_DUMP_SIZE 0x30 +#define EXCEPT_OFFSET 0x800 + +/* DSP peripherals */ +#define DMAC0_OFFSET 0xFE000 +#define DMAC1_OFFSET 0xFF000 +#define DMAC_SIZE 0x420 +#define SSP0_OFFSET 0xFC000 +#define SSP1_OFFSET 0xFD000 +#define SSP_SIZE 0x100 + +#define BDW_STACK_DUMP_SIZE 32 + +#define BDW_PANIC_OFFSET(x) ((x) & 0xFFFF) + +static const struct snd_sof_debugfs_map bdw_debugfs[] = { + {"dmac0", BDW_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dmac1", BDW_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp0", BDW_DSP_BAR, SSP0_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"ssp1", BDW_DSP_BAR, SSP1_OFFSET, SSP_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, + {"iram", BDW_DSP_BAR, IRAM_OFFSET, BDW_IRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"dram", BDW_DSP_BAR, DRAM_OFFSET, BDW_DRAM_SIZE, + SOF_DEBUGFS_ACCESS_D0_ONLY}, + {"shim", BDW_DSP_BAR, SHIM_OFFSET, SHIM_SIZE, + SOF_DEBUGFS_ACCESS_ALWAYS}, +}; + +static void bdw_host_done(struct snd_sof_dev *sdev); +static void bdw_dsp_done(struct snd_sof_dev *sdev); +static void bdw_get_reply(struct snd_sof_dev *sdev); + +/* + * DSP Control. + */ + +static int bdw_run(struct snd_sof_dev *sdev) +{ + /* set opportunistic mode on engine 0,1 for all channels */ + snd_sof_dsp_update_bits(sdev, BDW_DSP_BAR, SHIM_HMDC, + SHIM_HMDC_HDDA_E0_ALLCH | + SHIM_HMDC_HDDA_E1_ALLCH, 0); + + /* set DSP to RUN */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CSR, + SHIM_CSR_STALL, 0x0); + + /* return init core mask */ + return 1; +} + +static int bdw_reset(struct snd_sof_dev *sdev) +{ + /* put DSP into reset and stall */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CSR, + SHIM_CSR_RST | SHIM_CSR_STALL, + SHIM_CSR_RST | SHIM_CSR_STALL); + + /* keep in reset for 10ms */ + mdelay(10); + + /* take DSP out of reset and keep stalled for FW loading */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CSR, + SHIM_CSR_RST | SHIM_CSR_STALL, + SHIM_CSR_STALL); + + return 0; +} + +static int bdw_set_dsp_D0(struct snd_sof_dev *sdev) +{ + int tries = 10; + u32 reg; + + /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_VDRTCTL2, + PCI_VDRTCL2_DCLCGE | + PCI_VDRTCL2_DTCGE, 0); + + /* Disable D3PG (VDRTCTL0.D3PGD = 1) */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_VDRTCTL0, + PCI_VDRTCL0_D3PGD, PCI_VDRTCL0_D3PGD); + + /* Set D0 state */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_PMCS, + PCI_PMCS_PS_MASK, 0); + + /* check that ADSP shim is enabled */ + while (tries--) { + reg = readl(sdev->bar[BDW_PCI_BAR] + PCI_PMCS) + & PCI_PMCS_PS_MASK; + if (reg == 0) + goto finish; + + msleep(20); + } + + return -ENODEV; + +finish: + /* + * select SSP1 19.2MHz base clock, SSP clock 0, + * turn off Low Power Clock + */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CSR, + SHIM_CSR_S1IOCS | SHIM_CSR_SBCS1 | + SHIM_CSR_LPCS, 0x0); + + /* stall DSP core, set clk to 192/96Mhz */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, + SHIM_CSR, SHIM_CSR_STALL | + SHIM_CSR_DCS_MASK, + SHIM_CSR_STALL | + SHIM_CSR_DCS(4)); + + /* Set 24MHz MCLK, prevent local clock gating, enable SSP0 clock */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CLKCTL, + SHIM_CLKCTL_MASK | + SHIM_CLKCTL_DCPLCG | + SHIM_CLKCTL_SCOE0, + SHIM_CLKCTL_MASK | + SHIM_CLKCTL_DCPLCG | + SHIM_CLKCTL_SCOE0); + + /* Stall and reset core, set CSR */ + bdw_reset(sdev); + + /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_VDRTCTL2, + PCI_VDRTCL2_DCLCGE | + PCI_VDRTCL2_DTCGE, + PCI_VDRTCL2_DCLCGE | + PCI_VDRTCL2_DTCGE); + + usleep_range(50, 55); + + /* switch on audio PLL */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_VDRTCTL2, + PCI_VDRTCL2_APLLSE_MASK, 0); + + /* + * set default power gating control, enable power gating control for + * all blocks. that is, can't be accessed, please enable each block + * before accessing. + */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_PCI_BAR, PCI_VDRTCTL0, + 0xfffffffC, 0x0); + + /* disable DMA finish function for SSP0 & SSP1 */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_CSR2, + SHIM_CSR2_SDFD_SSP1, + SHIM_CSR2_SDFD_SSP1); + + /* set on-demond mode on engine 0,1 for all channels */ + snd_sof_dsp_update_bits(sdev, BDW_DSP_BAR, SHIM_HMDC, + SHIM_HMDC_HDDA_E0_ALLCH | + SHIM_HMDC_HDDA_E1_ALLCH, + SHIM_HMDC_HDDA_E0_ALLCH | + SHIM_HMDC_HDDA_E1_ALLCH); + + /* Enable Interrupt from both sides */ + snd_sof_dsp_update_bits(sdev, BDW_DSP_BAR, SHIM_IMRX, + (SHIM_IMRX_BUSY | SHIM_IMRX_DONE), 0x0); + snd_sof_dsp_update_bits(sdev, BDW_DSP_BAR, SHIM_IMRD, + (SHIM_IMRD_DONE | SHIM_IMRD_BUSY | + SHIM_IMRD_SSP0 | SHIM_IMRD_DMAC), 0x0); + + /* clear IPC registers */ + snd_sof_dsp_write(sdev, BDW_DSP_BAR, SHIM_IPCX, 0x0); + snd_sof_dsp_write(sdev, BDW_DSP_BAR, SHIM_IPCD, 0x0); + snd_sof_dsp_write(sdev, BDW_DSP_BAR, 0x80, 0x6); + snd_sof_dsp_write(sdev, BDW_DSP_BAR, 0xe0, 0x300a); + + return 0; +} + +static void bdw_get_registers(struct snd_sof_dev *sdev, + struct sof_ipc_dsp_oops_xtensa *xoops, + struct sof_ipc_panic_info *panic_info, + u32 *stack, size_t stack_words) +{ + /* first read regsisters */ + sof_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); + + /* then get panic info */ + sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), + panic_info, sizeof(*panic_info)); + + /* then get the stack */ + sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + + sizeof(*panic_info), stack, + stack_words * sizeof(u32)); +} + +static void bdw_dump(struct snd_sof_dev *sdev, u32 flags) +{ + struct sof_ipc_dsp_oops_xtensa xoops; + struct sof_ipc_panic_info panic_info; + u32 stack[BDW_STACK_DUMP_SIZE]; + u32 status, panic; + + /* now try generic SOF status messages */ + status = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD); + panic = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCX); + bdw_get_registers(sdev, &xoops, &panic_info, stack, + BDW_STACK_DUMP_SIZE); + snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, + BDW_STACK_DUMP_SIZE); +} + +/* + * IPC Doorbell IRQ handler and thread. + */ + +static irqreturn_t bdw_irq_handler(int irq, void *context) +{ + struct snd_sof_dev *sdev = context; + u32 isr; + int ret = IRQ_NONE; + + /* Interrupt arrived, check src */ + isr = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_ISRX); + if (isr & (SHIM_ISRX_DONE | SHIM_ISRX_BUSY)) + ret = IRQ_WAKE_THREAD; + + return ret; +} + +static irqreturn_t bdw_irq_thread(int irq, void *context) +{ + struct snd_sof_dev *sdev = context; + u32 ipcx, ipcd, imrx; + + imrx = snd_sof_dsp_read64(sdev, BDW_DSP_BAR, SHIM_IMRX); + ipcx = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCX); + + /* reply message from DSP */ + if (ipcx & SHIM_IPCX_DONE && + !(imrx & SHIM_IMRX_DONE)) { + /* Mask Done interrupt before return */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, + SHIM_IMRX, SHIM_IMRX_DONE, + SHIM_IMRX_DONE); + + /* + * handle immediate reply from DSP core. If the msg is + * found, set done bit in cmd_done which is called at the + * end of message processing function, else set it here + * because the done bit can't be set in cmd_done function + * which is triggered by msg + */ + bdw_get_reply(sdev); + snd_sof_ipc_reply(sdev, ipcx); + + bdw_dsp_done(sdev); + } + + ipcd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD); + + /* new message from DSP */ + if (ipcd & SHIM_IPCD_BUSY && + !(imrx & SHIM_IMRX_BUSY)) { + /* Mask Busy interrupt before return */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, + SHIM_IMRX, SHIM_IMRX_BUSY, + SHIM_IMRX_BUSY); + + /* Handle messages from DSP Core */ + if ((ipcd & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { + snd_sof_dsp_panic(sdev, BDW_PANIC_OFFSET(ipcx) + + MBOX_OFFSET); + } else { + snd_sof_ipc_msgs_rx(sdev); + } + + bdw_host_done(sdev); + } + + return IRQ_HANDLED; +} + +/* + * IPC Firmware ready. + */ +static void bdw_get_windows(struct snd_sof_dev *sdev) +{ + struct sof_ipc_window_elem *elem; + u32 outbox_offset = 0; + u32 stream_offset = 0; + u32 inbox_offset = 0; + u32 outbox_size = 0; + u32 stream_size = 0; + u32 inbox_size = 0; + int i; + + if (!sdev->info_window) { + dev_err(sdev->dev, "error: have no window info\n"); + return; + } + + for (i = 0; i < sdev->info_window->num_windows; i++) { + elem = &sdev->info_window->window[i]; + + switch (elem->type) { + case SOF_IPC_REGION_UPBOX: + inbox_offset = elem->offset + MBOX_OFFSET; + inbox_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[BDW_DSP_BAR] + + inbox_offset, + elem->size, "inbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_DOWNBOX: + outbox_offset = elem->offset + MBOX_OFFSET; + outbox_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[BDW_DSP_BAR] + + outbox_offset, + elem->size, "outbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_TRACE: + snd_sof_debugfs_io_item(sdev, + sdev->bar[BDW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "etrace", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_DEBUG: + snd_sof_debugfs_io_item(sdev, + sdev->bar[BDW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "debug", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_STREAM: + stream_offset = elem->offset + MBOX_OFFSET; + stream_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[BDW_DSP_BAR] + + stream_offset, + elem->size, "stream", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_REGS: + snd_sof_debugfs_io_item(sdev, + sdev->bar[BDW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "regs", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_EXCEPTION: + sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; + snd_sof_debugfs_io_item(sdev, + sdev->bar[BDW_DSP_BAR] + + elem->offset + + MBOX_OFFSET, + elem->size, "exception", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + default: + dev_err(sdev->dev, "error: get illegal window info\n"); + return; + } + } + + if (outbox_size == 0 || inbox_size == 0) { + dev_err(sdev->dev, "error: get illegal mailbox window\n"); + return; + } + + snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, + outbox_offset, outbox_size); + sdev->stream_box.offset = stream_offset; + sdev->stream_box.size = stream_size; + + dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", + inbox_offset, inbox_size); + dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", + outbox_offset, outbox_size); + dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", + stream_offset, stream_size); +} + +/* check for ABI compatibility and create memory windows on first boot */ +static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; + u32 offset; + int ret; + + /* mailbox must be on 4k boundary */ + offset = MBOX_OFFSET; + + dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset %d\n", + msg_id, offset); + + /* no need to re-check version/ABI for subsequent boots */ + if (!sdev->first_boot) + return 0; + + /* copy data from the DSP FW ready offset */ + sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, + sizeof(*fw_ready)); + + snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, + fw_ready->dspbox_size, + fw_ready->hostbox_offset, + fw_ready->hostbox_size); + + /* make sure ABI version is compatible */ + ret = snd_sof_ipc_valid(sdev); + if (ret < 0) + return ret; + + /* now check for extended data */ + snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + + sizeof(struct sof_ipc_fw_ready)); + + bdw_get_windows(sdev); + + return 0; +} + +/* + * IPC Mailbox IO + */ + +static int bdw_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + /* send the message */ + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + snd_sof_dsp_write(sdev, BDW_DSP_BAR, SHIM_IPCX, SHIM_IPCX_BUSY); + + return 0; +} + +static void bdw_get_reply(struct snd_sof_dev *sdev) +{ + struct snd_sof_ipc_msg *msg = sdev->msg; + struct sof_ipc_reply reply; + unsigned long flags; + int ret = 0; + + /* + * Sometimes, there is unexpected reply ipc arriving. The reply + * ipc belongs to none of the ipcs sent from driver. + * In this case, the driver must ignore the ipc. + */ + if (!msg) { + dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); + return; + } + + /* get reply */ + sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); + + spin_lock_irqsave(&sdev->ipc_lock, flags); + + if (reply.error < 0) { + memcpy(msg->reply_data, &reply, sizeof(reply)); + ret = reply.error; + } else { + /* reply correct size ? */ + if (reply.hdr.size != msg->reply_size) { + dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", + msg->reply_size, reply.hdr.size); + ret = -EINVAL; + } + + /* read the message */ + if (msg->reply_size > 0) + sof_mailbox_read(sdev, sdev->host_box.offset, + msg->reply_data, msg->reply_size); + } + + msg->reply_error = ret; + + spin_unlock_irqrestore(&sdev->ipc_lock, flags); +} + +static void bdw_host_done(struct snd_sof_dev *sdev) +{ + /* clear BUSY bit and set DONE bit - accept new messages */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCD, + SHIM_IPCD_BUSY | SHIM_IPCD_DONE, + SHIM_IPCD_DONE); + + /* unmask busy interrupt */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_BUSY, 0); +} + +static void bdw_dsp_done(struct snd_sof_dev *sdev) +{ + /* clear DONE bit - tell DSP we have completed */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IPCX, + SHIM_IPCX_DONE, 0); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX, + SHIM_IMRX_DONE, 0); +} + +/* + * Probe and remove. + */ +static int bdw_probe(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *pdata = sdev->pdata; + const struct sof_dev_desc *desc = pdata->desc; + struct platform_device *pdev = + container_of(sdev->dev, struct platform_device, dev); + struct resource *mmio; + u32 base, size; + int ret; + + /* LPE base */ + mmio = platform_get_resource(pdev, IORESOURCE_MEM, + desc->resindex_lpe_base); + if (mmio) { + base = mmio->start; + size = resource_size(mmio); + } else { + dev_err(sdev->dev, "error: failed to get LPE base at idx %d\n", + desc->resindex_lpe_base); + return -EINVAL; + } + + dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); + sdev->bar[BDW_DSP_BAR] = devm_ioremap(sdev->dev, base, size); + if (!sdev->bar[BDW_DSP_BAR]) { + dev_err(sdev->dev, + "error: failed to ioremap LPE base 0x%x size 0x%x\n", + base, size); + return -ENODEV; + } + dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[BDW_DSP_BAR]); + + /* TODO: add offsets */ + sdev->mmio_bar = BDW_DSP_BAR; + sdev->mailbox_bar = BDW_DSP_BAR; + + /* PCI base */ + mmio = platform_get_resource(pdev, IORESOURCE_MEM, + desc->resindex_pcicfg_base); + if (mmio) { + base = mmio->start; + size = resource_size(mmio); + } else { + dev_err(sdev->dev, "error: failed to get PCI base at idx %d\n", + desc->resindex_pcicfg_base); + return -ENODEV; + } + + dev_dbg(sdev->dev, "PCI base at 0x%x size 0x%x", base, size); + sdev->bar[BDW_PCI_BAR] = devm_ioremap(sdev->dev, base, size); + if (!sdev->bar[BDW_PCI_BAR]) { + dev_err(sdev->dev, + "error: failed to ioremap PCI base 0x%x size 0x%x\n", + base, size); + return -ENODEV; + } + dev_dbg(sdev->dev, "PCI VADDR %p\n", sdev->bar[BDW_PCI_BAR]); + + /* register our IRQ */ + sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc); + if (sdev->ipc_irq < 0) { + dev_err(sdev->dev, "error: failed to get IRQ at index %d\n", + desc->irqindex_host_ipc); + return sdev->ipc_irq; + } + + dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); + ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, + bdw_irq_handler, bdw_irq_thread, + IRQF_SHARED, "AudioDSP", sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to register IRQ %d\n", + sdev->ipc_irq); + return ret; + } + + /* enable the DSP SHIM */ + ret = bdw_set_dsp_D0(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DSP D0\n"); + return ret; + } + + /* DSP DMA can only access low 31 bits of host memory */ + ret = dma_coerce_mask_and_coherent(sdev->dev, DMA_BIT_MASK(31)); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DMA mask %d\n", ret); + return ret; + } + + /* set default mailbox */ + snd_sof_dsp_mailbox_init(sdev, MBOX_OFFSET, MBOX_SIZE, 0, 0); + + return ret; +} + +/* Broadwell DAIs */ +static struct snd_soc_dai_driver bdw_dai[] = { +{ + .name = "ssp0-port", +}, +{ + .name = "ssp1-port", +}, +}; + +/* broadwell ops */ +const struct snd_sof_dsp_ops sof_bdw_ops = { + /*Device init */ + .probe = bdw_probe, + + /* DSP Core Control */ + .run = bdw_run, + .reset = bdw_reset, + + /* Register IO */ + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* ipc */ + .send_msg = bdw_send_msg, + .fw_ready = bdw_fw_ready, + + .ipc_msg_data = intel_ipc_msg_data, + .ipc_pcm_params = intel_ipc_pcm_params, + + /* debug */ + .debug_map = bdw_debugfs, + .debug_map_count = ARRAY_SIZE(bdw_debugfs), + .dbg_dump = bdw_dump, + + /* stream callbacks */ + .pcm_open = intel_pcm_open, + .pcm_close = intel_pcm_close, + + /* Module loading */ + .load_module = snd_sof_parse_module_memcpy, + + /*Firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + + /* DAI drivers */ + .drv = bdw_dai, + .num_drv = ARRAY_SIZE(bdw_dai) +}; +EXPORT_SYMBOL(sof_bdw_ops); + +const struct sof_intel_dsp_desc bdw_chip_info = { + .cores_num = 1, + .cores_mask = 1, +}; +EXPORT_SYMBOL(bdw_chip_info); + +MODULE_LICENSE("Dual BSD/GPL"); From 370ea4abf831c834f022481c15fc67c2f26aa1e4 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 12 Apr 2019 11:08:46 -0500 Subject: [PATCH 1406/1995] ASoC: SOF: Intel: Add legacy IPC support Add IPC support required for devices introduced before Skylake (Merrifield, baytrail, CherryTrail, Haswell, Broadwell) Signed-off-by: Guennadi Liakhovetski Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 351d1174fef03adb4defed7ef14f1ede0251aae9) --- sound/soc/sof/intel/intel-ipc.c | 92 +++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 sound/soc/sof/intel/intel-ipc.c diff --git a/sound/soc/sof/intel/intel-ipc.c b/sound/soc/sof/intel/intel-ipc.c new file mode 100644 index 00000000000000..4edd92151fd5fb --- /dev/null +++ b/sound/soc/sof/intel/intel-ipc.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2019 Intel Corporation. All rights reserved. +// +// Authors: Guennadi Liakhovetski + +/* Intel-specific SOF IPC code */ + +#include +#include +#include +#include + +#include +#include + +#include "../ops.h" +#include "../sof-priv.h" + +struct intel_stream { + size_t posn_offset; +}; + +/* Mailbox-based Intel IPC implementation */ +void intel_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz) +{ + if (!substream || !sdev->stream_box.size) { + sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); + } else { + struct intel_stream *stream = substream->runtime->private_data; + + /* The stream might already be closed */ + if (stream) + sof_mailbox_read(sdev, stream->posn_offset, p, sz); + } +} +EXPORT_SYMBOL(intel_ipc_msg_data); + +int intel_ipc_pcm_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply) +{ + struct intel_stream *stream = substream->runtime->private_data; + size_t posn_offset = reply->posn_offset; + + /* check if offset is overflow or it is not aligned */ + if (posn_offset > sdev->stream_box.size || + posn_offset % sizeof(struct sof_ipc_stream_posn) != 0) + return -EINVAL; + + stream->posn_offset = sdev->stream_box.offset + posn_offset; + + dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu", + substream->stream, stream->posn_offset); + + return 0; +} +EXPORT_SYMBOL(intel_ipc_pcm_params); + +int intel_pcm_open(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct intel_stream *stream = kmalloc(sizeof(*stream), GFP_KERNEL); + + if (!stream) + return -ENOMEM; + + /* binding pcm substream to hda stream */ + substream->runtime->private_data = stream; + + return 0; +} +EXPORT_SYMBOL(intel_pcm_open); + +int intel_pcm_close(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct intel_stream *stream = substream->runtime->private_data; + + substream->runtime->private_data = NULL; + kfree(stream); + + return 0; +} +EXPORT_SYMBOL(intel_pcm_close); + +MODULE_LICENSE("Dual BSD/GPL"); From d7c55fa623e45a7b8db73c7f477f484af8e54d5c Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:08:47 -0500 Subject: [PATCH 1407/1995] ASoC: SOF: Intel: Add APL/CNL HW DSP support Add SOF hardware DSP support for Intel Apollolake and Cannonlake based devices. Signed-off-by: Keyon Jie Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit dd96daca6c83ecaf37f38ff49d8d174bbff576b4) --- sound/soc/sof/intel/hda.c | 671 ++++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 560 +++++++++++++++++++++++++++++++ 2 files changed, 1231 insertions(+) create mode 100644 sound/soc/sof/intel/hda.c create mode 100644 sound/soc/sof/intel/hda.h diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c new file mode 100644 index 00000000000000..b8fc19790f3b80 --- /dev/null +++ b/sound/soc/sof/intel/hda.c @@ -0,0 +1,671 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for generic Intel audio DSP HDA IP + */ + +#include +#include +#include +#include +#include "../ops.h" +#include "hda.h" +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +#include "../../codecs/hdac_hda.h" +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +#include +#endif + +/* platform specific devices */ +#include "shim.h" + +/* + * Debug + */ + +struct hda_dsp_msg_code { + u32 code; + const char *msg; +}; + +static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = { + {HDA_DSP_ROM_FW_MANIFEST_LOADED, "status: manifest loaded"}, + {HDA_DSP_ROM_FW_FW_LOADED, "status: fw loaded"}, + {HDA_DSP_ROM_FW_ENTERED, "status: fw entered"}, + {HDA_DSP_ROM_CSE_ERROR, "error: cse error"}, + {HDA_DSP_ROM_CSE_WRONG_RESPONSE, "error: cse wrong response"}, + {HDA_DSP_ROM_IMR_TO_SMALL, "error: IMR too small"}, + {HDA_DSP_ROM_BASE_FW_NOT_FOUND, "error: base fw not found"}, + {HDA_DSP_ROM_CSE_VALIDATION_FAILED, "error: signature verification failed"}, + {HDA_DSP_ROM_IPC_FATAL_ERROR, "error: ipc fatal error"}, + {HDA_DSP_ROM_L2_CACHE_ERROR, "error: L2 cache error"}, + {HDA_DSP_ROM_LOAD_OFFSET_TO_SMALL, "error: load offset too small"}, + {HDA_DSP_ROM_API_PTR_INVALID, "error: API ptr invalid"}, + {HDA_DSP_ROM_BASEFW_INCOMPAT, "error: base fw incompatble"}, + {HDA_DSP_ROM_UNHANDLED_INTERRUPT, "error: unhandled interrupt"}, + {HDA_DSP_ROM_MEMORY_HOLE_ECC, "error: ECC memory hole"}, + {HDA_DSP_ROM_KERNEL_EXCEPTION, "error: kernel exception"}, + {HDA_DSP_ROM_USER_EXCEPTION, "error: user exception"}, + {HDA_DSP_ROM_UNEXPECTED_RESET, "error: unexpected reset"}, + {HDA_DSP_ROM_NULL_FW_ENTRY, "error: null FW entry point"}, +}; + +static void hda_dsp_get_status_skl(struct snd_sof_dev *sdev) +{ + u32 status; + int i; + + status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_ADSP_FW_STATUS_SKL); + + for (i = 0; i < ARRAY_SIZE(hda_dsp_rom_msg); i++) { + if (status == hda_dsp_rom_msg[i].code) { + dev_err(sdev->dev, "%s - code %8.8x\n", + hda_dsp_rom_msg[i].msg, status); + return; + } + } + + /* not for us, must be generic sof message */ + dev_dbg(sdev->dev, "unknown ROM status value %8.8x\n", status); +} + +static void hda_dsp_get_status(struct snd_sof_dev *sdev) +{ + u32 status; + int i; + + status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_STATUS); + + for (i = 0; i < ARRAY_SIZE(hda_dsp_rom_msg); i++) { + if (status == hda_dsp_rom_msg[i].code) { + dev_err(sdev->dev, "%s - code %8.8x\n", + hda_dsp_rom_msg[i].msg, status); + return; + } + } + + /* not for us, must be generic sof message */ + dev_dbg(sdev->dev, "unknown ROM status value %8.8x\n", status); +} + +static void hda_dsp_get_registers(struct snd_sof_dev *sdev, + struct sof_ipc_dsp_oops_xtensa *xoops, + struct sof_ipc_panic_info *panic_info, + u32 *stack, size_t stack_words) +{ + /* first read registers */ + sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset, xoops, + sizeof(*xoops)); + + /* then get panic info */ + sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset + + sizeof(*xoops), panic_info, sizeof(*panic_info)); + + /* then get the stack */ + sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset + + sizeof(*xoops) + sizeof(*panic_info), stack, + stack_words * sizeof(u32)); +} + +void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags) +{ + struct sof_ipc_dsp_oops_xtensa xoops; + struct sof_ipc_panic_info panic_info; + u32 stack[HDA_DSP_STACK_DUMP_SIZE]; + u32 status, panic; + + /* try APL specific status message types first */ + hda_dsp_get_status_skl(sdev); + + /* now try generic SOF status messages */ + status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_ADSP_ERROR_CODE_SKL); + + /*TODO: Check: there is no define in spec, but it is used in the code*/ + panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_ADSP_ERROR_CODE_SKL + 0x4); + + if (sdev->boot_complete) { + hda_dsp_get_registers(sdev, &xoops, &panic_info, stack, + HDA_DSP_STACK_DUMP_SIZE); + snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, + stack, HDA_DSP_STACK_DUMP_SIZE); + } else { + dev_err(sdev->dev, "error: status = 0x%8.8x panic = 0x%8.8x\n", + status, panic); + hda_dsp_get_status_skl(sdev); + } +} + +void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) +{ + struct sof_ipc_dsp_oops_xtensa xoops; + struct sof_ipc_panic_info panic_info; + u32 stack[HDA_DSP_STACK_DUMP_SIZE]; + u32 status, panic; + + /* try APL specific status message types first */ + hda_dsp_get_status(sdev); + + /* now try generic SOF status messages */ + status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_FW_STATUS); + panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_TRACEP); + + if (sdev->boot_complete) { + hda_dsp_get_registers(sdev, &xoops, &panic_info, stack, + HDA_DSP_STACK_DUMP_SIZE); + snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, + stack, HDA_DSP_STACK_DUMP_SIZE); + } else { + dev_err(sdev->dev, "error: status = 0x%8.8x panic = 0x%8.8x\n", + status, panic); + hda_dsp_get_status(sdev); + } +} + +static int hda_init(struct snd_sof_dev *sdev) +{ + struct hda_bus *hbus; + struct hdac_bus *bus; + struct hdac_ext_bus_ops *ext_ops = NULL; + struct pci_dev *pci = to_pci_dev(sdev->dev); + int ret; + + hbus = sof_to_hbus(sdev); + bus = sof_to_bus(sdev); + + /* HDA bus init */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) + ext_ops = snd_soc_hdac_hda_get_ops(); +#endif + sof_hda_bus_init(bus, &pci->dev, ext_ops); + bus->use_posbuf = 1; + bus->bdl_pos_adj = 0; + + mutex_init(&hbus->prepare_mutex); + hbus->pci = pci; + hbus->mixer_assigned = -1; + hbus->modelname = "sofbus"; + + /* initialise hdac bus */ + bus->addr = pci_resource_start(pci, 0); + bus->remap_addr = pci_ioremap_bar(pci, 0); + if (!bus->remap_addr) { + dev_err(bus->dev, "error: ioremap error\n"); + return -ENXIO; + } + + /* HDA base */ + sdev->bar[HDA_DSP_HDA_BAR] = bus->remap_addr; + + /* get controller capabilities */ + ret = hda_dsp_ctrl_get_caps(sdev); + if (ret < 0) + dev_err(sdev->dev, "error: get caps error\n"); + + return ret; +} + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + +static const char *fixup_tplg_name(struct snd_sof_dev *sdev, + const char *sof_tplg_filename) +{ + const char *tplg_filename = NULL; + char *filename; + char *split_ext; + + filename = devm_kstrdup(sdev->dev, sof_tplg_filename, GFP_KERNEL); + if (!filename) + return NULL; + + /* this assumes a .tplg extension */ + split_ext = strsep(&filename, "."); + if (split_ext) { + tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, + "%s-idisp.tplg", split_ext); + if (!tplg_filename) + return NULL; + } + return tplg_filename; +} + +static int hda_init_caps(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_link *hlink; + struct snd_soc_acpi_mach_params *mach_params; + struct snd_soc_acpi_mach *hda_mach; + struct snd_sof_pdata *pdata = sdev->pdata; + struct snd_soc_acpi_mach *mach; + const char *tplg_filename; + int codec_num = 0; + int ret = 0; + int i; + + device_disable_async_suspend(bus->dev); + + /* check if dsp is there */ + if (bus->ppcap) + dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n"); + + if (bus->mlcap) + snd_hdac_ext_bus_get_ml_capabilities(bus); + + /* init i915 and HDMI codecs */ + ret = hda_codec_i915_init(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: no HDMI audio devices found\n"); + return ret; + } + + ret = hda_dsp_ctrl_init_chip(sdev, true); + if (ret < 0) { + dev_err(bus->dev, "error: init chip failed with ret: %d\n", ret); + goto out; + } + + /* codec detection */ + if (!bus->codec_mask) { + dev_info(bus->dev, "no hda codecs found!\n"); + } else { + dev_info(bus->dev, "hda codecs found, mask %lx\n", + bus->codec_mask); + + for (i = 0; i < HDA_MAX_CODECS; i++) { + if (bus->codec_mask & (1 << i)) + codec_num++; + } + + /* + * If no machine driver is found, then: + * + * hda machine driver is used if : + * 1. there is one HDMI codec and one external HDAudio codec + * 2. only HDMI codec + */ + if (!pdata->machine && codec_num <= 2 && + HDA_IDISP_CODEC(bus->codec_mask)) { + hda_mach = snd_soc_acpi_intel_hda_machines; + pdata->machine = hda_mach; + + /* topology: use the info from hda_machines */ + pdata->tplg_filename = + hda_mach->sof_tplg_filename; + + /* firmware: pick the first in machine list */ + mach = pdata->desc->machines; + pdata->fw_filename = mach->sof_fw_filename; + + dev_info(bus->dev, "using HDA machine driver %s now\n", + hda_mach->drv_name); + + /* fixup topology file for HDMI only platforms */ + if (codec_num == 1) { + /* use local variable for readability */ + tplg_filename = pdata->tplg_filename; + tplg_filename = fixup_tplg_name(sdev, tplg_filename); + if (!tplg_filename) + goto out; + pdata->tplg_filename = tplg_filename; + } + } + } + + /* used by hda machine driver to create dai links */ + if (pdata->machine) { + mach_params = (struct snd_soc_acpi_mach_params *) + &pdata->machine->mach_params; + mach_params->codec_mask = bus->codec_mask; + mach_params->platform = dev_name(sdev->dev); + } + + /* create codec instances */ + hda_codec_probe_bus(sdev); + + hda_codec_i915_put(sdev); + + /* + * we are done probing so decrement link counts + */ + list_for_each_entry(hlink, &bus->hlink_list, list) + snd_hdac_ext_bus_link_put(bus, hlink); + + return 0; + +out: + hda_codec_i915_exit(sdev); + return ret; +} + +#else + +static int hda_init_caps(struct snd_sof_dev *sdev) +{ + /* + * set CGCTL.MISCBDCGE to 0 during reset and set back to 1 + * when reset finished. + * TODO: maybe no need for init_caps? + */ + hda_dsp_ctrl_misc_clock_gating(sdev, 0); + + /* clear WAKESTS */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, + SOF_HDA_WAKESTS_INT_MASK, + SOF_HDA_WAKESTS_INT_MASK); + + return 0; +} + +#endif + +static const struct sof_intel_dsp_desc + *get_chip_info(struct snd_sof_pdata *pdata) +{ + const struct sof_dev_desc *desc = pdata->desc; + const struct sof_intel_dsp_desc *chip_info; + + chip_info = desc->chip_info; + + return chip_info; +} + +int hda_dsp_probe(struct snd_sof_dev *sdev) +{ + struct pci_dev *pci = to_pci_dev(sdev->dev); + struct sof_intel_hda_dev *hdev; + struct hdac_bus *bus; + struct hdac_stream *stream; + const struct sof_intel_dsp_desc *chip; + int sd_offset, ret = 0; + + /* + * detect DSP by checking class/subclass/prog-id information + * class=04 subclass 03 prog-if 00: no DSP, legacy driver is required + * class=04 subclass 01 prog-if 00: DSP is present + * (and may be required e.g. for DMIC or SSP support) + * class=04 subclass 03 prog-if 80: either of DSP or legacy mode works + */ + if (pci->class == 0x040300) { + dev_err(sdev->dev, "error: the DSP is not enabled on this platform, aborting probe\n"); + return -ENODEV; + } else if (pci->class != 0x040100 && pci->class != 0x040380) { + dev_err(sdev->dev, "error: unknown PCI class/subclass/prog-if 0x%06x found, aborting probe\n", pci->class); + return -ENODEV; + } + dev_info(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n", pci->class); + + chip = get_chip_info(sdev->pdata); + if (!chip) { + dev_err(sdev->dev, "error: no such device supported, chip id:%x\n", + pci->device); + ret = -EIO; + goto err; + } + + hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL); + if (!hdev) + return -ENOMEM; + sdev->pdata->hw_pdata = hdev; + hdev->desc = chip; + + hdev->dmic_dev = platform_device_register_data(sdev->dev, "dmic-codec", + PLATFORM_DEVID_NONE, + NULL, 0); + if (IS_ERR(hdev->dmic_dev)) { + dev_err(sdev->dev, "error: failed to create DMIC device\n"); + return PTR_ERR(hdev->dmic_dev); + } + + /* + * use position update IPC if either it is forced + * or we don't have other choice + */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION) + hdev->no_ipc_position = 0; +#else + hdev->no_ipc_position = sof_ops(sdev)->pcm_pointer ? 1 : 0; +#endif + + /* set up HDA base */ + bus = sof_to_bus(sdev); + ret = hda_init(sdev); + if (ret < 0) + goto hdac_bus_unmap; + + /* DSP base */ + sdev->bar[HDA_DSP_BAR] = pci_ioremap_bar(pci, HDA_DSP_BAR); + if (!sdev->bar[HDA_DSP_BAR]) { + dev_err(sdev->dev, "error: ioremap error\n"); + ret = -ENXIO; + goto hdac_bus_unmap; + } + + sdev->mmio_bar = HDA_DSP_BAR; + sdev->mailbox_bar = HDA_DSP_BAR; + + /* allow 64bit DMA address if supported by H/W */ + if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(64))) { + dev_dbg(sdev->dev, "DMA mask is 64 bit\n"); + dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(64)); + } else { + dev_dbg(sdev->dev, "DMA mask is 32 bit\n"); + dma_set_mask(&pci->dev, DMA_BIT_MASK(32)); + dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32)); + } + + /* init streams */ + ret = hda_dsp_stream_init(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to init streams\n"); + /* + * not all errors are due to memory issues, but trying + * to free everything does not harm + */ + goto free_streams; + } + + /* + * register our IRQ + * let's try to enable msi firstly + * if it fails, use legacy interrupt mode + * TODO: support interrupt mode selection with kernel parameter + * support msi multiple vectors + */ + ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI); + if (ret < 0) { + dev_info(sdev->dev, "use legacy interrupt mode\n"); + /* + * in IO-APIC mode, hda->irq and ipc_irq are using the same + * irq number of pci->irq + */ + hdev->irq = pci->irq; + sdev->ipc_irq = pci->irq; + sdev->msi_enabled = 0; + } else { + dev_info(sdev->dev, "use msi interrupt mode\n"); + hdev->irq = pci_irq_vector(pci, 0); + /* ipc irq number is the same of hda irq */ + sdev->ipc_irq = hdev->irq; + sdev->msi_enabled = 1; + } + + dev_dbg(sdev->dev, "using HDA IRQ %d\n", hdev->irq); + ret = request_threaded_irq(hdev->irq, hda_dsp_stream_interrupt, + hda_dsp_stream_threaded_handler, + IRQF_SHARED, "AudioHDA", bus); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to register HDA IRQ %d\n", + hdev->irq); + goto free_irq_vector; + } + + dev_dbg(sdev->dev, "using IPC IRQ %d\n", sdev->ipc_irq); + ret = request_threaded_irq(sdev->ipc_irq, hda_dsp_ipc_irq_handler, + sof_ops(sdev)->irq_thread, IRQF_SHARED, + "AudioDSP", sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to register IPC IRQ %d\n", + sdev->ipc_irq); + goto free_hda_irq; + } + + pci_set_master(pci); + synchronize_irq(pci->irq); + + /* + * clear TCSEL to clear playback on some HD Audio + * codecs. PCI TCSEL is defined in the Intel manuals. + */ + snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0); + + /* init HDA capabilities */ + ret = hda_init_caps(sdev); + if (ret < 0) + goto free_ipc_irq; + + /* reset HDA controller */ + ret = hda_dsp_ctrl_link_reset(sdev, true); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to reset HDA controller\n"); + goto free_ipc_irq; + } + + /* exit HDA controller reset */ + ret = hda_dsp_ctrl_link_reset(sdev, false); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to exit HDA controller reset\n"); + goto free_ipc_irq; + } + + /* clear stream status */ + list_for_each_entry(stream, &bus->stream_list, list) { + sd_offset = SOF_STREAM_SD_OFFSET(stream); + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + + SOF_HDA_ADSP_REG_CL_SD_STS, + SOF_HDA_CL_DMA_SD_INT_MASK, + SOF_HDA_CL_DMA_SD_INT_MASK); + } + + /* clear WAKESTS */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, + SOF_HDA_WAKESTS_INT_MASK, + SOF_HDA_WAKESTS_INT_MASK); + + /* clear interrupt status register */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM); + + /* enable CIE and GIE interrupts */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); + + /* re-enable CGCTL.MISCBDCGE after reset */ + hda_dsp_ctrl_misc_clock_gating(sdev, true); + + device_disable_async_suspend(&pci->dev); + + /* enable DSP features */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + SOF_HDA_PPCTL_GPROCEN, SOF_HDA_PPCTL_GPROCEN); + + /* enable DSP IRQ */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + SOF_HDA_PPCTL_PIE, SOF_HDA_PPCTL_PIE); + + /* initialize waitq for code loading */ + init_waitqueue_head(&sdev->waitq); + + /* set default mailbox offset for FW ready message */ + sdev->dsp_box.offset = HDA_DSP_MBOX_UPLINK_OFFSET; + + return 0; + +free_ipc_irq: + free_irq(sdev->ipc_irq, sdev); +free_hda_irq: + free_irq(hdev->irq, bus); +free_irq_vector: + if (sdev->msi_enabled) + pci_free_irq_vectors(pci); +free_streams: + hda_dsp_stream_free(sdev); +/* dsp_unmap: not currently used */ + iounmap(sdev->bar[HDA_DSP_BAR]); +hdac_bus_unmap: + iounmap(bus->remap_addr); +err: + return ret; +} + +int hda_dsp_remove(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + struct hdac_bus *bus = sof_to_bus(sdev); + struct pci_dev *pci = to_pci_dev(sdev->dev); + const struct sof_intel_dsp_desc *chip = hda->desc; + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* codec removal, invoke bus_device_remove */ + snd_hdac_ext_bus_device_remove(bus); +#endif + + if (!IS_ERR_OR_NULL(hda->dmic_dev)) + platform_device_unregister(hda->dmic_dev); + + /* disable DSP IRQ */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + SOF_HDA_PPCTL_PIE, 0); + + /* disable CIE and GIE interrupts */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, 0); + + /* disable cores */ + if (chip) + hda_dsp_core_reset_power_down(sdev, chip->cores_mask); + + /* disable DSP */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + SOF_HDA_PPCTL_GPROCEN, 0); + + free_irq(sdev->ipc_irq, sdev); + free_irq(hda->irq, bus); + if (sdev->msi_enabled) + pci_free_irq_vectors(pci); + + hda_dsp_stream_free(sdev); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + snd_hdac_link_free_all(bus); +#endif + + iounmap(sdev->bar[HDA_DSP_BAR]); + iounmap(bus->remap_addr); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + snd_hdac_ext_bus_exit(bus); +#endif + hda_codec_i915_exit(sdev); + + return 0; +} + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h new file mode 100644 index 00000000000000..4efcf85af6b5b0 --- /dev/null +++ b/sound/soc/sof/intel/hda.h @@ -0,0 +1,560 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + */ + +#ifndef __SOF_INTEL_HDA_H +#define __SOF_INTEL_HDA_H + +#include +#include +#include "shim.h" + +/* PCI registers */ +#define PCI_TCSEL 0x44 +#define PCI_PGCTL PCI_TCSEL +#define PCI_CGCTL 0x48 + +/* PCI_PGCTL bits */ +#define PCI_PGCTL_ADSPPGD BIT(2) +#define PCI_PGCTL_LSRMD_MASK BIT(4) + +/* PCI_CGCTL bits */ +#define PCI_CGCTL_MISCBDCGE_MASK BIT(6) +#define PCI_CGCTL_ADSPDCGE BIT(1) + +/* Legacy HDA registers and bits used - widths are variable */ +#define SOF_HDA_GCAP 0x0 +#define SOF_HDA_GCTL 0x8 +/* accept unsol. response enable */ +#define SOF_HDA_GCTL_UNSOL BIT(8) +#define SOF_HDA_LLCH 0x14 +#define SOF_HDA_INTCTL 0x20 +#define SOF_HDA_INTSTS 0x24 +#define SOF_HDA_WAKESTS 0x0E +#define SOF_HDA_WAKESTS_INT_MASK ((1 << 8) - 1) +#define SOF_HDA_RIRBSTS 0x5d +#define SOF_HDA_VS_EM2_L1SEN BIT(13) + +/* SOF_HDA_GCTL register bist */ +#define SOF_HDA_GCTL_RESET BIT(0) + +/* SOF_HDA_INCTL and SOF_HDA_INTSTS regs */ +#define SOF_HDA_INT_GLOBAL_EN BIT(31) +#define SOF_HDA_INT_CTRL_EN BIT(30) +#define SOF_HDA_INT_ALL_STREAM 0xff + +#define SOF_HDA_MAX_CAPS 10 +#define SOF_HDA_CAP_ID_OFF 16 +#define SOF_HDA_CAP_ID_MASK GENMASK(SOF_HDA_CAP_ID_OFF + 11,\ + SOF_HDA_CAP_ID_OFF) +#define SOF_HDA_CAP_NEXT_MASK 0xFFFF + +#define SOF_HDA_GTS_CAP_ID 0x1 +#define SOF_HDA_ML_CAP_ID 0x2 + +#define SOF_HDA_PP_CAP_ID 0x3 +#define SOF_HDA_REG_PP_PPCH 0x10 +#define SOF_HDA_REG_PP_PPCTL 0x04 +#define SOF_HDA_PPCTL_PIE BIT(31) +#define SOF_HDA_PPCTL_GPROCEN BIT(30) + +/* DPIB entry size: 8 Bytes = 2 DWords */ +#define SOF_HDA_DPIB_ENTRY_SIZE 0x8 + +#define SOF_HDA_SPIB_CAP_ID 0x4 +#define SOF_HDA_DRSM_CAP_ID 0x5 + +#define SOF_HDA_SPIB_BASE 0x08 +#define SOF_HDA_SPIB_INTERVAL 0x08 +#define SOF_HDA_SPIB_SPIB 0x00 +#define SOF_HDA_SPIB_MAXFIFO 0x04 + +#define SOF_HDA_PPHC_BASE 0x10 +#define SOF_HDA_PPHC_INTERVAL 0x10 + +#define SOF_HDA_PPLC_BASE 0x10 +#define SOF_HDA_PPLC_MULTI 0x10 +#define SOF_HDA_PPLC_INTERVAL 0x10 + +#define SOF_HDA_DRSM_BASE 0x08 +#define SOF_HDA_DRSM_INTERVAL 0x08 + +/* Descriptor error interrupt */ +#define SOF_HDA_CL_DMA_SD_INT_DESC_ERR 0x10 + +/* FIFO error interrupt */ +#define SOF_HDA_CL_DMA_SD_INT_FIFO_ERR 0x08 + +/* Buffer completion interrupt */ +#define SOF_HDA_CL_DMA_SD_INT_COMPLETE 0x04 + +#define SOF_HDA_CL_DMA_SD_INT_MASK \ + (SOF_HDA_CL_DMA_SD_INT_DESC_ERR | \ + SOF_HDA_CL_DMA_SD_INT_FIFO_ERR | \ + SOF_HDA_CL_DMA_SD_INT_COMPLETE) +#define SOF_HDA_SD_CTL_DMA_START 0x02 /* Stream DMA start bit */ + +/* Intel HD Audio Code Loader DMA Registers */ +#define SOF_HDA_ADSP_LOADER_BASE 0x80 +#define SOF_HDA_ADSP_DPLBASE 0x70 +#define SOF_HDA_ADSP_DPUBASE 0x74 +#define SOF_HDA_ADSP_DPLBASE_ENABLE 0x01 + +/* Stream Registers */ +#define SOF_HDA_ADSP_REG_CL_SD_CTL 0x00 +#define SOF_HDA_ADSP_REG_CL_SD_STS 0x03 +#define SOF_HDA_ADSP_REG_CL_SD_LPIB 0x04 +#define SOF_HDA_ADSP_REG_CL_SD_CBL 0x08 +#define SOF_HDA_ADSP_REG_CL_SD_LVI 0x0C +#define SOF_HDA_ADSP_REG_CL_SD_FIFOW 0x0E +#define SOF_HDA_ADSP_REG_CL_SD_FIFOSIZE 0x10 +#define SOF_HDA_ADSP_REG_CL_SD_FORMAT 0x12 +#define SOF_HDA_ADSP_REG_CL_SD_FIFOL 0x14 +#define SOF_HDA_ADSP_REG_CL_SD_BDLPL 0x18 +#define SOF_HDA_ADSP_REG_CL_SD_BDLPU 0x1C +#define SOF_HDA_ADSP_SD_ENTRY_SIZE 0x20 + +/* CL: Software Position Based FIFO Capability Registers */ +#define SOF_DSP_REG_CL_SPBFIFO \ + (SOF_HDA_ADSP_LOADER_BASE + 0x20) +#define SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCH 0x0 +#define SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL 0x4 +#define SOF_HDA_ADSP_REG_CL_SPBFIFO_SPIB 0x8 +#define SOF_HDA_ADSP_REG_CL_SPBFIFO_MAXFIFOS 0xc + +/* Stream Number */ +#define SOF_HDA_CL_SD_CTL_STREAM_TAG_SHIFT 20 +#define SOF_HDA_CL_SD_CTL_STREAM_TAG_MASK \ + GENMASK(SOF_HDA_CL_SD_CTL_STREAM_TAG_SHIFT + 3,\ + SOF_HDA_CL_SD_CTL_STREAM_TAG_SHIFT) + +#define HDA_DSP_HDA_BAR 0 +#define HDA_DSP_PP_BAR 1 +#define HDA_DSP_SPIB_BAR 2 +#define HDA_DSP_DRSM_BAR 3 +#define HDA_DSP_BAR 4 + +#define SRAM_WINDOW_OFFSET(x) (0x80000 + (x) * 0x20000) + +#define HDA_DSP_MBOX_OFFSET SRAM_WINDOW_OFFSET(0) + +#define HDA_DSP_PANIC_OFFSET(x) \ + (((x) & 0xFFFFFF) + HDA_DSP_MBOX_OFFSET) + +/* SRAM window 0 FW "registers" */ +#define HDA_DSP_SRAM_REG_ROM_STATUS (HDA_DSP_MBOX_OFFSET + 0x0) +#define HDA_DSP_SRAM_REG_ROM_ERROR (HDA_DSP_MBOX_OFFSET + 0x4) +/* FW and ROM share offset 4 */ +#define HDA_DSP_SRAM_REG_FW_STATUS (HDA_DSP_MBOX_OFFSET + 0x4) +#define HDA_DSP_SRAM_REG_FW_TRACEP (HDA_DSP_MBOX_OFFSET + 0x8) +#define HDA_DSP_SRAM_REG_FW_END (HDA_DSP_MBOX_OFFSET + 0xc) + +#define HDA_DSP_MBOX_UPLINK_OFFSET 0x81000 + +#define HDA_DSP_STREAM_RESET_TIMEOUT 300 +#define HDA_DSP_CL_TRIGGER_TIMEOUT 300 + +#define HDA_DSP_SPIB_ENABLE 1 +#define HDA_DSP_SPIB_DISABLE 0 + +#define SOF_HDA_MAX_BUFFER_SIZE (32 * PAGE_SIZE) + +#define HDA_DSP_STACK_DUMP_SIZE 32 + +/* ROM status/error values */ +#define HDA_DSP_ROM_STS_MASK 0xf +#define HDA_DSP_ROM_INIT 0x1 +#define HDA_DSP_ROM_FW_MANIFEST_LOADED 0x3 +#define HDA_DSP_ROM_FW_FW_LOADED 0x4 +#define HDA_DSP_ROM_FW_ENTERED 0x5 +#define HDA_DSP_ROM_RFW_START 0xf +#define HDA_DSP_ROM_CSE_ERROR 40 +#define HDA_DSP_ROM_CSE_WRONG_RESPONSE 41 +#define HDA_DSP_ROM_IMR_TO_SMALL 42 +#define HDA_DSP_ROM_BASE_FW_NOT_FOUND 43 +#define HDA_DSP_ROM_CSE_VALIDATION_FAILED 44 +#define HDA_DSP_ROM_IPC_FATAL_ERROR 45 +#define HDA_DSP_ROM_L2_CACHE_ERROR 46 +#define HDA_DSP_ROM_LOAD_OFFSET_TO_SMALL 47 +#define HDA_DSP_ROM_API_PTR_INVALID 50 +#define HDA_DSP_ROM_BASEFW_INCOMPAT 51 +#define HDA_DSP_ROM_UNHANDLED_INTERRUPT 0xBEE00000 +#define HDA_DSP_ROM_MEMORY_HOLE_ECC 0xECC00000 +#define HDA_DSP_ROM_KERNEL_EXCEPTION 0xCAFE0000 +#define HDA_DSP_ROM_USER_EXCEPTION 0xBEEF0000 +#define HDA_DSP_ROM_UNEXPECTED_RESET 0xDECAF000 +#define HDA_DSP_ROM_NULL_FW_ENTRY 0x4c4c4e55 +#define HDA_DSP_IPC_PURGE_FW 0x01004000 + +/* various timeout values */ +#define HDA_DSP_PU_TIMEOUT 50 +#define HDA_DSP_PD_TIMEOUT 50 +#define HDA_DSP_RESET_TIMEOUT_US 50000 +#define HDA_DSP_BASEFW_TIMEOUT_US 3000000 +#define HDA_DSP_INIT_TIMEOUT_US 500000 +#define HDA_DSP_CTRL_RESET_TIMEOUT 100 +#define HDA_DSP_WAIT_TIMEOUT 500 /* 500 msec */ +#define HDA_DSP_REG_POLL_INTERVAL_US 500 /* 0.5 msec */ + +#define HDA_DSP_ADSPIC_IPC 1 +#define HDA_DSP_ADSPIS_IPC 1 + +/* Intel HD Audio General DSP Registers */ +#define HDA_DSP_GEN_BASE 0x0 +#define HDA_DSP_REG_ADSPCS (HDA_DSP_GEN_BASE + 0x04) +#define HDA_DSP_REG_ADSPIC (HDA_DSP_GEN_BASE + 0x08) +#define HDA_DSP_REG_ADSPIS (HDA_DSP_GEN_BASE + 0x0C) +#define HDA_DSP_REG_ADSPIC2 (HDA_DSP_GEN_BASE + 0x10) +#define HDA_DSP_REG_ADSPIS2 (HDA_DSP_GEN_BASE + 0x14) + +/* Intel HD Audio Inter-Processor Communication Registers */ +#define HDA_DSP_IPC_BASE 0x40 +#define HDA_DSP_REG_HIPCT (HDA_DSP_IPC_BASE + 0x00) +#define HDA_DSP_REG_HIPCTE (HDA_DSP_IPC_BASE + 0x04) +#define HDA_DSP_REG_HIPCI (HDA_DSP_IPC_BASE + 0x08) +#define HDA_DSP_REG_HIPCIE (HDA_DSP_IPC_BASE + 0x0C) +#define HDA_DSP_REG_HIPCCTL (HDA_DSP_IPC_BASE + 0x10) + +/* HIPCI */ +#define HDA_DSP_REG_HIPCI_BUSY BIT(31) +#define HDA_DSP_REG_HIPCI_MSG_MASK 0x7FFFFFFF + +/* HIPCIE */ +#define HDA_DSP_REG_HIPCIE_DONE BIT(30) +#define HDA_DSP_REG_HIPCIE_MSG_MASK 0x3FFFFFFF + +/* HIPCCTL */ +#define HDA_DSP_REG_HIPCCTL_DONE BIT(1) +#define HDA_DSP_REG_HIPCCTL_BUSY BIT(0) + +/* HIPCT */ +#define HDA_DSP_REG_HIPCT_BUSY BIT(31) +#define HDA_DSP_REG_HIPCT_MSG_MASK 0x7FFFFFFF + +/* HIPCTE */ +#define HDA_DSP_REG_HIPCTE_MSG_MASK 0x3FFFFFFF + +#define HDA_DSP_ADSPIC_CL_DMA 0x2 +#define HDA_DSP_ADSPIS_CL_DMA 0x2 + +/* Delay before scheduling D0i3 entry */ +#define BXT_D0I3_DELAY 5000 + +#define FW_CL_STREAM_NUMBER 0x1 + +/* ADSPCS - Audio DSP Control & Status */ + +/* + * Core Reset - asserted high + * CRST Mask for a given core mask pattern, cm + */ +#define HDA_DSP_ADSPCS_CRST_SHIFT 0 +#define HDA_DSP_ADSPCS_CRST_MASK(cm) ((cm) << HDA_DSP_ADSPCS_CRST_SHIFT) + +/* + * Core run/stall - when set to '1' core is stalled + * CSTALL Mask for a given core mask pattern, cm + */ +#define HDA_DSP_ADSPCS_CSTALL_SHIFT 8 +#define HDA_DSP_ADSPCS_CSTALL_MASK(cm) ((cm) << HDA_DSP_ADSPCS_CSTALL_SHIFT) + +/* + * Set Power Active - when set to '1' turn cores on + * SPA Mask for a given core mask pattern, cm + */ +#define HDA_DSP_ADSPCS_SPA_SHIFT 16 +#define HDA_DSP_ADSPCS_SPA_MASK(cm) ((cm) << HDA_DSP_ADSPCS_SPA_SHIFT) + +/* + * Current Power Active - power status of cores, set by hardware + * CPA Mask for a given core mask pattern, cm + */ +#define HDA_DSP_ADSPCS_CPA_SHIFT 24 +#define HDA_DSP_ADSPCS_CPA_MASK(cm) ((cm) << HDA_DSP_ADSPCS_CPA_SHIFT) + +/* Mask for a given core index, c = 0.. number of supported cores - 1 */ +#define HDA_DSP_CORE_MASK(c) BIT(c) + +/* + * Mask for a given number of cores + * nc = number of supported cores + */ +#define SOF_DSP_CORES_MASK(nc) GENMASK(((nc) - 1), 0) + +/* Intel HD Audio Inter-Processor Communication Registers for Cannonlake*/ +#define CNL_DSP_IPC_BASE 0xc0 +#define CNL_DSP_REG_HIPCTDR (CNL_DSP_IPC_BASE + 0x00) +#define CNL_DSP_REG_HIPCTDA (CNL_DSP_IPC_BASE + 0x04) +#define CNL_DSP_REG_HIPCTDD (CNL_DSP_IPC_BASE + 0x08) +#define CNL_DSP_REG_HIPCIDR (CNL_DSP_IPC_BASE + 0x10) +#define CNL_DSP_REG_HIPCIDA (CNL_DSP_IPC_BASE + 0x14) +#define CNL_DSP_REG_HIPCCTL (CNL_DSP_IPC_BASE + 0x28) + +/* HIPCI */ +#define CNL_DSP_REG_HIPCIDR_BUSY BIT(31) +#define CNL_DSP_REG_HIPCIDR_MSG_MASK 0x7FFFFFFF + +/* HIPCIE */ +#define CNL_DSP_REG_HIPCIDA_DONE BIT(31) +#define CNL_DSP_REG_HIPCIDA_MSG_MASK 0x7FFFFFFF + +/* HIPCCTL */ +#define CNL_DSP_REG_HIPCCTL_DONE BIT(1) +#define CNL_DSP_REG_HIPCCTL_BUSY BIT(0) + +/* HIPCT */ +#define CNL_DSP_REG_HIPCTDR_BUSY BIT(31) +#define CNL_DSP_REG_HIPCTDR_MSG_MASK 0x7FFFFFFF + +/* HIPCTDA */ +#define CNL_DSP_REG_HIPCTDA_DONE BIT(31) +#define CNL_DSP_REG_HIPCTDA_MSG_MASK 0x7FFFFFFF + +/* HIPCTDD */ +#define CNL_DSP_REG_HIPCTDD_MSG_MASK 0x7FFFFFFF + +/* BDL */ +#define HDA_DSP_BDL_SIZE 4096 +#define HDA_DSP_MAX_BDL_ENTRIES \ + (HDA_DSP_BDL_SIZE / sizeof(struct sof_intel_dsp_bdl)) + +/* Number of DAIs */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +#define SOF_SKL_NUM_DAIS 14 +#else +#define SOF_SKL_NUM_DAIS 8 +#endif + +/* Intel HD Audio SRAM Window 0*/ +#define HDA_ADSP_SRAM0_BASE_SKL 0x8000 + +/* Firmware status window */ +#define HDA_ADSP_FW_STATUS_SKL HDA_ADSP_SRAM0_BASE_SKL +#define HDA_ADSP_ERROR_CODE_SKL (HDA_ADSP_FW_STATUS_SKL + 0x4) + +#define HDA_IDISP_CODEC(x) ((x) & BIT(2)) + +struct sof_intel_dsp_bdl { + __le32 addr_l; + __le32 addr_h; + __le32 size; + __le32 ioc; +} __attribute((packed)); + +#define SOF_HDA_PLAYBACK_STREAMS 16 +#define SOF_HDA_CAPTURE_STREAMS 16 +#define SOF_HDA_PLAYBACK 0 +#define SOF_HDA_CAPTURE 1 + +/* represents DSP HDA controller frontend - i.e. host facing control */ +struct sof_intel_hda_dev { + + struct hda_bus hbus; + + /* hw config */ + const struct sof_intel_dsp_desc *desc; + + /* trace */ + struct hdac_ext_stream *dtrace_stream; + + /* if position update IPC needed */ + u32 no_ipc_position; + + int irq; + + /* DMIC device */ + struct platform_device *dmic_dev; +}; + +static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s) +{ + struct sof_intel_hda_dev *hda = s->pdata->hw_pdata; + + return &hda->hbus.core; +} + +static inline struct hda_bus *sof_to_hbus(struct snd_sof_dev *s) +{ + struct sof_intel_hda_dev *hda = s->pdata->hw_pdata; + + return &hda->hbus; +} + +struct sof_intel_hda_stream { + struct hdac_ext_stream hda_stream; + struct sof_intel_stream stream; +}; + +#define bus_to_sof_hda(bus) \ + container_of(bus, struct sof_intel_hda_dev, hbus.core) + +#define SOF_STREAM_SD_OFFSET(s) \ + (SOF_HDA_ADSP_SD_ENTRY_SIZE * ((s)->index) \ + + SOF_HDA_ADSP_LOADER_BASE) + +/* + * DSP Core services. + */ +int hda_dsp_probe(struct snd_sof_dev *sdev); +int hda_dsp_remove(struct snd_sof_dev *sdev); +int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, + unsigned int core_mask); +int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, + unsigned int core_mask); +int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask); +int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask); +int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask); +int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask); +int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask); +bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, + unsigned int core_mask); +int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, + unsigned int core_mask); +void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev); +void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev); + +int hda_dsp_suspend(struct snd_sof_dev *sdev, int state); +int hda_dsp_resume(struct snd_sof_dev *sdev); +int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state); +int hda_dsp_runtime_resume(struct snd_sof_dev *sdev); +void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags); +void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags); + +/* + * DSP PCM Operations. + */ +int hda_dsp_pcm_open(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); +int hda_dsp_pcm_close(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); +int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct sof_ipc_stream_params *ipc_params); +int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, int cmd); +snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); + +/* + * DSP Stream Operations. + */ + +int hda_dsp_stream_init(struct snd_sof_dev *sdev); +void hda_dsp_stream_free(struct snd_sof_dev *sdev); +int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, + struct hdac_ext_stream *stream, + struct snd_dma_buffer *dmab, + struct snd_pcm_hw_params *params); +int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, + struct hdac_ext_stream *stream, int cmd); +irqreturn_t hda_dsp_stream_interrupt(int irq, void *context); +irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context); +int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab, + struct hdac_stream *stream); + +struct hdac_ext_stream * + hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction); +int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag); +int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, + struct hdac_ext_stream *stream, + int enable, u32 size); + +void hda_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz); +int hda_ipc_pcm_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply); + +/* + * DSP IPC Operations. + */ +int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg); +void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev); +int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id); +irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context); +irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context); +int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); + +/* + * DSP Code loader. + */ +int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev); +int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev); + +/* pre and post fw run ops */ +int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev); +int hda_dsp_post_fw_run(struct snd_sof_dev *sdev); + +/* + * HDA Controller Operations. + */ +int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev); +void hda_dsp_ctrl_ppcap_enable(struct snd_sof_dev *sdev, bool enable); +void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable); +int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset); +void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable); +int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable); +int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset); + +/* + * HDA bus operations. + */ +void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, + const struct hdac_ext_bus_ops *ext_ops); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +/* + * HDA Codec operations. + */ +int hda_codec_probe_bus(struct snd_sof_dev *sdev); + +#endif /* CONFIG_SND_SOC_SOF_HDA */ + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) && IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) + +void hda_codec_i915_get(struct snd_sof_dev *sdev); +void hda_codec_i915_put(struct snd_sof_dev *sdev); +int hda_codec_i915_init(struct snd_sof_dev *sdev); +int hda_codec_i915_exit(struct snd_sof_dev *sdev); + +#else + +static inline void hda_codec_i915_get(struct snd_sof_dev *sdev) { } +static inline void hda_codec_i915_put(struct snd_sof_dev *sdev) { } +static inline int hda_codec_i915_init(struct snd_sof_dev *sdev) { return 0; } +static inline int hda_codec_i915_exit(struct snd_sof_dev *sdev) { return 0; } + +#endif /* CONFIG_SND_SOC_SOF_HDA && CONFIG_SND_SOC_HDAC_HDMI */ + +/* + * Trace Control. + */ +int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag); +int hda_dsp_trace_release(struct snd_sof_dev *sdev); +int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd); + +/* common dai driver */ +extern struct snd_soc_dai_driver skl_dai[]; + +/* + * Platform Specific HW abstraction Ops. + */ +extern const struct snd_sof_dsp_ops sof_apl_ops; +extern const struct snd_sof_dsp_ops sof_cnl_ops; +extern const struct snd_sof_dsp_ops sof_skl_ops; + +extern const struct sof_intel_dsp_desc apl_chip_info; +extern const struct sof_intel_dsp_desc cnl_chip_info; +extern const struct sof_intel_dsp_desc skl_chip_info; + +#endif From 787188d216af658b32a9e785bbb68ab036d3e758 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:08:48 -0500 Subject: [PATCH 1408/1995] ASoC: SOF: Intel: Add HDA controller for Intel DSP Support HDA controller operations for DSP and provide space for future DSP HDA FW integration. Signed-off-by: Keyon Jie Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 8a300c8fb17c7546aaf3f2203a2eeff32debfb8f) --- sound/soc/sof/intel/hda-ctrl.c | 181 +++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 sound/soc/sof/intel/hda-ctrl.c diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c new file mode 100644 index 00000000000000..2c3645736e1f76 --- /dev/null +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for generic Intel audio DSP HDA IP + */ + +#include +#include +#include "../ops.h" +#include "hda.h" + +/* + * HDA Operations. + */ + +int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset) +{ + unsigned long timeout; + u32 gctl = 0; + u32 val; + + /* 0 to enter reset and 1 to exit reset */ + val = reset ? 0 : SOF_HDA_GCTL_RESET; + + /* enter/exit HDA controller reset */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL, + SOF_HDA_GCTL_RESET, val); + + /* wait to enter/exit reset */ + timeout = jiffies + msecs_to_jiffies(HDA_DSP_CTRL_RESET_TIMEOUT); + while (time_before(jiffies, timeout)) { + gctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCTL); + if ((gctl & SOF_HDA_GCTL_RESET) == val) + return 0; + usleep_range(500, 1000); + } + + /* enter/exit reset failed */ + dev_err(sdev->dev, "error: failed to %s HDA controller gctl 0x%x\n", + reset ? "reset" : "ready", gctl); + return -EIO; +} + +int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + u32 cap, offset, feature; + int count = 0; + + offset = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_LLCH); + + do { + cap = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, offset); + + dev_dbg(sdev->dev, "checking for capabilities at offset 0x%x\n", + offset & SOF_HDA_CAP_NEXT_MASK); + + feature = (cap & SOF_HDA_CAP_ID_MASK) >> SOF_HDA_CAP_ID_OFF; + + switch (feature) { + case SOF_HDA_PP_CAP_ID: + dev_dbg(sdev->dev, "found DSP capability at 0x%x\n", + offset); + bus->ppcap = bus->remap_addr + offset; + sdev->bar[HDA_DSP_PP_BAR] = bus->ppcap; + break; + case SOF_HDA_SPIB_CAP_ID: + dev_dbg(sdev->dev, "found SPIB capability at 0x%x\n", + offset); + bus->spbcap = bus->remap_addr + offset; + sdev->bar[HDA_DSP_SPIB_BAR] = bus->spbcap; + break; + case SOF_HDA_DRSM_CAP_ID: + dev_dbg(sdev->dev, "found DRSM capability at 0x%x\n", + offset); + bus->drsmcap = bus->remap_addr + offset; + sdev->bar[HDA_DSP_DRSM_BAR] = bus->drsmcap; + break; + case SOF_HDA_GTS_CAP_ID: + dev_dbg(sdev->dev, "found GTS capability at 0x%x\n", + offset); + bus->gtscap = bus->remap_addr + offset; + break; + case SOF_HDA_ML_CAP_ID: + dev_dbg(sdev->dev, "found ML capability at 0x%x\n", + offset); + bus->mlcap = bus->remap_addr + offset; + break; + default: + dev_vdbg(sdev->dev, "found capability %d at 0x%x\n", + feature, offset); + break; + } + + offset = cap & SOF_HDA_CAP_NEXT_MASK; + } while (count++ <= SOF_HDA_MAX_CAPS && offset); + + return 0; +} + +void hda_dsp_ctrl_ppcap_enable(struct snd_sof_dev *sdev, bool enable) +{ + u32 val = enable ? SOF_HDA_PPCTL_GPROCEN : 0; + + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + SOF_HDA_PPCTL_GPROCEN, val); +} + +void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable) +{ + u32 val = enable ? SOF_HDA_PPCTL_PIE : 0; + + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + SOF_HDA_PPCTL_PIE, val); +} + +void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable) +{ + u32 val = enable ? PCI_CGCTL_MISCBDCGE_MASK : 0; + + snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_MISCBDCGE_MASK, val); +} + +/* + * enable/disable audio dsp clock gating and power gating bits. + * This allows the HW to opportunistically power and clock gate + * the audio dsp when it is idle + */ +int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) +{ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + struct hdac_bus *bus = sof_to_bus(sdev); +#endif + u32 val; + + /* enable/disable audio dsp clock gating */ + val = enable ? PCI_CGCTL_ADSPDCGE : 0; + snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_ADSPDCGE, val); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* enable/disable L1 support */ + val = enable ? SOF_HDA_VS_EM2_L1SEN : 0; + snd_hdac_chip_updatel(bus, VS_EM2, SOF_HDA_VS_EM2_L1SEN, val); +#endif + + /* enable/disable audio dsp power gating */ + val = enable ? 0 : PCI_PGCTL_ADSPPGD; + snd_sof_pci_update_bits(sdev, PCI_PGCTL, PCI_PGCTL_ADSPPGD, val); + + return 0; +} + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +/* + * While performing reset, controller may not come back properly and causing + * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset + * (init chip) and then again set CGCTL.MISCBDCGE to 1 + */ +int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int ret; + + hda_dsp_ctrl_misc_clock_gating(sdev, false); + ret = snd_hdac_bus_init_chip(bus, full_reset); + hda_dsp_ctrl_misc_clock_gating(sdev, true); + + return ret; +} +#endif From 105c5fa819d91056c1f588f36d08f98f42543da2 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:08:49 -0500 Subject: [PATCH 1409/1995] ASoC: SOF: Intel: Add Intel specific HDA DSP HW operations Add support for various PM and core reset/run state transitions. Signed-off-by: Keyon Jie Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 747503b1813a3e6e4c52d9c0b4bd462b64940940) --- sound/soc/sof/intel/hda-dsp.c | 455 ++++++++++++++++++++++++++++++++++ 1 file changed, 455 insertions(+) create mode 100644 sound/soc/sof/intel/hda-dsp.c diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c new file mode 100644 index 00000000000000..311fed502e09fc --- /dev/null +++ b/sound/soc/sof/intel/hda-dsp.c @@ -0,0 +1,455 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for generic Intel audio DSP HDA IP + */ + +#include +#include +#include "../ops.h" +#include "hda.h" + +/* + * DSP Core control. + */ + +int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + u32 adspcs; + u32 reset; + int ret; + + /* set reset bits for cores */ + reset = HDA_DSP_ADSPCS_CRST_MASK(core_mask); + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, + reset, reset), + + /* poll with timeout to check if operation successful */ + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, adspcs, + ((adspcs & reset) == reset), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); + + /* has core entered reset ? */ + adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS); + if ((adspcs & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) != + HDA_DSP_ADSPCS_CRST_MASK(core_mask)) { + dev_err(sdev->dev, + "error: reset enter failed: core_mask %x adspcs 0x%x\n", + core_mask, adspcs); + ret = -EIO; + } + + return ret; +} + +int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + unsigned int crst; + u32 adspcs; + int ret; + + /* clear reset bits for cores */ + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_CRST_MASK(core_mask), + 0); + + /* poll with timeout to check if operation successful */ + crst = HDA_DSP_ADSPCS_CRST_MASK(core_mask); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, adspcs, + !(adspcs & crst), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); + + /* has core left reset ? */ + adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS); + if ((adspcs & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) != 0) { + dev_err(sdev->dev, + "error: reset leave failed: core_mask %x adspcs 0x%x\n", + core_mask, adspcs); + ret = -EIO; + } + + return ret; +} + +int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + /* stall core */ + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_CSTALL_MASK(core_mask), + HDA_DSP_ADSPCS_CSTALL_MASK(core_mask)); + + /* set reset state */ + return hda_dsp_core_reset_enter(sdev, core_mask); +} + +int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + int ret; + + /* leave reset state */ + ret = hda_dsp_core_reset_leave(sdev, core_mask); + if (ret < 0) + return ret; + + /* run core */ + dev_dbg(sdev->dev, "unstall/run core: core_mask = %x\n", core_mask); + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_CSTALL_MASK(core_mask), + 0); + + /* is core now running ? */ + if (!hda_dsp_core_is_enabled(sdev, core_mask)) { + hda_dsp_core_stall_reset(sdev, core_mask); + dev_err(sdev->dev, "error: DSP start core failed: core_mask %x\n", + core_mask); + ret = -EIO; + } + + return ret; +} + +/* + * Power Management. + */ + +int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + unsigned int cpa; + u32 adspcs; + int ret; + + /* update bits */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_SPA_MASK(core_mask), + HDA_DSP_ADSPCS_SPA_MASK(core_mask)); + + /* poll with timeout to check if operation successful */ + cpa = HDA_DSP_ADSPCS_CPA_MASK(core_mask); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, adspcs, + (adspcs & cpa) == cpa, + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) + dev_err(sdev->dev, "error: timeout on core powerup\n"); + + /* did core power up ? */ + adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS); + if ((adspcs & HDA_DSP_ADSPCS_CPA_MASK(core_mask)) != + HDA_DSP_ADSPCS_CPA_MASK(core_mask)) { + dev_err(sdev->dev, + "error: power up core failed core_mask %xadspcs 0x%x\n", + core_mask, adspcs); + ret = -EIO; + } + + return ret; +} + +int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + u32 adspcs; + + /* update bits */ + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, + HDA_DSP_ADSPCS_SPA_MASK(core_mask), 0); + + return snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPCS, adspcs, + !(adspcs & HDA_DSP_ADSPCS_SPA_MASK(core_mask)), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_PD_TIMEOUT * USEC_PER_MSEC); +} + +bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, + unsigned int core_mask) +{ + int val; + bool is_enable; + + val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS); + + is_enable = ((val & HDA_DSP_ADSPCS_CPA_MASK(core_mask)) && + (val & HDA_DSP_ADSPCS_SPA_MASK(core_mask)) && + !(val & HDA_DSP_ADSPCS_CRST_MASK(core_mask)) && + !(val & HDA_DSP_ADSPCS_CSTALL_MASK(core_mask))); + + dev_dbg(sdev->dev, "DSP core(s) enabled? %d : core_mask %x\n", + is_enable, core_mask); + + return is_enable; +} + +int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask) +{ + int ret; + + /* return if core is already enabled */ + if (hda_dsp_core_is_enabled(sdev, core_mask)) + return 0; + + /* power up */ + ret = hda_dsp_core_power_up(sdev, core_mask); + if (ret < 0) { + dev_err(sdev->dev, "error: dsp core power up failed: core_mask %x\n", + core_mask); + return ret; + } + + return hda_dsp_core_run(sdev, core_mask); +} + +int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, + unsigned int core_mask) +{ + int ret; + + /* place core in reset prior to power down */ + ret = hda_dsp_core_stall_reset(sdev, core_mask); + if (ret < 0) { + dev_err(sdev->dev, "error: dsp core reset failed: core_mask %x\n", + core_mask); + return ret; + } + + /* power down core */ + ret = hda_dsp_core_power_down(sdev, core_mask); + if (ret < 0) { + dev_err(sdev->dev, "error: dsp core power down fail mask %x: %d\n", + core_mask, ret); + return ret; + } + + /* make sure we are in OFF state */ + if (hda_dsp_core_is_enabled(sdev, core_mask)) { + dev_err(sdev->dev, "error: dsp core disable fail mask %x: %d\n", + core_mask, ret); + ret = -EIO; + } + + return ret; +} + +void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + + /* enable IPC DONE and BUSY interrupts */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, + HDA_DSP_REG_HIPCCTL_DONE | HDA_DSP_REG_HIPCCTL_BUSY, + HDA_DSP_REG_HIPCCTL_DONE | HDA_DSP_REG_HIPCCTL_BUSY); + + /* enable IPC interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); +} + +void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + + /* disable IPC interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_IPC, 0); + + /* disable IPC BUSY and DONE interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl, + HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0); +} + +static int hda_suspend(struct snd_sof_dev *sdev, int state) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + struct hdac_bus *bus = sof_to_bus(sdev); +#endif + int ret; + + /* disable IPC interrupts */ + hda_dsp_ipc_int_disable(sdev); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* power down all hda link */ + snd_hdac_ext_bus_link_power_down_all(bus); +#endif + + /* power down DSP */ + ret = hda_dsp_core_reset_power_down(sdev, chip->cores_mask); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to power down core during suspend\n"); + return ret; + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* disable ppcap interrupt */ + snd_hdac_ext_bus_ppcap_int_enable(bus, false); + snd_hdac_ext_bus_ppcap_enable(bus, false); + + /* disable hda bus irq and i/o */ + snd_hdac_bus_stop_chip(bus); +#else + /* disable ppcap interrupt */ + hda_dsp_ctrl_ppcap_enable(sdev, false); + hda_dsp_ctrl_ppcap_int_enable(sdev, false); + + /* disable hda bus irq */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, + 0); +#endif + + /* disable LP retention mode */ + snd_sof_pci_update_bits(sdev, PCI_PGCTL, + PCI_PGCTL_LSRMD_MASK, PCI_PGCTL_LSRMD_MASK); + + /* reset controller */ + ret = hda_dsp_ctrl_link_reset(sdev, true); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to reset controller during suspend\n"); + return ret; + } + + return 0; +} + +static int hda_resume(struct snd_sof_dev *sdev) +{ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_link *hlink = NULL; +#endif + int ret; + + /* + * clear TCSEL to clear playback on some HD Audio + * codecs. PCI TCSEL is defined in the Intel manuals. + */ + snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* reset and start hda controller */ + ret = hda_dsp_ctrl_init_chip(sdev, true); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to start controller after resume\n"); + return ret; + } + + hda_dsp_ctrl_misc_clock_gating(sdev, false); + + /* Reset stream-to-link mapping */ + list_for_each_entry(hlink, &bus->hlink_list, list) + bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); + + hda_dsp_ctrl_misc_clock_gating(sdev, true); + + /* enable ppcap interrupt */ + snd_hdac_ext_bus_ppcap_enable(bus, true); + snd_hdac_ext_bus_ppcap_int_enable(bus, true); +#else + + hda_dsp_ctrl_misc_clock_gating(sdev, false); + + /* reset controller */ + ret = hda_dsp_ctrl_link_reset(sdev, true); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to reset controller during resume\n"); + return ret; + } + + /* take controller out of reset */ + ret = hda_dsp_ctrl_link_reset(sdev, false); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to ready controller during resume\n"); + return ret; + } + + /* enable hda bus irq */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); + + hda_dsp_ctrl_misc_clock_gating(sdev, true); + + /* enable ppcap interrupt */ + hda_dsp_ctrl_ppcap_enable(sdev, true); + hda_dsp_ctrl_ppcap_int_enable(sdev, true); +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* turn off the links that were off before suspend */ + list_for_each_entry(hlink, &bus->hlink_list, list) { + if (!hlink->ref_count) + snd_hdac_ext_bus_link_power_down(hlink); + } + + /* check dma status and clean up CORB/RIRB buffers */ + if (!bus->cmd_dma_state) + snd_hdac_bus_stop_cmd_io(bus); +#endif + + return 0; +} + +int hda_dsp_resume(struct snd_sof_dev *sdev) +{ + /* init hda controller. DSP cores will be powered up during fw boot */ + return hda_resume(sdev); +} + +int hda_dsp_runtime_resume(struct snd_sof_dev *sdev) +{ + /* init hda controller. DSP cores will be powered up during fw boot */ + return hda_resume(sdev); +} + +int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state) +{ + /* stop hda controller and power dsp off */ + return hda_suspend(sdev, state); +} + +int hda_dsp_suspend(struct snd_sof_dev *sdev, int state) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int ret; + + /* stop hda controller and power dsp off */ + ret = hda_suspend(sdev, state); + if (ret < 0) { + dev_err(bus->dev, "error: suspending dsp\n"); + return ret; + } + + return 0; +} From 5956d5b7cf8d89b4c1f31e5521b8d0cb1ca7b864 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:08:50 -0500 Subject: [PATCH 1410/1995] ASoC: SOF: Intel: Add Intel specific HDA IPC mechanisms. Add HDA specific IPC mechanism for Intel DSP HW. Signed-off-by: Keyon Jie Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 6e9cde974863dc9d9c6cdb178f625e410c5be3d0) --- sound/soc/sof/intel/hda-ipc.c | 458 ++++++++++++++++++++++++++++++++++ 1 file changed, 458 insertions(+) create mode 100644 sound/soc/sof/intel/hda-ipc.c diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c new file mode 100644 index 00000000000000..a938f568dbb1c3 --- /dev/null +++ b/sound/soc/sof/intel/hda-ipc.c @@ -0,0 +1,458 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for generic Intel audio DSP HDA IP + */ + +#include "../ops.h" +#include "hda.h" + +static void hda_dsp_ipc_host_done(struct snd_sof_dev *sdev) +{ + /* + * tell DSP cmd is done - clear busy + * interrupt and send reply msg to dsp + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCT, + HDA_DSP_REG_HIPCT_BUSY, + HDA_DSP_REG_HIPCT_BUSY); + + /* unmask BUSY interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCCTL, + HDA_DSP_REG_HIPCCTL_BUSY, + HDA_DSP_REG_HIPCCTL_BUSY); +} + +static void hda_dsp_ipc_dsp_done(struct snd_sof_dev *sdev) +{ + /* + * set DONE bit - tell DSP we have received the reply msg + * from DSP, and processed it, don't send more reply to host + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCIE, + HDA_DSP_REG_HIPCIE_DONE, + HDA_DSP_REG_HIPCIE_DONE); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCCTL, + HDA_DSP_REG_HIPCCTL_DONE, + HDA_DSP_REG_HIPCCTL_DONE); +} + +int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + u32 cmd = msg->header; + + /* send IPC message to DSP */ + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI, + cmd | HDA_DSP_REG_HIPCI_BUSY); + + return 0; +} + +void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) +{ + struct snd_sof_ipc_msg *msg = sdev->msg; + struct sof_ipc_reply reply; + struct sof_ipc_cmd_hdr *hdr; + unsigned long flags; + int ret = 0; + + /* + * Sometimes, there is unexpected reply ipc arriving. The reply + * ipc belongs to none of the ipcs sent from driver. + * In this case, the driver must ignore the ipc. + */ + if (!msg) { + dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); + return; + } + spin_lock_irqsave(&sdev->ipc_lock, flags); + + hdr = msg->msg_data; + if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) { + /* + * memory windows are powered off before sending IPC reply, + * so we can't read the mailbox for CTX_SAVE reply. + */ + reply.error = 0; + reply.hdr.cmd = SOF_IPC_GLB_REPLY; + reply.hdr.size = sizeof(reply); + memcpy(msg->reply_data, &reply, sizeof(reply)); + goto out; + } + + /* get IPC reply from DSP in the mailbox */ + sof_mailbox_read(sdev, sdev->host_box.offset, &reply, + sizeof(reply)); + + if (reply.error < 0) { + memcpy(msg->reply_data, &reply, sizeof(reply)); + ret = reply.error; + } else { + /* reply correct size ? */ + if (reply.hdr.size != msg->reply_size) { + dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", + msg->reply_size, reply.hdr.size); + ret = -EINVAL; + } + + /* read the message */ + if (msg->reply_size > 0) + sof_mailbox_read(sdev, sdev->host_box.offset, + msg->reply_data, msg->reply_size); + } + +out: + msg->reply_error = ret; + + spin_unlock_irqrestore(&sdev->ipc_lock, flags); +} + +static bool hda_dsp_ipc_is_sof(uint32_t msg) +{ + return (msg & (HDA_DSP_IPC_PURGE_FW | 0xf << 9)) != msg || + (msg & HDA_DSP_IPC_PURGE_FW) != HDA_DSP_IPC_PURGE_FW; +} + +/* IPC handler thread */ +irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) +{ + struct snd_sof_dev *sdev = context; + irqreturn_t ret = IRQ_NONE; + u32 hipci; + u32 hipcie; + u32 hipct; + u32 hipcte; + u32 hipcctl; + u32 msg; + u32 msg_ext; + + /* here we handle IPC interrupts only */ + if (!(sdev->irq_status & HDA_DSP_ADSPIS_IPC)) + return IRQ_NONE; + + /* read IPC status */ + hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCIE); + hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT); + hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL); + + /* reenable IPC interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); + + /* is this a reply message from the DSP */ + if (hipcie & HDA_DSP_REG_HIPCIE_DONE && + hipcctl & HDA_DSP_REG_HIPCCTL_DONE) { + hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCI); + msg = hipci & HDA_DSP_REG_HIPCI_MSG_MASK; + msg_ext = hipcie & HDA_DSP_REG_HIPCIE_MSG_MASK; + + dev_vdbg(sdev->dev, + "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n", + msg, msg_ext); + + /* mask Done interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCCTL, + HDA_DSP_REG_HIPCCTL_DONE, 0); + + /* handle immediate reply from DSP core - ignore ROM messages */ + if (hda_dsp_ipc_is_sof(msg)) { + hda_dsp_ipc_get_reply(sdev); + snd_sof_ipc_reply(sdev, msg); + } + + /* wake up sleeper if we are loading code */ + if (sdev->code_loading) { + sdev->code_loading = 0; + wake_up(&sdev->waitq); + } + + /* set the done bit */ + hda_dsp_ipc_dsp_done(sdev); + + ret = IRQ_HANDLED; + } + + /* is this a new message from DSP */ + if (hipct & HDA_DSP_REG_HIPCT_BUSY && + hipcctl & HDA_DSP_REG_HIPCCTL_BUSY) { + + hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCTE); + msg = hipct & HDA_DSP_REG_HIPCT_MSG_MASK; + msg_ext = hipcte & HDA_DSP_REG_HIPCTE_MSG_MASK; + + dev_vdbg(sdev->dev, + "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n", + msg, msg_ext); + + /* mask BUSY interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + HDA_DSP_REG_HIPCCTL, + HDA_DSP_REG_HIPCCTL_BUSY, 0); + + /* handle messages from DSP */ + if ((hipct & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { + /* this is a PANIC message !! */ + snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext)); + } else { + /* normal message - process normally */ + snd_sof_ipc_msgs_rx(sdev); + } + + hda_dsp_ipc_host_done(sdev); + + ret = IRQ_HANDLED; + } + + return ret; +} + +/* is this IRQ for ADSP ? - we only care about IPC here */ +irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) +{ + struct snd_sof_dev *sdev = context; + int ret = IRQ_NONE; + + spin_lock(&sdev->hw_lock); + + /* store status */ + sdev->irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPIS); + + /* invalid message ? */ + if (sdev->irq_status == 0xffffffff) + goto out; + + /* IPC message ? */ + if (sdev->irq_status & HDA_DSP_ADSPIS_IPC) { + /* disable IPC interrupt */ + snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, + HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_IPC, 0); + ret = IRQ_WAKE_THREAD; + } + +out: + spin_unlock(&sdev->hw_lock); + return ret; +} + +/* IPC Firmware ready */ + +static void ipc_get_windows(struct snd_sof_dev *sdev) +{ + struct sof_ipc_window_elem *elem; + u32 outbox_offset = 0; + u32 stream_offset = 0; + u32 inbox_offset = 0; + u32 outbox_size = 0; + u32 stream_size = 0; + u32 inbox_size = 0; + int i; + + if (!sdev->info_window) { + dev_err(sdev->dev, "error: have no window info\n"); + return; + } + + for (i = 0; i < sdev->info_window->num_windows; i++) { + elem = &sdev->info_window->window[i]; + + switch (elem->type) { + case SOF_IPC_REGION_UPBOX: + inbox_offset = + elem->offset + SRAM_WINDOW_OFFSET(elem->id); + inbox_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[HDA_DSP_BAR] + + inbox_offset, + elem->size, "inbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_DOWNBOX: + outbox_offset = + elem->offset + SRAM_WINDOW_OFFSET(elem->id); + outbox_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[HDA_DSP_BAR] + + outbox_offset, + elem->size, "outbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_TRACE: + snd_sof_debugfs_io_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "etrace", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_DEBUG: + snd_sof_debugfs_io_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "debug", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_STREAM: + stream_offset = + elem->offset + SRAM_WINDOW_OFFSET(elem->id); + stream_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "stream", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_REGS: + snd_sof_debugfs_io_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "regs", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_EXCEPTION: + sdev->dsp_oops_offset = elem->offset + + SRAM_WINDOW_OFFSET(elem->id); + snd_sof_debugfs_io_item(sdev, + sdev->bar[HDA_DSP_BAR] + + elem->offset + + SRAM_WINDOW_OFFSET + (elem->id), + elem->size, "exception", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + default: + dev_err(sdev->dev, "error: get illegal window info\n"); + return; + } + } + + if (outbox_size == 0 || inbox_size == 0) { + dev_err(sdev->dev, "error: get illegal mailbox window\n"); + return; + } + + snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, + outbox_offset, outbox_size); + sdev->stream_box.offset = stream_offset; + sdev->stream_box.size = stream_size; + + dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", + inbox_offset, inbox_size); + dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", + outbox_offset, outbox_size); + dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", + stream_offset, stream_size); +} + +/* check for ABI compatibility and create memory windows on first boot */ +int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; + u32 offset; + int ret; + + /* mailbox must be on 4k boundary */ + offset = HDA_DSP_MBOX_UPLINK_OFFSET; + + dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n", + msg_id, offset); + + /* no need to re-check version/ABI for subsequent boots */ + if (!sdev->first_boot) + return 0; + + /* copy data from the DSP FW ready offset */ + sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, + sizeof(*fw_ready)); + + /* make sure ABI version is compatible */ + ret = snd_sof_ipc_valid(sdev); + if (ret < 0) + return ret; + + /* now check for extended data */ + snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, + HDA_DSP_MBOX_UPLINK_OFFSET + + sizeof(struct sof_ipc_fw_ready)); + + ipc_get_windows(sdev); + + return 0; +} + +void hda_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz) +{ + if (!substream || !sdev->stream_box.size) { + sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); + } else { + struct hdac_stream *hstream = substream->runtime->private_data; + struct sof_intel_hda_stream *hda_stream; + + hda_stream = container_of(hstream, + struct sof_intel_hda_stream, + hda_stream.hstream); + + /* The stream might already be closed */ + if (hstream) + sof_mailbox_read(sdev, hda_stream->stream.posn_offset, + p, sz); + } +} + +int hda_ipc_pcm_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct sof_intel_hda_stream *hda_stream; + /* validate offset */ + size_t posn_offset = reply->posn_offset; + + hda_stream = container_of(hstream, struct sof_intel_hda_stream, + hda_stream.hstream); + + /* check for unaligned offset or overflow */ + if (posn_offset > sdev->stream_box.size || + posn_offset % sizeof(struct sof_ipc_stream_posn) != 0) + return -EINVAL; + + hda_stream->stream.posn_offset = sdev->stream_box.offset + posn_offset; + + dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu", + substream->stream, hda_stream->stream.posn_offset); + + return 0; +} From cfb07f4f0fc7dbfb6e2027588e27f725e9d6ce0b Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:08:59 -0500 Subject: [PATCH 1411/1995] ASoC: SOF: Add ACPI device support Add support ACPI based SOF DSP devices. Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit cd679898cd323d958b35c014f97c575b4abb8ce2) --- sound/soc/sof/sof-acpi-dev.c | 312 +++++++++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+) create mode 100644 sound/soc/sof/sof-acpi-dev.c diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c new file mode 100644 index 00000000000000..e9cf69874b5b1f --- /dev/null +++ b/sound/soc/sof/sof-acpi-dev.c @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_X86 +#include +#endif + +#include "ops.h" + +/* platform specific devices */ +#include "intel/shim.h" + +static char *fw_path; +module_param(fw_path, charp, 0444); +MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); + +static char *tplg_path; +module_param(tplg_path, charp, 0444); +MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL) +static const struct sof_dev_desc sof_acpi_haswell_desc = { + .machines = snd_soc_acpi_intel_haswell_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = 1, + .resindex_imr_base = -1, + .irqindex_host_ipc = 0, + .chip_info = &hsw_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-hsw.ri", + .nocodec_tplg_filename = "sof-hsw-nocodec.tplg", + .ops = &sof_hsw_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) +static const struct sof_dev_desc sof_acpi_broadwell_desc = { + .machines = snd_soc_acpi_intel_broadwell_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = 1, + .resindex_imr_base = -1, + .irqindex_host_ipc = 0, + .chip_info = &bdw_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-bdw.ri", + .nocodec_tplg_filename = "sof-bdw-nocodec.tplg", + .ops = &sof_bdw_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) + +/* BYTCR uses different IRQ index */ +static const struct sof_dev_desc sof_acpi_baytrailcr_desc = { + .machines = snd_soc_acpi_intel_baytrail_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = 1, + .resindex_imr_base = 2, + .irqindex_host_ipc = 0, + .chip_info = &byt_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-byt.ri", + .nocodec_tplg_filename = "sof-byt-nocodec.tplg", + .ops = &sof_byt_ops, + .arch_ops = &sof_xtensa_arch_ops +}; + +static const struct sof_dev_desc sof_acpi_baytrail_desc = { + .machines = snd_soc_acpi_intel_baytrail_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = 1, + .resindex_imr_base = 2, + .irqindex_host_ipc = 5, + .chip_info = &byt_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-byt.ri", + .nocodec_tplg_filename = "sof-byt-nocodec.tplg", + .ops = &sof_byt_ops, + .arch_ops = &sof_xtensa_arch_ops +}; + +#ifdef CONFIG_X86 /* TODO: move this to common helper */ + +static bool is_byt_cr(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + int status; + + if (iosf_mbi_available()) { + u32 bios_status; + status = iosf_mbi_read(BT_MBI_UNIT_PMC, /* 0x04 PUNIT */ + MBI_REG_READ, /* 0x10 */ + 0x006, /* BIOS_CONFIG */ + &bios_status); + + if (status) { + dev_err(dev, "could not read PUNIT BIOS_CONFIG\n"); + } else { + /* bits 26:27 mirror PMIC options */ + bios_status = (bios_status >> 26) & 3; + + if (bios_status == 1 || bios_status == 3) { + dev_info(dev, "Detected Baytrail-CR platform\n"); + return true; + } + + dev_info(dev, "BYT-CR not detected\n"); + } + } else { + dev_info(dev, "IOSF_MBI not available, no BYT-CR detection\n"); + } + + if (platform_get_resource(pdev, IORESOURCE_IRQ, 5) == NULL) { + /* + * Some devices detected as BYT-T have only a single IRQ listed, + * causing platform_get_irq with index 5 to return -ENXIO. + * The correct IRQ in this case is at index 0, as on BYT-CR. + */ + dev_info(dev, "Falling back to Baytrail-CR platform\n"); + return true; + } + + return false; +} +#else +static int is_byt_cr(struct platform_device *pdev) +{ + return 0; +} +#endif + +static const struct sof_dev_desc sof_acpi_cherrytrail_desc = { + .machines = snd_soc_acpi_intel_cherrytrail_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = 1, + .resindex_imr_base = 2, + .irqindex_host_ipc = 5, + .chip_info = &cht_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-cht.ri", + .nocodec_tplg_filename = "sof-cht-nocodec.tplg", + .ops = &sof_cht_ops, + .arch_ops = &sof_xtensa_arch_ops +}; + +#endif + +static const struct dev_pm_ops sof_acpi_pm = { + SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) + SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, + NULL) +}; + +static void sof_acpi_probe_complete(struct device *dev) +{ + /* allow runtime_pm */ + pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); +} + +static int sof_acpi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct sof_dev_desc *desc; + struct snd_soc_acpi_mach *mach; + struct snd_sof_pdata *sof_pdata; + const struct snd_sof_dsp_ops *ops; + int ret; + + dev_dbg(&pdev->dev, "ACPI DSP detected"); + + sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); + if (!sof_pdata) + return -ENOMEM; + + desc = device_get_match_data(dev); + if (!desc) + return -ENODEV; + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) + if (desc == &sof_acpi_baytrail_desc && is_byt_cr(pdev)) + desc = &sof_acpi_baytrailcr_desc; +#endif + + /* get ops for platform */ + ops = desc->ops; + if (!ops) { + dev_err(dev, "error: no matching ACPI descriptor ops\n"); + return -ENODEV; + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) + /* force nocodec mode */ + dev_warn(dev, "Force to use nocodec mode\n"); + mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); + if (!mach) + return -ENOMEM; + ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); + if (ret < 0) + return ret; +#else + /* find machine */ + mach = snd_soc_acpi_find_machine(desc->machines); + if (!mach) { + dev_warn(dev, "warning: No matching ASoC machine driver found\n"); + } else { + sof_pdata->fw_filename = mach->sof_fw_filename; + sof_pdata->tplg_filename = mach->sof_tplg_filename; + } +#endif + + if (mach) { + mach->mach_params.platform = dev_name(dev); + mach->mach_params.acpi_ipc_irq_index = desc->irqindex_host_ipc; + } + + sof_pdata->machine = mach; + sof_pdata->desc = desc; + sof_pdata->dev = &pdev->dev; + sof_pdata->platform = dev_name(dev); + + /* alternate fw and tplg filenames ? */ + if (fw_path) + sof_pdata->fw_filename_prefix = fw_path; + else + sof_pdata->fw_filename_prefix = + sof_pdata->desc->default_fw_path; + + if (tplg_path) + sof_pdata->tplg_filename_prefix = tplg_path; + else + sof_pdata->tplg_filename_prefix = + sof_pdata->desc->default_tplg_path; + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) + /* set callback to enable runtime_pm */ + sof_pdata->sof_probe_complete = sof_acpi_probe_complete; +#endif + /* call sof helper for DSP hardware probe */ + ret = snd_sof_device_probe(dev, sof_pdata); + if (ret) { + dev_err(dev, "error: failed to probe DSP hardware!\n"); + return ret; + } + +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) + sof_acpi_probe_complete(dev); +#endif + + return ret; +} + +static int sof_acpi_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + /* call sof helper for DSP hardware remove */ + snd_sof_device_remove(&pdev->dev); + + return 0; +} + +static const struct acpi_device_id sof_acpi_match[] = { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL) + { "INT33C8", (unsigned long)&sof_acpi_haswell_desc }, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) + { "INT3438", (unsigned long)&sof_acpi_broadwell_desc }, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) + { "80860F28", (unsigned long)&sof_acpi_baytrail_desc }, + { "808622A8", (unsigned long)&sof_acpi_cherrytrail_desc }, +#endif + { } +}; +MODULE_DEVICE_TABLE(acpi, sof_acpi_match); + +/* acpi_driver definition */ +static struct platform_driver snd_sof_acpi_driver = { + .probe = sof_acpi_probe, + .remove = sof_acpi_remove, + .driver = { + .name = "sof-audio-acpi", + .pm = &sof_acpi_pm, + .acpi_match_table = ACPI_PTR(sof_acpi_match), + }, +}; +module_platform_driver(snd_sof_acpi_driver); + +MODULE_LICENSE("Dual BSD/GPL"); From 7b2e25467fae29c70d590f8c8cffb2ae8a942ffd Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:09:00 -0500 Subject: [PATCH 1412/1995] ASoC: SOF: Add PCI device support Add support for PCI based DSP devices. Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit a226893b85b3c35f6c7c168beb28de738211164a) --- sound/soc/sof/sof-pci-dev.c | 373 ++++++++++++++++++++++++++++++++++++ 1 file changed, 373 insertions(+) create mode 100644 sound/soc/sof/sof-pci-dev.c diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c new file mode 100644 index 00000000000000..b778dffb2d25c0 --- /dev/null +++ b/sound/soc/sof/sof-pci-dev.c @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood +// + +#include +#include +#include +#include +#include +#include +#include +#include "ops.h" + +/* platform specific devices */ +#include "intel/shim.h" +#include "intel/hda.h" + +static char *fw_path; +module_param(fw_path, charp, 0444); +MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); + +static char *tplg_path; +module_param(tplg_path, charp, 0444); +MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) +static const struct sof_dev_desc bxt_desc = { + .machines = snd_soc_acpi_intel_bxt_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &apl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-apl.ri", + .nocodec_tplg_filename = "sof-apl-nocodec.tplg", + .ops = &sof_apl_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) +static const struct sof_dev_desc glk_desc = { + .machines = snd_soc_acpi_intel_glk_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &apl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-glk.ri", + .nocodec_tplg_filename = "sof-glk-nocodec.tplg", + .ops = &sof_apl_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) +static struct snd_soc_acpi_mach sof_tng_machines[] = { + { + .id = "INT343A", + .drv_name = "edison", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt.tplg", + }, + {} +}; + +static const struct sof_dev_desc tng_desc = { + .machines = sof_tng_machines, + .resindex_lpe_base = 3, /* IRAM, but subtract IRAM offset */ + .resindex_pcicfg_base = -1, + .resindex_imr_base = 0, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &tng_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-byt.ri", + .nocodec_tplg_filename = "sof-byt.tplg", + .ops = &sof_tng_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) +static const struct sof_dev_desc cnl_desc = { + .machines = snd_soc_acpi_intel_cnl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &cnl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-cnl.ri", + .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", + .ops = &sof_cnl_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) +static const struct sof_dev_desc cfl_desc = { + .machines = snd_soc_acpi_intel_cnl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &cnl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-cnl.ri", + .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", + .ops = &sof_cnl_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) +static const struct sof_dev_desc icl_desc = { + .machines = snd_soc_acpi_intel_icl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &cnl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-icl.ri", + .nocodec_tplg_filename = "sof-icl-nocodec.tplg", + .ops = &sof_cnl_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) +static const struct sof_dev_desc skl_desc = { + .machines = snd_soc_acpi_intel_skl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &skl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-skl.ri", + .nocodec_tplg_filename = "sof-skl-nocodec.tplg", + .ops = &sof_skl_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) +static const struct sof_dev_desc kbl_desc = { + .machines = snd_soc_acpi_intel_kbl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &skl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-kbl.ri", + .nocodec_tplg_filename = "sof-kbl-nocodec.tplg", + .ops = &sof_skl_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + +static const struct dev_pm_ops sof_pci_pm = { + SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) + SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, + NULL) +}; + +static void sof_pci_probe_complete(struct device *dev) +{ + dev_dbg(dev, "Completing SOF PCI probe"); + + /* allow runtime_pm */ + pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(dev); + + /* + * runtime pm for pci device is "forbidden" by default. + * so call pm_runtime_allow() to enable it. + */ + pm_runtime_allow(dev); + + /* follow recommendation in pci-driver.c to decrement usage counter */ + pm_runtime_put_noidle(dev); +} + +static int sof_pci_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + struct device *dev = &pci->dev; + const struct sof_dev_desc *desc = + (const struct sof_dev_desc *)pci_id->driver_data; + struct snd_soc_acpi_mach *mach; + struct snd_sof_pdata *sof_pdata; + const struct snd_sof_dsp_ops *ops; + int ret; + + dev_dbg(&pci->dev, "PCI DSP detected"); + + /* get ops for platform */ + ops = desc->ops; + if (!ops) { + dev_err(dev, "error: no matching PCI descriptor ops\n"); + return -ENODEV; + } + + sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); + if (!sof_pdata) + return -ENOMEM; + + ret = pcim_enable_device(pci); + if (ret < 0) + return ret; + + ret = pci_request_regions(pci, "Audio DSP"); + if (ret < 0) + return ret; + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) + /* force nocodec mode */ + dev_warn(dev, "Force to use nocodec mode\n"); + mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); + if (!mach) { + ret = -ENOMEM; + goto release_regions; + } + ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); + if (ret < 0) + goto release_regions; + +#else + /* find machine */ + mach = snd_soc_acpi_find_machine(desc->machines); + if (!mach) { + dev_warn(dev, "warning: No matching ASoC machine driver found\n"); + } else { + mach->mach_params.platform = dev_name(dev); + sof_pdata->fw_filename = mach->sof_fw_filename; + sof_pdata->tplg_filename = mach->sof_tplg_filename; + } +#endif /* CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE */ + + sof_pdata->name = pci_name(pci); + sof_pdata->machine = mach; + sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data; + sof_pdata->dev = dev; + sof_pdata->platform = dev_name(dev); + + /* alternate fw and tplg filenames ? */ + if (fw_path) + sof_pdata->fw_filename_prefix = fw_path; + else + sof_pdata->fw_filename_prefix = + sof_pdata->desc->default_fw_path; + + if (tplg_path) + sof_pdata->tplg_filename_prefix = tplg_path; + else + sof_pdata->tplg_filename_prefix = + sof_pdata->desc->default_tplg_path; + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) + /* set callback to enable runtime_pm */ + sof_pdata->sof_probe_complete = sof_pci_probe_complete; +#endif + /* call sof helper for DSP hardware probe */ + ret = snd_sof_device_probe(dev, sof_pdata); + if (ret) { + dev_err(dev, "error: failed to probe DSP hardware!\n"); + goto release_regions; + } + +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) + sof_pci_probe_complete(dev); +#endif + + return ret; + +release_regions: + pci_release_regions(pci); + + return ret; +} + +static void sof_pci_remove(struct pci_dev *pci) +{ + /* call sof helper for DSP hardware remove */ + snd_sof_device_remove(&pci->dev); + + /* follow recommendation in pci-driver.c to increment usage counter */ + pm_runtime_get_noresume(&pci->dev); + + /* release pci regions and disable device */ + pci_release_regions(pci); +} + +/* PCI IDs */ +static const struct pci_device_id sof_pci_ids[] = { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) + { PCI_DEVICE(0x8086, 0x119a), + .driver_data = (unsigned long)&tng_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) + /* BXT-P & Apollolake */ + { PCI_DEVICE(0x8086, 0x5a98), + .driver_data = (unsigned long)&bxt_desc}, + { PCI_DEVICE(0x8086, 0x1a98), + .driver_data = (unsigned long)&bxt_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) + { PCI_DEVICE(0x8086, 0x3198), + .driver_data = (unsigned long)&glk_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) + { PCI_DEVICE(0x8086, 0x9dc8), + .driver_data = (unsigned long)&cnl_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) + { PCI_DEVICE(0x8086, 0xa348), + .driver_data = (unsigned long)&cfl_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_KABYLAKE) + { PCI_DEVICE(0x8086, 0x9d71), + .driver_data = (unsigned long)&kbl_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_SKYLAKE) + { PCI_DEVICE(0x8086, 0x9d70), + .driver_data = (unsigned long)&skl_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) + { PCI_DEVICE(0x8086, 0x34C8), + .driver_data = (unsigned long)&icl_desc}, +#endif + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sof_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_driver = { + .name = "sof-audio-pci", + .id_table = sof_pci_ids, + .probe = sof_pci_probe, + .remove = sof_pci_remove, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_driver); + +MODULE_LICENSE("Dual BSD/GPL"); From 92c8b8b4753f4d1aaf8b6280046b4f795ce7d1d0 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:08:51 -0500 Subject: [PATCH 1413/1995] ASoC: SOF: Intel: Add Intel specific HDA firmware loader Add support for loading DSP firmware on Intel HDA based platforms. Signed-off-by: Keyon Jie Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit d16046ffa6de040bf580a64d5f4d0aa18258a854) --- sound/soc/sof/intel/hda-loader.c | 371 +++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 sound/soc/sof/intel/hda-loader.c diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c new file mode 100644 index 00000000000000..6a44bc349e44ce --- /dev/null +++ b/sound/soc/sof/intel/hda-loader.c @@ -0,0 +1,371 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for HDA DSP code loader + */ + +#include +#include +#include +#include "../ops.h" +#include "hda.h" + +#define HDA_FW_BOOT_ATTEMPTS 3 + +static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, + unsigned int size, struct snd_dma_buffer *dmab, + int direction) +{ + struct hdac_ext_stream *dsp_stream; + struct hdac_stream *hstream; + struct pci_dev *pci = to_pci_dev(sdev->dev); + int ret; + + if (direction != SNDRV_PCM_STREAM_PLAYBACK) { + dev_err(sdev->dev, "error: code loading DMA is playback only\n"); + return -EINVAL; + } + + dsp_stream = hda_dsp_stream_get(sdev, direction); + + if (!dsp_stream) { + dev_err(sdev->dev, "error: no stream available\n"); + return -ENODEV; + } + hstream = &dsp_stream->hstream; + + /* allocate DMA buffer */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab); + if (ret < 0) { + dev_err(sdev->dev, "error: memory alloc failed: %x\n", ret); + goto error; + } + + hstream->period_bytes = 0;/* initialize period_bytes */ + hstream->format_val = format; + hstream->bufsize = size; + + ret = hda_dsp_stream_hw_params(sdev, dsp_stream, dmab, NULL); + if (ret < 0) { + dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret); + goto error; + } + + hda_dsp_stream_spib_config(sdev, dsp_stream, HDA_DSP_SPIB_ENABLE, size); + + return hstream->stream_tag; + +error: + hda_dsp_stream_put(sdev, direction, hstream->stream_tag); + snd_dma_free_pages(dmab); + return ret; +} + +/* + * first boot sequence has some extra steps. core 0 waits for power + * status on core 1, so power up core 1 also momentarily, keep it in + * reset/stall and then turn it off + */ +static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, + u32 fwsize, int stream_tag) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + const struct sof_intel_dsp_desc *chip = hda->desc; + unsigned int status; + int ret; + + /* step 1: power up corex */ + ret = hda_dsp_core_power_up(sdev, chip->cores_mask); + if (ret < 0) { + dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n"); + goto err; + } + + /* step 2: purge FW request */ + snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, + chip->ipc_req_mask | (HDA_DSP_IPC_PURGE_FW | + ((stream_tag - 1) << 9))); + + /* step 3: unset core 0 reset state & unstall/run core 0 */ + ret = hda_dsp_core_run(sdev, HDA_DSP_CORE_MASK(0)); + if (ret < 0) { + dev_err(sdev->dev, "error: dsp core start failed %d\n", ret); + ret = -EIO; + goto err; + } + + /* step 4: wait for IPC DONE bit from ROM */ + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + chip->ipc_ack, status, + ((status & chip->ipc_ack_mask) + == chip->ipc_ack_mask), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_INIT_TIMEOUT_US); + + if (ret < 0) { + dev_err(sdev->dev, "error: waiting for HIPCIE done\n"); + goto err; + } + + /* step 5: power down corex */ + ret = hda_dsp_core_power_down(sdev, + chip->cores_mask & ~(HDA_DSP_CORE_MASK(0))); + if (ret < 0) { + dev_err(sdev->dev, "error: dsp core x power down failed\n"); + goto err; + } + + /* step 6: enable IPC interrupts */ + hda_dsp_ipc_int_enable(sdev); + + /* step 7: wait for ROM init */ + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_STATUS, status, + ((status & HDA_DSP_ROM_STS_MASK) + == HDA_DSP_ROM_INIT), + HDA_DSP_REG_POLL_INTERVAL_US, + chip->rom_init_timeout * + USEC_PER_MSEC); + if (!ret) + return 0; + +err: + hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); + hda_dsp_core_reset_power_down(sdev, chip->cores_mask); + + return ret; +} + +static int cl_trigger(struct snd_sof_dev *sdev, + struct hdac_ext_stream *stream, int cmd) +{ + struct hdac_stream *hstream = &stream->hstream; + int sd_offset = SOF_STREAM_SD_OFFSET(hstream); + + /* code loader is special case that reuses stream ops */ + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + wait_event_timeout(sdev->waitq, !sdev->code_loading, + HDA_DSP_CL_TRIGGER_TIMEOUT); + + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + 1 << hstream->index, + 1 << hstream->index); + + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset, + SOF_HDA_SD_CTL_DMA_START | + SOF_HDA_CL_DMA_SD_INT_MASK, + SOF_HDA_SD_CTL_DMA_START | + SOF_HDA_CL_DMA_SD_INT_MASK); + + hstream->running = true; + return 0; + default: + return hda_dsp_stream_trigger(sdev, stream, cmd); + } +} + +static struct hdac_ext_stream *get_stream_with_tag(struct snd_sof_dev *sdev, + int tag) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *s; + + /* get stream with tag */ + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == SNDRV_PCM_STREAM_PLAYBACK && + s->stream_tag == tag) { + return stream_to_hdac_ext_stream(s); + } + } + + return NULL; +} + +static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, + struct hdac_ext_stream *stream) +{ + struct hdac_stream *hstream = &stream->hstream; + int sd_offset = SOF_STREAM_SD_OFFSET(hstream); + int ret; + + ret = hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); + + hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_PLAYBACK, + hstream->stream_tag); + hstream->running = 0; + hstream->substream = NULL; + + /* reset BDL address */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, 0); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0); + + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0); + snd_dma_free_pages(dmab); + dmab->area = NULL; + hstream->bufsize = 0; + hstream->format_val = 0; + + return ret; +} + +static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) +{ + unsigned int reg; + int ret, status; + + ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_START); + if (ret < 0) { + dev_err(sdev->dev, "error: DMA trigger start failed\n"); + return ret; + } + + status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_STATUS, reg, + ((reg & HDA_DSP_ROM_STS_MASK) + == HDA_DSP_ROM_FW_ENTERED), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_BASEFW_TIMEOUT_US); + + ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_STOP); + if (ret < 0) { + dev_err(sdev->dev, "error: DMA trigger stop failed\n"); + return ret; + } + + return status; +} + +int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *plat_data = sdev->pdata; + const struct sof_dev_desc *desc = plat_data->desc; + const struct sof_intel_dsp_desc *chip_info; + struct hdac_ext_stream *stream; + struct firmware stripped_firmware; + int ret, ret1, tag, i; + + chip_info = desc->chip_info; + + stripped_firmware.data = plat_data->fw->data; + stripped_firmware.size = plat_data->fw->size; + + /* init for booting wait */ + init_waitqueue_head(&sdev->boot_wait); + sdev->boot_complete = false; + + /* prepare DMA for code loader stream */ + tag = cl_stream_prepare(sdev, 0x40, stripped_firmware.size, + &sdev->dmab, SNDRV_PCM_STREAM_PLAYBACK); + + if (tag < 0) { + dev_err(sdev->dev, "error: dma prepare for fw loading err: %x\n", + tag); + return tag; + } + + /* get stream with tag */ + stream = get_stream_with_tag(sdev, tag); + if (!stream) { + dev_err(sdev->dev, + "error: could not get stream with stream tag %d\n", + tag); + ret = -ENODEV; + goto err; + } + + memcpy(sdev->dmab.area, stripped_firmware.data, + stripped_firmware.size); + + /* try ROM init a few times before giving up */ + for (i = 0; i < HDA_FW_BOOT_ATTEMPTS; i++) { + ret = cl_dsp_init(sdev, stripped_firmware.data, + stripped_firmware.size, tag); + + /* don't retry anymore if successful */ + if (!ret) + break; + + dev_err(sdev->dev, "error: Error code=0x%x: FW status=0x%x\n", + snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_ERROR), + snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_SRAM_REG_ROM_STATUS)); + dev_err(sdev->dev, "error: iteration %d of Core En/ROM load failed: %d\n", + i, ret); + } + + if (i == HDA_FW_BOOT_ATTEMPTS) { + dev_err(sdev->dev, "error: dsp init failed after %d attempts with err: %d\n", + i, ret); + goto cleanup; + } + + /* + * at this point DSP ROM has been initialized and + * should be ready for code loading and firmware boot + */ + ret = cl_copy_fw(sdev, stream); + if (!ret) + dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); + else + dev_err(sdev->dev, "error: load fw failed ret: %d\n", ret); + +cleanup: + /* + * Perform codeloader stream cleanup. + * This should be done even if firmware loading fails. + */ + ret1 = cl_cleanup(sdev, &sdev->dmab, stream); + if (ret1 < 0) { + dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); + + /* set return value to indicate cleanup failure */ + ret = ret1; + } + + /* + * return master core id if both fw copy + * and stream clean up are successful + */ + if (!ret) + return chip_info->init_core_mask; + + /* dump dsp registers and disable DSP upon error */ +err: + hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); + + /* disable DSP */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, + SOF_HDA_REG_PP_PPCTL, + SOF_HDA_PPCTL_GPROCEN, 0); + return ret; +} + +/* pre fw run operations */ +int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev) +{ + /* disable clock gating and power gating */ + return hda_dsp_ctrl_clock_power_gating(sdev, false); +} + +/* post fw run operations */ +int hda_dsp_post_fw_run(struct snd_sof_dev *sdev) +{ + /* re-enable clock gating and power gating */ + return hda_dsp_ctrl_clock_power_gating(sdev, true); +} From bb22447864c9836804c1947c24e73857303242c2 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:08:52 -0500 Subject: [PATCH 1414/1995] ASoC: SOF: Intel: Add Intel specific HDA PCM operations Add PCM operations for Intel HDA based DSPs. Signed-off-by: Keyon Jie Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit c6be710f5e2a92204f92d872a0c0b4fe29666492) --- sound/soc/sof/intel/hda-pcm.c | 240 ++++++++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 sound/soc/sof/intel/hda-pcm.c diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c new file mode 100644 index 00000000000000..5714a79fbe1a16 --- /dev/null +++ b/sound/soc/sof/intel/hda-pcm.c @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for generic Intel audio DSP HDA IP + */ + +#include +#include +#include +#include "../ops.h" +#include "hda.h" + +#define SDnFMT_BASE(x) ((x) << 14) +#define SDnFMT_MULT(x) (((x) - 1) << 11) +#define SDnFMT_DIV(x) (((x) - 1) << 8) +#define SDnFMT_BITS(x) ((x) << 4) +#define SDnFMT_CHAN(x) ((x) << 0) + +static inline u32 get_mult_div(struct snd_sof_dev *sdev, int rate) +{ + switch (rate) { + case 8000: + return SDnFMT_DIV(6); + case 9600: + return SDnFMT_DIV(5); + case 11025: + return SDnFMT_BASE(1) | SDnFMT_DIV(4); + case 16000: + return SDnFMT_DIV(3); + case 22050: + return SDnFMT_BASE(1) | SDnFMT_DIV(2); + case 32000: + return SDnFMT_DIV(3) | SDnFMT_MULT(2); + case 44100: + return SDnFMT_BASE(1); + case 48000: + return 0; + case 88200: + return SDnFMT_BASE(1) | SDnFMT_MULT(2); + case 96000: + return SDnFMT_MULT(2); + case 176400: + return SDnFMT_BASE(1) | SDnFMT_MULT(4); + case 192000: + return SDnFMT_MULT(4); + default: + dev_warn(sdev->dev, "can't find div rate %d using 48kHz\n", + rate); + return 0; /* use 48KHz if not found */ + } +}; + +static inline u32 get_bits(struct snd_sof_dev *sdev, int sample_bits) +{ + switch (sample_bits) { + case 8: + return SDnFMT_BITS(0); + case 16: + return SDnFMT_BITS(1); + case 20: + return SDnFMT_BITS(2); + case 24: + return SDnFMT_BITS(3); + case 32: + return SDnFMT_BITS(4); + default: + dev_warn(sdev->dev, "can't find %d bits using 16bit\n", + sample_bits); + return SDnFMT_BITS(1); /* use 16bits format if not found */ + } +}; + +int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct sof_ipc_stream_params *ipc_params) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream); + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + struct snd_dma_buffer *dmab; + int ret; + u32 size, rate, bits; + + size = params_buffer_bytes(params); + rate = get_mult_div(sdev, params_rate(params)); + bits = get_bits(sdev, params_width(params)); + + hstream->substream = substream; + + dmab = substream->runtime->dma_buffer_p; + + hstream->format_val = rate | bits | (params_channels(params) - 1); + hstream->bufsize = size; + hstream->period_bytes = params_period_bytes(params); + hstream->no_period_wakeup = + (params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) && + (params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP); + + ret = hda_dsp_stream_hw_params(sdev, stream, dmab, params); + if (ret < 0) { + dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret); + return ret; + } + + /* disable SPIB, to enable buffer wrap for stream */ + hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); + + /* set host_period_bytes to 0 if no IPC position */ + if (hda && hda->no_ipc_position) + ipc_params->host_period_bytes = 0; + + ipc_params->stream_tag = hstream->stream_tag; + + return 0; +} + +int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, int cmd) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream); + + return hda_dsp_stream_trigger(sdev, stream, cmd); +} + +snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct hdac_stream *hstream = substream->runtime->private_data; + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + struct snd_sof_pcm *spcm; + snd_pcm_uframes_t pos; + + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) { + dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n", + rtd->dai_link->id); + return 0; + } + + if (hda && !hda->no_ipc_position) { + /* read position from IPC position */ + pos = spcm->stream[substream->stream].posn.host_posn; + goto found; + } + + /* + * DPIB/posbuf position mode: + * For Playback, Use DPIB register from HDA space which + * reflects the actual data transferred. + * For Capture, Use the position buffer for pointer, as DPIB + * is not accurate enough, its update may be completed + * earlier than the data written to DDR. + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hstream->index)); + } else { + /* + * For capture stream, we need more workaround to fix the + * position incorrect issue: + * + * 1. Wait at least 20us before reading position buffer after + * the interrupt generated(IOC), to make sure position update + * happens on frame boundary i.e. 20.833uSec for 48KHz. + * 2. Perform a dummy Read to DPIB register to flush DMA + * position value. + * 3. Read the DMA Position from posbuf. Now the readback + * value should be >= period boundary. + */ + usleep_range(20, 21); + snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hstream->index)); + pos = snd_hdac_stream_get_pos_posbuf(hstream); + } + + if (pos >= hstream->bufsize) + pos = 0; + +found: + pos = bytes_to_frames(substream->runtime, pos); + + dev_vdbg(sdev->dev, "PCM: stream %d dir %d position %lu\n", + hstream->index, substream->stream, pos); + return pos; +} + +int hda_dsp_pcm_open(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct hdac_ext_stream *dsp_stream; + int direction = substream->stream; + + dsp_stream = hda_dsp_stream_get(sdev, direction); + + if (!dsp_stream) { + dev_err(sdev->dev, "error: no stream available\n"); + return -ENODEV; + } + + /* binding pcm substream to hda stream */ + substream->runtime->private_data = &dsp_stream->hstream; + return 0; +} + +int hda_dsp_pcm_close(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + int direction = substream->stream; + int ret; + + ret = hda_dsp_stream_put(sdev, direction, hstream->stream_tag); + + if (ret) { + dev_dbg(sdev->dev, "stream %s not opened!\n", substream->name); + return -ENODEV; + } + + /* unbinding pcm substream to hda stream */ + substream->runtime->private_data = NULL; + return 0; +} From fa4163062b7b69196ed8e9b80fe9c6345d658c8f Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 12 Apr 2019 11:08:53 -0500 Subject: [PATCH 1415/1995] ASoC: SOF: Intel: Add hda-bus support and initialization Use hdac_io_ops and configure all required spin_locks/mutex to use hdac_hda_ext library. Keep the code conditional so that the HDA link and audio codec support can be removed. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 78ad1f07a49a56fa3714ee36573133a39e32593d) --- sound/soc/sof/intel/hda-bus.c | 108 ++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 sound/soc/sof/intel/hda-bus.c diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c new file mode 100644 index 00000000000000..62cc9921bb5597 --- /dev/null +++ b/sound/soc/sof/intel/hda-bus.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Keyon Jie + +#include +#include +#include "../sof-priv.h" +#include "hda.h" + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + +static const struct hdac_bus_ops bus_ops = { + .command = snd_hdac_bus_send_cmd, + .get_response = snd_hdac_bus_get_response, +}; + +#endif + +static void sof_hda_writel(u32 value, u32 __iomem *addr) +{ + writel(value, addr); +} + +static u32 sof_hda_readl(u32 __iomem *addr) +{ + return readl(addr); +} + +static void sof_hda_writew(u16 value, u16 __iomem *addr) +{ + writew(value, addr); +} + +static u16 sof_hda_readw(u16 __iomem *addr) +{ + return readw(addr); +} + +static void sof_hda_writeb(u8 value, u8 __iomem *addr) +{ + writeb(value, addr); +} + +static u8 sof_hda_readb(u8 __iomem *addr) +{ + return readb(addr); +} + +static int sof_hda_dma_alloc_pages(struct hdac_bus *bus, int type, + size_t size, struct snd_dma_buffer *buf) +{ + return snd_dma_alloc_pages(type, bus->dev, size, buf); +} + +static void sof_hda_dma_free_pages(struct hdac_bus *bus, + struct snd_dma_buffer *buf) +{ + snd_dma_free_pages(buf); +} + +static const struct hdac_io_ops io_ops = { + .reg_writel = sof_hda_writel, + .reg_readl = sof_hda_readl, + .reg_writew = sof_hda_writew, + .reg_readw = sof_hda_readw, + .reg_writeb = sof_hda_writeb, + .reg_readb = sof_hda_readb, + .dma_alloc_pages = sof_hda_dma_alloc_pages, + .dma_free_pages = sof_hda_dma_free_pages, +}; + +/* + * This can be used for both with/without hda link support. + */ +void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, + const struct hdac_ext_bus_ops *ext_ops) +{ + static int idx; + + memset(bus, 0, sizeof(*bus)); + bus->dev = dev; + + bus->io_ops = &io_ops; + INIT_LIST_HEAD(&bus->stream_list); + + bus->irq = -1; + bus->ext_ops = ext_ops; + bus->idx = idx++; + + spin_lock_init(&bus->reg_lock); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + INIT_LIST_HEAD(&bus->codec_list); + INIT_LIST_HEAD(&bus->hlink_list); + + mutex_init(&bus->cmd_mutex); + mutex_init(&bus->lock); + bus->ops = &bus_ops; + INIT_WORK(&bus->unsol_work, snd_hdac_bus_process_unsol_events); + bus->cmd_dma_state = true; +#endif + +} From 98d1b3de03f5a1bf76ed2cac4fad52bfcf222dca Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:08:54 -0500 Subject: [PATCH 1416/1995] ASoC: SOF: Intel: Add Intel specific HDA stream operations Add support or HDA DSP stream operations for Intel HDA DSPs. Signed-off-by: Keyon Jie Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit a1d1e266b44517e736a456b3771152c33504f13d) --- sound/soc/sof/intel/hda-stream.c | 692 +++++++++++++++++++++++++++++++ 1 file changed, 692 insertions(+) create mode 100644 sound/soc/sof/intel/hda-stream.c diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c new file mode 100644 index 00000000000000..6290b2df5e621d --- /dev/null +++ b/sound/soc/sof/intel/hda-stream.c @@ -0,0 +1,692 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for generic Intel audio DSP HDA IP + */ + +#include +#include +#include +#include +#include "../ops.h" +#include "hda.h" + +/* + * set up one of BDL entries for a stream + */ +static int hda_setup_bdle(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab, + struct hdac_stream *stream, + struct sof_intel_dsp_bdl **bdlp, + int offset, int size, int ioc) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct sof_intel_dsp_bdl *bdl = *bdlp; + + while (size > 0) { + dma_addr_t addr; + int chunk; + + if (stream->frags >= HDA_DSP_MAX_BDL_ENTRIES) { + dev_err(sdev->dev, "error: stream frags exceeded\n"); + return -EINVAL; + } + + addr = snd_sgbuf_get_addr(dmab, offset); + /* program BDL addr */ + bdl->addr_l = cpu_to_le32(lower_32_bits(addr)); + bdl->addr_h = cpu_to_le32(upper_32_bits(addr)); + /* program BDL size */ + chunk = snd_sgbuf_get_chunk_size(dmab, offset, size); + /* one BDLE should not cross 4K boundary */ + if (bus->align_bdle_4k) { + u32 remain = 0x1000 - (offset & 0xfff); + + if (chunk > remain) + chunk = remain; + } + bdl->size = cpu_to_le32(chunk); + /* only program IOC when the whole segment is processed */ + size -= chunk; + bdl->ioc = (size || !ioc) ? 0 : cpu_to_le32(0x01); + bdl++; + stream->frags++; + offset += chunk; + + dev_vdbg(sdev->dev, "bdl, frags:%d, chunk size:0x%x;\n", + stream->frags, chunk); + } + + *bdlp = bdl; + return offset; +} + +/* + * set up Buffer Descriptor List (BDL) for host memory transfer + * BDL describes the location of the individual buffers and is little endian. + */ +int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, + struct snd_dma_buffer *dmab, + struct hdac_stream *stream) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + struct sof_intel_dsp_bdl *bdl; + int i, offset, period_bytes, periods; + int remain, ioc; + + period_bytes = stream->period_bytes; + dev_dbg(sdev->dev, "period_bytes:0x%x\n", period_bytes); + if (!period_bytes) + period_bytes = stream->bufsize; + + periods = stream->bufsize / period_bytes; + + dev_dbg(sdev->dev, "periods:%d\n", periods); + + remain = stream->bufsize % period_bytes; + if (remain) + periods++; + + /* program the initial BDL entries */ + bdl = (struct sof_intel_dsp_bdl *)stream->bdl.area; + offset = 0; + stream->frags = 0; + + /* + * set IOC if don't use position IPC + * and period_wakeup needed. + */ + ioc = hda->no_ipc_position ? + !stream->no_period_wakeup : 0; + + for (i = 0; i < periods; i++) { + if (i == (periods - 1) && remain) + /* set the last small entry */ + offset = hda_setup_bdle(sdev, dmab, + stream, &bdl, offset, + remain, 0); + else + offset = hda_setup_bdle(sdev, dmab, + stream, &bdl, offset, + period_bytes, ioc); + } + + return offset; +} + +int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev, + struct hdac_ext_stream *stream, + int enable, u32 size) +{ + struct hdac_stream *hstream = &stream->hstream; + u32 mask; + + if (!sdev->bar[HDA_DSP_SPIB_BAR]) { + dev_err(sdev->dev, "error: address of spib capability is NULL\n"); + return -EINVAL; + } + + mask = (1 << hstream->index); + + /* enable/disable SPIB for the stream */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_SPIB_BAR, + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, mask, + enable << hstream->index); + + /* set the SPIB value */ + sof_io_write(sdev, stream->spib_addr, size); + + return 0; +} + +/* get next unused stream */ +struct hdac_ext_stream * +hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_stream *stream = NULL; + struct hdac_stream *s; + + spin_lock_irq(&bus->reg_lock); + + /* get an unused stream */ + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == direction && !s->opened) { + s->opened = true; + stream = stream_to_hdac_ext_stream(s); + break; + } + } + + spin_unlock_irq(&bus->reg_lock); + + /* stream found ? */ + if (!stream) + dev_err(sdev->dev, "error: no free %s streams\n", + direction == SNDRV_PCM_STREAM_PLAYBACK ? + "playback" : "capture"); + + return stream; +} + +/* free a stream */ +int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *s; + + spin_lock_irq(&bus->reg_lock); + + /* find used stream */ + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == direction && + s->opened && s->stream_tag == stream_tag) { + s->opened = false; + spin_unlock_irq(&bus->reg_lock); + return 0; + } + } + + spin_unlock_irq(&bus->reg_lock); + + dev_dbg(sdev->dev, "stream_tag %d not opened!\n", stream_tag); + return -ENODEV; +} + +int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, + struct hdac_ext_stream *stream, int cmd) +{ + struct hdac_stream *hstream = &stream->hstream; + int sd_offset = SOF_STREAM_SD_OFFSET(hstream); + + /* cmd must be for audio stream */ + switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_START: + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + 1 << hstream->index, + 1 << hstream->index); + + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset, + SOF_HDA_SD_CTL_DMA_START | + SOF_HDA_CL_DMA_SD_INT_MASK, + SOF_HDA_SD_CTL_DMA_START | + SOF_HDA_CL_DMA_SD_INT_MASK); + + hstream->running = true; + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_STOP: + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset, + SOF_HDA_SD_CTL_DMA_START | + SOF_HDA_CL_DMA_SD_INT_MASK, 0x0); + + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset + + SOF_HDA_ADSP_REG_CL_SD_STS, + SOF_HDA_CL_DMA_SD_INT_MASK); + + hstream->running = false; + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + 1 << hstream->index, 0x0); + break; + default: + dev_err(sdev->dev, "error: unknown command: %d\n", cmd); + return -EINVAL; + } + + return 0; +} + +/* + * prepare for common hdac registers settings, for both code loader + * and normal stream. + */ +int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, + struct hdac_ext_stream *stream, + struct snd_dma_buffer *dmab, + struct snd_pcm_hw_params *params) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *hstream = &stream->hstream; + int sd_offset = SOF_STREAM_SD_OFFSET(hstream); + int ret, timeout = HDA_DSP_STREAM_RESET_TIMEOUT; + u32 val, mask; + + if (!stream) { + dev_err(sdev->dev, "error: no stream available\n"); + return -ENODEV; + } + + /* decouple host and link DMA */ + mask = 0x1 << hstream->index; + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + mask, mask); + + if (!dmab) { + dev_err(sdev->dev, "error: no dma buffer allocated!\n"); + return -ENODEV; + } + + /* clear stream status */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, + SOF_HDA_CL_DMA_SD_INT_MASK | + SOF_HDA_SD_CTL_DMA_START, 0); + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, + SOF_HDA_CL_DMA_SD_INT_MASK, + SOF_HDA_CL_DMA_SD_INT_MASK); + + /* stream reset */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, 0x1, + 0x1); + udelay(3); + do { + val = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, + sd_offset); + if (val & 0x1) + break; + } while (--timeout); + if (timeout == 0) { + dev_err(sdev->dev, "error: stream reset failed\n"); + return -ETIMEDOUT; + } + + timeout = HDA_DSP_STREAM_RESET_TIMEOUT; + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, 0x1, + 0x0); + + /* wait for hardware to report that stream is out of reset */ + udelay(3); + do { + val = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, + sd_offset); + if ((val & 0x1) == 0) + break; + } while (--timeout); + if (timeout == 0) { + dev_err(sdev->dev, "error: timeout waiting for stream reset\n"); + return -ETIMEDOUT; + } + + if (hstream->posbuf) + *hstream->posbuf = 0; + + /* reset BDL address */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, + 0x0); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, + 0x0); + + /* clear stream status */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, + SOF_HDA_CL_DMA_SD_INT_MASK | + SOF_HDA_SD_CTL_DMA_START, 0); + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, + SOF_HDA_CL_DMA_SD_INT_MASK, + SOF_HDA_CL_DMA_SD_INT_MASK); + + hstream->frags = 0; + + ret = hda_dsp_stream_setup_bdl(sdev, dmab, hstream); + if (ret < 0) { + dev_err(sdev->dev, "error: set up of BDL failed\n"); + return ret; + } + + /* program stream tag to set up stream descriptor for DMA */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, + SOF_HDA_CL_SD_CTL_STREAM_TAG_MASK, + hstream->stream_tag << + SOF_HDA_CL_SD_CTL_STREAM_TAG_SHIFT); + + /* program cyclic buffer length */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, + hstream->bufsize); + + /* + * Recommended hardware programming sequence for HDAudio DMA format + * + * 1. Put DMA into coupled mode by clearing PPCTL.PROCEN bit + * for corresponding stream index before the time of writing + * format to SDxFMT register. + * 2. Write SDxFMT + * 3. Set PPCTL.PROCEN bit for corresponding stream index to + * enable decoupled mode + */ + + /* couple host and link DMA, disable DSP features */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + mask, 0); + + /* program stream format */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + + SOF_HDA_ADSP_REG_CL_SD_FORMAT, + 0xffff, hstream->format_val); + + /* decouple host and link DMA, enable DSP features */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, + mask, mask); + + /* program last valid index */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, + 0xffff, (hstream->frags - 1)); + + /* program BDL address */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, + (u32)hstream->bdl.addr); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, + upper_32_bits(hstream->bdl.addr)); + + /* enable position buffer */ + if (!(snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE) + & SOF_HDA_ADSP_DPLBASE_ENABLE)) { + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPUBASE, + upper_32_bits(bus->posbuf.addr)); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE, + (u32)bus->posbuf.addr | + SOF_HDA_ADSP_DPLBASE_ENABLE); + } + + /* set interrupt enable bits */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, + SOF_HDA_CL_DMA_SD_INT_MASK, + SOF_HDA_CL_DMA_SD_INT_MASK); + + /* read FIFO size */ + if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK) { + hstream->fifo_size = + snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, + sd_offset + + SOF_HDA_ADSP_REG_CL_SD_FIFOSIZE); + hstream->fifo_size &= 0xffff; + hstream->fifo_size += 1; + } else { + hstream->fifo_size = 0; + } + + return ret; +} + +irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) +{ + struct hdac_bus *bus = context; + u32 status; + + if (!pm_runtime_active(bus->dev)) + return IRQ_NONE; + + spin_lock(&bus->reg_lock); + + status = snd_hdac_chip_readl(bus, INTSTS); + if (status == 0 || status == 0xffffffff) { + spin_unlock(&bus->reg_lock); + return IRQ_NONE; + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* clear rirb int */ + status = snd_hdac_chip_readb(bus, RIRBSTS); + if (status & RIRB_INT_MASK) { + if (status & RIRB_INT_RESPONSE) + snd_hdac_bus_update_rirb(bus); + snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); + } +#endif + + spin_unlock(&bus->reg_lock); + + return snd_hdac_chip_readl(bus, INTSTS) ? IRQ_WAKE_THREAD : IRQ_HANDLED; +} + +irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) +{ + struct hdac_bus *bus = context; + struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); + struct hdac_stream *s; + u32 status = snd_hdac_chip_readl(bus, INTSTS); + u32 sd_status; + + /* check streams */ + list_for_each_entry(s, &bus->stream_list, list) { + if (status & (1 << s->index) && s->opened) { + sd_status = snd_hdac_stream_readb(s, SD_STS); + + dev_vdbg(bus->dev, "stream %d status 0x%x\n", + s->index, sd_status); + + snd_hdac_stream_writeb(s, SD_STS, SD_INT_MASK); + + if (!s->substream || + !s->running || + (sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0) + continue; + + /* Inform ALSA only in case not do that with IPC */ + if (sof_hda->no_ipc_position) + snd_pcm_period_elapsed(s->substream); + + } + } + + return IRQ_HANDLED; +} + +int hda_dsp_stream_init(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_ext_stream *stream; + struct hdac_stream *hstream; + struct pci_dev *pci = to_pci_dev(sdev->dev); + int sd_offset; + int i, num_playback, num_capture, num_total, ret; + u32 gcap; + + gcap = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_GCAP); + dev_dbg(sdev->dev, "hda global caps = 0x%x\n", gcap); + + /* get stream count from GCAP */ + num_capture = (gcap >> 8) & 0x0f; + num_playback = (gcap >> 12) & 0x0f; + num_total = num_playback + num_capture; + + dev_dbg(sdev->dev, "detected %d playback and %d capture streams\n", + num_playback, num_capture); + + if (num_playback >= SOF_HDA_PLAYBACK_STREAMS) { + dev_err(sdev->dev, "error: too many playback streams %d\n", + num_playback); + return -EINVAL; + } + + if (num_capture >= SOF_HDA_CAPTURE_STREAMS) { + dev_err(sdev->dev, "error: too many capture streams %d\n", + num_playback); + return -EINVAL; + } + + /* + * mem alloc for the position buffer + * TODO: check position buffer update + */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, + SOF_HDA_DPIB_ENTRY_SIZE * num_total, + &bus->posbuf); + if (ret < 0) { + dev_err(sdev->dev, "error: posbuffer dma alloc failed\n"); + return -ENOMEM; + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* mem alloc for the CORB/RIRB ringbuffers */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, + PAGE_SIZE, &bus->rb); + if (ret < 0) { + dev_err(sdev->dev, "error: RB alloc failed\n"); + return -ENOMEM; + } +#endif + + /* create capture streams */ + for (i = 0; i < num_capture; i++) { + struct sof_intel_hda_stream *hda_stream; + + hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream), + GFP_KERNEL); + if (!hda_stream) + return -ENOMEM; + + stream = &hda_stream->hda_stream; + + stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] + + SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i; + + stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] + + SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total + + SOF_HDA_PPLC_INTERVAL * i; + + /* do we support SPIB */ + if (sdev->bar[HDA_DSP_SPIB_BAR]) { + stream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] + + SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + + SOF_HDA_SPIB_SPIB; + + stream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] + + SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + + SOF_HDA_SPIB_MAXFIFO; + } + + hstream = &stream->hstream; + hstream->bus = bus; + hstream->sd_int_sta_mask = 1 << i; + hstream->index = i; + sd_offset = SOF_STREAM_SD_OFFSET(hstream); + hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset; + hstream->stream_tag = i + 1; + hstream->opened = false; + hstream->running = false; + hstream->direction = SNDRV_PCM_STREAM_CAPTURE; + + /* memory alloc for stream BDL */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, + HDA_DSP_BDL_SIZE, &hstream->bdl); + if (ret < 0) { + dev_err(sdev->dev, "error: stream bdl dma alloc failed\n"); + return -ENOMEM; + } + hstream->posbuf = (__le32 *)(bus->posbuf.area + + (hstream->index) * 8); + + list_add_tail(&hstream->list, &bus->stream_list); + } + + /* create playback streams */ + for (i = num_capture; i < num_total; i++) { + struct sof_intel_hda_stream *hda_stream; + + hda_stream = devm_kzalloc(sdev->dev, sizeof(*hda_stream), + GFP_KERNEL); + if (!hda_stream) + return -ENOMEM; + + stream = &hda_stream->hda_stream; + + /* we always have DSP support */ + stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] + + SOF_HDA_PPHC_BASE + SOF_HDA_PPHC_INTERVAL * i; + + stream->pplc_addr = sdev->bar[HDA_DSP_PP_BAR] + + SOF_HDA_PPLC_BASE + SOF_HDA_PPLC_MULTI * num_total + + SOF_HDA_PPLC_INTERVAL * i; + + /* do we support SPIB */ + if (sdev->bar[HDA_DSP_SPIB_BAR]) { + stream->spib_addr = sdev->bar[HDA_DSP_SPIB_BAR] + + SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + + SOF_HDA_SPIB_SPIB; + + stream->fifo_addr = sdev->bar[HDA_DSP_SPIB_BAR] + + SOF_HDA_SPIB_BASE + SOF_HDA_SPIB_INTERVAL * i + + SOF_HDA_SPIB_MAXFIFO; + } + + hstream = &stream->hstream; + hstream->bus = bus; + hstream->sd_int_sta_mask = 1 << i; + hstream->index = i; + sd_offset = SOF_STREAM_SD_OFFSET(hstream); + hstream->sd_addr = sdev->bar[HDA_DSP_HDA_BAR] + sd_offset; + hstream->stream_tag = i - num_capture + 1; + hstream->opened = false; + hstream->running = false; + hstream->direction = SNDRV_PCM_STREAM_PLAYBACK; + + /* mem alloc for stream BDL */ + ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, + HDA_DSP_BDL_SIZE, &hstream->bdl); + if (ret < 0) { + dev_err(sdev->dev, "error: stream bdl dma alloc failed\n"); + return -ENOMEM; + } + + hstream->posbuf = (__le32 *)(bus->posbuf.area + + (hstream->index) * 8); + + list_add_tail(&hstream->list, &bus->stream_list); + } + + return 0; +} + +void hda_dsp_stream_free(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *s, *_s; + struct hdac_ext_stream *stream; + struct sof_intel_hda_stream *hda_stream; + + /* free position buffer */ + if (bus->posbuf.area) + snd_dma_free_pages(&bus->posbuf); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* free position buffer */ + if (bus->rb.area) + snd_dma_free_pages(&bus->rb); +#endif + + list_for_each_entry_safe(s, _s, &bus->stream_list, list) { + /* TODO: decouple */ + + /* free bdl buffer */ + if (s->bdl.area) + snd_dma_free_pages(&s->bdl); + list_del(&s->list); + stream = stream_to_hdac_ext_stream(s); + hda_stream = container_of(stream, struct sof_intel_hda_stream, + hda_stream); + devm_kfree(sdev->dev, hda_stream); + } +} From 832d0c90ad2aa18cfbf6c178341d760bd112d418 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:08:55 -0500 Subject: [PATCH 1417/1995] ASoC: SOF: Intel: Add Intel specific HDA trace operations Add trace operations for Intel based HDA DSPs Signed-off-by: Keyon Jie Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit ba00ed7572cd581bfd483d13193d36a38a3942a8) --- sound/soc/sof/intel/hda-trace.c | 94 +++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 sound/soc/sof/intel/hda-trace.c diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c new file mode 100644 index 00000000000000..33b23bd6a01e1b --- /dev/null +++ b/sound/soc/sof/intel/hda-trace.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for generic Intel audio DSP HDA IP + */ + +#include +#include "../ops.h" +#include "hda.h" + +static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + struct hdac_ext_stream *stream = hda->dtrace_stream; + struct hdac_stream *hstream = &stream->hstream; + struct snd_dma_buffer *dmab = &sdev->dmatb; + int ret; + + hstream->period_bytes = 0;/* initialize period_bytes */ + hstream->bufsize = sdev->dmatb.bytes; + + ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL); + if (ret < 0) + dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret); + + return ret; +} + +int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + int ret; + + hda->dtrace_stream = hda_dsp_stream_get(sdev, + SNDRV_PCM_STREAM_CAPTURE); + + if (!hda->dtrace_stream) { + dev_err(sdev->dev, + "error: no available capture stream for DMA trace\n"); + return -ENODEV; + } + + *stream_tag = hda->dtrace_stream->hstream.stream_tag; + + /* + * initialize capture stream, set BDL address and return corresponding + * stream tag which will be sent to the firmware by IPC message. + */ + ret = hda_dsp_trace_prepare(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: hdac trace init failed: %x\n", ret); + hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_CAPTURE, *stream_tag); + hda->dtrace_stream = NULL; + *stream_tag = 0; + } + + return ret; +} + +int hda_dsp_trace_release(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + struct hdac_stream *hstream; + + if (hda->dtrace_stream) { + hstream = &hda->dtrace_stream->hstream; + hda_dsp_stream_put(sdev, + SNDRV_PCM_STREAM_CAPTURE, + hstream->stream_tag); + hda->dtrace_stream = NULL; + return 0; + } + + dev_dbg(sdev->dev, "DMA trace stream is not opened!\n"); + return -ENODEV; +} + +int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + + return hda_dsp_stream_trigger(sdev, hda->dtrace_stream, cmd); +} From e611aaa0be1d1ae5985bb055e8d88504997e8ce3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Apr 2019 11:08:56 -0500 Subject: [PATCH 1418/1995] ASoC: SOF: Intel: Add support for HDAudio codecs Add probe, init and cleanup routines for HDaudio. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 5507b8103e2653b4f5fc2e4c339d7eacde00da2d) --- sound/soc/sof/intel/hda-codec.c | 171 ++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 sound/soc/sof/intel/hda-codec.c diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c new file mode 100644 index 00000000000000..b8b37f08230940 --- /dev/null +++ b/sound/soc/sof/intel/hda-codec.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Keyon Jie +// + +#include +#include +#include +#include +#include +#include "../ops.h" +#include "hda.h" +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +#include "../../codecs/hdac_hda.h" +#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) +#define IDISP_VID_INTEL 0x80860000 + +/* load the legacy HDA codec driver */ +#ifdef MODULE +static void hda_codec_load_module(struct hda_codec *codec) +{ + char alias[MODULE_NAME_LEN]; + const char *module = alias; + + snd_hdac_codec_modalias(&codec->core, alias, sizeof(alias)); + dev_dbg(&codec->core.dev, "loading codec module: %s\n", module); + request_module(module); +} +#else +static void hda_codec_load_module(struct hda_codec *codec) {} +#endif + +#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ + +/* probe individual codec */ +static int hda_codec_probe(struct snd_sof_dev *sdev, int address) +{ + struct hda_bus *hbus = sof_to_hbus(sdev); + struct hdac_device *hdev; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) + struct hdac_hda_priv *hda_priv; +#endif + u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) | + (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; + u32 resp = -1; + int ret; + + mutex_lock(&hbus->core.cmd_mutex); + snd_hdac_bus_send_cmd(&hbus->core, hda_cmd); + snd_hdac_bus_get_response(&hbus->core, address, &resp); + mutex_unlock(&hbus->core.cmd_mutex); + if (resp == -1) + return -EIO; + dev_dbg(sdev->dev, "HDA codec #%d probed OK: response: %x\n", + address, resp); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) + /* snd_hdac_ext_bus_device_exit will use kfree to free hdev */ + hda_priv = kzalloc(sizeof(*hda_priv), GFP_KERNEL); + if (!hda_priv) + return -ENOMEM; + + hda_priv->codec.bus = hbus; + hdev = &hda_priv->codec.core; + + ret = snd_hdac_ext_bus_device_init(&hbus->core, address, hdev); + if (ret < 0) + return ret; + + /* use legacy bus only for HDA codecs, idisp uses ext bus */ + if ((resp & 0xFFFF0000) != IDISP_VID_INTEL) { + hdev->type = HDA_DEV_LEGACY; + hda_codec_load_module(&hda_priv->codec); + } + + return 0; +#else + /* snd_hdac_ext_bus_device_exit will use kfree to free hdev */ + hdev = kzalloc(sizeof(*hdev), GFP_KERNEL); + if (!hdev) + return -ENOMEM; + + ret = snd_hdac_ext_bus_device_init(&hbus->core, address, hdev); + + return ret; +#endif +} + +/* Codec initialization */ +int hda_codec_probe_bus(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int i, ret; + + /* probe codecs in avail slots */ + for (i = 0; i < HDA_MAX_CODECS; i++) { + + if (!(bus->codec_mask & (1 << i))) + continue; + + ret = hda_codec_probe(sdev, i); + if (ret < 0) { + dev_err(bus->dev, "error: codec #%d probe error, ret: %d\n", + i, ret); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL(hda_codec_probe_bus); + +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) + +void hda_codec_i915_get(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + dev_dbg(bus->dev, "Turning i915 HDAC power on\n"); + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); +} +EXPORT_SYMBOL(hda_codec_i915_get); + +void hda_codec_i915_put(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + dev_dbg(bus->dev, "Turning i915 HDAC power off\n"); + snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); +} +EXPORT_SYMBOL(hda_codec_i915_put); + +int hda_codec_i915_init(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int ret; + + /* i915 exposes a HDA codec for HDMI audio */ + ret = snd_hdac_i915_init(bus); + if (ret < 0) + return ret; + + hda_codec_i915_get(sdev); + + return 0; +} +EXPORT_SYMBOL(hda_codec_i915_init); + +int hda_codec_i915_exit(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int ret; + + hda_codec_i915_put(sdev); + + ret = snd_hdac_i915_exit(bus); + + return ret; +} +EXPORT_SYMBOL(hda_codec_i915_exit); + +#endif /* CONFIG_SND_SOC_HDAC_HDMI */ + +MODULE_LICENSE("Dual BSD/GPL"); From 6b9bea6ba4a90155db8e6375d8a396bd139b4946 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 12 Apr 2019 11:08:57 -0500 Subject: [PATCH 1419/1995] ASoC: SOF: Intel: add SKL+ platform DAIs Add declarations for DAIs and utilities for link DMA management Signed-off-by: Keyon Jie Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit fdd961e37e47f2d450638f3a653cdb96911969ea) --- sound/soc/sof/intel/hda-dai.c | 351 ++++++++++++++++++++++++++++++++++ 1 file changed, 351 insertions(+) create mode 100644 sound/soc/sof/intel/hda-dai.c diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c new file mode 100644 index 00000000000000..830328af19c5ef --- /dev/null +++ b/sound/soc/sof/intel/hda-dai.c @@ -0,0 +1,351 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Keyon Jie +// + +#include +#include +#include "../sof-priv.h" +#include "hda.h" + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + +struct hda_pipe_params { + u8 host_dma_id; + u8 link_dma_id; + u32 ch; + u32 s_freq; + u32 s_fmt; + u8 linktype; + snd_pcm_format_t format; + int link_index; + int stream; + unsigned int host_bps; + unsigned int link_bps; +}; + +/* + * Unlike GP dma, there is a set of stream registers in hda controller + * to control the link dma channels. Each register controls one link + * dma channel and the relation is fixed. To make sure FW uses correct + * link dma channels, host allocates stream registers and sends the + * corresponding link dma channels to FW to allocate link dma channel + * + * FIXME: this API is abused in the sense that tx_num and rx_num are + * passed as arguments, not returned. We need to find a better way to + * retrieve the stream tag allocated for the link DMA + */ +static int hda_link_dma_get_channels(struct snd_soc_dai *dai, + unsigned int *tx_num, + unsigned int *tx_slot, + unsigned int *rx_num, + unsigned int *rx_slot) +{ + struct hdac_bus *bus; + struct hdac_ext_stream *stream; + struct snd_pcm_substream substream; + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(dai->component); + + bus = sof_to_bus(sdev); + + memset(&substream, 0, sizeof(substream)); + if (*tx_num == 1) { + substream.stream = SNDRV_PCM_STREAM_PLAYBACK; + stream = snd_hdac_ext_stream_assign(bus, &substream, + HDAC_EXT_STREAM_TYPE_LINK); + if (!stream) { + dev_err(bus->dev, "error: failed to find a free hda ext stream for playback"); + return -EBUSY; + } + + snd_soc_dai_set_dma_data(dai, &substream, stream); + *tx_slot = hdac_stream(stream)->stream_tag - 1; + + dev_dbg(bus->dev, "link dma channel %d for playback", *tx_slot); + } + + if (*rx_num == 1) { + substream.stream = SNDRV_PCM_STREAM_CAPTURE; + stream = snd_hdac_ext_stream_assign(bus, &substream, + HDAC_EXT_STREAM_TYPE_LINK); + if (!stream) { + dev_err(bus->dev, "error: failed to find a free hda ext stream for capture"); + return -EBUSY; + } + + snd_soc_dai_set_dma_data(dai, &substream, stream); + *rx_slot = hdac_stream(stream)->stream_tag - 1; + + dev_dbg(bus->dev, "link dma channel %d for capture", *rx_slot); + } + + return 0; +} + +static int hda_link_dma_params(struct hdac_ext_stream *stream, + struct hda_pipe_params *params) +{ + struct hdac_stream *hstream = &stream->hstream; + unsigned char stream_tag = hstream->stream_tag; + struct hdac_bus *bus = hstream->bus; + struct hdac_ext_link *link; + unsigned int format_val; + + snd_hdac_ext_stream_decouple(bus, stream, true); + snd_hdac_ext_link_stream_reset(stream); + + format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch, + params->format, + params->link_bps, 0); + + dev_dbg(bus->dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", + format_val, params->s_freq, params->ch, params->format); + + snd_hdac_ext_link_stream_setup(stream, format_val); + + if (stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) { + list_for_each_entry(link, &bus->hlink_list, list) { + if (link->index == params->link_index) + snd_hdac_ext_link_set_stream_id(link, + stream_tag); + } + } + + stream->link_prepared = 1; + + return 0; +} + +static int hda_link_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct hdac_stream *hstream = substream->runtime->private_data; + struct hdac_bus *bus = hstream->bus; + struct hdac_ext_stream *link_dev; + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct hda_pipe_params p_params = {0}; + struct hdac_ext_link *link; + int stream_tag; + + link_dev = snd_soc_dai_get_dma_data(dai, substream); + + link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name); + if (!link) + return -EINVAL; + + stream_tag = hdac_stream(link_dev)->stream_tag; + + /* set the stream tag in the codec dai dma params */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0); + else + snd_soc_dai_set_tdm_slot(codec_dai, 0, stream_tag, 0, 0); + + p_params.s_fmt = snd_pcm_format_width(params_format(params)); + p_params.ch = params_channels(params); + p_params.s_freq = params_rate(params); + p_params.stream = substream->stream; + p_params.link_dma_id = stream_tag - 1; + p_params.link_index = link->index; + p_params.format = params_format(params); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + p_params.link_bps = codec_dai->driver->playback.sig_bits; + else + p_params.link_bps = codec_dai->driver->capture.sig_bits; + + return hda_link_dma_params(link_dev, &p_params); +} + +static int hda_link_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_sof_dev *sdev = + snd_soc_component_get_drvdata(dai->component); + struct snd_sof_pcm *spcm; + int stream = substream->stream; + + spcm = snd_sof_find_spcm_dai(sdev, rtd); + if (!spcm) + return -EINVAL; + + /* setup hw_params again only if resuming from system suspend */ + if (!spcm->hw_params_upon_resume[stream]) + return 0; + + dev_dbg(sdev->dev, "hda: prepare stream %d dir %d\n", + spcm->pcm.pcm_id, substream->stream); + + return hda_link_hw_params(substream, &rtd->dpcm[stream].hw_params, + dai); +} + +static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct hdac_ext_stream *link_dev = + snd_soc_dai_get_dma_data(dai, substream); + int ret; + + dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); + switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + /* set up hw_params */ + ret = hda_link_pcm_prepare(substream, dai); + if (ret < 0) { + dev_err(dai->dev, + "error: setting up hw_params during resume\n"); + return ret; + } + + /* fallthrough */ + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + snd_hdac_ext_link_stream_start(link_dev); + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + snd_hdac_ext_link_stream_clear(link_dev); + break; + default: + return -EINVAL; + } + return 0; +} + +/* + * FIXME: This API is also abused since it's used for two purposes. + * when the substream argument is NULL this function is used for cleanups + * that aren't necessarily required, and called explicitly by handling + * ASoC core structures, which is not recommended. + * This part will be reworked in follow-up patches. + */ +static int hda_link_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + const char *name; + unsigned int stream_tag; + struct hdac_bus *bus; + struct hdac_ext_link *link; + struct hdac_stream *hstream; + struct hdac_ext_stream *stream; + struct snd_soc_pcm_runtime *rtd; + struct hdac_ext_stream *link_dev; + struct snd_pcm_substream pcm_substream; + + memset(&pcm_substream, 0, sizeof(pcm_substream)); + if (substream) { + hstream = substream->runtime->private_data; + bus = hstream->bus; + rtd = snd_pcm_substream_chip(substream); + link_dev = snd_soc_dai_get_dma_data(dai, substream); + snd_hdac_ext_stream_decouple(bus, link_dev, false); + name = rtd->codec_dai->component->name; + link = snd_hdac_ext_bus_get_link(bus, name); + if (!link) + return -EINVAL; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + stream_tag = hdac_stream(link_dev)->stream_tag; + snd_hdac_ext_link_clear_stream_id(link, stream_tag); + } + + link_dev->link_prepared = 0; + } else { + /* release all hda streams when dai link is unloaded */ + pcm_substream.stream = SNDRV_PCM_STREAM_PLAYBACK; + stream = snd_soc_dai_get_dma_data(dai, &pcm_substream); + if (stream) { + snd_soc_dai_set_dma_data(dai, &pcm_substream, NULL); + snd_hdac_ext_stream_release(stream, + HDAC_EXT_STREAM_TYPE_LINK); + } + + pcm_substream.stream = SNDRV_PCM_STREAM_CAPTURE; + stream = snd_soc_dai_get_dma_data(dai, &pcm_substream); + if (stream) { + snd_soc_dai_set_dma_data(dai, &pcm_substream, NULL); + snd_hdac_ext_stream_release(stream, + HDAC_EXT_STREAM_TYPE_LINK); + } + } + + return 0; +} + +static const struct snd_soc_dai_ops hda_link_dai_ops = { + .hw_params = hda_link_hw_params, + .hw_free = hda_link_hw_free, + .trigger = hda_link_pcm_trigger, + .prepare = hda_link_pcm_prepare, + .get_channel_map = hda_link_dma_get_channels, +}; +#endif + +/* + * common dai driver for skl+ platforms. + * some products who use this DAI array only physically have a subset of + * the DAIs, but no harm is done here by adding the whole set. + */ +struct snd_soc_dai_driver skl_dai[] = { +{ + .name = "SSP0 Pin", +}, +{ + .name = "SSP1 Pin", +}, +{ + .name = "SSP2 Pin", +}, +{ + .name = "SSP3 Pin", +}, +{ + .name = "SSP4 Pin", +}, +{ + .name = "SSP5 Pin", +}, +{ + .name = "DMIC01 Pin", +}, +{ + .name = "DMIC16k Pin", +}, +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +{ + .name = "iDisp1 Pin", + .ops = &hda_link_dai_ops, +}, +{ + .name = "iDisp2 Pin", + .ops = &hda_link_dai_ops, +}, +{ + .name = "iDisp3 Pin", + .ops = &hda_link_dai_ops, +}, +{ + .name = "Analog CPU DAI", + .ops = &hda_link_dai_ops, +}, +{ + .name = "Digital CPU DAI", + .ops = &hda_link_dai_ops, +}, +{ + .name = "Alt Analog CPU DAI", + .ops = &hda_link_dai_ops, +}, +#endif +}; From 191b92b1eae45053e94fdbeed75a2d50efd6bd24 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:08:58 -0500 Subject: [PATCH 1420/1995] ASoC: SOF: Intel: Add platform differentiation for APL and CNL Add platform differentiation operations for different Intel HDA DSP platforms. Signed-off-by: Keyon Jie Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 273020522ef62361c5d86eebe45a72418ed8dea4) --- sound/soc/sof/intel/apl.c | 109 +++++++++++++++++ sound/soc/sof/intel/cnl.c | 249 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 358 insertions(+) create mode 100644 sound/soc/sof/intel/apl.c create mode 100644 sound/soc/sof/intel/cnl.c diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c new file mode 100644 index 00000000000000..8c628260694467 --- /dev/null +++ b/sound/soc/sof/intel/apl.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for audio DSP on Apollolake and GeminiLake + */ + +#include "../sof-priv.h" +#include "hda.h" + +static const struct snd_sof_debugfs_map apl_dsp_debugfs[] = { + {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, +}; + +/* apollolake ops */ +const struct snd_sof_dsp_ops sof_apl_ops = { + /* probe and remove */ + .probe = hda_dsp_probe, + .remove = hda_dsp_remove, + + /* Register IO */ + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* doorbell */ + .irq_handler = hda_dsp_ipc_irq_handler, + .irq_thread = hda_dsp_ipc_irq_thread, + + /* ipc */ + .send_msg = hda_dsp_ipc_send_msg, + .fw_ready = hda_dsp_ipc_fw_ready, + + .ipc_msg_data = hda_ipc_msg_data, + .ipc_pcm_params = hda_ipc_pcm_params, + + /* debug */ + .debug_map = apl_dsp_debugfs, + .debug_map_count = ARRAY_SIZE(apl_dsp_debugfs), + .dbg_dump = hda_dsp_dump, + + /* stream callbacks */ + .pcm_open = hda_dsp_pcm_open, + .pcm_close = hda_dsp_pcm_close, + .pcm_hw_params = hda_dsp_pcm_hw_params, + .pcm_trigger = hda_dsp_pcm_trigger, + .pcm_pointer = hda_dsp_pcm_pointer, + + /* firmware loading */ + .load_firmware = snd_sof_load_firmware_raw, + + /* firmware run */ + .run = hda_dsp_cl_boot_firmware, + + /* pre/post fw run */ + .pre_fw_run = hda_dsp_pre_fw_run, + .post_fw_run = hda_dsp_post_fw_run, + + /* dsp core power up/down */ + .core_power_up = hda_dsp_enable_core, + .core_power_down = hda_dsp_core_reset_power_down, + + /* trace callback */ + .trace_init = hda_dsp_trace_init, + .trace_release = hda_dsp_trace_release, + .trace_trigger = hda_dsp_trace_trigger, + + /* DAI drivers */ + .drv = skl_dai, + .num_drv = SOF_SKL_NUM_DAIS, + + /* PM */ + .suspend = hda_dsp_suspend, + .resume = hda_dsp_resume, + .runtime_suspend = hda_dsp_runtime_suspend, + .runtime_resume = hda_dsp_runtime_resume, +}; +EXPORT_SYMBOL(sof_apl_ops); + +const struct sof_intel_dsp_desc apl_chip_info = { + /* Apollolake */ + .cores_num = 2, + .init_core_mask = 1, + .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1), + .ipc_req = HDA_DSP_REG_HIPCI, + .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY, + .ipc_ack = HDA_DSP_REG_HIPCIE, + .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, + .ipc_ctl = HDA_DSP_REG_HIPCCTL, + .rom_init_timeout = 150, +}; +EXPORT_SYMBOL(apl_chip_info); diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c new file mode 100644 index 00000000000000..3e95c1e5e49120 --- /dev/null +++ b/sound/soc/sof/intel/cnl.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Authors: Liam Girdwood +// Ranjani Sridharan +// Rander Wang +// Keyon Jie +// + +/* + * Hardware interface for audio DSP on Cannonlake. + */ + +#include "../ops.h" +#include "hda.h" + +static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = { + {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, + {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, +}; + +static void cnl_ipc_host_done(struct snd_sof_dev *sdev); +static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev); + +static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) +{ + struct snd_sof_dev *sdev = context; + u32 hipci; + u32 hipcctl; + u32 hipcida; + u32 hipctdr; + u32 hipctdd; + u32 msg; + u32 msg_ext; + irqreturn_t ret = IRQ_NONE; + + /* here we handle IPC interrupts only */ + if (!(sdev->irq_status & HDA_DSP_ADSPIS_IPC)) + return ret; + + hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); + hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL); + hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR); + + /* reenable IPC interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); + + /* reply message from DSP */ + if (hipcida & CNL_DSP_REG_HIPCIDA_DONE && + hipcctl & CNL_DSP_REG_HIPCCTL_DONE) { + hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCIDR); + msg_ext = hipci & CNL_DSP_REG_HIPCIDR_MSG_MASK; + msg = hipcida & CNL_DSP_REG_HIPCIDA_MSG_MASK; + + dev_vdbg(sdev->dev, + "ipc: firmware response, msg:0x%x, msg_ext:0x%x\n", + msg, msg_ext); + + /* mask Done interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCCTL, + CNL_DSP_REG_HIPCCTL_DONE, 0); + + /* handle immediate reply from DSP core */ + hda_dsp_ipc_get_reply(sdev); + snd_sof_ipc_reply(sdev, msg); + + if (sdev->code_loading) { + sdev->code_loading = 0; + wake_up(&sdev->waitq); + } + + cnl_ipc_dsp_done(sdev); + + ret = IRQ_HANDLED; + } + + /* new message from DSP */ + if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) { + hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCTDD); + msg = hipctdr & CNL_DSP_REG_HIPCTDR_MSG_MASK; + msg_ext = hipctdd & CNL_DSP_REG_HIPCTDD_MSG_MASK; + + dev_vdbg(sdev->dev, + "ipc: firmware initiated, msg:0x%x, msg_ext:0x%x\n", + msg, msg_ext); + + /* handle messages from DSP */ + if ((hipctdr & SOF_IPC_PANIC_MAGIC_MASK) == + SOF_IPC_PANIC_MAGIC) { + snd_sof_dsp_panic(sdev, HDA_DSP_PANIC_OFFSET(msg_ext)); + } else { + snd_sof_ipc_msgs_rx(sdev); + } + + /* + * clear busy interrupt to tell dsp controller this + * interrupt has been accepted, not trigger it again + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCTDR, + CNL_DSP_REG_HIPCTDR_BUSY, + CNL_DSP_REG_HIPCTDR_BUSY); + + cnl_ipc_host_done(sdev); + + ret = IRQ_HANDLED; + } + + return ret; +} + +static void cnl_ipc_host_done(struct snd_sof_dev *sdev) +{ + /* + * set done bit to ack dsp the msg has been + * processed and send reply msg to dsp + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCTDA, + CNL_DSP_REG_HIPCTDA_DONE, + CNL_DSP_REG_HIPCTDA_DONE); +} + +static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev) +{ + /* + * set DONE bit - tell DSP we have received the reply msg + * from DSP, and processed it, don't send more reply to host + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCIDA, + CNL_DSP_REG_HIPCIDA_DONE, + CNL_DSP_REG_HIPCIDA_DONE); + + /* unmask Done interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCCTL, + CNL_DSP_REG_HIPCCTL_DONE, + CNL_DSP_REG_HIPCCTL_DONE); +} + +static int cnl_ipc_send_msg(struct snd_sof_dev *sdev, + struct snd_sof_ipc_msg *msg) +{ + u32 cmd = msg->header; + + /* send the message */ + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, + cmd | CNL_DSP_REG_HIPCIDR_BUSY); + + return 0; +} + +/* cannonlake ops */ +const struct snd_sof_dsp_ops sof_cnl_ops = { + /* probe and remove */ + .probe = hda_dsp_probe, + .remove = hda_dsp_remove, + + /* Register IO */ + .write = sof_io_write, + .read = sof_io_read, + .write64 = sof_io_write64, + .read64 = sof_io_read64, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* doorbell */ + .irq_handler = hda_dsp_ipc_irq_handler, + .irq_thread = cnl_ipc_irq_thread, + + /* ipc */ + .send_msg = cnl_ipc_send_msg, + .fw_ready = hda_dsp_ipc_fw_ready, + + .ipc_msg_data = hda_ipc_msg_data, + .ipc_pcm_params = hda_ipc_pcm_params, + + /* debug */ + .debug_map = cnl_dsp_debugfs, + .debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs), + .dbg_dump = hda_dsp_dump, + + /* stream callbacks */ + .pcm_open = hda_dsp_pcm_open, + .pcm_close = hda_dsp_pcm_close, + .pcm_hw_params = hda_dsp_pcm_hw_params, + .pcm_trigger = hda_dsp_pcm_trigger, + + /* firmware loading */ + .load_firmware = snd_sof_load_firmware_raw, + + /* pre/post fw run */ + .pre_fw_run = hda_dsp_pre_fw_run, + .post_fw_run = hda_dsp_post_fw_run, + + /* dsp core power up/down */ + .core_power_up = hda_dsp_enable_core, + .core_power_down = hda_dsp_core_reset_power_down, + + /* firmware run */ + .run = hda_dsp_cl_boot_firmware, + + /* trace callback */ + .trace_init = hda_dsp_trace_init, + .trace_release = hda_dsp_trace_release, + .trace_trigger = hda_dsp_trace_trigger, + + /* DAI drivers */ + .drv = skl_dai, + .num_drv = SOF_SKL_NUM_DAIS, + + /* PM */ + .suspend = hda_dsp_suspend, + .resume = hda_dsp_resume, + .runtime_suspend = hda_dsp_runtime_suspend, + .runtime_resume = hda_dsp_runtime_resume, +}; +EXPORT_SYMBOL(sof_cnl_ops); + +const struct sof_intel_dsp_desc cnl_chip_info = { + /* Cannonlake */ + .cores_num = 4, + .init_core_mask = 1, + .cores_mask = HDA_DSP_CORE_MASK(0) | + HDA_DSP_CORE_MASK(1) | + HDA_DSP_CORE_MASK(2) | + HDA_DSP_CORE_MASK(3), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .rom_init_timeout = 300, +}; +EXPORT_SYMBOL(cnl_chip_info); From 4c6aeb3b15a0af543a35f4b217e069146a2ca636 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Apr 2019 11:09:01 -0500 Subject: [PATCH 1421/1995] ASoC: Intel: Kconfig: expose common option between SST and SOF drivers Both drivers rely on the same module, expose it for both configurations Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit e6b140e918e93ec76265007b86092a6a3068ca1d) --- sound/soc/intel/Kconfig | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index bd9fd2035c554b..fc1396adde7140 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -196,13 +196,18 @@ config SND_SOC_INTEL_SKYLAKE_COMMON endif ## SND_SOC_INTEL_SKYLAKE_FAMILY +endif ## SND_SOC_INTEL_SST_TOPLEVEL + +if SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL + config SND_SOC_ACPI_INTEL_MATCH tristate select SND_SOC_ACPI if ACPI # this option controls the compilation of ACPI matching tables and # helpers and is not meant to be selected by the user. -endif ## SND_SOC_INTEL_SST_TOPLEVEL +endif ## SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL + # ASoC codec drivers source "sound/soc/intel/boards/Kconfig" From 91fbb8b680ab3b116734926f158c2c92ab964b23 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:09:02 -0500 Subject: [PATCH 1422/1995] ASoC: SOF: Add Build support for SOF core and Intel drivers Build SOF core and Intel-specific drivers. Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 7e978fa37df7f771a5d02934ff828a0ee36bcf11) --- sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/sof/Kconfig | 141 +++++++++++++++++++++ sound/soc/sof/Makefile | 18 +++ sound/soc/sof/intel/Kconfig | 230 +++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/Makefile | 19 +++ 6 files changed, 410 insertions(+) create mode 100644 sound/soc/sof/Kconfig create mode 100644 sound/soc/sof/Makefile create mode 100644 sound/soc/sof/intel/Kconfig create mode 100644 sound/soc/sof/intel/Makefile diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 6592a422a04725..9e832c58fee551 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -63,6 +63,7 @@ source "sound/soc/rockchip/Kconfig" source "sound/soc/samsung/Kconfig" source "sound/soc/sh/Kconfig" source "sound/soc/sirf/Kconfig" +source "sound/soc/sof/Kconfig" source "sound/soc/spear/Kconfig" source "sound/soc/sti/Kconfig" source "sound/soc/stm/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 48c48c1c893ce3..3f08deb0c716ac 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_SND_SOC) += rockchip/ obj-$(CONFIG_SND_SOC) += samsung/ obj-$(CONFIG_SND_SOC) += sh/ obj-$(CONFIG_SND_SOC) += sirf/ +obj-$(CONFIG_SND_SOC) += sof/ obj-$(CONFIG_SND_SOC) += spear/ obj-$(CONFIG_SND_SOC) += sti/ obj-$(CONFIG_SND_SOC) += stm/ diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig new file mode 100644 index 00000000000000..eaa380092c3bab --- /dev/null +++ b/sound/soc/sof/Kconfig @@ -0,0 +1,141 @@ +config SND_SOC_SOF_TOPLEVEL + bool "Sound Open Firmware Support" + help + This adds support for Sound Open Firmware (SOF). SOF is a free and + generic open source audio DSP firmware for multiple devices. + Say Y if you have such a device that is supported by SOF. + If unsure select "N". + +if SND_SOC_SOF_TOPLEVEL + +config SND_SOC_SOF_PCI + tristate "SOF PCI enumeration support" + depends on PCI + select SND_SOC_SOF + select SND_SOC_ACPI if ACPI + select SND_SOC_SOF_OPTIONS + select SND_SOC_SOF_INTEL_PCI if SND_SOC_SOF_INTEL_TOPLEVEL + help + This adds support for PCI enumeration. This option is + required to enable Intel Skylake+ devices + Say Y if you need this option + If unsure select "N". + +config SND_SOC_SOF_ACPI + tristate "SOF ACPI enumeration support" + depends on ACPI || COMPILE_TEST + select SND_SOC_SOF + select SND_SOC_ACPI if ACPI + select SND_SOC_SOF_OPTIONS + select SND_SOC_SOF_INTEL_ACPI if SND_SOC_SOF_INTEL_TOPLEVEL + select IOSF_MBI if X86 + help + This adds support for ACPI enumeration. This option is required + to enable Intel Haswell/Broadwell/Baytrail/Cherrytrail devices + Say Y if you need this option + If unsure select "N". + +config SND_SOC_SOF_OPTIONS + tristate + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +if SND_SOC_SOF_OPTIONS + +config SND_SOC_SOF_NOCODEC + tristate "SOF nocodec mode Support" + help + This adds support for a dummy/nocodec machine driver fallback + option if no known codec is detected. This is typically only + enabled for developers or devices where the sound card is + controlled externally + Say Y if you need this nocodec fallback option + If unsure select "N". + +config SND_SOC_SOF_DEBUG + bool "SOF debugging features" + help + This option can be used to enable or disable individual SOF firmware + and driver debugging options. + Say Y if you are debugging SOF FW or drivers. + If unsure select "N". + +if SND_SOC_SOF_DEBUG + +config SND_SOC_SOF_FORCE_NOCODEC_MODE + bool "SOF force nocodec Mode" + depends on SND_SOC_SOF_NOCODEC + help + This forces SOF to use dummy/nocodec as machine driver, even + though there is a codec detected on the real platform. This is + typically only enabled for developers for debug purposes, before + codec/machine driver is ready, or to exclude the impact of those + drivers + Say Y if you need this force nocodec mode option + If unsure select "N". + +config SND_SOC_SOF_DEBUG_XRUN_STOP + bool "SOF stop on XRUN" + help + This option forces PCMs to stop on any XRUN event. This is useful to + preserve any trace data ond pipeline status prior to the XRUN. + Say Y if you are debugging SOF FW pipeline XRUNs. + If unsure select "N". + +config SND_SOC_SOF_DEBUG_VERBOSE_IPC + bool "SOF verbose IPC logs" + help + This option enables more verbose IPC logs, with command types in + human-readable form instead of just 32-bit hex dumps. This is useful + if you are trying to debug IPC with the DSP firmware. + If unsure select "N". + +config SND_SOC_SOF_DEBUG_FORCE_IPC_POSITION + bool "SOF force to use IPC for position update on SKL+" + help + This option force to handle stream position update IPCs and run pcm + elapse to inform ALSA about that, on platforms (e.g. Intel SKL+) that + with other approach (e.g. HDAC DPIB/posbuf) to elapse PCM. + On platforms (e.g. Intel SKL-) where position update IPC is the only + one choice, this setting won't impact anything. + if you are trying to debug pointer update with position IPCs or where + DPIB/posbuf is not ready, select "Y". + If unsure select "N". + +config SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE + bool "SOF enable debugfs caching" + help + This option enables caching of debugfs + memory -> DSP resource (memory, register, etc) + before the audio DSP is suspended. This will increase the suspend + latency and therefore should be used for debug purposes only. + Say Y if you want to enable caching the memory windows. + If unsure, select "N". + +endif ## SND_SOC_SOF_DEBUG + +endif ## SND_SOC_SOF_OPTIONS + +config SND_SOC_SOF + tristate + select SND_SOC_TOPOLOGY + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + The selection is made at the top level and does not exactly follow + module dependencies but since the module or built-in type is decided + at the top level it doesn't matter. + +config SND_SOC_SOF_PROBE_WORK_QUEUE + bool + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + When selected, the probe is handled in two steps, for example to + avoid lockdeps if request_module is used in the probe. + +source "sound/soc/sof/intel/Kconfig" +source "sound/soc/sof/xtensa/Kconfig" + +endif diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile new file mode 100644 index 00000000000000..8f14c9d2950be2 --- /dev/null +++ b/sound/soc/sof/Makefile @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) + +snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ + control.o trace.o utils.o + +snd-sof-pci-objs := sof-pci-dev.o +snd-sof-acpi-objs := sof-acpi-dev.o +snd-sof-nocodec-objs := nocodec.o + +obj-$(CONFIG_SND_SOC_SOF) += snd-sof.o +obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o + + +obj-$(CONFIG_SND_SOC_SOF_ACPI) += sof-acpi-dev.o +obj-$(CONFIG_SND_SOC_SOF_PCI) += sof-pci-dev.o + +obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/ +obj-$(CONFIG_SND_SOC_SOF_XTENSA) += xtensa/ diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig new file mode 100644 index 00000000000000..32ee0fabab9253 --- /dev/null +++ b/sound/soc/sof/intel/Kconfig @@ -0,0 +1,230 @@ +config SND_SOC_SOF_INTEL_TOPLEVEL + bool "SOF support for Intel audio DSPs" + depends on X86 || COMPILE_TEST + help + This adds support for Sound Open Firmware for Intel(R) platforms. + Say Y if you have such a device. + If unsure select "N". + +if SND_SOC_SOF_INTEL_TOPLEVEL + +config SND_SOC_SOF_INTEL_ACPI + tristate + select SND_SOC_SOF_BAYTRAIL if SND_SOC_SOF_BAYTRAIL_SUPPORT + select SND_SOC_SOF_BROADWELL if SND_SOC_SOF_BROADWELL_SUPPORT + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_INTEL_PCI + tristate + select SND_SOC_SOF_MERRIFIELD if SND_SOC_SOF_MERRIFIELD_SUPPORT + select SND_SOC_SOF_APOLLOLAKE if SND_SOC_SOF_APOLLOLAKE_SUPPORT + select SND_SOC_SOF_GEMINILAKE if SND_SOC_SOF_GEMINILAKE_SUPPORT + select SND_SOC_SOF_CANNONLAKE if SND_SOC_SOF_CANNONLAKE_SUPPORT + select SND_SOC_SOF_COFFEELAKE if SND_SOC_SOF_COFFEELAKE_SUPPORT + select SND_SOC_SOF_ICELAKE if SND_SOC_SOF_ICELAKE_SUPPORT + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_INTEL_HIFI_EP_IPC + tristate + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_INTEL_ATOM_HIFI_EP + tristate + select SND_SOC_INTEL_COMMON + select SND_SOC_SOF_INTEL_HIFI_EP_IPC + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_INTEL_COMMON + tristate + select SND_SOC_ACPI_INTEL_MATCH + select SND_SOC_SOF_XTENSA + select SND_SOC_INTEL_MACH + select SND_SOC_ACPI if ACPI + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +if SND_SOC_SOF_INTEL_ACPI + +config SND_SOC_SOF_BAYTRAIL_SUPPORT + bool "SOF support for Baytrail, Braswell and Cherrytrail" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Baytrail, Braswell or Cherrytrail processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_BAYTRAIL + tristate + select SND_SOC_SOF_INTEL_ATOM_HIFI_EP + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_BROADWELL_SUPPORT + bool "SOF support for Broadwell" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Broadwell processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_BROADWELL + tristate + select SND_SOC_SOF_INTEL_COMMON + select SND_SOC_SOF_INTEL_HIFI_EP_IPC + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +endif ## SND_SOC_SOF_INTEL_ACPI + +if SND_SOC_SOF_INTEL_PCI + +config SND_SOC_SOF_MERRIFIELD_SUPPORT + bool "SOF support for Tangier/Merrifield" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Tangier/Merrifield processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_MERRIFIELD + tristate + select SND_SOC_SOF_INTEL_ATOM_HIFI_EP + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_APOLLOLAKE_SUPPORT + bool "SOF support for Apollolake" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Apollolake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_APOLLOLAKE + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_GEMINILAKE_SUPPORT + bool "SOF support for GeminiLake" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Geminilake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_GEMINILAKE + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_CANNONLAKE_SUPPORT + bool "SOF support for Cannonlake" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Cannonlake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_CANNONLAKE + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_COFFEELAKE_SUPPORT + bool "SOF support for CoffeeLake" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Coffeelake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_COFFEELAKE + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_ICELAKE_SUPPORT + bool "SOF support for Icelake" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Icelake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_ICELAKE + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_HDA_COMMON + tristate + select SND_SOC_SOF_INTEL_COMMON + select SND_SOC_SOF_HDA_LINK_BASELINE + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +if SND_SOC_SOF_HDA_COMMON + +config SND_SOC_SOF_HDA_LINK + bool "SOF support for HDA Links(HDA/HDMI)" + depends on SND_SOC_SOF_NOCODEC=n + select SND_SOC_SOF_PROBE_WORK_QUEUE + help + This adds support for HDA links(HDA/HDMI) with Sound Open Firmware + for Intel(R) platforms. + Say Y if you want to enable HDA links with SOF. + If unsure select "N". + +config SND_SOC_SOF_HDA_AUDIO_CODEC + bool "SOF support for HDAudio codecs" + depends on SND_SOC_SOF_HDA_LINK + help + This adds support for HDAudio codecs with Sound Open Firmware + for Intel(R) platforms. + Say Y if you want to enable HDAudio codecs with SOF. + If unsure select "N". + +endif ## SND_SOC_SOF_HDA_COMMON + +config SND_SOC_SOF_HDA_LINK_BASELINE + tristate + select SND_SOC_SOF_HDA if SND_SOC_SOF_HDA_LINK + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_HDA + tristate + select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK + select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +endif ## SND_SOC_SOF_INTEL_PCI + +endif ## SND_SOC_SOF_INTEL_TOPLEVEL diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile new file mode 100644 index 00000000000000..b8f58e006e29e5 --- /dev/null +++ b/sound/soc/sof/intel/Makefile @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) + +snd-sof-intel-byt-objs := byt.o +snd-sof-intel-bdw-objs := bdw.o + +snd-sof-intel-ipc-objs := intel-ipc.o + +snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ + hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \ + hda-dai.o hda-bus.o \ + apl.o cnl.o + +snd-sof-intel-hda-objs := hda-codec.o + +obj-$(CONFIG_SND_SOC_SOF_INTEL_ATOM_HIFI_EP) += snd-sof-intel-byt.o +obj-$(CONFIG_SND_SOC_SOF_BROADWELL) += snd-sof-intel-bdw.o +obj-$(CONFIG_SND_SOC_SOF_INTEL_HIFI_EP_IPC) += snd-sof-intel-ipc.o +obj-$(CONFIG_SND_SOC_SOF_HDA_COMMON) += snd-sof-intel-hda-common.o +obj-$(CONFIG_SND_SOC_SOF_HDA) += snd-sof-intel-hda.o From 279e8b6b38f33aea9bd4c9f2bdfef6cdddd761c1 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 12 Apr 2019 11:09:03 -0500 Subject: [PATCH 1423/1995] ASoC: Intel: Make sure BDW based machine drivers build for SOF BDW uses hard coded IPC calls to set SSP, not needed in SOF as SSP is configured via topology. Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit f35bf70f61d389754fafd7fce75efbb3bd2eea87) --- sound/soc/intel/boards/bdw-rt5677.c | 4 ++++ sound/soc/intel/boards/broadwell.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 1844c88ea4e2a0..6520a8ea553758 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -180,6 +180,7 @@ static const struct snd_soc_ops bdw_rt5677_ops = { .hw_params = bdw_rt5677_hw_params, }; +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); @@ -198,6 +199,7 @@ static int bdw_rt5677_rtd_init(struct snd_soc_pcm_runtime *rtd) return 0; } +#endif static int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) { @@ -265,7 +267,9 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { .dynamic = 1, .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) .init = bdw_rt5677_rtd_init, +#endif .trigger = { SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index b86c746d9b7a86..0f18f8964f51fb 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -131,6 +131,7 @@ static const struct snd_soc_ops broadwell_rt286_ops = { .hw_params = broadwell_rt286_hw_params, }; +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); @@ -149,6 +150,7 @@ static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) return 0; } +#endif /* broadwell digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link broadwell_rt286_dais[] = { @@ -161,7 +163,9 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { .dynamic = 1, .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) .init = broadwell_rtd_init, +#endif .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dpcm_playback = 1, .dpcm_capture = 1, From c3af9ed0063a29c2739dbc1b242284bbec62c69c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 12 Apr 2019 11:09:04 -0500 Subject: [PATCH 1424/1995] ASoC: Intel: select relevant machine drivers for SOF SOF can only support specific machine drivers, handle dependencies Signed-off-by: Pierre-Louis Bossart Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 10b02b53a99865f2005497c3933342c1f7946cd6) --- sound/soc/intel/boards/Kconfig | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 12d6b73e9531d7..bf6d7a11f94a03 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -1,6 +1,6 @@ menuconfig SND_SOC_INTEL_MACH bool "Intel Machine drivers" - depends on SND_SOC_INTEL_SST_TOPLEVEL + depends on SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL help Intel ASoC Machine Drivers. If you have a Intel machine that has an audio controller with a DSP and I2S or DMIC port, then @@ -24,6 +24,10 @@ config SND_SOC_INTEL_HASWELL_MACH Say Y or m if you have such a device. If unsure select "N". +endif ## SND_SOC_INTEL_HASWELL + +if SND_SOC_INTEL_HASWELL || SND_SOC_SOF_BROADWELL + config SND_SOC_INTEL_BDW_RT5677_MACH tristate "Broadwell with RT5677 codec" depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM && GPIOLIB @@ -43,7 +47,7 @@ config SND_SOC_INTEL_BROADWELL_MACH Ultrabook platforms. Say Y or m if you have such a device. This is a recommended option. If unsure select "N". -endif ## SND_SOC_INTEL_HASWELL +endif ## SND_SOC_INTEL_HASWELL || SND_SOC_SOF_BROADWELL if SND_SOC_INTEL_BAYTRAIL @@ -68,7 +72,7 @@ config SND_SOC_INTEL_BYT_RT5640_MACH endif ## SND_SOC_INTEL_BAYTRAIL -if SND_SST_ATOM_HIFI2_PLATFORM +if SND_SST_ATOM_HIFI2_PLATFORM || SND_SOC_SOF_BAYTRAIL config SND_SOC_INTEL_BYTCR_RT5640_MACH tristate "Baytrail and Baytrail-CR with RT5640 codec" @@ -158,6 +162,10 @@ config SND_SOC_INTEL_BYT_CHT_ES8316_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +endif ## SND_SST_ATOM_HIFI2_PLATFORM || SND_SOC_SOF_BAYTRAIL + +if SND_SST_ATOM_HIFI2_PLATFORM + config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH tristate "Baytrail & Cherrytrail platform with no codec (MinnowBoard MAX, Up)" depends on X86_INTEL_LPSS && I2C && ACPI @@ -314,7 +322,7 @@ config SND_SOC_INTEL_KBL_RT5660_MACH endif ## SND_SOC_INTEL_KBL -if SND_SOC_INTEL_GLK +if SND_SOC_INTEL_GLK || (SND_SOC_SOF_GEMINILAKE && SND_SOC_SOF_HDA_LINK) config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH tristate "GLK with RT5682 and MAX98357A in I2S Mode" @@ -330,9 +338,9 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH Say Y if you have such a device. If unsure select "N". -endif ## SND_SOC_INTEL_GLK +endif ## SND_SOC_INTEL_GLK || (SND_SOC_SOF_GEMINILAKE && SND_SOC_SOF_HDA_LINK) -if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC +if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH tristate "SKL/KBL/BXT/APL with HDA Codecs" @@ -344,6 +352,6 @@ config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". -endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC +endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC endif ## SND_SOC_INTEL_MACH From 08ba3b3814eea65a6029e8c9caa458eeb6484294 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Sun, 28 Apr 2019 04:53:39 +0800 Subject: [PATCH 1425/1995] ALSA: hda: fix unregister device twice on ASoC driver snd_hda_codec_device_new() is used by both legacy HDA and ASoC driver. However, we will call snd_hdac_device_unregister() in snd_hdac_ext_bus_device_remove() for ASoC device. This patch uses the type flag in hdac_device struct to determine is it a ASoC device or legacy HDA device and call snd_hdac_device_unregister() in snd_hda_codec_dev_free() only if it is a legacy HDA device. Signed-off-by: Bard liao Signed-off-by: Takashi Iwai (cherry picked from commit 4d95c51776b2edb4d4ebcea00b6e5a1fe538ce66) --- sound/pci/hda/hda_codec.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9f8d59e7e89f46..ae1b7475dc81fb 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -841,7 +841,13 @@ static int snd_hda_codec_dev_free(struct snd_device *device) struct hda_codec *codec = device->device_data; codec->in_freeing = 1; - snd_hdac_device_unregister(&codec->core); + /* + * snd_hda_codec_device_new() is used by legacy HDA and ASoC driver. + * We can't unregister ASoC device since it will be unregistered in + * snd_hdac_ext_bus_device_remove(). + */ + if (codec->core.type == HDA_DEV_LEGACY) + snd_hdac_device_unregister(&codec->core); codec_display_power(codec, false); put_device(hda_codec_dev(codec)); return 0; From e8599a165cf5e8cd091f81a6d43a056eddb34834 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Sun, 28 Apr 2019 04:53:40 +0800 Subject: [PATCH 1426/1995] ASoC: hdac_hda: overwrite hdev type to HDA_DEV_ASOC In ASoC driver, snd_hdac_device_register() will be called by snd_hdac_ext_bus_device_init() and snd_hdac_device_unregister() will called by snd_hdac_ext_bus_device_remove(). However when ASoC codec driver call snd_hda_codec_device_new() to create a new hda codec, it will assign snd_hda_codec_dev_free() to the dev_free ops and snd_hda_codec_dev_free() will call snd_hdac_device_unregister(). As a result, snd_hdac_device_unregister() will be called twice in ASoC driver. To prevent it, we use hdev type to determine if the hda codec is registered by legacy HDA driver or ASoC driver and unregister device in snd_hda_codec_dev_free() only if it is a legacy HDA device. This patch will overwrite the hdev type so that we can know it is a ASoC device. Signed-off-by: Bard liao Signed-off-by: Takashi Iwai (cherry picked from commit b60ee2e281b6c67cbe0bb8412f3cae53903173c6) --- sound/soc/codecs/hdac_hda.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index f889d94c8e3cf7..7d494025691498 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -328,6 +328,12 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) dev_err(&hdev->dev, "failed to create hda codec %d\n", ret); goto error_no_pm; } + /* + * Overwrite type to HDA_DEV_ASOC since it is a ASoC driver + * hda_codec.c will check this flag to determine if unregister + * device is needed. + */ + hdev->type = HDA_DEV_ASOC; /* * snd_hda_codec_device_new decrements the usage count so call get pm From 3050c9cc7879b08b48b32d910616d5299c9c004f Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 17 Apr 2019 16:10:32 +0800 Subject: [PATCH 1427/1995] ALSA: hda/realtek - add two more pin configuration sets to quirk table We have two Dell laptops which have the codec 10ec0236 and 10ec0256 respectively, the headset mic on them can't work, need to apply the quirk of ALC255_FIXUP_DELL1_MIC_NO_PRESENCE. So adding their pin configurations in the pin quirk table. Cc: Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai (cherry picked from commit b26e36b7ef36a8a3a147b1609b2505f8a4ecf511) --- sound/pci/hda/patch_realtek.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1ffa36e987b40d..2c88c02afd1c8b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7139,6 +7139,8 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x12, 0x90a60140}, {0x14, 0x90170150}, {0x21, 0x02211020}), + SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x21, 0x02211020}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, {0x14, 0x90170110}, {0x21, 0x02211020}), @@ -7249,6 +7251,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x21, 0x0221101f}), SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, ALC256_STANDARD_PINS), + SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x14, 0x90170110}, + {0x1b, 0x01011020}, + {0x21, 0x0221101f}), SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC, {0x14, 0x90170110}, {0x1b, 0x90a70130}, From a53bb24554955b3942ff393746080193b42c2ed9 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Wed, 24 Apr 2019 16:34:25 +0800 Subject: [PATCH 1428/1995] ALSA: hda/realtek - Add new Dell platform for headset mode Add two Dell platform for headset mode. [ Note: this is a further correction / addition of the previous pin-based quirks for Dell machines; another entry for ALC236 with the d-mic pin 0x12 and an entry for ALC295 -- tiwai ] Fixes: b26e36b7ef36 ("ALSA: hda/realtek - add two more pin configuration sets to quirk table") Signed-off-by: Kailang Yang Cc: Signed-off-by: Takashi Iwai (cherry picked from commit 0a29c57b76624723b6b00c027e0e992d130ace49) (cherry picked from commit 6896b25ef27677748a92679669e038560bd26e5b) --- sound/pci/hda/patch_realtek.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 2c88c02afd1c8b..a83e9df2c24ba4 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7141,6 +7141,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x21, 0x02211020}), SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x21, 0x02211020}), + SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x40000000}, + {0x14, 0x90170110}, + {0x21, 0x02211020}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, {0x14, 0x90170110}, {0x21, 0x02211020}), @@ -7398,6 +7402,9 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x12, 0x90a60130}, {0x17, 0x90170110}, {0x21, 0x04211020}), + SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x14, 0x90170110}, + {0x21, 0x04211020}), SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, ALC295_STANDARD_PINS, {0x17, 0x21014020}, From f0bfc9af4c25611bb122e6c00091eabec67da720 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 30 Apr 2019 16:55:30 -0500 Subject: [PATCH 1429/1995] ASoC: Intel: sof-rt5682: fix style issues Children, run checkpatch.pl ! Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/sof_rt5682.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 823033c87db9e1..f28fb98cc30632 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -33,7 +33,6 @@ #define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6)) #define SOF_RT5682_SSP_AMP_SHIFT 6 - /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | SOF_RT5682_SSP_CODEC(0); @@ -431,14 +430,15 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, if (!links[id].cpu_dai_name) goto devm_err; - idisp_components[i-1].name = "ehdaudio0D2"; - idisp_components[i-1].dai_name = devm_kasprintf(dev, GFP_KERNEL, - "intel-hdmi-" - "hifi%d", i); - if (!idisp_components[i-1].dai_name) + idisp_components[i - 1].name = "ehdaudio0D2"; + idisp_components[i - 1].dai_name = devm_kasprintf(dev, + GFP_KERNEL, + "intel-hdmi-hifi%d", + i); + if (!idisp_components[i - 1].dai_name) goto devm_err; - links[id].codecs = &idisp_components[i-1]; + links[id].codecs = &idisp_components[i - 1]; links[id].num_codecs = 1; links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); From 1071743ab1cf1f3e3653088d36967589c916bc5e Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Thu, 2 May 2019 17:45:16 +0300 Subject: [PATCH 1430/1995] ASoC: SOF: fix race in FW boot timeout handling A race condition exists in handling firmware boot timeout. If FW sends FW_READY just after boot timeout has expired in driver, a kernel exception will result as FW_READY handler will be run while the state is still being cleaned up in snd_sof_run_firmware(). Avoid the race by setting boot_complete also in the error case. Signed-off-by: Kai Vehmanen --- sound/soc/sof/loader.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 81c7452aae1718..628fae5524424a 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -372,6 +372,8 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) msecs_to_jiffies(sdev->boot_timeout)); if (ret == 0) { dev_err(sdev->dev, "error: firmware boot failure\n"); + /* after this point FW_READY msg should be ignored */ + sdev->boot_complete = true; snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX | SOF_DBG_TEXT | SOF_DBG_PCI); return -EIO; From f65843f947d9a964ba02b836178a3a7273f4d7e3 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Sun, 5 May 2019 23:31:13 -0700 Subject: [PATCH 1431/1995] ASoC: SOF: fix error in verbose ipc command parsing Remove the erroneous addition of "SET_VALUE" to the GLB IPC command string. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index ba1bb17a8d1e5f..0e8d1a79ceab39 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -115,7 +115,7 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) } break; case SOF_IPC_GLB_COMP_MSG: - str = "GLB_COMP_MSG: SET_VALUE"; + str = "GLB_COMP_MSG"; switch (type) { case SOF_IPC_COMP_SET_VALUE: str2 = "SET_VALUE"; break; From 1af872baa860c373eba88ad3b518f10eeebf9551 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Sun, 5 May 2019 23:41:43 -0700 Subject: [PATCH 1432/1995] ASoC: SOF: pcm: remove runtime PM calls during pcm open/close pm_runtime_get_sync()/pm_runtime_put_autosuspend() calls are already invoked by the ASoC core in soc_pcm_open() and soc_pcm_close(). So the SOF component driver does not need to call them again. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/pcm.c | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 649968841dad9f..4f536c0de0a55f 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -416,7 +416,6 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) struct snd_sof_pcm *spcm; struct snd_soc_tplg_stream_caps *caps; int ret; - int err; /* nothing to do for BE */ if (rtd->dai_link->no_pcm) @@ -434,14 +433,6 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) caps = &spcm->pcm.caps[substream->stream]; - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err(sdev->dev, "error: pcm open failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - /* set any runtime constraints based on topology */ snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, @@ -485,17 +476,8 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) spcm->stream[substream->stream].substream = substream; ret = snd_sof_pcm_platform_open(sdev, substream); - if (ret < 0) { - dev_err(sdev->dev, "error: pcm open failed %d\n", - ret); - - pm_runtime_mark_last_busy(sdev->dev); - - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err(sdev->dev, "error: pcm close failed to idle %d\n", - err); - } + if (ret < 0) + dev_err(sdev->dev, "error: pcm open failed %d\n", ret); return ret; } @@ -530,13 +512,6 @@ static int sof_pcm_close(struct snd_pcm_substream *substream) */ } - pm_runtime_mark_last_busy(sdev->dev); - - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err(sdev->dev, "error: pcm close failed to idle %d\n", - err); - return 0; } From 820e8413685c48a92e1d834c3e86a66a967935c8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 3 May 2019 11:10:36 -0500 Subject: [PATCH 1433/1995] [NOT FOR UPSTREAM] CODEOWNERS: Initial version I am not happy with the level of SOF reviews, so from now on we will designate mandatory reviews for parts of the code so as to distribute the work and increase accountability. Signed-off-by: Pierre-Louis Bossart --- CODEOWNERS | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 CODEOWNERS diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 00000000000000..81d9cd03e423fa --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,73 @@ +# Lines starting with '#' are comments. +# Each line is a file pattern followed by one or more owners. + +# These owners will be the default owners for everything in the repo. +* @lgirdwood @plbossart + +# Order is important. The last matching pattern has the most precedence. +# So if a pull request only touches javascript files, only these owners +# will be requested to review. + +# include files +include/sound/sof/control.h @ranj063 @singalsu @dbaluta +include/sound/sof/dai.h @ranj063 @singalsu @juimonen @dbaluta +include/sound/sof/dai-intel.h @ranj063 @singalsu @juimonen +include/sound/sof/header.h @lyakh @ranj063 @keyonjie @juimonen +include/sound/sof/info.h @lyakh @ranj063 @keyonjie @juimonen +include/sound/sof/pm.h @lyakh @ranj063 @keyonjie @juimonen +include/sound/sof/stream.h @lyakh @ranj063 @keyonjie @juimonen +include/sound/sof/topology.h @ranj063 @singalsu @bardliao @juimonen +include/sound/sof/trace.h @juimonen @lyakh @kv2019i +include/sound/sof/xtensa.h @lyakh @xiulipan + +include/uapi/sound/sof/abi.h @lyakh @juimonen @dbaluta +include/uapi/sound/sof/eq.h @singalsu @ranj063 @juimonen +include/uapi/sound/sof/fw.h @lyakh @ranj063 @keyonjie @juimonen +include/uapi/sound/sof/header.h @lyakh @ranj063 @keyonjie @juimonen +include/uapi/sound/sof/manifest.h @lyakh @ranj063 @keyonjie @juimonen +include/uapi/sound/sof/tokens.h @lyakh @ranj063 @keyonjie @juimonen +include/uapi/sound/sof/tone.h @singalsu @ranj063 @juimonen +include/uapi/sound/sof/trace.h @juimonen @lyakh @kv2019i + + +# core parts +sound/soc/sof/compressed @plbossart @dbaluta +sound/soc/sof/control.c @ranj063 @singalsu +sound/soc/sof/core.c @plbossart @dbaluta +sound/soc/sof/debug.c @ranj063 @xiulipan +sound/soc/sof/ipc.c @lyakh @dbaluta +sound/soc/sof/Kconfig @lyakh @dbaluta +sound/soc/sof/loader.c @lyakh @ranj063 @keyonjie @juimonen +sound/soc/sof/Makefile @lyakh @dbaluta +sound/soc/sof/nocodec.c @bardliao @libinyang +sound/soc/sof/ops.* @lyakh @ranj063 @keyonjie +sound/soc/sof/pcm.c @lyakh @ranj063 @keyonjie @juimonen +sound/soc/sof/pm.c @lyakh @ranj063 @keyonjie @juimonen +sound/soc/sof/sof-acpi-dev.c @juimonen @RanderWang +sound/soc/sof/sof-pci-dev.c @lyakh @bardliao @libinyang +sound/soc/sof/sof-priv.h @lyakh @ranj063 @keyonjie @juimonen +sound/soc/sof/topology.c @ranj063 @singalsu @bardliao @juimonen +sound/soc/sof/trace.c @juimonen @lyakh @kv2019i +sound/soc/sof/utils.c @juimonen @lyakh @kv2019i + +# intel parts +sound/soc/sof/apl.c @keyonjie @libinyang @bardliao @lyakh +sound/soc/sof/bdw.c @RanderWang @keyonjie +sound/soc/sof/byt.c @juimonen @keyonjie +sound/soc/sof/cnl.c @keyonjie @libinyang @bardliao @RanderWang +sound/soc/sof/hda-bus.c @keyonjie @libinyang @bardliao +sound/soc/sof/hda.c @keyonjie @libinyang @bardliao +sound/soc/sof/hda-codec.c @keyonjie @libinyang @bardliao +sound/soc/sof/hda-ctrl.c @keyonjie @libinyang @bardliao +sound/soc/sof/hda-dai.c @keyonjie @libinyang @bardliao @RanderWang +sound/soc/sof/hda-dsp.c @keyonjie @libinyang @bardliao +sound/soc/sof/hda.h @keyonjie @libinyang @bardliao @lyakh +sound/soc/sof/hda-ipc.c @keyonjie @libinyang @bardliao @lyakh +sound/soc/sof/hda-loader.c @keyonjie @libinyang @bardliao @lyakh +sound/soc/sof/hda-pcm.c @keyonjie @libinyang @bardliao @lyakh +sound/soc/sof/hda-stream.c @keyonjie @libinyang @bardliao @lyakh +sound/soc/sof/hda-trace.c @keyonjie @libinyang @bardliao @lyakh +sound/soc/sof/intel-ipc.c @keyonjie @libinyang @bardliao @lyakh +sound/soc/sof/Kconfig @keyonjie @libinyang +sound/soc/sof/Makefile @keyonjie @libinyang +sound/soc/sof/shim.h @keyonjie @libinyang @bardliao @lyakh @juimonen From d3161c8ae682c1f533eb5ce6f2a43d32c2ecbe86 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Tue, 7 May 2019 14:05:14 +0800 Subject: [PATCH 1434/1995] ASoC: SOF: Intel: ICL: add Icelake SSP count On Icelake we have 6 SSP ports, add ICL SSP count to enable all SSPs, instead of using the SSP count defined for CNL. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index b9ef5f8eb36c39..a2c06757deee2b 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -349,6 +349,7 @@ /* SSP Count of the Platform */ #define APL_SSP_COUNT 6 #define CNL_SSP_COUNT 3 +#define ICL_SSP_COUNT 6 /* SSP Registers */ #define SSP_SSC1_OFFSET 0x4 From 31e1a45f4998a1ce4ed8835cb6f5a52747c18921 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Tue, 7 May 2019 14:11:47 +0800 Subject: [PATCH 1435/1995] ASoC: SOF: Intel: ICL add Icelake chip info struct Icelake has different count of SSP other than CNL, using the new defined ICL SSP count, and copy other parameters from CNL chip info. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/cnl.c | 19 +++++++++++++++++++ sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/sof-pci-dev.c | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 08a1a3d3c08d65..c059d1170bab99 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -266,3 +266,22 @@ const struct sof_intel_dsp_desc cnl_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, }; EXPORT_SYMBOL(cnl_chip_info); + +const struct sof_intel_dsp_desc icl_chip_info = { + /* Icelake */ + .cores_num = 4, + .init_core_mask = 1, + .cores_mask = HDA_DSP_CORE_MASK(0) | + HDA_DSP_CORE_MASK(1) | + HDA_DSP_CORE_MASK(2) | + HDA_DSP_CORE_MASK(3), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .rom_init_timeout = 300, + .ssp_count = ICL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, +}; +EXPORT_SYMBOL(icl_chip_info); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index a2c06757deee2b..ffaf394fb7403d 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -581,5 +581,6 @@ extern const struct snd_sof_dsp_ops sof_skl_ops; extern const struct sof_intel_dsp_desc apl_chip_info; extern const struct sof_intel_dsp_desc cnl_chip_info; extern const struct sof_intel_dsp_desc skl_chip_info; +extern const struct sof_intel_dsp_desc icl_chip_info; #endif diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index b778dffb2d25c0..5f0eccbafc2204 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -137,7 +137,7 @@ static const struct sof_dev_desc icl_desc = { .resindex_imr_base = -1, .irqindex_host_ipc = -1, .resindex_dma_base = -1, - .chip_info = &cnl_chip_info, + .chip_info = &icl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", .nocodec_fw_filename = "sof-icl.ri", From 9ea9d4f29a1dc7465e83afa3eec83782f3053d0a Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Thu, 9 May 2019 11:06:36 +0300 Subject: [PATCH 1436/1995] ASoC: SOF: uapi: remove unused sof header files These header files are not used by kernel but internally by SOF firmware and possibly by user space applications. If needed, they should be included from include dir exported by SOF. Signed-off-by: Jaska Uimonen --- include/uapi/sound/sof/eq.h | 172 --------------------------- include/uapi/sound/sof/manifest.h | 188 ------------------------------ include/uapi/sound/sof/tone.h | 21 ---- include/uapi/sound/sof/trace.h | 66 ----------- 4 files changed, 447 deletions(-) delete mode 100644 include/uapi/sound/sof/eq.h delete mode 100644 include/uapi/sound/sof/manifest.h delete mode 100644 include/uapi/sound/sof/tone.h delete mode 100644 include/uapi/sound/sof/trace.h diff --git a/include/uapi/sound/sof/eq.h b/include/uapi/sound/sof/eq.h deleted file mode 100644 index 666c2b6a3229d1..00000000000000 --- a/include/uapi/sound/sof/eq.h +++ /dev/null @@ -1,172 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - */ - -#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_EQ_H__ -#define __INCLUDE_UAPI_SOUND_SOF_USER_EQ_H__ - -/* FIR EQ type */ - -#define SOF_EQ_FIR_IDX_SWITCH 0 - -#define SOF_EQ_FIR_MAX_SIZE 4096 /* Max size allowed for coef data in bytes */ - -#define SOF_EQ_FIR_MAX_LENGTH 192 /* Max length for individual filter */ - -#define SOF_EQ_FIR_MAX_RESPONSES 8 /* A blob can define max 8 FIR EQs */ - -/* - * eq_fir_configuration data structure contains this information - * uint32_t size - * This is the number of bytes need to store the received EQ - * configuration. - * uint16_t channels_in_config - * This describes the number of channels in this EQ config data. It - * can be different from PLATFORM_MAX_CHANNELS. - * uint16_t number_of_responses - * 0=no responses, 1=one response defined, 2=two responses defined, etc. - * int16_t data[] - * assign_response[channels_in_config] - * 0 = use first response, 1 = use 2nd response, etc. - * E.g. {0, 0, 0, 0, 1, 1, 1, 1} would apply to channels 0-3 the - * same first defined response and for to channels 4-7 the second. - * coef_data[] - * Repeated data - * { filter_length, output_shift, h[] } - * for every EQ response defined where vector h has filter_length - * number of coefficients. Coefficients in h[] are in Q1.15 format. - * E.g. 16384 (Q1.15) = 0.5. The shifts are number of right shifts. - * - * NOTE: The channels_in_config must be even to have coef_data aligned to - * 32 bit word in RAM. Therefore a mono EQ assign must be duplicated to 2ch - * even if it would never used. Similarly a 5ch EQ assign must be increased - * to 6ch. EQ init will return an error if this is not met. - * - * NOTE: The filter_length must be multiple of four. Therefore the filter must - * be padded from the end with zeros have this condition met. - */ - -struct sof_eq_fir_config { - uint32_t size; - uint16_t channels_in_config; - uint16_t number_of_responses; - - /* reserved */ - uint32_t reserved[4]; - - int16_t data[]; -} __packed; - -struct sof_eq_fir_coef_data { - int16_t length; /* Number of FIR taps */ - int16_t out_shift; /* Amount of right shifts at output */ - - /* reserved */ - uint32_t reserved[4]; - - int16_t coef[]; /* FIR coefficients */ -} __packed; - -/* In the struct above there's two 16 bit words (length, shift) and four - * reserved 32 bit words before the actual FIR coefficients. This information - * is used in parsing of the configuration blob. - */ -#define SOF_EQ_FIR_COEF_NHEADER \ - (sizeof(struct sof_eq_fir_coef_data) / sizeof(int16_t)) - -/* IIR EQ type */ - -#define SOF_EQ_IIR_IDX_SWITCH 0 - -#define SOF_EQ_IIR_MAX_SIZE 1024 /* Max size allowed for coef data in bytes */ - -#define SOF_EQ_IIR_MAX_RESPONSES 8 /* A blob can define max 8 IIR EQs */ - -/* eq_iir_configuration - * uint32_t channels_in_config - * This describes the number of channels in this EQ config data. It - * can be different from PLATFORM_MAX_CHANNELS. - * uint32_t number_of_responses_defined - * 0=no responses, 1=one response defined, 2=two responses defined, etc. - * int32_t data[] - * Data consist of two parts. First is the response assign vector that - * has length of channels_in_config. The latter part is coefficient - * data. - * uint32_t assign_response[channels_in_config] - * -1 = not defined, 0 = use first response, 1 = use 2nd, etc. - * E.g. {0, 0, 0, 0, -1, -1, -1, -1} would apply to channels 0-3 the - * same first defined response and leave channels 4-7 unequalized. - * coefficient_data[] - * <1st EQ> - * uint32_t num_biquads - * uint32_t num_biquads_in_series - * <1st biquad> - * int32_t coef_a2 Q2.30 format - * int32_t coef_a1 Q2.30 format - * int32_t coef_b2 Q2.30 format - * int32_t coef_b1 Q2.30 format - * int32_t coef_b0 Q2.30 format - * int32_t output_shift number of shifts right, shift left is negative - * int32_t output_gain Q2.14 format - * <2nd biquad> - * ... - * <2nd EQ> - * - * Note: A flat response biquad can be made with a section set to - * b0 = 1.0, gain = 1.0, and other parameters set to 0 - * {0, 0, 0, 0, 1073741824, 0, 16484} - */ - -struct sof_eq_iir_config { - uint32_t size; - uint32_t channels_in_config; - uint32_t number_of_responses; - - /* reserved */ - uint32_t reserved[4]; - - int32_t data[]; /* eq_assign[channels], eq 0, eq 1, ... */ -} __packed; - -struct sof_eq_iir_header_df2t { - uint32_t num_sections; - uint32_t num_sections_in_series; - - /* reserved */ - uint32_t reserved[4]; - - int32_t biquads[]; /* Repeated biquad coefficients */ -} __packed; - -struct sof_eq_iir_biquad_df2t { - int32_t a2; /* Q2.30 */ - int32_t a1; /* Q2.30 */ - int32_t b2; /* Q2.30 */ - int32_t b1; /* Q2.30 */ - int32_t b0; /* Q2.30 */ - int32_t output_shift; /* Number of right shifts */ - int32_t output_gain; /* Q2.14 */ -} __packed; - -/* A full 22th order equalizer with 11 biquads cover octave bands 1-11 in - * in the 0 - 20 kHz bandwidth. - */ -#define SOF_EQ_IIR_DF2T_BIQUADS_MAX 11 - -/* The number of int32_t words in sof_eq_iir_header_df2t: - * num_sections, num_sections_in_series, reserved[4] - */ -#define SOF_EQ_IIR_NHEADER_DF2T \ - (sizeof(struct sof_eq_iir_header_df2t) / sizeof(int32_t)) - -/* The number of int32_t words in sof_eq_iir_biquad_df2t: - * a2, a1, b2, b1, b0, output_shift, output_gain - */ -#define SOF_EQ_IIR_NBIQUAD_DF2T \ - (sizeof(struct sof_eq_iir_biquad_df2t) / sizeof(int32_t)) - -#endif diff --git a/include/uapi/sound/sof/manifest.h b/include/uapi/sound/sof/manifest.h deleted file mode 100644 index 2009ee30fad022..00000000000000 --- a/include/uapi/sound/sof/manifest.h +++ /dev/null @@ -1,188 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - */ - -#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_MANIFEST_H__ -#define __INCLUDE_UAPI_SOUND_SOF_USER_MANIFEST_H__ - -/* start offset for base FW module */ -#define SOF_MAN_ELF_TEXT_OFFSET 0x2000 - -/* FW Extended Manifest Header id = $AE1 */ -#define SOF_MAN_EXT_HEADER_MAGIC 0x31454124 - -/* module type load type */ -#define SOF_MAN_MOD_TYPE_BUILTIN 0 -#define SOF_MAN_MOD_TYPE_MODULE 1 - -struct sof_man_module_type { - uint32_t load_type:4; /* SOF_MAN_MOD_TYPE_ */ - uint32_t auto_start:1; - uint32_t domain_ll:1; - uint32_t domain_dp:1; - uint32_t rsvd_:25; -}; - -/* segment flags.type */ -#define SOF_MAN_SEGMENT_TEXT 0 -#define SOF_MAN_SEGMENT_RODATA 1 -#define SOF_MAN_SEGMENT_DATA 1 -#define SOF_MAN_SEGMENT_BSS 2 -#define SOF_MAN_SEGMENT_EMPTY 15 - -union sof_man_segment_flags { - uint32_t ul; - struct { - uint32_t contents:1; - uint32_t alloc:1; - uint32_t load:1; - uint32_t readonly:1; - uint32_t code:1; - uint32_t data:1; - uint32_t _rsvd0:2; - uint32_t type:4; /* MAN_SEGMENT_ */ - uint32_t _rsvd1:4; - uint32_t length:16; /* of segment in pages */ - } r; -} __packed; - -/* - * Module segment descriptor. Used by ROM - Immutable. - */ -struct sof_man_segment_desc { - union sof_man_segment_flags flags; - uint32_t v_base_addr; - uint32_t file_offset; -} __packed; - -/* - * The firmware binary can be split into several modules. - */ - -#define SOF_MAN_MOD_ID_LEN 4 -#define SOF_MAN_MOD_NAME_LEN 8 -#define SOF_MAN_MOD_SHA256_LEN 32 -#define SOF_MAN_MOD_ID {'$', 'A', 'M', 'E'} - -/* - * Each module has an entry in the FW header. Used by ROM - Immutable. - */ -struct sof_man_module { - uint8_t struct_id[SOF_MAN_MOD_ID_LEN]; /* SOF_MAN_MOD_ID */ - uint8_t name[SOF_MAN_MOD_NAME_LEN]; - uint8_t uuid[16]; - struct sof_man_module_type type; - uint8_t hash[SOF_MAN_MOD_SHA256_LEN]; - uint32_t entry_point; - uint16_t cfg_offset; - uint16_t cfg_count; - uint32_t affinity_mask; - uint16_t instance_max_count; /* max number of instances */ - uint16_t instance_bss_size; /* instance (pages) */ - struct sof_man_segment_desc segment[3]; -} __packed; - -/* - * Each module has a configuration in the FW header. Used by ROM - Immutable. - */ -struct sof_man_mod_config { - uint32_t par[4]; /* module parameters */ - uint32_t is_pages; /* actual size of instance .bss (pages) */ - uint32_t cps; /* cycles per second */ - uint32_t ibs; /* input buffer size (bytes) */ - uint32_t obs; /* output buffer size (bytes) */ - uint32_t module_flags; /* flags, reserved for future use */ - uint32_t cpc; /* cycles per single run */ - uint32_t obls; /* output block size, reserved for future use */ -} __packed; - -/* - * FW Manifest Header - */ - -#define SOF_MAN_FW_HDR_FW_NAME_LEN 8 -#define SOF_MAN_FW_HDR_ID {'$', 'A', 'M', '1'} -#define SOF_MAN_FW_HDR_NAME "ADSPFW" -#define SOF_MAN_FW_HDR_FLAGS 0x0 -#define SOF_MAN_FW_HDR_FEATURES 0xff - -/* - * The firmware has a standard header that is checked by the ROM on firmware - * loading. preload_page_count is used by DMA code loader and is entire - * image size on CNL. i.e. CNL: total size of the binary’s .text and .rodata - * Used by ROM - Immutable. - */ -struct sof_man_fw_header { - uint8_t header_id[4]; - uint32_t header_len; - uint8_t name[SOF_MAN_FW_HDR_FW_NAME_LEN]; - /* number of pages of preloaded image loaded by driver */ - uint32_t preload_page_count; - uint32_t fw_image_flags; - uint32_t feature_mask; - uint16_t major_version; - uint16_t minor_version; - uint16_t hotfix_version; - uint16_t build_version; - uint32_t num_module_entries; - uint32_t hw_buf_base_addr; - uint32_t hw_buf_length; - /* target address for binary loading as offset in IMR - must be == base offset */ - uint32_t load_offset; -} __packed; - -/* - * Firmware manifest descriptor. This can contain N modules and N module - * configs. Used by ROM - Immutable. - */ -struct sof_man_fw_desc { - struct sof_man_fw_header header; - - /* Warning - hack for module arrays. For some unknown reason the we - * have a variable size array of struct man_module followed by a - * variable size array of struct mod_config. These should have been - * merged into a variable array of a parent structure. We have to hack - * around this in many places.... - * - * struct sof_man_module man_module[]; - * struct sof_man_mod_config mod_config[]; - */ - -} __packed; - -/* - * Component Descriptor. Used by ROM - Immutable. - */ -struct sof_man_component_desc { - uint32_t reserved[2]; /* all 0 */ - uint32_t version; - uint8_t hash[SOF_MAN_MOD_SHA256_LEN]; - uint32_t base_offset; - uint32_t limit_offset; - uint32_t attributes[4]; -} __packed; - -/* - * Audio DSP extended metadata. Used by ROM - Immutable. - */ -struct sof_man_adsp_meta_file_ext { - uint32_t ext_type; /* always 17 for ADSP extension */ - uint32_t ext_len; - uint32_t imr_type; - uint8_t reserved[16]; /* all 0 */ - struct sof_man_component_desc comp_desc[1]; -} __packed; - -/* - * Module Manifest for rimage module metadata. Not used by ROM. - */ -struct sof_man_module_manifest { - struct sof_man_module module; - uint32_t text_size; -} __packed; - -#endif diff --git a/include/uapi/sound/sof/tone.h b/include/uapi/sound/sof/tone.h deleted file mode 100644 index d7c6e5d8317ebb..00000000000000 --- a/include/uapi/sound/sof/tone.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* -* This file is provided under a dual BSD/GPLv2 license. When using or -* redistributing this file, you may do so under either license. -* -* Copyright(c) 2018 Intel Corporation. All rights reserved. -*/ - -#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_TONE_H__ -#define __INCLUDE_UAPI_SOUND_SOF_USER_TONE_H__ - -#define SOF_TONE_IDX_FREQUENCY 0 -#define SOF_TONE_IDX_AMPLITUDE 1 -#define SOF_TONE_IDX_FREQ_MULT 2 -#define SOF_TONE_IDX_AMPL_MULT 3 -#define SOF_TONE_IDX_LENGTH 4 -#define SOF_TONE_IDX_PERIOD 5 -#define SOF_TONE_IDX_REPEATS 6 -#define SOF_TONE_IDX_LIN_RAMP_STEP 7 - -#endif diff --git a/include/uapi/sound/sof/trace.h b/include/uapi/sound/sof/trace.h deleted file mode 100644 index ffa7288a0f16f0..00000000000000 --- a/include/uapi/sound/sof/trace.h +++ /dev/null @@ -1,66 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * Copyright(c) 2018 Intel Corporation. All rights reserved. - */ - -#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_TRACE_H__ -#define __INCLUDE_UAPI_SOUND_SOF_USER_TRACE_H__ - -/* - * Host system time. - * - * This property is used by the driver to pass down information about - * current system time. It is expressed in us. - * FW translates timestamps (in log entries, probe pockets) to this time - * domain. - * - * (cavs: SystemTime). - */ -struct system_time { - uint32_t val_l; /* Lower dword of current host time value */ - uint32_t val_u; /* Upper dword of current host time value */ -} __packed; - -#define LOG_ENABLE 1 /* Enable logging */ -#define LOG_DISABLE 0 /* Disable logging */ - -#define LOG_LEVEL_CRITICAL 1 /* (FDK fatal) */ -#define LOG_LEVEL_VERBOSE 2 - -/* - * Layout of a log fifo. - */ -struct log_buffer_layout { - uint32_t read_ptr; /*read pointer */ - uint32_t write_ptr; /* write pointer */ - uint32_t buffer[0]; /* buffer */ -} __packed; - -/* - * Log buffer status reported by FW. - */ -struct log_buffer_status { - uint32_t core_id; /* ID of core that logged to other half */ -} __packed; - -#define TRACE_ID_LENGTH 12 - -/* - * Log entry header. - * - * The header is followed by an array of arguments (uint32_t[]). - * Number of arguments is specified by the params_num field of log_entry - */ -struct log_entry_header { - uint32_t id_0 : TRACE_ID_LENGTH; /* e.g. Pipeline ID */ - uint32_t id_1 : TRACE_ID_LENGTH; /* e.g. Component ID */ - uint32_t core_id : 8; /* Reporting core's id */ - - uint64_t timestamp; /* Timestamp (in dsp ticks) */ - uint32_t log_entry_address; /* Address of log entry in ELF */ -} __packed; - -#endif From ffdf2bc2c3c7d14670f8e02cfcb2dccd5f0d2626 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Mon, 6 May 2019 17:55:40 +0800 Subject: [PATCH 1437/1995] ASoC: Intel: bxt-da7219-max98357a: add BE dailink for dmic16k We need dmic16k BE(and FE, in tplg file) dailink for keyword detection feature on bxt-da7219-max98357a machine, here add it in driver side. Signed-off-by: Keyon Jie --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 5cadb7f654f3a0..d8c7d64bb1d7de 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -566,6 +566,17 @@ static struct snd_soc_dai_link broxton_dais[] = { .dpcm_playback = 1, .no_pcm = 1, }, + { + .name = "dmic16k", + .id = 6, + .cpu_dai_name = "DMIC16k Pin", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", + .platform_name = "0000:00:1f.3", + .be_hw_params_fixup = broxton_dmic_fixup, + .dpcm_capture = 1, + .no_pcm = 1, + }, }; static const struct x86_cpu_id glk_ids[] = { From 7a6986ec7023d9608a59ff181d2792ff9fb0c60c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 8 May 2019 14:45:59 -0500 Subject: [PATCH 1438/1995] ASOC: SOF: remove SPI compilation This is not upstream and not used, remove. The code can still be found on the archive/compressed-hsw-skl-kbl-spi-20190508 branch on GitHub Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/Kconfig | 19 ------------------- sound/soc/sof/Makefile | 4 ---- 2 files changed, 23 deletions(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 589acc77d163ed..a8d7210be6337b 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -35,25 +35,6 @@ config SND_SOC_SOF_ACPI Say Y if you need this option If unsure select "N". -config SND_SOC_SOF_SPI - tristate "SOF SPI support" - select SPI - select SPI_MASTER - select SND_SOC_SOF - select SND_SOC_SOF_OPTIONS - select SND_SOC_SOF_SPIDSP - help - This adds support for Sound Open Firmware over SPI for Device - Tree based systems. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_SOF_SPIDSP - tristate - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level - config SND_SOC_SOF_OPTIONS tristate help diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index b3d6defe6c39e6..416631f2a2f9d2 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -5,7 +5,6 @@ ccflags-y += -DDEBUG snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ control.o trace.o utils.o snd-sof-objs += compressed.o -snd-sof-spi-objs := hw-spi.o snd-sof-pci-objs := sof-pci-dev.o snd-sof-acpi-objs := sof-acpi-dev.o @@ -17,9 +16,6 @@ obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o obj-$(CONFIG_SND_SOC_SOF_ACPI) += sof-acpi-dev.o obj-$(CONFIG_SND_SOC_SOF_PCI) += sof-pci-dev.o -obj-$(CONFIG_SND_SOC_SOF_SPI) += sof-spi-dev.o - -obj-$(CONFIG_SND_SOC_SOF_SPIDSP) += snd-sof-spi.o obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/ obj-$(CONFIG_SND_SOC_SOF_XTENSA) += xtensa/ From 02af16b9dc0e85fba53be28f97a4191aab146813 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 8 May 2019 14:48:12 -0500 Subject: [PATCH 1439/1995] ASOC: SOF: remove SPI support This is not upstream and not used, remove. The code can still be found on the archive/compressed-hsw-skl-kbl-spi-20190508 branch on GitHub Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/hw-spi.c | 316 ------------------------------------ sound/soc/sof/hw-spi.h | 12 -- sound/soc/sof/sof-spi-dev.c | 206 ----------------------- 3 files changed, 534 deletions(-) delete mode 100644 sound/soc/sof/hw-spi.c delete mode 100644 sound/soc/sof/hw-spi.h delete mode 100644 sound/soc/sof/sof-spi-dev.c diff --git a/sound/soc/sof/hw-spi.c b/sound/soc/sof/hw-spi.c deleted file mode 100644 index 7e1eaf9ac9e0a6..00000000000000 --- a/sound/soc/sof/hw-spi.c +++ /dev/null @@ -1,316 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) -// -// This file is provided under a dual BSD/GPLv2 license. When using or -// redistributing this file, you may do so under either license. -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Liam Girdwood -// - -/* - * Hardware interface for audio DSPs via SPI - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "intel/shim.h" -#include "sof-priv.h" -#include "hw-spi.h" -#include "ops.h" - -/* - * Memory copy. - */ - -static void spi_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, - void *dest, size_t size) -{ - u8 *buf; - int ret; - - if (offset) { - buf = kmalloc(size + offset, GFP_KERNEL); - if (!buf) { - dev_err(sdev->dev, "error: buffer allocation failed\n"); - return; - } - } else { - buf = dest; - } - - ret = spi_read(to_spi_device(sdev->dev), buf, size + offset); - if (ret < 0) - dev_err(sdev->dev, "error: SPI read failed: %d\n", ret); - - if (offset) { - memcpy(dest, buf + offset, size); - kfree(buf); - } -} - -static void spi_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, - void *src, size_t size) -{ - int ret; - u8 *buf; - - if (offset) { - buf = kmalloc(size + offset, GFP_KERNEL); - if (!buf) { - dev_err(sdev->dev, "error: buffer allocation failed\n"); - return; - } - - /* Use Read-Modify-Wwrite */ - ret = spi_read(to_spi_device(sdev->dev), buf, size + offset); - if (ret < 0) { - dev_err(sdev->dev, "error: SPI read failed: %d\n", ret); - goto free; - } - - memcpy(buf + offset, src, size); - } else { - buf = src; - } - - ret = spi_write(to_spi_device(sdev->dev), buf, size + offset); - if (ret < 0) - dev_err(sdev->dev, "error: SPI write failed: %d\n", ret); - -free: - if (offset) - kfree(buf); -} - -/* - * IPC Firmware ready. - * TODO: check for ABI compatibility - */ -static int spi_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) -{ - struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; - struct sof_ipc_fw_version *v = &fw_ready->version; - - dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x\n", msg_id); - - // read local buffer with SPI data - - dev_info(sdev->dev, "Firmware info: version %d:%d-%s build %d on %s:%s\n", - v->major, v->minor, v->tag, v->build, v->date, v->time); - - return 0; -} - -/* - * IPC Mailbox IO - */ - -static void spi_mailbox_write(struct snd_sof_dev *sdev __maybe_unused, - u32 offset __maybe_unused, - void *message __maybe_unused, - size_t bytes __maybe_unused) -{ - /* - * this will copy to a local memory buffer that will be sent to DSP via - * SPI at next IPC - */ -} - -static void spi_mailbox_read(struct snd_sof_dev *sdev __maybe_unused, - u32 offset __maybe_unused, - void *message, size_t bytes) -{ - memset(message, 0, bytes); - - /* - * this will copy from a local memory buffer that was received from - * DSP via SPI at last IPC - */ -} - -/* - * IPC Doorbell IRQ handler and thread. - */ - -/* - * If the handler only has to wake up the thread, we might use the standard one - * as well - */ -static irqreturn_t spi_irq_handler(int irq __maybe_unused, void *context) -{ - const struct snd_sof_dev *sdev = context; - struct snd_sof_pdata *sof_pdata = sdev->pdata; - struct sof_spi_dev *sof_spi = sof_pdata->hw_pdata; - - // on SPI based devices this will likely come via a SoC GPIO IRQ - - // check if GPIO is assetred and if so run thread. - if (sof_spi->gpio >= 0 && - gpio_get_value(sof_spi->gpio) == sof_spi->active) - return IRQ_WAKE_THREAD; - - return IRQ_NONE; -} - -static int spi_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) -{ - /* send the message */ - spi_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, - msg->msg_size); - - return 0; -} - -static int spi_get_reply(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) -{ - struct sof_ipc_reply reply; - int ret = 0; - u32 size; - - /* - * Sometimes, there is unexpected reply ipc arriving. The reply - * ipc belongs to none of the ipcs sent from driver. - * In this case, the driver must ignore the ipc. - */ - if (!msg) { - dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); - return 0; - } - - /* get reply */ - spi_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); - if (reply.error < 0) { - size = sizeof(reply); - ret = reply.error; - } else { - /* reply correct size ? */ - if (reply.hdr.size != msg->reply_size) { - dev_err(sdev->dev, "error: reply expected 0x%zx got 0x%x bytes\n", - msg->reply_size, reply.hdr.size); - size = msg->reply_size; - ret = -EINVAL; - } else { - size = reply.hdr.size; - } - } - - /* read the message */ - if (msg->msg_data && size > 0) - spi_mailbox_read(sdev, sdev->host_box.offset, msg->reply_data, - size); - - return ret; -} - -static irqreturn_t spi_irq_thread(int irq __maybe_unused, void *context __maybe_unused) -{ - struct snd_sof_dev *sdev = context; - - // read SPI data into local buffer and determine IPC cmd or reply - - /* - * if reply. Handle Immediate reply from DSP Core and set DSP - * state to ready - */ - - /* if cmd, Handle messages from DSP Core */ - spi_get_reply(sdev, sdev->msg); - - return IRQ_HANDLED; -} - -/* - * Probe and remove. - */ - -static int spi_sof_probe(struct snd_sof_dev *sdev) -{ - struct platform_device *pdev = - container_of(sdev->dev, struct platform_device, dev); - struct snd_sof_pdata *sof_pdata = sdev->pdata; - struct sof_spi_dev *sof_spi = sof_pdata->hw_pdata; - /* get IRQ from Device tree or ACPI - register our IRQ */ - struct irq_data *irqd; - struct spi_device *spi = to_spi_device(pdev->dev.parent); - unsigned int irq_trigger, irq_sense; - int ret; - - sdev->ipc_irq = spi->irq; - dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); - irqd = irq_get_irq_data(sdev->ipc_irq); - if (!irqd) - return -EINVAL; - - irq_trigger = irqd_get_trigger_type(irqd); - irq_sense = irq_trigger & IRQ_TYPE_SENSE_MASK; - sof_spi->active = irq_sense == IRQ_TYPE_EDGE_RISING || - irq_sense == IRQ_TYPE_LEVEL_HIGH; - - ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, - spi_irq_handler, spi_irq_thread, - irq_trigger | IRQF_ONESHOT, - "AudioDSP", sdev); - if (ret < 0) - dev_err(sdev->dev, "error: failed to register IRQ %d\n", - sdev->ipc_irq); - - return ret; -} - -static int spi_sof_remove(struct snd_sof_dev *sdev) -{ - return 0; -} - -/* SPI SOF ops */ -const struct snd_sof_dsp_ops snd_sof_spi_ops = { - /* device init */ - .probe = spi_sof_probe, - .remove = spi_sof_remove, - - /* Block IO */ - .block_read = spi_block_read, - .block_write = spi_block_write, - - /* doorbell */ - .irq_handler = spi_irq_handler, - .irq_thread = spi_irq_thread, - - /* ipc */ - .send_msg = spi_send_msg, - .fw_ready = spi_fw_ready, - - /* debug */ - .debug_map = NULL/*spi_debugfs*/, - .debug_map_count = 0/*ARRAY_SIZE(spi_debugfs)*/, - .dbg_dump = NULL/*spi_dump*/, - - /* module loading */ - .load_module = snd_sof_parse_module_memcpy, - - /*Firmware loading */ - .load_firmware = snd_sof_load_firmware_memcpy, -}; -EXPORT_SYMBOL(snd_sof_spi_ops); - -const struct sof_intel_dsp_desc spi_chip_info = { - .cores_num = 2, - .cores_mask = 0x3, -}; -EXPORT_SYMBOL(spi_chip_info); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/hw-spi.h b/sound/soc/sof/hw-spi.h deleted file mode 100644 index 5348f38b393160..00000000000000 --- a/sound/soc/sof/hw-spi.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef HW_SPI_H -#define HW_SPI_H - -extern const struct snd_sof_dsp_ops snd_sof_spi_ops; -extern const struct sof_intel_dsp_desc spi_chip_info; - -struct sof_spi_dev { - int gpio; - unsigned int active; -}; - -#endif diff --git a/sound/soc/sof/sof-spi-dev.c b/sound/soc/sof/sof-spi-dev.c deleted file mode 100644 index 7cc051d17f0162..00000000000000 --- a/sound/soc/sof/sof-spi-dev.c +++ /dev/null @@ -1,206 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) -// -// This file is provided under a dual BSD/GPLv2 license. When using or -// redistributing this file, you may do so under either license. -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Liam Girdwood -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "intel/shim.h" -#include "sof-priv.h" -#include "hw-spi.h" -#include "ops.h" - -static char *fw_path; -module_param(fw_path, charp, 0444); -MODULE_PARM_DESC(fw_path, "alternate path for SOF firmware."); - -static char *tplg_path; -module_param(tplg_path, charp, 0444); -MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); - -/* FIXME: replace with some meaningful values */ -static struct snd_soc_acpi_mach spi_machines[] = { - { - .id = "INT343A", - .drv_name = "bxt_alc298s_i2s", - .sof_fw_filename = "sof-spi.ri", - .sof_tplg_filename = "sof-spi.tplg", - }, -}; - -static const struct sof_dev_desc spi_desc = { - .machines = spi_machines, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .nocodec_fw_filename = "sof-spi.ri", - .nocodec_tplg_filename = "sof-spi.tplg", - .resindex_lpe_base = -1, - .resindex_pcicfg_base = -1, - .resindex_imr_base = -1, - .irqindex_host_ipc = -1, - .resindex_dma_base = -1, - .chip_info = &spi_chip_info, - .ops = &snd_sof_spi_ops -}; - -static int sof_spi_probe(struct spi_device *spi) -{ - struct device *dev = &spi->dev; - const struct sof_dev_desc *desc = of_device_get_match_data(dev); - struct snd_soc_acpi_mach *machines, *mach; - struct snd_sof_pdata *sof_pdata; - struct sof_spi_dev *sof_spi; - const char *tplg, *fw; - struct gpio_desc *gpiod; - int ret, irq; - - if (!dev->of_node || !desc) - return -ENODEV; - - machines = desc->machines; - if (!machines) - return -ENODEV; - - dev_dbg(&spi->dev, "SPI DSP detected"); - - sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); - if (!sof_pdata) - return -ENOMEM; - - ret = of_property_read_string(dev->of_node, "tplg_filename", &tplg); - if (ret < 0 || !tplg) - return -EINVAL; - - ret = of_property_read_string(dev->of_node, "fw_filename", &fw); - if (ret < 0 || !fw) - return -EINVAL; - - /* - * Get an IRQ GPIO descriptor from an "irq-gpios" property - * If the IRQ is optional, use devm_gpiod_get_optional() - */ - gpiod = devm_gpiod_get(dev, "irq", GPIOD_IN); - if (IS_ERR(gpiod)) - return PTR_ERR(gpiod); - - sof_spi = devm_kzalloc(dev, sizeof(*sof_spi), GFP_KERNEL); - if (!sof_spi) - return -ENOMEM; - - sof_spi->gpio = desc_to_gpio(gpiod); - sof_pdata->hw_pdata = sof_spi; - - irq = gpiod_to_irq(gpiod); - if (irq < 0) - return irq; - - /* TODO: add any required regulators */ - - /* use nocodec machine atm */ - dev_err(dev, "error: no matching ASoC machine driver found - using nocodec\n"); - sof_pdata->drv_name = "sof-nocodec"; - mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); - if (!mach) - return -ENOMEM; - - mach->drv_name = "sof-nocodec"; - /* - * desc->nocodec_*_filename are selected as long as nocodec is used. - * Later machine->*_filename will have to be used. - */ - mach->sof_fw_filename = desc->nocodec_fw_filename; - mach->sof_tplg_filename = desc->nocodec_tplg_filename; - mach->mach_params.platform = dev_name(dev); - - sof_pdata->name = dev_name(&spi->dev); - sof_pdata->machine = mach; - sof_pdata->desc = desc; - sof_pdata->dev = dev; - - /* alternate fw and tplg filenames ? */ - if (fw_path) - sof_pdata->fw_filename_prefix = fw_path; - else - sof_pdata->fw_filename_prefix = - sof_pdata->desc->default_fw_path; - - if (tplg_path) - sof_pdata->tplg_filename_prefix = tplg_path; - else - sof_pdata->tplg_filename_prefix = - sof_pdata->desc->default_tplg_path; - - sof_pdata->fw_filename = mach->sof_fw_filename; - sof_pdata->tplg_filename = mach->sof_tplg_filename; - - /* call sof helper for DSP hardware probe */ - ret = snd_sof_device_probe(dev, sof_pdata); - if (ret) { - dev_err(dev, "error: failed to probe DSP hardware!\n"); - return ret; - } - - spi->irq = irq; - - /* allow runtime_pm */ - pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); - pm_runtime_use_autosuspend(dev); - pm_runtime_allow(dev); - - return ret; -} - -static int sof_spi_remove(struct spi_device *spi) -{ - /* call sof helper for DSP hardware remove */ - snd_sof_device_remove(&spi->dev); - - return 0; -} - -static const struct of_device_id sof_of_match[] = { - { .compatible = "sof,spi-sue-creek", .data = &spi_desc }, - { } -}; - -static struct spi_driver sof_spi_driver = { - .driver = { - .name = "sof-spi-dev", - .of_match_table = sof_of_match, - }, - .probe = sof_spi_probe, - .remove = sof_spi_remove, -}; - -static int __init sof_spi_modinit(void) -{ - int ret; - - ret = spi_register_driver(&sof_spi_driver); - if (ret != 0) - pr_err("Failed to register SOF SPI driver: %d\n", ret); - - return ret; -} -module_init(sof_spi_modinit); - -static void __exit sof_spi_modexit(void) -{ - spi_unregister_driver(&sof_spi_driver); -} -module_exit(sof_spi_modexit); - -MODULE_LICENSE("Dual BSD/GPL"); From 74fb69a7623b736f33396a9706b16e99baa22175 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 8 May 2019 14:50:52 -0500 Subject: [PATCH 1440/1995] device-tree: remove RPI changes for SOF This is not upstream and not used, remove. The code can still be found on the archive/compressed-hsw-skl-kbl-spi-20190508 branch on GitHub Signed-off-by: Pierre-Louis Bossart --- arch/arm/boot/dts/bcm2836-rpi-2-b.dts | 1 - arch/arm/boot/dts/bcm283x-rpi-sof.dtsi | 17 ----------------- 2 files changed, 18 deletions(-) delete mode 100644 arch/arm/boot/dts/bcm283x-rpi-sof.dtsi diff --git a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts index e5809b35464f5f..ac4408b34b58ef 100644 --- a/arch/arm/boot/dts/bcm2836-rpi-2-b.dts +++ b/arch/arm/boot/dts/bcm2836-rpi-2-b.dts @@ -4,7 +4,6 @@ #include "bcm2836-rpi.dtsi" #include "bcm283x-rpi-smsc9514.dtsi" #include "bcm283x-rpi-usb-host.dtsi" -//#include "bcm283x-rpi-sof.dtsi" / { compatible = "raspberrypi,2-model-b", "brcm,bcm2836"; diff --git a/arch/arm/boot/dts/bcm283x-rpi-sof.dtsi b/arch/arm/boot/dts/bcm283x-rpi-sof.dtsi deleted file mode 100644 index 2243ef50c3477c..00000000000000 --- a/arch/arm/boot/dts/bcm283x-rpi-sof.dtsi +++ /dev/null @@ -1,17 +0,0 @@ -// FIXME: which SPI bus is the card connected to? -@spi { - status = "okay"; - - sue-creek: sof-sue-creek@0 { - reg = <0>; - compatible = "sof,spi-sue-creek"; - // FIXME: frequency value - spi-max-frequency = <54000000>; - fw_filename = "sof-spi.ri"; - tplg_filename = "sof-spi.tplg"; - // FIXME: GPIO controller and IRQ number and sense - interrupt-parent = <&gpio1>; - interrupts = <9 IRQ_TYPE_EDGE_FALLING>; - irq-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; - }; -}; From 5485f71593cf1ccdd2862a95293fa76293e6a9fd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 8 May 2019 14:49:28 -0500 Subject: [PATCH 1441/1995] ASoC: SOF: remove virtio This is not upstream and not used, remove. The code can still be found on the archive/compressed-hsw-skl-kbl-spi-20190508 branch on GitHub Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/virtio-be.c | 125 ------------------------------------- sound/soc/sof/virtio-fe.c | 126 -------------------------------------- 2 files changed, 251 deletions(-) delete mode 100644 sound/soc/sof/virtio-be.c delete mode 100644 sound/soc/sof/virtio-fe.c diff --git a/sound/soc/sof/virtio-be.c b/sound/soc/sof/virtio-be.c deleted file mode 100644 index bd71466a368a64..00000000000000 --- a/sound/soc/sof/virtio-be.c +++ /dev/null @@ -1,125 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) -// -// This file is provided under a dual BSD/GPLv2 license. When using or -// redistributing this file, you may do so under either license. -// -// Copyright(c) 2017 Intel Corporation. All rights reserved. -// -// Author: Liam Girdwood -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sof-priv.h" -#include "ops.h" - -/* - * BE driver - * - * This driver will create IO Queues for communition from FE drivers. - * The FE driver will send real IPC structures over the queue and then - * the BE driver will send the structures directlt to the DSP. The BE will - * get the IPC reply from the DSP and send it back to the FE over the queue. - * - * The virt IO message Q handlers in this file will :- - * - * 1) Check that the message is valid and not for any componenets that don't - * belong to the guest. - * - * 2) Call snd_sof_dsp_tx_msg(struct snd_sof_dev *sdev, - * struct snd_sof_ipc_msg *msg) to send the message to the DSP. - * - * Replies will be sent back using a similar method. - */ - -static int sof_virtio_validate(struct virtio_device *dev) -{ - /* do we need this func ?? */ - return 0; -} - -static int sof_virtio_probe(struct virtio_device *dev) -{ - /* register fe device with sof core */ - //snd_sof_virtio_register_fe(dev); - - /* create our virtqueues */s - - /* send topology data to fe via virtq */ - - return 0; -} - -static void sof_virtio_remove(struct virtio_device *dev) -{ - /* remove topology from fe via virtqueue */ - - /* destroy virtqueue */ -} - -#ifdef CONFIG_PM -static int sof_virtio_freeze(struct virtio_device *dev) -{ - /* pause and suspend any streams for this FE */ - return 0; -} - -static int sof_virtio_restore(struct virtio_device *dev) -{ - /* restore and unpause any streams for this FE */ - return 0; -} -#endif - -/* IDs of FEs */ -static const struct virtio_device_id *fe_id_table[] + { -}; - -static struct virtio_driver sof_be_virtio_driver = { - .driver = { - .name = "sof-virtio-be", - .owner = THIS_MODULE, - }, - - .id_table = fe_id_table, - - //const unsigned int *feature_table; - //unsigned int feature_table_size; - //const unsigned int *feature_table_legacy; - //unsigned int feature_table_size_legacy; - - validate = sof_virtio_validate, - probe = sof_virtio_probe, - remove = sof_virtio_remove, - -#ifdef CONFIG_PM - freeze = sof_virtio_freeze, - restore = sof_virtio_restore, -#endif -}; - -/* this will be called by sof core when core is ready */ -int sof_virtio_register(struct snd_sof_dev *sdev) -{ - int ret; - - ret = register_virtio_driver(&sof_be_virtio_driver); - /* do we need to do anythig else here */ - return ret; -} - -/* called by sof core when driver is removed */ -void sof_virtio_unregister(struct snd_sof_dev *sdev) -{ - unregister_virtio_driver(&sof_be_virtio_driver); - /* do we need to do anythig else here */ -} diff --git a/sound/soc/sof/virtio-fe.c b/sound/soc/sof/virtio-fe.c deleted file mode 100644 index 3af6f37bd897ae..00000000000000 --- a/sound/soc/sof/virtio-fe.c +++ /dev/null @@ -1,126 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) -// -// This file is provided under a dual BSD/GPLv2 license. When using or -// redistributing this file, you may do so under either license. -// -// Copyright(c) 2017 Intel Corporation. All rights reserved. -// -// Author: Liam Girdwood -// - -/* - * virt IO FE driver - * - * The SOF driver thinks this driver is another audio DSP, however the calls - * made by the SOF driver core do not directly go to HW, but over a virtIO - * message Q to the virtIO BE driver. - * - * The virtIO message Q will use the *exact* same IPC structures as we currently - * use in the mailbox. - * - * Guest OS SOF core -> SOF FE -> virtIO Q -> SOF BE -> - * System OS SOF core -> DSP - * - * The mailbox IO and TX/RX msg functions below will do IO on the virt IO Q. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sof-priv.h" -#include "ops.h" - -/* - * IPC Firmware ready. - */ -static int virtio_fe_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) -{ - /* not needed for FE ? */ - return 0; -} - -/* - * IPC Mailbox IO - */ - -static void virtio_fe_mailbox_write(struct snd_sof_dev *sdev, u32 offset, - void *message, size_t bytes) -{ - /* write data to message Q buffer before sending message */ -} - -static void virtio_fe_mailbox_read(struct snd_sof_dev *sdev, u32 offset, - void *message, size_t bytes) -{ - /* read data from message Q buffer after receiving message */ -} - -static int virtio_fe_tx_busy(struct snd_sof_dev *sdev) -{ - /* return 1 if tx message Q is busy */ -} - -static int virtio_fe_tx_msg(struct snd_sof_dev *sdev, - struct snd_sof_ipc_msg *msg) -{ - /* write msg to the virtio queue message for BE */ - - return 0; -} - -static int virtio_fe_rx_msg(struct snd_sof_dev *sdev, - struct snd_sof_ipc_msg *msg) -{ - /* read the virtio queue message from BE and copy to msg */ - return 0; -} - -/* - * Probe and remove. - */ - -static int virtio_fe_probe(struct snd_sof_dev *sdev) -{ - /* register virtio device */ - - /* conenct virt queues to BE */ -} - -static int virtio_fe_remove(struct snd_sof_dev *sdev) -{ - /* free virtio resurces and unregister device */ -} - -/* baytrail ops */ -const struct snd_sof_dsp_ops snd_sof_virtio_fe_ops = { - /* device init */ - .probe = virtio_fe_probe, - .remove = virtio_fe_remove, - - /* mailbox */ - .mailbox_read = virtio_fe_mailbox_read, - .mailbox_write = virtio_fe_mailbox_write, - - /* ipc */ - .tx_msg = virtio_fe_tx_msg, - .rx_msg = virtio_fe_rx_msg, - .fw_ready = virtio_fe_fw_ready, - .tx_busy = virtio_fe_tx_busy, - - /* module loading */ -// .load_module = snd_sof_parse_module_memcpy, - - /*Firmware loading */ - .load_firmware = snd_sof_load_firmware_memcpy, -}; -EXPORT_SYMBOL(snd_sof_virtio_fe_ops); - -MODULE_LICENSE("Dual BSD/GPL"); From 82bcd4deaf5881f95a76212cf4e185fd7c3a0a1a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 8 May 2019 14:52:26 -0500 Subject: [PATCH 1442/1995] ASOC: Intel: common: remove CNL table entry This is not upstream and not used, remove. The code can still be found on the archive/compressed-hsw-skl-kbl-spi-20190508 branch on GitHub Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index 7d0230070e624a..df7c52cad5c3f6 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -28,14 +28,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .sof_fw_filename = "sof-cnl.ri", .sof_tplg_filename = "sof-cnl-rt274.tplg", }, - { - .id = "MX98373", - .drv_name = "cnl_max98373", - .fw_filename = "intel/dsp_fw_cnl.bin", - .pdata = &cnl_pdata, - .sof_fw_filename = "sof-cnl.ri", - .sof_tplg_filename = "sof-cnl.tplg", - }, { .id = "10EC5682", .drv_name = "sof_rt5682", From 4e26674ead5f8bb91ed72504723fa6074b666aa4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 8 May 2019 14:53:57 -0500 Subject: [PATCH 1443/1995] ASoC: SOF: remove support for compressed streams This is not upstream and not used for now, remove. The code can still be found on the archive/compressed-hsw-skl-kbl-spi-20190508 branch on GitHub This will have to be re-added later, but let's do it right next time. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/Kconfig | 8 -------- sound/soc/sof/Makefile | 1 - 2 files changed, 9 deletions(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index a8d7210be6337b..a1a9ffe605dc66 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -43,13 +43,6 @@ config SND_SOC_SOF_OPTIONS if SND_SOC_SOF_OPTIONS -config SND_SOC_SOF_COMPRESS - bool "SOF ALSA Compressed API support" - help - This adds support for the ALSA compressed API in SOF - Say Y if you need this option - If unsure select "N". - config SND_SOC_SOF_NOCODEC tristate "SOF nocodec mode Support" help @@ -142,7 +135,6 @@ endif ## SND_SOC_SOF_OPTIONS config SND_SOC_SOF tristate select SND_SOC_TOPOLOGY - select SND_SOC_COMPRESS if SND_SOC_SOF_COMPRESS=y help This option is not user-selectable but automagically handled by 'select' statements at a higher level diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 416631f2a2f9d2..33c3ded2b7e20d 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -4,7 +4,6 @@ ccflags-y += -DDEBUG snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ control.o trace.o utils.o -snd-sof-objs += compressed.o snd-sof-pci-objs := sof-pci-dev.o snd-sof-acpi-objs := sof-acpi-dev.o From baa58ecfe32950dc1ee98455de5bceafd8520463 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 8 May 2019 14:55:24 -0500 Subject: [PATCH 1444/1995] ASoC: SOF: remove compressed streams This is not upstream and not used for now, remove. The code can still be found on the archive/compressed-hsw-skl-kbl-spi-20190508 branch on GitHub This will have to be re-added later, but let's do it right next time. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/compressed.c | 182 ------------------------------------- 1 file changed, 182 deletions(-) delete mode 100644 sound/soc/sof/compressed.c diff --git a/sound/soc/sof/compressed.c b/sound/soc/sof/compressed.c deleted file mode 100644 index 6703db3920b270..00000000000000 --- a/sound/soc/sof/compressed.c +++ /dev/null @@ -1,182 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) -// -// This file is provided under a dual BSD/GPLv2 license. When using or -// redistributing this file, you may do so under either license. -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Liam Girdwood -// - -#include -#include -#include -#include "sof-priv.h" - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) - -#define DRV_NAME "sof-audio-component" - -static int sof_compressed_open(struct snd_compr_stream *cstream) -{ - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(component); - struct snd_sof_pcm *spcm = rtd->private; - int ret; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err(sdev->dev, "error: comp open failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - } - return ret; -} - -static int sof_compressed_free(struct snd_compr_stream *cstream) -{ - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(component); - struct snd_sof_pcm *spcm = rtd->private; - int err; - - err = pm_runtime_put(sdev->dev); - if (err < 0) - dev_err(sdev->dev, "error: comp close failed to idle %d\n", - err); - return err; -} - -static int sof_vorbis_set_params(struct snd_compr_stream *cstream, - struct snd_compr_params *params) -{ - return 0; -} - -static int sof_mp3_set_params(struct snd_compr_stream *cstream, - struct snd_compr_params *params) -{ - return 0; -} - -static int sof_compressed_set_params(struct snd_compr_stream *cstream, - struct snd_compr_params *params) -{ - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(component); - - switch (params->codec.id) { - case SND_AUDIOCODEC_VORBIS: - return sof_vorbis_set_params(cstream, params); - case SND_AUDIOCODEC_MP3: - return sof_mp3_set_params(cstream, params); - default: - dev_err(sdev->dev, "error: codec id %d not supported\n", - params->codec.id); - return -EINVAL; - } -} - -static int sof_compressed_trigger(struct snd_compr_stream *cstream, int cmd) -{ - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(component); - struct snd_sof_pcm *spcm = rtd->private; - struct sof_ipc_stream stream; - struct sof_ipc_reply reply; - - stream.hdr.size = sizeof(stream); - stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG; - stream.comp_id = spcm->stream[cstream->direction].comp_id; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_START; - break; - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE; - break; - case SNDRV_PCM_TRIGGER_STOP: - stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; - break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_PAUSE; - break; - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_RESUME: - default: - break; - } - - /* send IPC to the DSP */ - return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, - sizeof(stream), &reply, sizeof(reply)); -} - -static int sof_compressed_pointer(struct snd_compr_stream *cstream, - struct snd_compr_tstamp *tstamp) -{ - struct snd_soc_pcm_runtime *rtd = cstream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(component); - struct sof_ipc_stream_posn posn; - struct snd_sof_pcm *spcm = rtd->private; - - snd_sof_ipc_stream_posn(sdev, spcm, cstream->direction, &posn); - - dev_vdbg(sdev->dev, "CPCM: DMA position %llu DAI position %llu\n", - posn.host_posn, posn.dai_posn); - - return 0; -} - -static int sof_compressed_ack(struct snd_compr_stream *cstream, - size_t bytes) -{ - return 0; -} - -static int sof_compressed_get_caps(struct snd_compr_stream *cstream, - struct snd_compr_caps *caps) -{ - return 0; -} - -static int sof_compressed_get_codec_caps(struct snd_compr_stream *cstream, - struct snd_compr_codec_caps *codec) -{ - return 0; -} - -static int sof_compressed_set_metadata(struct snd_compr_stream *cstream, - struct snd_compr_metadata *metadata) -{ - return 0; -} - -struct snd_compr_ops sof_compressed_ops = { - .open = sof_compressed_open, - .free = sof_compressed_free, - .set_params = sof_compressed_set_params, - .set_metadata = sof_compressed_set_metadata, - .trigger = sof_compressed_trigger, - .pointer = sof_compressed_pointer, - .ack = sof_compressed_ack, - .get_caps = sof_compressed_get_caps, - .get_codec_caps = sof_compressed_get_codec_caps, -}; -#endif From a875a8c0659b42a1e683bcbdffcb19017ded8161 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 8 May 2019 14:58:10 -0500 Subject: [PATCH 1445/1995] ASoC: SOF: remove build support for SKL and KBL This is not upstream and not used for now, remove. The code can still be found on the archive/compressed-hsw-skl-kbl-spi-20190508 branch on GitHub Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/Kconfig | 32 -------------------------------- sound/soc/sof/intel/Makefile | 4 ++-- 2 files changed, 2 insertions(+), 34 deletions(-) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index c20f2d3164498b..0001217db17ead 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -24,8 +24,6 @@ config SND_SOC_SOF_INTEL_PCI select SND_SOC_SOF_GEMINILAKE if SND_SOC_SOF_GEMINILAKE_SUPPORT select SND_SOC_SOF_CANNONLAKE if SND_SOC_SOF_CANNONLAKE_SUPPORT select SND_SOC_SOF_COFFEELAKE if SND_SOC_SOF_COFFEELAKE_SUPPORT - select SND_SOC_SOF_KABYLAKE if SND_SOC_SOF_KABYLAKE_SUPPORT - select SND_SOC_SOF_SKYLAKE if SND_SOC_SOF_SKYLAKE_SUPPORT select SND_SOC_SOF_ICELAKE if SND_SOC_SOF_ICELAKE_SUPPORT help This option is not user-selectable but automagically handled by @@ -183,36 +181,6 @@ config SND_SOC_SOF_COFFEELAKE This option is not user-selectable but automagically handled by 'select' statements at a higher level -config SND_SOC_SOF_KABYLAKE_SUPPORT - bool "SOF support for Kabylake" - help - This adds support for Sound Open Firmware for Intel(R) platforms - using the Kabylake processors. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_SOF_KABYLAKE - tristate - select SND_SOC_SOF_HDA_COMMON - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level - -config SND_SOC_SOF_SKYLAKE_SUPPORT - bool "SOF support for Skylake" - help - This adds support for Sound Open Firmware for Intel(R) platforms - using the Skylake processors. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_SOF_SKYLAKE - tristate - select SND_SOC_SOF_HDA_COMMON - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level - config SND_SOC_SOF_ICELAKE_SUPPORT bool "SOF support for Icelake" help diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index 03b22924d0c4eb..0ba9c9e8b8e73c 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -10,8 +10,8 @@ snd-sof-intel-ipc-objs := intel-ipc.o snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ hda-dsp.o hda-ipc.o hda-ctrl.o hda-pcm.o \ - hda-dai.o hda-bus.o hda-loader-skl.o \ - skl.o apl.o cnl.o + hda-dai.o hda-bus.o \ + apl.o cnl.o snd-sof-intel-hda-objs := hda-codec.o From 6c475d73c9e070cef4a8223afa1f1b0e22f9cf0f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 8 May 2019 14:59:25 -0500 Subject: [PATCH 1446/1995] ASoC: SOF: remove platform differentiation for SKL This is not upstream and not used, remove. The code can still be found on the archive/compressed-hsw-skl-kbl-spi-20190508 branch on GitHub Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/skl.c | 102 -------------------------------------- 1 file changed, 102 deletions(-) delete mode 100644 sound/soc/sof/intel/skl.c diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c deleted file mode 100644 index 34f7aa93c86597..00000000000000 --- a/sound/soc/sof/intel/skl.c +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) -// -// This file is provided under a dual BSD/GPLv2 license. When using or -// redistributing this file, you may do so under either license. -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Authors: Liam Girdwood -// Ranjani Sridharan -// Rander Wang -// Keyon Jie -// - -/* - * Hardware interface for audio DSP on Skylake and Kabylake. - */ - -#include "../sof-priv.h" -#include "hda.h" - -static const struct snd_sof_debugfs_map skl_dsp_debugfs[] = { - {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, - {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, - {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, -}; - -/* skylake ops */ -const struct snd_sof_dsp_ops sof_skl_ops = { - /* probe and remove */ - .probe = hda_dsp_probe, - .remove = hda_dsp_remove, - - /* Register IO */ - .write = sof_io_write, - .read = sof_io_read, - .write64 = sof_io_write64, - .read64 = sof_io_read64, - - /* Block IO */ - .block_read = sof_block_read, - .block_write = sof_block_write, - - /* doorbell */ - .irq_handler = hda_dsp_ipc_irq_handler, - .irq_thread = hda_dsp_ipc_irq_thread, - - /* ipc */ - .send_msg = hda_dsp_ipc_send_msg, - .fw_ready = hda_dsp_ipc_fw_ready, - - .ipc_msg_data = hda_ipc_msg_data, - .ipc_pcm_params = hda_ipc_pcm_params, - - /* debug */ - .debug_map = skl_dsp_debugfs, - .debug_map_count = ARRAY_SIZE(skl_dsp_debugfs), - .dbg_dump = hda_dsp_dump_skl, - - /* stream callbacks */ - .pcm_open = hda_dsp_pcm_open, - .pcm_close = hda_dsp_pcm_close, - .pcm_hw_params = hda_dsp_pcm_hw_params, - .pcm_trigger = hda_dsp_pcm_trigger, - - /* firmware loading */ - .load_firmware = snd_sof_load_firmware_raw, - - /* pre/post fw run */ - .pre_fw_run = hda_dsp_pre_fw_run, - .post_fw_run = hda_dsp_post_fw_run, - - /* dsp core power up/down */ - .core_power_up = hda_dsp_enable_core, - .core_power_down = hda_dsp_core_reset_power_down, - - /* firmware run */ - .run = hda_dsp_cl_boot_firmware_skl, - - /* trace callback */ - .trace_init = hda_dsp_trace_init, - .trace_release = hda_dsp_trace_release, - .trace_trigger = hda_dsp_trace_trigger, - - /* DAI drivers */ - .drv = skl_dai, - .num_drv = SOF_SKL_NUM_DAIS, -}; -EXPORT_SYMBOL(sof_skl_ops); - -const struct sof_intel_dsp_desc skl_chip_info = { - /* Skylake */ - .cores_num = 2, - .init_core_mask = 1, - .cores_mask = HDA_DSP_CORE_MASK(0) | HDA_DSP_CORE_MASK(1), - .ipc_req = HDA_DSP_REG_HIPCI, - .ipc_req_mask = HDA_DSP_REG_HIPCI_BUSY, - .ipc_ack = HDA_DSP_REG_HIPCIE, - .ipc_ack_mask = HDA_DSP_REG_HIPCIE_DONE, - .ipc_ctl = HDA_DSP_REG_HIPCCTL, - .rom_init_timeout = 150, -}; -EXPORT_SYMBOL(skl_chip_info); From 9d4c21f4fdc4bfc6c768d0286ece001d00c31c74 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 8 May 2019 15:01:17 -0500 Subject: [PATCH 1447/1995] ASoC: SOF: remove SKL-specific code loader This is not upstream and not used, remove. The code can still be found on the archive/compressed-hsw-skl-kbl-spi-20190508 branch on GitHub Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-loader-skl.c | 516 --------------------------- sound/soc/sof/intel/hda.h | 1 - 2 files changed, 517 deletions(-) delete mode 100644 sound/soc/sof/intel/hda-loader-skl.c diff --git a/sound/soc/sof/intel/hda-loader-skl.c b/sound/soc/sof/intel/hda-loader-skl.c deleted file mode 100644 index 3a94aa378567f5..00000000000000 --- a/sound/soc/sof/intel/hda-loader-skl.c +++ /dev/null @@ -1,516 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) -// -// This file is provided under a dual BSD/GPLv2 license. When using or -// redistributing this file, you may do so under either license. -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Authors: Liam Girdwood -// Zhu Yingjiang -// - -#include -#include -#include -#include "../ops.h" -#include "hda.h" - -#define HDA_SKL_WAIT_TIMEOUT 500 /* 500 msec */ -#define HDA_SKL_CLDMA_MAX_BUFFER_SIZE (32 * PAGE_SIZE) - -/* Stream Reset */ -#define HDA_CL_SD_CTL_SRST_SHIFT 0 -#define HDA_CL_SD_CTL_SRST(x) (((x) & 0x1) << \ - HDA_CL_SD_CTL_SRST_SHIFT) - -/* Stream Run */ -#define HDA_CL_SD_CTL_RUN_SHIFT 1 -#define HDA_CL_SD_CTL_RUN(x) (((x) & 0x1) << \ - HDA_CL_SD_CTL_RUN_SHIFT) - -/* Interrupt On Completion Enable */ -#define HDA_CL_SD_CTL_IOCE_SHIFT 2 -#define HDA_CL_SD_CTL_IOCE(x) (((x) & 0x1) << \ - HDA_CL_SD_CTL_IOCE_SHIFT) - -/* FIFO Error Interrupt Enable */ -#define HDA_CL_SD_CTL_FEIE_SHIFT 3 -#define HDA_CL_SD_CTL_FEIE(x) (((x) & 0x1) << \ - HDA_CL_SD_CTL_FEIE_SHIFT) - -/* Descriptor Error Interrupt Enable */ -#define HDA_CL_SD_CTL_DEIE_SHIFT 4 -#define HDA_CL_SD_CTL_DEIE(x) (((x) & 0x1) << \ - HDA_CL_SD_CTL_DEIE_SHIFT) - -/* FIFO Limit Change */ -#define HDA_CL_SD_CTL_FIFOLC_SHIFT 5 -#define HDA_CL_SD_CTL_FIFOLC(x) (((x) & 0x1) << \ - HDA_CL_SD_CTL_FIFOLC_SHIFT) - -/* Stripe Control */ -#define HDA_CL_SD_CTL_STRIPE_SHIFT 16 -#define HDA_CL_SD_CTL_STRIPE(x) (((x) & 0x3) << \ - HDA_CL_SD_CTL_STRIPE_SHIFT) - -/* Traffic Priority */ -#define HDA_CL_SD_CTL_TP_SHIFT 18 -#define HDA_CL_SD_CTL_TP(x) (((x) & 0x1) << \ - HDA_CL_SD_CTL_TP_SHIFT) - -/* Bidirectional Direction Control */ -#define HDA_CL_SD_CTL_DIR_SHIFT 19 -#define HDA_CL_SD_CTL_DIR(x) (((x) & 0x1) << \ - HDA_CL_SD_CTL_DIR_SHIFT) - -/* Stream Number */ -#define HDA_CL_SD_CTL_STRM_SHIFT 20 -#define HDA_CL_SD_CTL_STRM(x) (((x) & 0xf) << \ - HDA_CL_SD_CTL_STRM_SHIFT) - -#define HDA_CL_SD_CTL_INT(x) \ - (HDA_CL_SD_CTL_IOCE(x) | \ - HDA_CL_SD_CTL_FEIE(x) | \ - HDA_CL_SD_CTL_DEIE(x)) - -#define HDA_CL_SD_CTL_INT_MASK \ - (HDA_CL_SD_CTL_IOCE(1) | \ - HDA_CL_SD_CTL_FEIE(1) | \ - HDA_CL_SD_CTL_DEIE(1)) - -#define DMA_ADDRESS_128_BITS_ALIGNMENT 7 -#define BDL_ALIGN(x) ((x) >> DMA_ADDRESS_128_BITS_ALIGNMENT) - -/* Buffer Descriptor List Lower Base Address */ -#define HDA_CL_SD_BDLPLBA_SHIFT 7 -#define HDA_CL_SD_BDLPLBA_MASK GENMASK(HDA_CL_SD_BDLPLBA_SHIFT + 24,\ - HDA_CL_SD_BDLPLBA_SHIFT) -#define HDA_CL_SD_BDLPLBA(x) \ - ((BDL_ALIGN(lower_32_bits(x)) << HDA_CL_SD_BDLPLBA_SHIFT) & \ - HDA_CL_SD_BDLPLBA_MASK) - -/* Buffer Descriptor List Upper Base Address */ -#define HDA_CL_SD_BDLPUBA_SHIFT 0 -#define HDA_CL_SD_BDLPUBA_MASK GENMASK(HDA_CL_SD_BDLPUBA_SHIFT + 31,\ - HDA_CL_SD_BDLPUBA_SHIFT) -#define HDA_CL_SD_BDLPUBA(x) \ - ((upper_32_bits(x) << HDA_CL_SD_BDLPUBA_SHIFT) & \ - HDA_CL_SD_BDLPUBA_MASK) - -/* Software Position in Buffer Enable */ -#define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT 0 -#define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK \ - BIT(HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) - -#define HDA_CL_SPBFIFO_SPBFCCTL_SPIBE(x) \ - (((x) << HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & \ - HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK) - -static void cl_skl_cldma_setup_bdle(struct snd_sof_dev *sdev, - struct snd_dma_buffer *dmab_data, - __le32 **bdlp) -{ - const unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; - phys_addr_t addr = virt_to_phys(dmab_data->area); - __le32 *bdl = *bdlp; - - /* - * The CLDMA using a single physically-contiguous memory - * to transfer the data to DSP, so need an interrupt at the - * end of every transfer. - */ - bdl[0] = cpu_to_le32(lower_32_bits(addr)); - bdl[1] = cpu_to_le32(upper_32_bits(addr)); - - bdl[2] = cpu_to_le32(bufsize); - - bdl[3] = cpu_to_le32(0x01); -} - -static void cl_skl_cldma_stream_run(struct snd_sof_dev *sdev, bool enable) -{ - unsigned char val; - int timeout; - int sd_offset = SOF_HDA_ADSP_LOADER_BASE; - u32 run = enable ? 0x1 : 0; - - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, - HDA_CL_SD_CTL_RUN(1), HDA_CL_SD_CTL_RUN(run)); - - udelay(3); - timeout = 300; - do { - /* waiting for hardware to report the stream Run bit set */ - val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL) - & HDA_CL_SD_CTL_RUN(1); - if (enable && val) - break; - else if (!enable && !val) - break; - udelay(3); - } while (--timeout); - - if (timeout == 0) - dev_err(sdev->dev, "error: failed to set Run bit=%d enable=%d\n", - val, enable); -} - -static void cl_skl_cldma_stream_clear(struct snd_sof_dev *sdev) -{ - int sd_offset = SOF_HDA_ADSP_LOADER_BASE; - - /* make sure Run bit is cleared before setting stream register */ - cl_skl_cldma_stream_run(sdev, 0); - - /* - * Disable the Interrupt On Completion, FIFO Error Interrupt, - * Descriptor Error Interrupt and set the cldma stream number to 0. - */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, - HDA_CL_SD_CTL_INT_MASK, HDA_CL_SD_CTL_INT(0)); - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, - HDA_CL_SD_CTL_STRM(0xf), HDA_CL_SD_CTL_STRM(0)); - - snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, - HDA_CL_SD_BDLPLBA(0)); - snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, 0); - - /* Set the Cyclic Buffer Length to 0. */ - snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, 0); - /* Set the Last Valid Index. */ - snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, 0); -} - -static void cl_skl_cldma_setup_spb(struct snd_sof_dev *sdev, - unsigned int size, bool enable) -{ - int sd_offset = SOF_DSP_REG_CL_SPBFIFO; - - if (enable) - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - sd_offset + - SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, - HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, - HDA_CL_SPBFIFO_SPBFCCTL_SPIBE(1)); - - snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPIB, size); -} - -static void cl_skl_cldma_set_intr(struct snd_sof_dev *sdev, bool enable) -{ - u32 val = enable ? HDA_DSP_ADSPIC_CL_DMA : 0; - - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, - HDA_DSP_ADSPIC_CL_DMA, val); -} - -static void cl_skl_cldma_cleanup_spb(struct snd_sof_dev *sdev) -{ - int sd_offset = SOF_DSP_REG_CL_SPBFIFO; - - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - sd_offset + - SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, - HDA_CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, - HDA_CL_SPBFIFO_SPBFCCTL_SPIBE(0)); - - snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SPBFIFO_SPIB, 0); -} - -static void cl_skl_cldma_setup_controller(struct snd_sof_dev *sdev, - struct snd_dma_buffer *dmab_bdl) -{ - const unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; - int sd_offset = SOF_HDA_ADSP_LOADER_BASE; - - /* Clear the stream first and then set it. */ - cl_skl_cldma_stream_clear(sdev); - - /* setting the stream register */ - snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPL, - HDA_CL_SD_BDLPLBA(dmab_bdl->addr)); - snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_BDLPU, - HDA_CL_SD_BDLPUBA(dmab_bdl->addr)); - - /* Set the Cyclic Buffer Length. */ - snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CBL, bufsize); - /* Set the Last Valid Index. */ - snd_sof_dsp_write(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_LVI, 0); - - /* - * Set the Interrupt On Completion, FIFO Error Interrupt, - * Descriptor Error Interrupt and the cldma stream number. - */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, - HDA_CL_SD_CTL_INT_MASK, HDA_CL_SD_CTL_INT(1)); - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, - sd_offset + SOF_HDA_ADSP_REG_CL_SD_CTL, - HDA_CL_SD_CTL_STRM(0xf), - HDA_CL_SD_CTL_STRM(1)); -} - -static int cl_stream_prepare_skl(struct snd_sof_dev *sdev) -{ - struct pci_dev *pci = to_pci_dev(sdev->dev); - int ret; - __le32 *bdl; - const unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; - - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, bufsize, - &sdev->dmab); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to alloc fw buffer: %x\n", - ret); - return ret; - } - - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &pci->dev, bufsize, - &sdev->dmab_bdl); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to alloc blde: %x\n", ret); - snd_dma_free_pages(&sdev->dmab); - return ret; - } - - bdl = (__le32 *)sdev->dmab_bdl.area; - cl_skl_cldma_setup_bdle(sdev, &sdev->dmab, &bdl); - cl_skl_cldma_setup_controller(sdev, &sdev->dmab_bdl); - - return ret; -} - -static void cl_cleanup_skl(struct snd_sof_dev *sdev) -{ - cl_skl_cldma_cleanup_spb(sdev); - cl_skl_cldma_stream_clear(sdev); - snd_dma_free_pages(&sdev->dmab); - snd_dma_free_pages(&sdev->dmab_bdl); - sdev->dmab.area = NULL; -} - -static int cl_dsp_init_skl(struct snd_sof_dev *sdev) -{ - struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; - const struct sof_intel_dsp_desc *chip = hda->desc; - unsigned int sts; - int ret; - - /* - * check if the core is already enabled, if yes, reset and - * make it run. If not, powerdown and enable it again. - */ - if (hda_dsp_core_is_enabled(sdev, HDA_DSP_CORE_MASK(0))) { - - /* if enabled, reset it, and run the core. */ - ret = hda_dsp_core_stall_reset(sdev, HDA_DSP_CORE_MASK(0)); - if (ret < 0) - goto err; - - ret = hda_dsp_core_run(sdev, HDA_DSP_CORE_MASK(0)); - if (ret < 0) { - dev_err(sdev->dev, "error: dsp core start failed %d\n", - ret); - goto err; - } - } else { - /* - * if not enabled, power down it first and - * then powerup and run the core. - */ - ret = hda_dsp_core_reset_power_down(sdev, HDA_DSP_CORE_MASK(0)); - if (ret < 0) { - dev_err(sdev->dev, "error: dsp core0 disable fail: %d\n", ret); - goto err; - } - ret = hda_dsp_enable_core(sdev, HDA_DSP_CORE_MASK(0)); - if (ret < 0) { - dev_err(sdev->dev, "error: dsp core0 enable fail: %d\n", ret); - goto err; - } - } - - /* prepare DMA for code loader stream */ - ret = cl_stream_prepare_skl(sdev); - if (ret < 0) { - dev_err(sdev->dev, "error: dma prepare fw loading err: %x\n", - ret); - return ret; - } - - /* enable IPC interrupts */ - hda_dsp_ipc_int_enable(sdev); - - /* polling the ROM init status information. */ - ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, - HDA_ADSP_FW_STATUS_SKL, sts, - ((sts & HDA_DSP_ROM_STS_MASK) - == HDA_DSP_ROM_INIT), - HDA_DSP_REG_POLL_INTERVAL_US, - chip->rom_init_timeout * - USEC_PER_MSEC); - if (ret < 0) - goto err; - - return ret; - -err: - hda_dsp_dump_skl(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); - cl_cleanup_skl(sdev); - hda_dsp_core_reset_power_down(sdev, HDA_DSP_CORE_MASK(0)); - return ret; -} - -static void cl_skl_cldma_fill_buffer(struct snd_sof_dev *sdev, - unsigned int size, - const void *curr_pos, - bool intr_enable, bool trigger) -{ - /* 1. copy the image into the buffer. */ - memcpy(sdev->dmab.area, curr_pos, size); - - /* 2. Set the interrupt. */ - if (intr_enable) - cl_skl_cldma_set_intr(sdev, true); - - /* 3. Set the SPB. */ - cl_skl_cldma_setup_spb(sdev, size, trigger); - - /* 4. Trigger the code loading stream. */ - if (trigger) - cl_skl_cldma_stream_run(sdev, true); -} - -static int -cl_skl_cldma_copy_to_buf(struct snd_sof_dev *sdev, const void *bin, - u32 total_size, u32 bufsize) -{ - unsigned int bytes_left = total_size; - const u8 *curr_pos = (u8 *)bin; - - if (total_size <= 0) - return -EINVAL; - - while (bytes_left > 0) { - - if (bytes_left > bufsize) { - - dev_dbg(sdev->dev, "cldma copy 0x%x bytes\n", - bufsize); - - cl_skl_cldma_fill_buffer(sdev, bufsize, - curr_pos, true, true); - - bytes_left -= bufsize; - curr_pos += bufsize; - } else { - - dev_dbg(sdev->dev, "cldma copy 0x%x bytes\n", - bytes_left); - - cl_skl_cldma_set_intr(sdev, false); - cl_skl_cldma_fill_buffer(sdev, bytes_left, - curr_pos, false, false); - return 0; - } - } - - return bytes_left; -} - -static int cl_copy_fw_skl(struct snd_sof_dev *sdev) -{ - struct snd_sof_pdata *plat_data = sdev->pdata; - const struct firmware *fw = plat_data->fw; - unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE; - unsigned int status; - int ret = 0; - - dev_dbg(sdev->dev, "firmware size: 0x%zx buffer size 0x%x\n", fw->size, - bufsize); - - ret = cl_skl_cldma_copy_to_buf(sdev, fw->data, fw->size, bufsize); - if (ret < 0) { - dev_err(sdev->dev, "error: fw copy failed %d\n", ret); - return ret; - } - - ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, - HDA_ADSP_FW_STATUS_SKL, status, - ((status & HDA_DSP_ROM_STS_MASK) - == HDA_DSP_ROM_FW_FW_LOADED), - HDA_DSP_REG_POLL_INTERVAL_US, - HDA_DSP_BASEFW_TIMEOUT_US); - if (ret < 0) - dev_err(sdev->dev, "error: firmware transfer timeout!"); - - cl_skl_cldma_stream_run(sdev, false); - cl_cleanup_skl(sdev); - - return ret; -} - -int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev) -{ - int ret; - - ret = cl_dsp_init_skl(sdev); - - /* retry enabling core and ROM load. seemed to help */ - if (ret < 0) { - ret = cl_dsp_init_skl(sdev); - if (ret < 0) { - dev_err(sdev->dev, "error: Error code=0x%x: FW status=0x%x\n", - snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_ADSP_ERROR_CODE_SKL), - snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_ADSP_FW_STATUS_SKL)); - dev_err(sdev->dev, "error: Core En/ROM load fail:%d\n", ret); - goto irq_err; - } - } - - dev_dbg(sdev->dev, "ROM init successful\n"); - - /* init for booting wait */ - init_waitqueue_head(&sdev->boot_wait); - sdev->boot_complete = false; - - /* - * at this point DSP ROM has been initialized and should - * be ready for code loading and firmware boot - */ - ret = cl_copy_fw_skl(sdev); - if (ret < 0) { - dev_err(sdev->dev, "error: load firmware failed : %d\n", ret); - goto irq_err; - } - - dev_dbg(sdev->dev, "Firmware download successful, booting...\n"); - - return ret; - -irq_err: - hda_dsp_dump_skl(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); - - /* power down DSP */ - hda_dsp_core_reset_power_down(sdev, HDA_DSP_CORE_MASK(0)); - cl_cleanup_skl(sdev); - - dev_err(sdev->dev, "error: load fw failed err: %d\n", ret); - return ret; -} diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index ffaf394fb7403d..455046612b9494 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -61,7 +61,6 @@ #define SOF_HDA_PP_CAP_ID 0x3 #define SOF_HDA_REG_PP_PPCH 0x10 #define SOF_HDA_REG_PP_PPCTL 0x04 -#define SOF_HDA_REG_PP_PPSTS 0x08 #define SOF_HDA_PPCTL_PIE BIT(31) #define SOF_HDA_PPCTL_GPROCEN BIT(30) From ba9115474c2c6e5425173f13190cd793fef6c0fb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 8 May 2019 15:02:16 -0500 Subject: [PATCH 1448/1995] ASoC: SOF: remove build support for Haswell This is not upstream and not used, remove. The code can still be found on the archive/compressed-hsw-skl-kbl-spi-20190508 branch on GitHub Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/Kconfig | 17 ----------------- sound/soc/sof/intel/Makefile | 2 -- 2 files changed, 19 deletions(-) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 0001217db17ead..32ee0fabab9253 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -11,7 +11,6 @@ if SND_SOC_SOF_INTEL_TOPLEVEL config SND_SOC_SOF_INTEL_ACPI tristate select SND_SOC_SOF_BAYTRAIL if SND_SOC_SOF_BAYTRAIL_SUPPORT - select SND_SOC_SOF_HASWELL if SND_SOC_SOF_HASWELL_SUPPORT select SND_SOC_SOF_BROADWELL if SND_SOC_SOF_BROADWELL_SUPPORT help This option is not user-selectable but automagically handled by @@ -70,22 +69,6 @@ config SND_SOC_SOF_BAYTRAIL This option is not user-selectable but automagically handled by 'select' statements at a higher level -config SND_SOC_SOF_HASWELL_SUPPORT - bool "SOF support for Haswell" - help - This adds support for Sound Open Firmware for Intel(R) platforms - using the Haswell processors. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_SOF_HASWELL - tristate - select SND_SOC_SOF_INTEL_COMMON - select SND_SOC_SOF_INTEL_HIFI_EP_IPC - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level - config SND_SOC_SOF_BROADWELL_SUPPORT bool "SOF support for Broadwell" help diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index 0ba9c9e8b8e73c..587b91bb18b019 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -3,7 +3,6 @@ ccflags-y += -DDEBUG snd-sof-intel-byt-objs := byt.o -snd-sof-intel-hsw-objs := hsw.o snd-sof-intel-bdw-objs := bdw.o snd-sof-intel-ipc-objs := intel-ipc.o @@ -16,7 +15,6 @@ snd-sof-intel-hda-common-objs := hda.o hda-loader.o hda-stream.o hda-trace.o \ snd-sof-intel-hda-objs := hda-codec.o obj-$(CONFIG_SND_SOC_SOF_INTEL_ATOM_HIFI_EP) += snd-sof-intel-byt.o -obj-$(CONFIG_SND_SOC_SOF_HASWELL) += snd-sof-intel-hsw.o obj-$(CONFIG_SND_SOC_SOF_BROADWELL) += snd-sof-intel-bdw.o obj-$(CONFIG_SND_SOC_SOF_INTEL_HIFI_EP_IPC) += snd-sof-intel-ipc.o obj-$(CONFIG_SND_SOC_SOF_HDA_COMMON) += snd-sof-intel-hda-common.o From 299ff82d38b3679d738ac0ab0db29fe01b51abf5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 8 May 2019 15:03:44 -0500 Subject: [PATCH 1449/1995] ASoC: SOF: remove Haswell DSP support This is not upstream and not used, remove. The code can still be found on the archive/compressed-hsw-skl-kbl-spi-20190508 branch on GitHub Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hsw.c | 714 -------------------------------------- 1 file changed, 714 deletions(-) delete mode 100644 sound/soc/sof/intel/hsw.c diff --git a/sound/soc/sof/intel/hsw.c b/sound/soc/sof/intel/hsw.c deleted file mode 100644 index 5389d55d07a228..00000000000000 --- a/sound/soc/sof/intel/hsw.c +++ /dev/null @@ -1,714 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) -// -// This file is provided under a dual BSD/GPLv2 license. When using or -// redistributing this file, you may do so under either license. -// -// Copyright(c) 2018 Intel Corporation. All rights reserved. -// -// Author: Liam Girdwood -// - -/* - * Hardware interface for audio DSP on Haswell - */ - -#include -#include -#include -#include "../ops.h" -#include "shim.h" - -/* BARs */ -#define HSW_DSP_BAR 0 -#define HSW_PCI_BAR 1 - -/* - * Debug - */ - -/* DSP memories for HSW */ -#define IRAM_OFFSET 0x80000 -#define HSW_IRAM_SIZE (10 * 32 * 1024) -#define DRAM_OFFSET 0x00000 -#define HSW_DRAM_SIZE (16 * 32 * 1024) -#define SHIM_OFFSET 0xE7000 -#define SHIM_SIZE 0x100 -#define MBOX_OFFSET 0x7E000 -#define MBOX_SIZE 0x1000 -#define MBOX_DUMP_SIZE 0x30 -#define EXCEPT_OFFSET 0x800 - -/* DSP peripherals */ -#define DMAC0_OFFSET 0xFE000 -#define DMAC1_OFFSET 0xFF000 -#define DMAC_SIZE 0x420 -#define SSP0_OFFSET 0xFC000 -#define SSP1_OFFSET 0xFD000 -#define SSP_SIZE 0x100 - -#define HSW_STACK_DUMP_SIZE 32 - -#define HSW_PANIC_OFFSET(x) ((x) & 0xFFFF) - -static const struct snd_sof_debugfs_map hsw_debugfs[] = { - {"dmac0", HSW_DSP_BAR, DMAC0_OFFSET, DMAC_SIZE, - SOF_DEBUGFS_ACCESS_ALWAYS}, - {"dmac1", HSW_DSP_BAR, DMAC1_OFFSET, DMAC_SIZE, - SOF_DEBUGFS_ACCESS_ALWAYS}, - {"ssp0", HSW_DSP_BAR, SSP0_OFFSET, SSP_SIZE, - SOF_DEBUGFS_ACCESS_ALWAYS}, - {"ssp1", HSW_DSP_BAR, SSP1_OFFSET, SSP_SIZE, - SOF_DEBUGFS_ACCESS_ALWAYS}, - {"iram", HSW_DSP_BAR, IRAM_OFFSET, HSW_IRAM_SIZE, - SOF_DEBUGFS_ACCESS_D0_ONLY}, - {"dram", HSW_DSP_BAR, DRAM_OFFSET, HSW_DRAM_SIZE, - SOF_DEBUGFS_ACCESS_D0_ONLY}, - {"shim", HSW_DSP_BAR, SHIM_OFFSET, SHIM_SIZE, - SOF_DEBUGFS_ACCESS_ALWAYS}, -}; - -static void hsw_host_done(struct snd_sof_dev *sdev); -static void hsw_dsp_done(struct snd_sof_dev *sdev); -static void hsw_get_reply(struct snd_sof_dev *sdev); - -/* - * DSP Control. - */ - -static int hsw_run(struct snd_sof_dev *sdev) -{ - /* set opportunistic mode on engine 0,1 for all channels */ - snd_sof_dsp_update_bits(sdev, HSW_DSP_BAR, SHIM_HMDC, - SHIM_HMDC_HDDA_E0_ALLCH | - SHIM_HMDC_HDDA_E1_ALLCH, 0); - - /* set DSP to RUN */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_CSR, - SHIM_CSR_STALL, 0x0); - - /* return init core mask */ - return 1; -} - -static int hsw_reset(struct snd_sof_dev *sdev) -{ - /* put DSP into reset and stall */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_CSR, - SHIM_CSR_RST | SHIM_CSR_STALL, - SHIM_CSR_RST | SHIM_CSR_STALL); - - /* keep in reset for 10ms */ - mdelay(10); - - /* take DSP out of reset and keep stalled for FW loading */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_CSR, - SHIM_CSR_RST | SHIM_CSR_STALL, - SHIM_CSR_STALL); - - return 0; //TODO: Fix return value -} - -static int hsw_set_dsp_D0(struct snd_sof_dev *sdev) -{ - int tries = 10; - u32 reg; - - /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_PCI_BAR, PCI_VDRTCTL2, - PCI_VDRTCL2_DCLCGE | PCI_VDRTCL2_DTCGE, - 0); - - /* Disable D3PG (VDRTCTL0.D3PGD = 1) */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_PCI_BAR, PCI_VDRTCTL0, - PCI_VDRTCL0_D3PGD, PCI_VDRTCL0_D3PGD); - - /* Set D0 state */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_PCI_BAR, PCI_PMCS, - PCI_PMCS_PS_MASK, 0); - - /* check that ADSP shim is enabled */ - while (tries--) { - reg = readl(sdev->bar[HSW_PCI_BAR] + PCI_PMCS) - & PCI_PMCS_PS_MASK; - if (reg == 0) - goto finish; - - msleep(20); - } - - return -ENODEV; - -finish: - /* - * select SSP1 19.2MHz base clock, SSP clock 0, - * turn off Low Power Clock - */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_CSR, - SHIM_CSR_S1IOCS | SHIM_CSR_SBCS1 | - SHIM_CSR_LPCS, 0x0); - - /* stall DSP core, set clk to 192/96Mhz */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, - SHIM_CSR, SHIM_CSR_STALL | - SHIM_CSR_DCS_MASK, - SHIM_CSR_STALL | SHIM_CSR_DCS(4)); - - /* Set 24MHz MCLK, prevent local clock gating, enable SSP0 clock */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_CLKCTL, - SHIM_CLKCTL_MASK | SHIM_CLKCTL_DCPLCG | - SHIM_CLKCTL_SCOE0, - SHIM_CLKCTL_MASK | SHIM_CLKCTL_DCPLCG | - SHIM_CLKCTL_SCOE0); - - /* Stall and reset core, set CSR */ - hsw_reset(sdev); - - /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_PCI_BAR, PCI_VDRTCTL2, - PCI_VDRTCL2_DCLCGE | - PCI_VDRTCL2_DTCGE, - PCI_VDRTCL2_DCLCGE | - PCI_VDRTCL2_DTCGE); - - usleep_range(50, 55); - - /* switch on audio PLL */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_PCI_BAR, PCI_VDRTCTL2, - PCI_VDRTCL2_APLLSE_MASK, 0); - - /* - * set default power gating control, enable power gating control for - * all blocks. that is, can't be accessed, please enable each block - * before accessing. - */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_PCI_BAR, PCI_VDRTCTL0, - PCI_VDRTCL0_DSRAMPGE_MASK | - PCI_VDRTCL0_ISRAMPGE_MASK, 0); - - /* disable DMA finish function for SSP0 & SSP1 */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_CSR2, - SHIM_CSR2_SDFD_SSP1, - SHIM_CSR2_SDFD_SSP1); - - /* set on-demond mode on engine 0,1 for all channels */ - snd_sof_dsp_update_bits(sdev, HSW_DSP_BAR, SHIM_HMDC, - SHIM_HMDC_HDDA_E0_ALLCH | - SHIM_HMDC_HDDA_E1_ALLCH, - SHIM_HMDC_HDDA_E0_ALLCH | - SHIM_HMDC_HDDA_E1_ALLCH); - - /* Enable Interrupt from both sides */ - snd_sof_dsp_update_bits(sdev, HSW_DSP_BAR, SHIM_IMRX, - (SHIM_IMRX_BUSY | SHIM_IMRX_DONE), 0x0); - snd_sof_dsp_update_bits(sdev, HSW_DSP_BAR, SHIM_IMRD, - (SHIM_IMRD_DONE | SHIM_IMRD_BUSY | - SHIM_IMRD_SSP0 | SHIM_IMRD_DMAC), 0x0); - - /* clear IPC registers */ - snd_sof_dsp_write(sdev, HSW_DSP_BAR, SHIM_IPCX, 0x0); - snd_sof_dsp_write(sdev, HSW_DSP_BAR, SHIM_IPCD, 0x0); - snd_sof_dsp_write(sdev, HSW_DSP_BAR, 0x80, 0x6); - snd_sof_dsp_write(sdev, HSW_DSP_BAR, 0xe0, 0x300a); - - return 0; -} - -static void hsw_get_registers(struct snd_sof_dev *sdev, - struct sof_ipc_dsp_oops_xtensa *xoops, - struct sof_ipc_panic_info *panic_info, - u32 *stack, size_t stack_words) -{ - /* first read regsisters */ - sof_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); - - /* then get panic info */ - sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), - panic_info, sizeof(*panic_info)); - - /* then get the stack */ - sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + - sizeof(*panic_info), stack, - stack_words * sizeof(u32)); -} - -static void hsw_dump(struct snd_sof_dev *sdev, u32 flags) -{ - struct sof_ipc_dsp_oops_xtensa xoops; - struct sof_ipc_panic_info panic_info; - u32 stack[HSW_STACK_DUMP_SIZE]; - u32 status, panic; - - /* now try generic SOF status messages */ - status = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_IPCD); - panic = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_IPCX); - hsw_get_registers(sdev, &xoops, &panic_info, stack, - HSW_STACK_DUMP_SIZE); - snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, - HSW_STACK_DUMP_SIZE); -} - -/* - * IPC Doorbell IRQ handler and thread. - */ - -static irqreturn_t hsw_irq_handler(int irq, void *context) -{ - struct snd_sof_dev *sdev = context; - u32 isr; - int ret = IRQ_NONE; - - spin_lock(&sdev->hw_lock); - - /* Interrupt arrived, check src */ - isr = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_ISRX); - if (isr & (SHIM_ISRX_DONE | SHIM_ISRX_BUSY)) - ret = IRQ_WAKE_THREAD; - - spin_unlock(&sdev->hw_lock); - return ret; -} - -static irqreturn_t hsw_irq_thread(int irq, void *context) -{ - struct snd_sof_dev *sdev = context; - u32 ipcx, ipcd, imrx; - - imrx = snd_sof_dsp_read64(sdev, HSW_DSP_BAR, SHIM_IMRX); - ipcx = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_IPCX); - - /* reply message from DSP */ - if (ipcx & SHIM_IPCX_DONE && - !(imrx & SHIM_IMRX_DONE)) { - /* Mask Done interrupt before return */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, - SHIM_IMRX, SHIM_IMRX_DONE, - SHIM_IMRX_DONE); - - /* - * handle immediate reply from DSP core. If the msg is - * found, set done bit in cmd_done which is called at the - * end of message processing function, else set it here - * because the done bit can't be set in cmd_done function - * which is triggered by msg - */ - hsw_get_reply(sdev); - snd_sof_ipc_reply(sdev, ipcx); - - hsw_dsp_done(sdev); - } - - ipcd = snd_sof_dsp_read(sdev, HSW_DSP_BAR, SHIM_IPCD); - - /* new message from DSP */ - if (ipcd & SHIM_IPCD_BUSY && - !(imrx & SHIM_IMRX_BUSY)) { - /* Mask Busy interrupt before return */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, - SHIM_IMRX, SHIM_IMRX_BUSY, - SHIM_IMRX_BUSY); - - /* Handle messages from DSP Core */ - if ((ipcd & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { - snd_sof_dsp_panic(sdev, HSW_PANIC_OFFSET(ipcx) + - MBOX_OFFSET); - } else { - snd_sof_ipc_msgs_rx(sdev); - } - - hsw_host_done(sdev); - } - - return IRQ_HANDLED; -} - -/* - * IPC Firmware ready. - */ -static void hsw_get_windows(struct snd_sof_dev *sdev) -{ - struct sof_ipc_window_elem *elem; - u32 outbox_offset = 0; - u32 stream_offset = 0; - u32 inbox_offset = 0; - u32 outbox_size = 0; - u32 stream_size = 0; - u32 inbox_size = 0; - int i; - - if (!sdev->info_window) { - dev_err(sdev->dev, "error: have no window info\n"); - return; - } - - for (i = 0; i < sdev->info_window->num_windows; i++) { - elem = &sdev->info_window->window[i]; - - switch (elem->type) { - case SOF_IPC_REGION_UPBOX: - inbox_offset = elem->offset + MBOX_OFFSET; - inbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[HSW_DSP_BAR] + - inbox_offset, - elem->size, "inbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DOWNBOX: - outbox_offset = elem->offset + MBOX_OFFSET; - outbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[HSW_DSP_BAR] + - outbox_offset, - elem->size, "outbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_io_item(sdev, - sdev->bar[HSW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "etrace", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_io_item(sdev, - sdev->bar[HSW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "debug", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_STREAM: - stream_offset = elem->offset + MBOX_OFFSET; - stream_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[HSW_DSP_BAR] + - stream_offset, - elem->size, "stream", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_REGS: - snd_sof_debugfs_io_item(sdev, - sdev->bar[HSW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "regs", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_EXCEPTION: - sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; - snd_sof_debugfs_io_item(sdev, - sdev->bar[HSW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "exception", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - default: - dev_err(sdev->dev, "error: get illegal window info\n"); - return; - } - } - - if (outbox_size == 0 || inbox_size == 0) { - dev_err(sdev->dev, "error: get illegal mailbox window\n"); - return; - } - - snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, - outbox_offset, outbox_size); - sdev->stream_box.offset = stream_offset; - sdev->stream_box.size = stream_size; - - dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", - inbox_offset, inbox_size); - dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", - outbox_offset, outbox_size); - dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", - stream_offset, stream_size); -} - -/* check for ABI compatibility and create memory windows on first boot */ -static int hsw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) -{ - struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; - u32 offset; - int ret; - - /* mailbox must be on 4k boundary */ - offset = MBOX_OFFSET; - - dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset %d\n", - msg_id, offset); - - /* no need to re-check version/ABI for subsequent boots */ - if (!sdev->first_boot) - return 0; - - /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, - sizeof(*fw_ready)); - - snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, - fw_ready->dspbox_size, - fw_ready->hostbox_offset, - fw_ready->hostbox_size); - - /* make sure ABI version is compatible */ - ret = snd_sof_ipc_valid(sdev); - if (ret < 0) - return ret; - - /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + - sizeof(struct sof_ipc_fw_ready)); - - hsw_get_windows(sdev); - - return 0; -} - -/* - * IPC Mailbox IO - */ - -static int hsw_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) -{ - /* send the message */ - sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, - msg->msg_size); - snd_sof_dsp_write(sdev, HSW_DSP_BAR, SHIM_IPCX, SHIM_IPCX_BUSY); - - return 0; -} - -static void hsw_get_reply(struct snd_sof_dev *sdev) -{ - struct snd_sof_ipc_msg *msg = sdev->msg; - struct sof_ipc_reply reply; - unsigned long flags; - int ret = 0; - - /* - * Sometimes, there is unexpected reply ipc arriving. The reply - * ipc belongs to none of the ipcs sent from driver. - * In this case, the driver must ignore the ipc. - */ - if (!msg) { - dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); - return; - } - - spin_lock_irqsave(&sdev->ipc_lock, flags); - - /* get reply */ - sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); - if (reply.error < 0) { - memcpy(msg->reply_data, &reply, sizeof(reply)); - ret = reply.error; - } else { - /* reply correct size ? */ - if (reply.hdr.size != msg->reply_size) { - dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", - msg->reply_size, reply.hdr.size); - ret = -EINVAL; - } - - /* read the message */ - if (msg->reply_size > 0) - sof_mailbox_read(sdev, sdev->host_box.offset, - msg->reply_data, msg->reply_size); - } - - msg->reply_error = ret; - - spin_unlock_irqrestore(&sdev->ipc_lock, flags); -} - -static void hsw_host_done(struct snd_sof_dev *sdev) -{ - /* clear BUSY bit and set DONE bit - accept new messages */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IPCD, - SHIM_IPCD_BUSY | SHIM_IPCD_DONE, - SHIM_IPCD_DONE); - - /* unmask busy interrupt */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_BUSY, 0); -} - -static void hsw_dsp_done(struct snd_sof_dev *sdev) -{ - /* clear DONE bit - tell DSP we have completed */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IPCX, - SHIM_IPCX_DONE, 0); - - /* unmask Done interrupt */ - snd_sof_dsp_update_bits_unlocked(sdev, HSW_DSP_BAR, SHIM_IMRX, - SHIM_IMRX_DONE, 0); -} - -/* - * Probe and remove. - */ -static int hsw_probe(struct snd_sof_dev *sdev) -{ - struct snd_sof_pdata *pdata = sdev->pdata; - const struct sof_dev_desc *desc = pdata->desc; - struct platform_device *pdev = - container_of(sdev->dev, struct platform_device, dev); - struct resource *mmio; - u32 base, size; - int ret; - - /* LPE base */ - mmio = platform_get_resource(pdev, IORESOURCE_MEM, - desc->resindex_lpe_base); - if (mmio) { - base = mmio->start; - size = resource_size(mmio); - } else { - dev_err(sdev->dev, "error: failed to get LPE base at idx %d\n", - desc->resindex_lpe_base); - return -EINVAL; - } - - dev_dbg(sdev->dev, "LPE PHY base at 0x%x size 0x%x", base, size); - sdev->bar[HSW_DSP_BAR] = devm_ioremap(sdev->dev, base, size); - if (!sdev->bar[HSW_DSP_BAR]) { - dev_err(sdev->dev, - "error: failed to ioremap LPE base 0x%x size 0x%x\n", - base, size); - return -ENODEV; - } - dev_dbg(sdev->dev, "LPE VADDR %p\n", sdev->bar[HSW_DSP_BAR]); - - /* TODO: add offsets */ - sdev->mmio_bar = HSW_DSP_BAR; - sdev->mailbox_bar = HSW_DSP_BAR; - - /* PCI base */ - mmio = platform_get_resource(pdev, IORESOURCE_MEM, - desc->resindex_pcicfg_base); - if (mmio) { - base = mmio->start; - size = resource_size(mmio); - } else { - dev_err(sdev->dev, "error: failed to get PCI base at idx %d\n", - desc->resindex_pcicfg_base); - return -ENODEV; - } - - dev_dbg(sdev->dev, "PCI base at 0x%x size 0x%x", base, size); - sdev->bar[HSW_PCI_BAR] = devm_ioremap(sdev->dev, base, size); - if (!sdev->bar[HSW_PCI_BAR]) { - dev_err(sdev->dev, - "error: failed to ioremap PCI base 0x%x size 0x%x\n", - base, size); - return -ENODEV; - } - dev_dbg(sdev->dev, "PCI VADDR %p\n", sdev->bar[HSW_PCI_BAR]); - - /* register our IRQ */ - sdev->ipc_irq = platform_get_irq(pdev, desc->irqindex_host_ipc); - if (sdev->ipc_irq < 0) { - dev_err(sdev->dev, "error: failed to get IRQ at index %d\n", - desc->irqindex_host_ipc); - return sdev->ipc_irq; - } - - dev_dbg(sdev->dev, "using IRQ %d\n", sdev->ipc_irq); - ret = devm_request_threaded_irq(sdev->dev, sdev->ipc_irq, - hsw_irq_handler, hsw_irq_thread, - 0, "AudioDSP", sdev); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to register IRQ %d\n", - sdev->ipc_irq); - return ret; - } - - /* enable the DSP SHIM */ - ret = hsw_set_dsp_D0(sdev); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to set DSP D0\n"); - return ret; - } - - /* DSP DMA can only access low 31 bits of host memory */ - ret = dma_coerce_mask_and_coherent(sdev->dev, DMA_BIT_MASK(31)); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to set DMA mask %d\n", ret); - return ret; - } - - /* set default mailbox */ - snd_sof_dsp_mailbox_init(sdev, MBOX_OFFSET, MBOX_SIZE, 0, 0); - - return ret; -} - -/* Haswell DAIs */ -static struct snd_soc_dai_driver hsw_dai[] = { -{ - .name = "ssp0-port", -}, -{ - .name = "ssp1-port", -}, -}; - -/* haswell ops */ -const struct snd_sof_dsp_ops sof_hsw_ops = { - /*Device init */ - .probe = hsw_probe, - - /* DSP Core Control */ - .run = hsw_run, - .reset = hsw_reset, - - /* Register IO */ - .write = sof_io_write, - .read = sof_io_read, - .write64 = sof_io_write64, - .read64 = sof_io_read64, - - /* Block IO */ - .block_read = sof_block_read, - .block_write = sof_block_write, - - /* ipc */ - .send_msg = hsw_send_msg, - .fw_ready = hsw_fw_ready, - - .ipc_msg_data = intel_ipc_msg_data, - .ipc_pcm_params = intel_ipc_pcm_params, - - /* debug */ - .debug_map = hsw_debugfs, - .debug_map_count = ARRAY_SIZE(hsw_debugfs), - .dbg_dump = hsw_dump, - - /* stream callbacks */ - .pcm_open = intel_pcm_open, - .pcm_close = intel_pcm_close, - - /* Module loading */ - .load_module = snd_sof_parse_module_memcpy, - - /*Firmware loading */ - .load_firmware = snd_sof_load_firmware_memcpy, - - /* DAI drivers */ - .drv = hsw_dai, - .num_drv = ARRAY_SIZE(hsw_dai) - -}; -EXPORT_SYMBOL(sof_hsw_ops); - -const struct sof_intel_dsp_desc hsw_chip_info = { - .cores_num = 1, - .cores_mask = 1, -}; -EXPORT_SYMBOL(hsw_chip_info); - -MODULE_LICENSE("Dual BSD/GPL"); From ebdcc3c416d33aeffd11418b218a5b99d96e3c1e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 8 May 2019 15:06:15 -0500 Subject: [PATCH 1450/1995] ASoC: Intel: remove HSW machine driver build support for SOF This is not upstream and not used for now, remove. The code can still be found on the archive/compressed-hsw-skl-kbl-spi-20190508 branch on GitHub Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index ccdf69acd9f7a1..19e67e2b3fc379 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -12,7 +12,7 @@ menuconfig SND_SOC_INTEL_MACH if SND_SOC_INTEL_MACH -if SND_SOC_INTEL_HASWELL || SND_SOC_SOF_HASWELL +if SND_SOC_INTEL_HASWELL config SND_SOC_INTEL_HASWELL_MACH tristate "Haswell Lynxpoint" @@ -24,7 +24,7 @@ config SND_SOC_INTEL_HASWELL_MACH Say Y or m if you have such a device. If unsure select "N". -endif ## SND_SOC_INTEL_HASWELL || SND_SOC_SOF_HASWELL +endif ## SND_SOC_INTEL_HASWELL if SND_SOC_INTEL_HASWELL || SND_SOC_SOF_BROADWELL From 8663570d25bf5f60c8bb84aba39ba89046b35524 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 8 May 2019 15:04:36 -0500 Subject: [PATCH 1451/1995] ASoC: Intel: remove Haswell machine driver support for SOF This is not upstream and not used for now, remove. The code can still be found on the archive/compressed-hsw-skl-kbl-spi-20190508 branch on GitHub Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/haswell.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index 93eb691c9d494a..971226d420420b 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -86,7 +86,6 @@ static const struct snd_soc_ops haswell_rt5640_ops = { .hw_params = haswell_rt5640_hw_params, }; -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL) static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); @@ -105,7 +104,6 @@ static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd) return 0; } -#endif static struct snd_soc_dai_link haswell_rt5640_dais[] = { /* Front End DAI links */ @@ -117,9 +115,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = { .dynamic = 1, .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL) .init = haswell_rtd_init, -#endif .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, .dpcm_playback = 1, .dpcm_capture = 1, From 54be9ee957308ae09b5cd73db24bd5c2fc24a24f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 9 May 2019 13:54:22 -0500 Subject: [PATCH 1452/1995] ASoC: Intel: bxt_pcm512x: use acpi_dev_get_first_dev() Mirror changes in all other machine drivers, acpi_dev_get_first_name() was deprecated and is now removed. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bxt_pcm512x.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/bxt_pcm512x.c b/sound/soc/intel/boards/bxt_pcm512x.c index c0d6e8a9d7943b..848b83729ac55d 100644 --- a/sound/soc/intel/boards/bxt_pcm512x.c +++ b/sound/soc/intel/boards/bxt_pcm512x.c @@ -253,7 +253,7 @@ static int bxt_pcm512x_probe(struct platform_device *pdev) struct snd_soc_card *card; struct snd_soc_acpi_mach *mach; struct bxt_card_private *ctx; - const char *i2c_name = NULL; + struct acpi_device *adev; int dai_index = 0; int ret_val = 0; int i; @@ -284,10 +284,11 @@ static int bxt_pcm512x_probe(struct platform_device *pdev) } /* fixup codec name based on HID */ - i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); - if (i2c_name) { + adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); + if (adev) { snprintf(codec_name, sizeof(codec_name), - "%s%s", "i2c-", i2c_name); + "%s%s", "i2c-", acpi_dev_name(adev)); + put_device(&adev->dev); dailink[dai_index].codec_name = codec_name; } From 0511365df473d01c22cfc6887b6e64a24d0595f4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 9 May 2019 13:55:45 -0500 Subject: [PATCH 1453/1995] ASoC: Intel: bxt_wm8804: use acpi_dev_get_first_dev() Mirror changes in all other machine drivers, acpi_dev_get_first_name() was deprecated and is now removed. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bxt_wm8804.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/bxt_wm8804.c b/sound/soc/intel/boards/bxt_wm8804.c index 2cf51115482ef8..0506ab7c43a740 100644 --- a/sound/soc/intel/boards/bxt_wm8804.c +++ b/sound/soc/intel/boards/bxt_wm8804.c @@ -214,7 +214,7 @@ static int bxt_wm8804_probe(struct platform_device *pdev) { struct snd_soc_card *card; struct snd_soc_acpi_mach *mach; - const char *i2c_name = NULL; + struct acpi_device *adev; int dai_index = 0; int ret_val = 0; int i; @@ -232,10 +232,11 @@ static int bxt_wm8804_probe(struct platform_device *pdev) } /* fixup codec name based on HID */ - i2c_name = acpi_dev_get_first_match_name(mach->id, NULL, -1); - if (i2c_name) { + adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); + if (adev) { snprintf(codec_name, sizeof(codec_name), - "%s%s", "i2c-", i2c_name); + "%s%s", "i2c-", acpi_dev_name(adev)); + put_device(&adev->dev); dailink[dai_index].codec_name = codec_name; } From 66aa6396844aca0869337ffefcd354a5adb08f85 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 6 May 2019 12:01:40 -0700 Subject: [PATCH 1454/1995] ASoC: sound/soc/sof/: fix kconfig dependency warning Fix kconfig warning for unmet dependency for IOSF_MBI when PCI is not set/enabled. Fixes this warning: WARNING: unmet direct dependencies detected for IOSF_MBI Depends on [n]: PCI [=n] Selected by [y]: - SND_SOC_SOF_ACPI [=y] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && SND_SOC_SOF_TOPLEVEL [=y] && (ACPI [=y] || COMPILE_TEST [=n]) && X86 [=y] Signed-off-by: Randy Dunlap Cc: Liam Girdwood Cc: Mark Brown Cc: alsa-devel@alsa-project.org Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 4c88519133bdd802fb0df4707b5a8c066af7154d) --- sound/soc/sof/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index a1a9ffe605dc66..b204c65698f9f7 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -28,7 +28,7 @@ config SND_SOC_SOF_ACPI select SND_SOC_ACPI if ACPI select SND_SOC_SOF_OPTIONS select SND_SOC_SOF_INTEL_ACPI if SND_SOC_SOF_INTEL_TOPLEVEL - select IOSF_MBI if X86 + select IOSF_MBI if X86 && PCI help This adds support for ACPI enumeration. This option is required to enable Intel Haswell/Broadwell/Baytrail/Cherrytrail devices From 6b071479cf1aeecbd509a3837ebb9e12ff4af8f7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 6 May 2019 17:02:23 +0200 Subject: [PATCH 1455/1995] ASoC: SOF: Fix a compile warning with CONFIG_PCI=n MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A trivial fix for the randconfig build error: sound/soc/sof/ops.c:20:6: warning: ‘ret’ is used uninitialized in this function [-Wuninitialized] Fixes: d1d95fcb63e3 ("ASoC: SOF: Add DSP HW abstraction operations") Signed-off-by: Takashi Iwai Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit c41d384c39f17ffb5326531da2374a1ab5859403) --- sound/soc/sof/ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/ops.c b/sound/soc/sof/ops.c index 80f907740b82ce..7a27c3b719e772 100644 --- a/sound/soc/sof/ops.c +++ b/sound/soc/sof/ops.c @@ -17,7 +17,7 @@ bool snd_sof_pci_update_bits_unlocked(struct snd_sof_dev *sdev, u32 offset, { struct pci_dev *pci = to_pci_dev(sdev->dev); unsigned int old, new; - u32 ret; + u32 ret = 0; pci_read_config_dword(pci, offset, &ret); old = ret; From 929845f8a09b7b6e1ef10fae79acc436f693ca25 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 7 May 2019 21:39:10 +0200 Subject: [PATCH 1456/1995] ASoC: SOF: Propagate sof_get_ctrl_copy_params() error properly This fixes a compile warning below by properly handling the error code from sof_get_ctrl_copy_params(): include/linux/kernel.h:843:43: warning: 'sparams.pl_size' may be used uninitialized in this function [-Wmaybe-uninitialized] sound/soc/sof/ipc.c:639:34: note: 'sparams.pl_size' was declared here The function returns an error before setting sparams.pl_size, so it'd assign an uninitialized value at a later point. Fixes: 53e0c72d98ba ("ASoC: SOF: Add support for IPC IO between DSP and Host") Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 54d198d5019dd98b9bcb9099a389608d7e2cccad) --- sound/soc/sof/ipc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 0e8d1a79ceab39..894e68cbd69d5d 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -567,7 +567,7 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev, size_t offset = 0; size_t msg_bytes; size_t pl_size; - int err = 0; + int err; int i; /* allocate max ipc size because we have at least one */ @@ -576,9 +576,13 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev, return -ENOMEM; if (send) - sof_get_ctrl_copy_params(cdata->type, cdata, partdata, sparams); + err = sof_get_ctrl_copy_params(cdata->type, cdata, partdata, + sparams); else - sof_get_ctrl_copy_params(cdata->type, partdata, cdata, sparams); + err = sof_get_ctrl_copy_params(cdata->type, partdata, cdata, + sparams); + if (err < 0) + return err; msg_bytes = sparams->msg_bytes; pl_size = sparams->pl_size; From bfaf649fffab035ab5a0abc92a2ba4870c8cb0d6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 May 2019 11:32:35 -0500 Subject: [PATCH 1457/1995] ASoC: SOF: xtensa: fix undefined references The SND_SOC_INTEL_COMMON Kconfig was removed months ago from SOF Kconfig files but is still selected instead of the correct SND_SOC_SOF_INTEL_COMMON kconfig which does select xtensa stuff, leading to the following errors. ld: sound/soc/sof/sof-acpi-dev.o:(.rodata+0x120): undefined reference to `sof_xtensa_arch_ops' ld: sound/soc/sof/sof-acpi-dev.o:(.rodata+0x180): undefined reference to `sof_xtensa_arch_ops' ld: sound/soc/sof/sof-acpi-dev.o:(.rodata+0x1e0): undefined reference to `sof_xtensa_arch_ops' Reported-by: kbuild test robot Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit 78989ff8aeaddc183237da558ee07deee35fbbbd) --- sound/soc/sof/intel/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 32ee0fabab9253..603e0db4f01281 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -36,7 +36,7 @@ config SND_SOC_SOF_INTEL_HIFI_EP_IPC config SND_SOC_SOF_INTEL_ATOM_HIFI_EP tristate - select SND_SOC_INTEL_COMMON + select SND_SOC_SOF_INTEL_COMMON select SND_SOC_SOF_INTEL_HIFI_EP_IPC help This option is not user-selectable but automagically handled by From 84bbcfc6756d13c6af1751b7c70944a66a418deb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 May 2019 11:32:36 -0500 Subject: [PATCH 1458/1995] ASoC: SOF: core: fix undefined nocodec reference The existing code mistakenly uses IS_ENABLED in C code instead of as in conditional compilation, leading to the following error: ld: sound/soc/sof/core.o: in function `sof_machine_check': sound/soc/sof/core.c:279: undefined reference to `sof_nocodec_setup' Fix by using #if !IS_ENABLED() Reported-by: kbuild test robot Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown (cherry picked from commit ce38a75089f70f6380fc63a5478a7659b4eb3f47) --- sound/soc/sof/core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 39cbd84ff9c8ca..5ddbfa8f1a2871 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -265,11 +265,10 @@ static int sof_machine_check(struct snd_sof_dev *sdev) if (plat_data->machine) return 0; - if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) { - dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); - return -ENODEV; - } - +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) + dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); + return -ENODEV; +#else /* fallback to nocodec mode */ dev_warn(sdev->dev, "No ASoC machine driver found - using nocodec\n"); machine = devm_kzalloc(sdev->dev, sizeof(*machine), GFP_KERNEL); @@ -284,6 +283,7 @@ static int sof_machine_check(struct snd_sof_dev *sdev) plat_data->machine = machine; return 0; +#endif } static int sof_probe_continue(struct snd_sof_dev *sdev) From bb3a356685312ad976003749b0339bdd0d57b544 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 8 May 2019 10:50:37 +0200 Subject: [PATCH 1459/1995] ASoC: SOF: Fix unused variable warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The recent fix for the build fix caused a couple of unused variable compiler warnings when CONFIG_SND_SOC_SOF_NOCODEC isn't set: sound/soc/sof/core.c:263:6: warning: unused variable ‘ret’ [-Wunused-variable] sound/soc/sof/core.c:262:28: warning: unused variable ‘machine’ [-Wunused-variable] Fix them by adding another ifdef. Fixes: ce38a75089f7 ("ASoC: SOF: core: fix undefined nocodec reference") Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown (cherry picked from commit 7f6647ced298d56027218e47619b7f0d925fc83e) --- sound/soc/sof/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 5ddbfa8f1a2871..32105e0fabe884 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -259,8 +259,10 @@ int snd_sof_create_page_table(struct snd_sof_dev *sdev, static int sof_machine_check(struct snd_sof_dev *sdev) { struct snd_sof_pdata *plat_data = sdev->pdata; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) struct snd_soc_acpi_mach *machine; int ret; +#endif if (plat_data->machine) return 0; From da2349e1c975cc92871b9c1656722556cda7225c Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 23 Apr 2019 10:44:59 -0700 Subject: [PATCH 1460/1995] ASoC: SOF: core: remove DSP after unregistering machine driver snd_sof_remove() disables the DSP and unmaps the DSP BAR. Removing topology after disabling the DSP results in a kernel panic while unloading the pipeline widget. This is because pipeline widget unload attempts to power down the core it is scheduled on by accessing the DSP registers. So, the suggested fix here is to unregister the machine driver first to remove the topology and then disable the DSP to avoid the situation described above. Note that the kernel panic only happens in cases where the HDaudio link is not managed by the hdac library, e.g. no codec or when HDMI is not supported. When the hdac library is used, snd_sof_remove() calls snd_hdac_ext_bus_device_remove() to remove the codec which unregisters the component driver thereby also removing the topology before the DSP is disabled. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 39cbd84ff9c8ca..fd1ed0ad47373a 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -482,7 +482,6 @@ int snd_sof_device_remove(struct device *dev) snd_sof_ipc_free(sdev); snd_sof_free_debug(sdev); snd_sof_free_trace(sdev); - snd_sof_remove(sdev); /* * Unregister machine driver. This will unbind the snd_card which @@ -492,6 +491,14 @@ int snd_sof_device_remove(struct device *dev) if (!IS_ERR_OR_NULL(pdata->pdev_mach)) platform_device_unregister(pdata->pdev_mach); + /* + * Unregistering the machine driver results in unloading the topology. + * Some widgets, ex: scheduler, attempt to power down the core they are + * scheduled on, when they are unloaded. Therefore, the DSP must be + * removed only after the topology has been unloaded. + */ + snd_sof_remove(sdev); + /* release firmware */ release_firmware(pdata->fw); pdata->fw = NULL; From f19ab80480b896abab1517f2a844a49d561e83d6 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Sun, 5 May 2019 23:07:19 -0700 Subject: [PATCH 1461/1995] ASoC: SOF: core: remove snd_soc_unregister_component in case of error No need to call snd_soc_unregister_component in case of error because the component device is resource-managed. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index fd1ed0ad47373a..b2cd4fd79d950e 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -380,7 +380,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) if (IS_ERR(plat_data->pdev_mach)) { ret = PTR_ERR(plat_data->pdev_mach); - goto comp_err; + goto fw_run_err; } dev_dbg(sdev->dev, "created machine %s\n", @@ -391,8 +391,6 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) return 0; -comp_err: - snd_soc_unregister_component(sdev->dev); fw_run_err: snd_sof_fw_unload(sdev); fw_load_err: From 8c5dcb01c128c7be82c01fe305483fe28ead63e7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 6 May 2019 15:39:31 -0500 Subject: [PATCH 1462/1995] ASoC: SOF: uapi: align comments with firmware files No functional change, just mirror firmware comment changes Signed-off-by: Pierre-Louis Bossart --- include/sound/sof/topology.h | 4 ++-- include/sound/sof/trace.h | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h index 46b2a7e63167bb..4afed7f1c6b21a 100644 --- a/include/sound/sof/topology.h +++ b/include/sound/sof/topology.h @@ -83,9 +83,9 @@ struct sof_ipc_buffer { struct sof_ipc_comp_config { struct sof_ipc_cmd_hdr hdr; uint32_t periods_sink; /**< 0 means variable */ - uint32_t periods_source; /**< 0 means variable */ + uint32_t periods_source;/**< 0 means variable */ uint32_t reserved1; /**< reserved */ - uint32_t frame_fmt; /**< SOF_IPC_FRAME_ */ + uint32_t frame_fmt; /**< SOF_IPC_FRAME_ */ uint32_t xrun_action; /* reserved for future use */ diff --git a/include/sound/sof/trace.h b/include/sound/sof/trace.h index 7d211f319a92e2..fdb30078448fd1 100644 --- a/include/sound/sof/trace.h +++ b/include/sound/sof/trace.h @@ -56,7 +56,9 @@ struct sof_ipc_dma_trace_posn { #define SOF_IPC_PANIC_WFI (SOF_IPC_PANIC_MAGIC | 0xa) #define SOF_IPC_PANIC_ASSERT (SOF_IPC_PANIC_MAGIC | 0xb) -/* panic info include filename and line number */ +/* panic info include filename and line number + * filename array will not include null terminator if fully filled + */ struct sof_ipc_panic_info { struct sof_ipc_hdr hdr; uint32_t code; /* SOF_IPC_PANIC_ */ From 35d7759478a978eb57e563189a0c385b649b2f24 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 6 May 2019 15:40:28 -0500 Subject: [PATCH 1463/1995] ASoC: SOF: uapi: mirror firmware changes We missed these two definitions for GDB support and component notifications, they are defined for the SOF firmware. Since they are not used by the kernel so far, we can still add them without any ABI change. Signed-off-by: Pierre-Louis Bossart --- include/sound/sof/header.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index ccb6a004b37b78..0aeb2c8ad6fdc4 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -48,6 +48,7 @@ #define SOF_IPC_FW_READY SOF_GLB_TYPE(0x7U) #define SOF_IPC_GLB_DAI_MSG SOF_GLB_TYPE(0x8U) #define SOF_IPC_GLB_TRACE_MSG SOF_GLB_TYPE(0x9U) +#define SOF_IPC_GLB_GDB_DEBUG SOF_GLB_TYPE(0xAU) /* * DSP Command Message Types @@ -78,6 +79,7 @@ #define SOF_IPC_COMP_GET_VALUE SOF_CMD_TYPE(0x002) #define SOF_IPC_COMP_SET_DATA SOF_CMD_TYPE(0x003) #define SOF_IPC_COMP_GET_DATA SOF_CMD_TYPE(0x004) +#define SOF_IPC_COMP_NOTIFICATION SOF_CMD_TYPE(0x005) /* DAI messages */ #define SOF_IPC_DAI_CONFIG SOF_CMD_TYPE(0x001) From 7271e69af824e45bc488b9a3771461165fa15047 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Thu, 25 Apr 2019 13:00:32 +0800 Subject: [PATCH 1464/1995] ASoC: soc-pcm: BE dai needs prepare when pause release after resume If playback/capture is paused and system enters S3, after system returns from suspend, BE dai needs to call prepare() callback when playback/capture is released from pause. Signed-off-by: Libin Yang --- sound/soc/soc-pcm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 0a4f60c7a188cd..c46ad0f6629212 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2479,7 +2479,8 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) && - (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND)) + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED)) continue; dev_dbg(be->dev, "ASoC: prepare BE %s\n", From 9257554c1cc173b62d36ba88c42598b7e49692bc Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Mon, 13 May 2019 15:44:13 +0800 Subject: [PATCH 1465/1995] ASoC: SOF: pcm: clear hw_params_upon_resume flag correctly sof_pcm_hw_params() can only be called once to setup the FW hw_params. So after calling sof_pcm_hw_params(), hw_params_upon_resume flag must be cleared to avoid multiple invoking sof_pcm_hw_params() by prepare. For example, after resume, there is an xrun happened, prepare() will be called. As the hw_params_upon_resume flag is not cleared, sof_pcm_hw_params() will be called and this will cause IPC timeout. This patch fixes such issues. Signed-off-by: Libin Yang --- sound/soc/sof/pcm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 4f536c0de0a55f..e9489205369068 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -214,6 +214,9 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work, sof_pcm_period_elapsed_work); + /* clear hw_params_upon_resume flag */ + spcm->hw_params_upon_resume[substream->stream] = 0; + return ret; } @@ -428,9 +431,6 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); - /* clear hw_params_upon_resume flag */ - spcm->hw_params_upon_resume[substream->stream] = 0; - caps = &spcm->pcm.caps[substream->stream]; /* set any runtime constraints based on topology */ From 333ee2257de8f6bf8077e0bd04333154cc9281fb Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Thu, 9 May 2019 15:16:35 +0800 Subject: [PATCH 1466/1995] ASoC: SOF: Intel: hda: fix the hda init chip re-write hda_init_caps and remove the HDA reset, clean HDA streams and clear interrupt steps in hda_dsp_probe so the HDA init steps will not be called twice if the CONFIG_SND_SOC_SOF_HDA is true. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-ctrl.c | 102 ++++++++++++++++++++++++++++++--- sound/soc/sof/intel/hda.c | 99 ++++++-------------------------- 2 files changed, 112 insertions(+), 89 deletions(-) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 2c3645736e1f76..07bc123112c9ba 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -161,21 +161,105 @@ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) return 0; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) -/* - * While performing reset, controller may not come back properly and causing - * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset - * (init chip) and then again set CGCTL.MISCBDCGE to 1 - */ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) { struct hdac_bus *bus = sof_to_bus(sdev); - int ret; + struct hdac_stream *stream; + int sd_offset, ret = 0; + + if (bus->chip_init) + return 0; hda_dsp_ctrl_misc_clock_gating(sdev, false); - ret = snd_hdac_bus_init_chip(bus, full_reset); + + if (full_reset) { + /* clear WAKESTS */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, + SOF_HDA_WAKESTS_INT_MASK, + SOF_HDA_WAKESTS_INT_MASK); + + /* reset HDA controller */ + ret = hda_dsp_ctrl_link_reset(sdev, true); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to reset HDA controller\n"); + return ret; + } + + usleep_range(500, 1000); + + /* exit HDA controller reset */ + ret = hda_dsp_ctrl_link_reset(sdev, false); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to exit HDA controller reset\n"); + return ret; + } + + usleep_range(1000, 1200); + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* check to see if controller is ready */ + if (!snd_hdac_chip_readb(bus, GCTL)) { + dev_dbg(bus->dev, "controller not ready!\n"); + return -EBUSY; + } + + /* Accept unsolicited responses */ + snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL); + + /* detect codecs */ + if (!bus->codec_mask) { + bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS); + dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask); + } +#endif + + /* clear stream status */ + list_for_each_entry(stream, &bus->stream_list, list) { + sd_offset = SOF_STREAM_SD_OFFSET(stream); + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + + SOF_HDA_ADSP_REG_CL_SD_STS, + SOF_HDA_CL_DMA_SD_INT_MASK, + SOF_HDA_CL_DMA_SD_INT_MASK); + } + + /* clear WAKESTS */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, + SOF_HDA_WAKESTS_INT_MASK, + SOF_HDA_WAKESTS_INT_MASK); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* clear rirb status */ + snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); +#endif + + /* clear interrupt status register */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* initialize the codec command I/O */ + snd_hdac_bus_init_cmd_io(bus); +#endif + + /* enable CIE and GIE interrupts */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* program the position buffer */ + if (bus->use_posbuf && bus->posbuf.addr) { + snd_hdac_chip_writel(bus, DPLBASE, (u32)bus->posbuf.addr); + snd_hdac_chip_writel(bus, DPUBASE, + upper_32_bits(bus->posbuf.addr)); + } +#endif + + bus->chip_init = true; + hda_dsp_ctrl_misc_clock_gating(sdev, true); return ret; } -#endif diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 7e3980a2f7ba22..e47f03dc62f01f 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -264,9 +264,12 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev, return tplg_filename; } +#endif + static int hda_init_caps(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_ext_link *hlink; struct snd_soc_acpi_mach_params *mach_params; struct snd_soc_acpi_mach *hda_mach; @@ -274,8 +277,9 @@ static int hda_init_caps(struct snd_sof_dev *sdev) struct snd_soc_acpi_mach *mach; const char *tplg_filename; int codec_num = 0; - int ret = 0; int i; +#endif + int ret = 0; device_disable_async_suspend(bus->dev); @@ -283,6 +287,14 @@ static int hda_init_caps(struct snd_sof_dev *sdev) if (bus->ppcap) dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n"); + ret = hda_dsp_ctrl_init_chip(sdev, true); + if (ret < 0) { + dev_err(bus->dev, "error: init chip failed with ret: %d\n", + ret); + return ret; + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) if (bus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(bus); @@ -293,12 +305,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) return ret; } - ret = hda_dsp_ctrl_init_chip(sdev, true); - if (ret < 0) { - dev_err(bus->dev, "error: init chip failed with ret: %d\n", ret); - goto out; - } - /* codec detection */ if (!bus->codec_mask) { dev_info(bus->dev, "no hda codecs found!\n"); @@ -339,8 +345,10 @@ static int hda_init_caps(struct snd_sof_dev *sdev) /* use local variable for readability */ tplg_filename = pdata->tplg_filename; tplg_filename = fixup_tplg_name(sdev, tplg_filename); - if (!tplg_filename) - goto out; + if (!tplg_filename) { + hda_codec_i915_exit(sdev); + return ret; + } pdata->tplg_filename = tplg_filename; } } @@ -364,35 +372,10 @@ static int hda_init_caps(struct snd_sof_dev *sdev) */ list_for_each_entry(hlink, &bus->hlink_list, list) snd_hdac_ext_bus_link_put(bus, hlink); - - return 0; - -out: - hda_codec_i915_exit(sdev); - return ret; -} - -#else - -static int hda_init_caps(struct snd_sof_dev *sdev) -{ - /* - * set CGCTL.MISCBDCGE to 0 during reset and set back to 1 - * when reset finished. - * TODO: maybe no need for init_caps? - */ - hda_dsp_ctrl_misc_clock_gating(sdev, 0); - - /* clear WAKESTS */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, - SOF_HDA_WAKESTS_INT_MASK, - SOF_HDA_WAKESTS_INT_MASK); - +#endif return 0; } -#endif - static const struct sof_intel_dsp_desc *get_chip_info(struct snd_sof_pdata *pdata) { @@ -409,9 +392,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) struct pci_dev *pci = to_pci_dev(sdev->dev); struct sof_intel_hda_dev *hdev; struct hdac_bus *bus; - struct hdac_stream *stream; const struct sof_intel_dsp_desc *chip; - int sd_offset, ret = 0; + int ret = 0; /* * detect DSP by checking class/subclass/prog-id information @@ -558,49 +540,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) if (ret < 0) goto free_ipc_irq; - /* reset HDA controller */ - ret = hda_dsp_ctrl_link_reset(sdev, true); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to reset HDA controller\n"); - goto free_ipc_irq; - } - - /* exit HDA controller reset */ - ret = hda_dsp_ctrl_link_reset(sdev, false); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to exit HDA controller reset\n"); - goto free_ipc_irq; - } - - /* clear stream status */ - list_for_each_entry(stream, &bus->stream_list, list) { - sd_offset = SOF_STREAM_SD_OFFSET(stream); - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - sd_offset + - SOF_HDA_ADSP_REG_CL_SD_STS, - SOF_HDA_CL_DMA_SD_INT_MASK, - SOF_HDA_CL_DMA_SD_INT_MASK); - } - - /* clear WAKESTS */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, - SOF_HDA_WAKESTS_INT_MASK, - SOF_HDA_WAKESTS_INT_MASK); - - /* clear interrupt status register */ - snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM); - - /* enable CIE and GIE interrupts */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); - - /* re-enable CGCTL.MISCBDCGE after reset */ - hda_dsp_ctrl_misc_clock_gating(sdev, true); - - device_disable_async_suspend(&pci->dev); - /* enable DSP features */ snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, SOF_HDA_PPCTL_GPROCEN, SOF_HDA_PPCTL_GPROCEN); From 09d424352fe4bc035b6a6659a6f8d535115ce8ae Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Thu, 9 May 2019 15:29:53 +0800 Subject: [PATCH 1467/1995] ASoC: SOF: Intel: hda: use the defined ppcap functions There are already defined ppcap and ppcap interrupt functions, use the already defined functions for easy code read. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index e47f03dc62f01f..7edeee4fc74b4f 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -540,13 +540,9 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) if (ret < 0) goto free_ipc_irq; - /* enable DSP features */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, - SOF_HDA_PPCTL_GPROCEN, SOF_HDA_PPCTL_GPROCEN); - - /* enable DSP IRQ */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, - SOF_HDA_PPCTL_PIE, SOF_HDA_PPCTL_PIE); + /* enable ppcap interrupt */ + hda_dsp_ctrl_ppcap_enable(sdev, true); + hda_dsp_ctrl_ppcap_int_enable(sdev, true); /* initialize waitq for code loading */ init_waitqueue_head(&sdev->waitq); From 44443cb789635bd524deac4c2ce8318809fdde5b Mon Sep 17 00:00:00 2001 From: Slawomir Blauciak Date: Mon, 13 May 2019 13:52:11 +0200 Subject: [PATCH 1468/1995] ipc: replace fw ready bitfield with explicit bit ordering Previously the structure used bitfields, which do not guarantee bit ordering. This change makes sure the order is clearly defined. It also renames and repurposes the field for general use. Signed-off-by: Slawomir Blauciak --- include/sound/sof/info.h | 20 ++++++++++---------- sound/soc/sof/ipc.c | 11 +++++++---- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/include/sound/sof/info.h b/include/sound/sof/info.h index 21dae04d818398..16528d2b4a504e 100644 --- a/include/sound/sof/info.h +++ b/include/sound/sof/info.h @@ -18,6 +18,14 @@ #define SOF_IPC_MAX_ELEMS 16 +/* + * Firmware boot info flag bits (64-bit) + */ +#define SOF_IPC_INFO_BUILD BIT(0) +#define SOF_IPC_INFO_LOCKS BIT(1) +#define SOF_IPC_INFO_LOCKSV BIT(2) +#define SOF_IPC_INFO_GDB BIT(3) + /* extended data types that can be appended onto end of sof_ipc_fw_ready */ enum sof_ipc_ext_data { SOF_IPC_EXT_DMA_BUFFER = 0, @@ -49,16 +57,8 @@ struct sof_ipc_fw_ready { uint32_t hostbox_size; struct sof_ipc_fw_version version; - /* Miscellaneous debug flags showing build/debug features enabled */ - union { - uint64_t reserved; - struct { - uint64_t build:1; - uint64_t locks:1; - uint64_t locks_verbose:1; - uint64_t gdb:1; - } bits; - } debug; + /* Miscellaneous flags */ + uint64_t flags; /* reserved for future use */ uint32_t reserved[4]; diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 894e68cbd69d5d..4671eb6b553d42 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -776,16 +776,19 @@ int snd_sof_ipc_valid(struct snd_sof_dev *sdev) } } - if (ready->debug.bits.build) { + if (ready->flags & SOF_IPC_INFO_BUILD) { dev_info(sdev->dev, "Firmware debug build %d on %s-%s - options:\n" " GDB: %s\n" " lock debug: %s\n" " lock vdebug: %s\n", v->build, v->date, v->time, - ready->debug.bits.gdb ? "enabled" : "disabled", - ready->debug.bits.locks ? "enabled" : "disabled", - ready->debug.bits.locks_verbose ? "enabled" : "disabled"); + ready->flags & SOF_IPC_INFO_GDB ? + "enabled" : "disabled", + ready->flags & SOF_IPC_INFO_LOCKS ? + "enabled" : "disabled", + ready->flags & SOF_IPC_INFO_LOCKSV ? + "enabled" : "disabled"); } /* copy the fw_version into debugfs at first boot */ From 18e1f86730d35056c9a1ce92f0532a4106143d11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Wed, 17 Apr 2019 14:21:11 +0200 Subject: [PATCH 1469/1995] ALSA: hdac: fix memory release for SST and SOF drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 6298542fa33b ("ALSA: hdac: remove memory allocation from snd_hdac_ext_bus_device_init") changed way in which we get hdev in snd_hdac_ext_bus_device_init() to use one preallocated with devm_kzalloc(), however it still left kfree(hdev) in snd_hdac_ext_bus_device_exit(). It leads to oopses when trying to rmmod and modprobe. Fix it, by just removing kfree call. SOF also uses some of the snd_hdac_ functions for HDAudio support but allocated the memory with kzalloc. Use devm_kzalloc to align all users of the snd_hdac_ library. The two changes are combined in a single patch to avoid bisect issues. Signed-off-by: Amadeusz SÅ‚awiÅ„ski Signed-off-by: Libin Yang --- sound/hda/ext/hdac_ext_bus.c | 1 - sound/soc/sof/intel/hda-codec.c | 6 ++---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c index ec7715c6b0c02c..c147ebe542da92 100644 --- a/sound/hda/ext/hdac_ext_bus.c +++ b/sound/hda/ext/hdac_ext_bus.c @@ -172,7 +172,6 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_init); void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev) { snd_hdac_device_exit(hdev); - kfree(hdev); } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit); diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index b8b37f08230940..0d8437b080bfa5 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -62,8 +62,7 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) address, resp); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) - /* snd_hdac_ext_bus_device_exit will use kfree to free hdev */ - hda_priv = kzalloc(sizeof(*hda_priv), GFP_KERNEL); + hda_priv = devm_kzalloc(sdev->dev, sizeof(*hda_priv), GFP_KERNEL); if (!hda_priv) return -ENOMEM; @@ -82,8 +81,7 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) return 0; #else - /* snd_hdac_ext_bus_device_exit will use kfree to free hdev */ - hdev = kzalloc(sizeof(*hdev), GFP_KERNEL); + hdev = devm_kzalloc(sdev->dev, sizeof(*hdev), GFP_KERNEL); if (!hdev) return -ENOMEM; From eff444de80880e1f6cd0764b64114307fa26dce1 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Tue, 14 May 2019 19:08:59 +0800 Subject: [PATCH 1470/1995] ASoC: SOF: control: correct the copy size for bytes kcontrol put The size for the bytes kcontrol should include the abi header, that is, data->size + sizeof(*data), it is also aligned with get method after this change. Signed-off-by: Keyon Jie --- sound/soc/sof/control.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 11762c4580f102..84e2cbfbbcbb3c 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -349,6 +349,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_abi_hdr *data = cdata->data; + size_t size = data->size + sizeof(*data); int ret, err; if (be->max > sizeof(ucontrol->value.bytes.data)) { @@ -358,10 +359,10 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, return -EINVAL; } - if (data->size > be->max) { + if (size > be->max) { dev_err_ratelimited(sdev->dev, - "error: size too big %d bytes max is %d\n", - data->size, be->max); + "error: size too big %zu bytes max is %d\n", + size, be->max); return -EINVAL; } @@ -375,7 +376,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, } /* copy from kcontrol */ - memcpy(data, ucontrol->value.bytes.data, data->size); + memcpy(data, ucontrol->value.bytes.data, size); /* notify DSP of byte control updates */ snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, From 465c8e4061a58c67c496be58d46441bc1b82de18 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 14 May 2019 13:48:41 -0500 Subject: [PATCH 1471/1995] ASoC: SOF: core: fix error handling with the probe workqueue In some configurations, it's a requirement to split the probe in two, with a second part handled in a workqueue (e.g. for HDMI support which depends on the DRM modules). SOF already handles these configurations but the error flow is incorrect. When an error occurs in the workqueue, the probe has technically already completed. If we release the resources on errors, this generates kernel oops/use-after-free when the resources are released a second time on module removal. GitHub issue: https://github.com/thesofproject/linux/issues/945 Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/core.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 693ad83bffc9c3..5beda47cdf9fc7 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -393,6 +393,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) return 0; +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) fw_run_err: snd_sof_fw_unload(sdev); fw_load_err: @@ -401,6 +402,21 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) snd_sof_free_debug(sdev); dbg_err: snd_sof_remove(sdev); +#else + + /* + * when the probe_continue is handled in a work queue, the + * probe does not fail so we don't release resources here. + * They will be released with an explicit call to + * snd_sof_device_remove() when the PCI/ACPI device is removed + */ + +fw_run_err: +fw_load_err: +ipc_err: +dbg_err: + +#endif return ret; } From 84de37967e749bea031e539ba0faaa0caf96c5f7 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 15 May 2019 14:47:21 +0300 Subject: [PATCH 1472/1995] ASoC: SOF: fix DSP oops definitions in FW ABI The definitions for DSP oops structures were not aligned correctly to current FW ABI version 3.6.0, leading to invalid data being printed out to debug logs. Fix the structs and update related platform code accordingly. Signed-off-by: Kai Vehmanen --- include/sound/sof/header.h | 21 +++++++++++++++++++++ include/sound/sof/xtensa.h | 9 +++++++-- sound/soc/sof/intel/bdw.c | 17 ++++++++++------- sound/soc/sof/intel/byt.c | 15 +++++++++------ sound/soc/sof/intel/hda.c | 16 ++++++++++------ sound/soc/sof/xtensa/core.c | 2 +- 6 files changed, 58 insertions(+), 22 deletions(-) diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index 0aeb2c8ad6fdc4..1efcf7b18ec20c 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -155,6 +155,27 @@ struct sof_ipc_compound_hdr { uint32_t count; /**< count of 0 means end of compound sequence */ } __packed; +/** + * OOPS header architecture specific data. + */ +struct sof_ipc_dsp_oops_arch_hdr { + uint32_t arch; /* Identifier of architecture */ + uint32_t totalsize; /* Total size of oops message */ +} __packed; + +/** + * OOPS header platform specific data. + */ +struct sof_ipc_dsp_oops_plat_hdr { + uint32_t configidhi; /* ConfigID hi 32bits */ + uint32_t configidlo; /* ConfigID lo 32bits */ + uint32_t numaregs; /* Special regs num */ + uint32_t stackoffset; /* Offset to stack pointer from beginning of + * oops message + */ + uint32_t stackptr; /* Stack ptr */ +} __packed; + /** @}*/ #endif diff --git a/include/sound/sof/xtensa.h b/include/sound/sof/xtensa.h index a7189984000d5d..d25c764b10e8b4 100644 --- a/include/sound/sof/xtensa.h +++ b/include/sound/sof/xtensa.h @@ -17,7 +17,8 @@ /* Xtensa Firmware Oops data */ struct sof_ipc_dsp_oops_xtensa { - struct sof_ipc_hdr hdr; + struct sof_ipc_dsp_oops_arch_hdr arch_hdr; + struct sof_ipc_dsp_oops_plat_hdr plat_hdr; uint32_t exccause; uint32_t excvaddr; uint32_t ps; @@ -38,7 +39,11 @@ struct sof_ipc_dsp_oops_xtensa { uint32_t intenable; uint32_t interrupt; uint32_t sar; - uint32_t stack; + uint32_t debugcause; + uint32_t windowbase; + uint32_t windowstart; + uint32_t excsave1; + uint32_t ar[]; } __packed; #endif diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 065cb868bdface..ddec6faffffb59 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -220,17 +220,20 @@ static void bdw_get_registers(struct snd_sof_dev *sdev, struct sof_ipc_panic_info *panic_info, u32 *stack, size_t stack_words) { - /* first read regsisters */ - sof_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); + u32 offset = sdev->dsp_oops_offset; + + /* first read registers */ + sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops)); + + /* note: variable AR register array is not read */ /* then get panic info */ - sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), - panic_info, sizeof(*panic_info)); + offset += xoops->arch_hdr.totalsize; + sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info)); /* then get the stack */ - sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + - sizeof(*panic_info), stack, - stack_words * sizeof(u32)); + offset += sizeof(*panic_info); + sof_mailbox_read(sdev, offset, stack, stack_words * sizeof(u32)); } static void bdw_dump(struct snd_sof_dev *sdev, u32 flags) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 7bf9143d310673..2d1f8b405238ed 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -265,17 +265,20 @@ static void byt_get_registers(struct snd_sof_dev *sdev, struct sof_ipc_panic_info *panic_info, u32 *stack, size_t stack_words) { + u32 offset = sdev->dsp_oops_offset; + /* first read regsisters */ - sof_mailbox_read(sdev, sdev->dsp_oops_offset, xoops, sizeof(*xoops)); + sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops)); + + /* note: variable AR register array is not read */ /* then get panic info */ - sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops), - panic_info, sizeof(*panic_info)); + offset += xoops->arch_hdr.totalsize; + sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info)); /* then get the stack */ - sof_mailbox_read(sdev, sdev->dsp_oops_offset + sizeof(*xoops) + - sizeof(*panic_info), stack, - stack_words * sizeof(u32)); + offset += sizeof(*panic_info); + sof_mailbox_read(sdev, offset, stack, stack_words * sizeof(u32)); } static void byt_dump(struct snd_sof_dev *sdev, u32 flags) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 7edeee4fc74b4f..5c78f4dde6f529 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -108,17 +108,21 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev, struct sof_ipc_panic_info *panic_info, u32 *stack, size_t stack_words) { + u32 offset = sdev->dsp_oops_offset; + /* first read registers */ - sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset, xoops, - sizeof(*xoops)); + sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops)); + + /* note: variable AR register array is not read */ /* then get panic info */ - sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset + - sizeof(*xoops), panic_info, sizeof(*panic_info)); + offset += xoops->arch_hdr.totalsize; + sof_block_read(sdev, sdev->mmio_bar, offset, + panic_info, sizeof(*panic_info)); /* then get the stack */ - sof_block_read(sdev, sdev->mmio_bar, sdev->dsp_oops_offset + - sizeof(*xoops) + sizeof(*panic_info), stack, + offset += sizeof(*panic_info); + sof_block_read(sdev, sdev->mmio_bar, offset, stack, stack_words * sizeof(u32)); } diff --git a/sound/soc/sof/xtensa/core.c b/sound/soc/sof/xtensa/core.c index c3ad23a85b99fe..46a4905a9dce15 100644 --- a/sound/soc/sof/xtensa/core.c +++ b/sound/soc/sof/xtensa/core.c @@ -110,7 +110,7 @@ static void xtensa_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack, u32 stack_words) { struct sof_ipc_dsp_oops_xtensa *xoops = oops; - u32 stack_ptr = xoops->stack; + u32 stack_ptr = xoops->plat_hdr.stackptr; /* 4 * 8chars + 3 ws + 1 terminating NUL */ unsigned char buf[4 * 8 + 3 + 1]; int i; From e4efb2b9ddb50002bee4c196d964e13c890b1056 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 15 May 2019 11:42:25 -0500 Subject: [PATCH 1473/1995] ASoC: SOF: bump to ABI 3.6 We had a couple of misses with ABI changes, e.g. for Xtensa oops information and the integration of sound trigger, before we set-up a formal process to track evolutions. With this patch, the SOF kernel patches are officially aligned with the firmware 3.6 level. Changing this level has no impact on existing users and is fully backwards-compatible. Signed-off-by: Pierre-Louis Bossart --- include/uapi/sound/sof/abi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index 13a4eca04577cb..0868eb47acf7e8 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 5 +#define SOF_ABI_MINOR 6 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ From 0b0589d035eba6b27be23420abff9c44f44bcaed Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 26 Apr 2019 13:04:20 +0300 Subject: [PATCH 1474/1995] ASoC: SOF: trace: remove code duplication in sof_wait_trace_avail() Move duplicated code in sof_wait_trace_avail() to a helper function. Signed-off-by: Kai Vehmanen --- sound/soc/sof/trace.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index d588e4b70fad3e..a2d89d295f0f82 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -13,10 +13,9 @@ #include "sof-priv.h" #include "ops.h" -static size_t sof_wait_trace_avail(struct snd_sof_dev *sdev, - loff_t pos, size_t buffer_size) +static size_t sof_trace_avail(struct snd_sof_dev *sdev, + loff_t pos, size_t buffer_size) { - wait_queue_entry_t wait; loff_t host_offset = READ_ONCE(sdev->host_offset); /* @@ -31,6 +30,19 @@ static size_t sof_wait_trace_avail(struct snd_sof_dev *sdev, if (host_offset > pos) return host_offset - pos; + return 0; +} + +static size_t sof_wait_trace_avail(struct snd_sof_dev *sdev, + loff_t pos, size_t buffer_size) +{ + wait_queue_entry_t wait; + size_t ret = sof_trace_avail(sdev, pos, buffer_size); + + /* data immediately available */ + if (ret) + return ret; + /* wait for available trace data from FW */ init_waitqueue_entry(&wait, current); set_current_state(TASK_INTERRUPTIBLE); @@ -42,12 +54,7 @@ static size_t sof_wait_trace_avail(struct snd_sof_dev *sdev, } remove_wait_queue(&sdev->trace_sleep, &wait); - /* return bytes available for copy */ - host_offset = READ_ONCE(sdev->host_offset); - if (host_offset < pos) - return buffer_size - pos; - - return host_offset - pos; + return sof_trace_avail(sdev, pos, buffer_size); } static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer, From 2291b8c29a77e822f514d96433efc9a4cf00d1e8 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 26 Apr 2019 13:05:27 +0300 Subject: [PATCH 1475/1995] ASoC: SOF: force end-of-file for debugfs trace at suspend Current trace implementation gets out of sync when sof device is put to suspend. The debugfs file handle is kept open, but firmware will reset its state. After resume, debugfs client's read offset will not be synchronized to firmware and this may result in traces read in incorrect order and/or stale data being read after resume. Add logic to signal end-of-file to read() when firmware tracing has ended, and all trace data has been read. This allows debugfs client to capture all trace data, and reopen the trace file to ensure proper synchronization with firmware after reopening the node. Signed-off-by: Kai Vehmanen --- sound/soc/sof/sof-priv.h | 2 ++ sound/soc/sof/trace.c | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 1e85d6f9c5c308..01a6219c326b7f 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -417,6 +417,8 @@ struct snd_sof_dev { u32 host_offset; u32 dtrace_is_enabled; u32 dtrace_error; + u32 dtrace_draining; + u32 msi_enabled; void *private; /* core does not touch this */ diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index a2d89d295f0f82..b02520f8e5954f 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -43,6 +43,15 @@ static size_t sof_wait_trace_avail(struct snd_sof_dev *sdev, if (ret) return ret; + if (!sdev->dtrace_is_enabled && sdev->dtrace_draining) { + /* + * tracing has ended and all traces have been + * read by client, return EOF + */ + sdev->dtrace_draining = false; + return 0; + } + /* wait for available trace data from FW */ init_waitqueue_entry(&wait, current); set_current_state(TASK_INTERRUPTIBLE); @@ -104,10 +113,23 @@ static ssize_t sof_dfsentry_trace_read(struct file *file, char __user *buffer, return count; } +static int sof_dfsentry_trace_release(struct inode *inode, struct file *file) +{ + struct snd_sof_dfsentry *dfse = inode->i_private; + struct snd_sof_dev *sdev = dfse->sdev; + + /* avoid duplicate traces at next open */ + if (!sdev->dtrace_is_enabled) + sdev->host_offset = 0; + + return 0; +} + static const struct file_operations sof_dfs_trace_fops = { .open = simple_open, .read = sof_dfsentry_trace_read, .llseek = default_llseek, + .release = sof_dfsentry_trace_release, }; static int trace_debugfs_create(struct snd_sof_dev *sdev) @@ -155,6 +177,7 @@ int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) params.stream_tag = 0; sdev->host_offset = 0; + sdev->dtrace_draining = false; ret = snd_sof_dma_trace_init(sdev, ¶ms.stream_tag); if (ret < 0) { @@ -291,6 +314,8 @@ void snd_sof_release_trace(struct snd_sof_dev *sdev) "error: fail in snd_sof_dma_trace_release %d\n", ret); sdev->dtrace_is_enabled = false; + sdev->dtrace_draining = true; + wake_up(&sdev->trace_sleep); } EXPORT_SYMBOL(snd_sof_release_trace); From 1da89022aed1db0b15d0f5214d4b6377b5186218 Mon Sep 17 00:00:00 2001 From: Sathya Prakash M R Date: Fri, 10 May 2019 12:18:40 +0530 Subject: [PATCH 1476/1995] ASoC: Intel: sof-rt5682: Few minor fixes for AMP SSP and codec button This fixes: 1. BIT mask for AMP SSP was incorrect. 2. The RT5682 codec button mapping is corrected. Signed-off-by: Sathya Prakash M R --- sound/soc/intel/boards/sof_rt5682.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index f28fb98cc30632..e441dc9799666f 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -29,9 +29,10 @@ #define SOF_RT5682_MCLK_EN BIT(3) #define SOF_RT5682_MCLK_24MHZ BIT(4) #define SOF_SPEAKER_AMP_PRESENT BIT(5) -#define SOF_RT5682_SSP_AMP(quirk) ((quirk) & GENMASK(8, 6)) -#define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6)) #define SOF_RT5682_SSP_AMP_SHIFT 6 +#define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6)) +#define SOF_RT5682_SSP_AMP(quirk) \ + (((quirk) << SOF_RT5682_SSP_AMP_SHIFT) & SOF_RT5682_SSP_AMP_MASK) /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | @@ -144,9 +145,9 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) jack = &ctx->sof_headset; snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); ret = snd_soc_component_set_jack(component, jack, NULL); if (ret) { @@ -519,6 +520,7 @@ static int sof_audio_probe(struct platform_device *pdev) /* compute number of dai links */ sof_audio_card_rt5682.num_links = 1 + dmic_num + hdmi_num; + if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) sof_audio_card_rt5682.num_links++; From 0f3e63c8f1bffda8292fbcf3998c9a9bc66fa1a3 Mon Sep 17 00:00:00 2001 From: Sathya Prakash M R Date: Fri, 10 May 2019 12:25:02 +0530 Subject: [PATCH 1477/1995] ASoC: Intel: soc-acpi: Fix machine selection order The selection order of m/c in match table is corrected to use common codec as last in the list. Signed-off-by: Sathya Prakash M R --- sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index df7c52cad5c3f6..c36c0aa4f68325 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -29,17 +29,17 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .sof_tplg_filename = "sof-cnl-rt274.tplg", }, { - .id = "10EC5682", + .id = "MX98357A", .drv_name = "sof_rt5682", + .quirk_data = &cml_codecs, .sof_fw_filename = "sof-cnl.ri", - .sof_tplg_filename = "sof-cml-rt5682.tplg", + .sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg", }, { - .id = "MX98357A", + .id = "10EC5682", .drv_name = "sof_rt5682", - .quirk_data = &cml_codecs, .sof_fw_filename = "sof-cnl.ri", - .sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg", + .sof_tplg_filename = "sof-cml-rt5682.tplg", }, {}, From 6b58a108b2aa98cb0cd8d49d0987c0b67be3a8c8 Mon Sep 17 00:00:00 2001 From: Libin Yang Date: Wed, 15 May 2019 13:50:23 +0800 Subject: [PATCH 1478/1995] ASoC: intel: skl_hda_dsp_common: create HDMI jack kctl This patch call snd_jack_add_new_kctl() to create the HDMI jack kctls. Userspace needs these kctls to detect the hdmi monitor hotplug. In /usr/share/alsa/ucm, the config file needs to assign a jack kctl to "JackControl" to let PA get the jack hotplug status. Signed-off-by: Libin Yang --- sound/soc/intel/boards/skl_hda_dsp_common.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c index 8b68f41a5b8856..cf98a04cb9275a 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_common.c +++ b/sound/soc/intel/boards/skl_hda_dsp_common.c @@ -132,6 +132,11 @@ int skl_hda_hdmi_jack_init(struct snd_soc_card *card) if (err) return err; + err = snd_jack_add_new_kctl(pcm->hdmi_jack.jack, + jack_name, SND_JACK_AVOUT); + if (err) + dev_warn(component->dev, "failed creating Jack kctl\n"); + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, &pcm->hdmi_jack); if (err < 0) From ceec5493a8a69badb177bd24a3009b73317cbdb4 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Wed, 27 Mar 2019 21:50:56 +0800 Subject: [PATCH 1479/1995] ASoC: SOF: send time stamp to FW for alignment Timer will be reset when DSP is powered down. So the time stamp of trace log will be reset after resume. Send time stamp to FW can align the time stamp and avoid reset time stamp in trace log. Signed-off-by: Bard liao --- include/sound/sof/header.h | 1 + include/sound/sof/trace.h | 10 ++++++++++ include/uapi/sound/sof/abi.h | 2 +- sound/soc/sof/trace.c | 16 +++++++++++++--- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index 1efcf7b18ec20c..ab5862d80afedf 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -102,6 +102,7 @@ /* trace and debug */ #define SOF_IPC_TRACE_DMA_PARAMS SOF_CMD_TYPE(0x001) #define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002) +#define SOF_IPC_TRACE_DMA_PARAMS_EXT SOF_CMD_TYPE(0x003) /* Get message component id */ #define SOF_IPC_MESSAGE_ID(x) ((x) & 0xffff) diff --git a/include/sound/sof/trace.h b/include/sound/sof/trace.h index fdb30078448fd1..9257d5473d97b5 100644 --- a/include/sound/sof/trace.h +++ b/include/sound/sof/trace.h @@ -19,12 +19,22 @@ #define SOF_TRACE_FILENAME_SIZE 32 /* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS */ +/* Deprecated - use sof_ipc_dma_trace_params_ext */ struct sof_ipc_dma_trace_params { struct sof_ipc_cmd_hdr hdr; struct sof_ipc_host_buffer buffer; uint32_t stream_tag; } __packed; +/* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS_EXT */ +struct sof_ipc_dma_trace_params_ext { + struct sof_ipc_cmd_hdr hdr; + struct sof_ipc_host_buffer buffer; + uint32_t stream_tag; + uint64_t timestamp_ns; /* in nanosecond */ + uint32_t reserved[8]; +} __packed; + /* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS */ struct sof_ipc_dma_trace_posn { struct sof_ipc_reply rhdr; diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index 0868eb47acf7e8..92eee681bc6286 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 6 +#define SOF_ABI_MINOR 7 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index b02520f8e5954f..befed975161cb7 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -161,7 +161,9 @@ static int trace_debugfs_create(struct snd_sof_dev *sdev) int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) { - struct sof_ipc_dma_trace_params params; + struct sof_ipc_fw_ready *ready = &sdev->fw_ready; + struct sof_ipc_fw_version *v = &ready->version; + struct sof_ipc_dma_trace_params_ext params; struct sof_ipc_reply ipc_reply; int ret; @@ -169,8 +171,16 @@ int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) return -EINVAL; /* set IPC parameters */ - params.hdr.size = sizeof(params); - params.hdr.cmd = SOF_IPC_GLB_TRACE_MSG | SOF_IPC_TRACE_DMA_PARAMS; + params.hdr.cmd = SOF_IPC_GLB_TRACE_MSG; + /* PARAMS_EXT is only supported from ABI 3.7.0 onwards */ + if (v->abi_version >= SOF_ABI_VER(3, 7, 0)) { + params.hdr.size = sizeof(struct sof_ipc_dma_trace_params_ext); + params.hdr.cmd |= SOF_IPC_TRACE_DMA_PARAMS_EXT; + params.timestamp_ns = ktime_get(); /* in nanosecond */ + } else { + params.hdr.size = sizeof(struct sof_ipc_dma_trace_params); + params.hdr.cmd |= SOF_IPC_TRACE_DMA_PARAMS; + } params.buffer.phy_addr = sdev->dmatp.addr; params.buffer.size = sdev->dmatb.bytes; params.buffer.pages = sdev->dma_trace_pages; From 042d6db4eb54a66cfd0b462013c505d8ec8bffb9 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 14 May 2019 14:50:31 +0200 Subject: [PATCH 1480/1995] ASoC: SOF: ipc: fix a race, leading to IPC timeouts Currently on all supported platforms the IPC IRQ thread first signals the sender when an IPC response is received from the DSP, then unmasks the IPC interrupt. Those actions are performed without holding any locks, so the thread can be interrupted between them. IPC timeouts have been observed in such scenarios: if the sender is woken up and it proceeds with sending the next message without unmasking the IPC interrupt, it can miss the next response. This patch takes a spin-lock to prevent the IRQ thread from being preempted at that point. It also makes sure, that the next IPC transmission by the host cannot take place before the IRQ thread has finished updating all the required IPC registers. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/bdw.c | 11 ++++++----- sound/soc/sof/intel/byt.c | 12 +++++++----- sound/soc/sof/intel/cnl.c | 6 ++++++ sound/soc/sof/intel/hda-ipc.c | 19 ++++++++++++++++--- sound/soc/sof/ipc.c | 13 ------------- 5 files changed, 35 insertions(+), 26 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index ddec6faffffb59..4c06332b4de3e6 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -281,11 +281,15 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) /* reply message from DSP */ if (ipcx & SHIM_IPCX_DONE && !(imrx & SHIM_IMRX_DONE)) { + unsigned long flags; + /* Mask Done interrupt before return */ snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX, SHIM_IMRX_DONE, SHIM_IMRX_DONE); + spin_lock_irqsave(&sdev->ipc_lock, flags); + /* * handle immediate reply from DSP core. If the msg is * found, set done bit in cmd_done which is called at the @@ -297,6 +301,8 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) snd_sof_ipc_reply(sdev, ipcx); bdw_dsp_done(sdev); + + spin_unlock_irqrestore(&sdev->ipc_lock, flags); } ipcd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD); @@ -488,7 +494,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) { struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; - unsigned long flags; int ret = 0; /* @@ -504,8 +509,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); - spin_lock_irqsave(&sdev->ipc_lock, flags); - if (reply.error < 0) { memcpy(msg->reply_data, &reply, sizeof(reply)); ret = reply.error; @@ -524,8 +527,6 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) } msg->reply_error = ret; - - spin_unlock_irqrestore(&sdev->ipc_lock, flags); } static void bdw_host_done(struct snd_sof_dev *sdev) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 2d1f8b405238ed..45c4ed73b88210 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -327,11 +327,16 @@ static irqreturn_t byt_irq_thread(int irq, void *context) /* reply message from DSP */ if (ipcx & SHIM_BYT_IPCX_DONE && !(imrx & SHIM_IMRX_DONE)) { + unsigned long flags; + /* Mask Done interrupt before first */ snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, SHIM_IMRX_DONE, SHIM_IMRX_DONE); + + spin_lock_irqsave(&sdev->ipc_lock, flags); + /* * handle immediate reply from DSP core. If the msg is * found, set done bit in cmd_done which is called at the @@ -343,6 +348,8 @@ static irqreturn_t byt_irq_thread(int irq, void *context) snd_sof_ipc_reply(sdev, ipcx); byt_dsp_done(sdev); + + spin_unlock_irqrestore(&sdev->ipc_lock, flags); } /* new message from DSP */ @@ -386,7 +393,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev) { struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; - unsigned long flags; int ret = 0; /* @@ -402,8 +408,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev) /* get reply */ sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); - spin_lock_irqsave(&sdev->ipc_lock, flags); - if (reply.error < 0) { memcpy(msg->reply_data, &reply, sizeof(reply)); ret = reply.error; @@ -422,8 +426,6 @@ static void byt_get_reply(struct snd_sof_dev *sdev) } msg->reply_error = ret; - - spin_unlock_irqrestore(&sdev->ipc_lock, flags); } static void byt_host_done(struct snd_sof_dev *sdev) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index c059d1170bab99..797ba3d4b2e353 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -50,6 +50,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) /* reply message from DSP */ if (hipcida & CNL_DSP_REG_HIPCIDA_DONE && hipcctl & CNL_DSP_REG_HIPCCTL_DONE) { + unsigned long flags; + hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR); msg_ext = hipci & CNL_DSP_REG_HIPCIDR_MSG_MASK; @@ -64,6 +66,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) CNL_DSP_REG_HIPCCTL, CNL_DSP_REG_HIPCCTL_DONE, 0); + spin_lock_irqsave(&sdev->ipc_lock, flags); + /* handle immediate reply from DSP core */ hda_dsp_ipc_get_reply(sdev); snd_sof_ipc_reply(sdev, msg); @@ -75,6 +79,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) cnl_ipc_dsp_done(sdev); + spin_unlock_irqrestore(&sdev->ipc_lock, flags); + ret = IRQ_HANDLED; } diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 73ead7070cdefd..c977a447051d59 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -72,7 +72,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) struct snd_sof_ipc_msg *msg = sdev->msg; struct sof_ipc_reply reply; struct sof_ipc_cmd_hdr *hdr; - unsigned long flags; int ret = 0; /* @@ -84,7 +83,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) dev_warn(sdev->dev, "unexpected ipc interrupt raised!\n"); return; } - spin_lock_irqsave(&sdev->ipc_lock, flags); hdr = msg->msg_data; if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) { @@ -123,7 +121,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) out: msg->reply_error = ret; - spin_unlock_irqrestore(&sdev->ipc_lock, flags); } static bool hda_dsp_ipc_is_sof(uint32_t msg) @@ -158,6 +155,8 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) /* is this a reply message from the DSP */ if (hipcie & HDA_DSP_REG_HIPCIE_DONE && hipcctl & HDA_DSP_REG_HIPCCTL_DONE) { + unsigned long flags; + hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI); msg = hipci & HDA_DSP_REG_HIPCI_MSG_MASK; @@ -172,6 +171,18 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) HDA_DSP_REG_HIPCCTL, HDA_DSP_REG_HIPCCTL_DONE, 0); + /* + * Make sure the interrupt thread cannot be preempted between + * waking up the sender and re-enabling the interrupt. Also + * protect against a theoretical race with sof_ipc_tx_message(): + * if the DSP is fast enough to receive an IPC message, reply to + * it, and the host interrupt processing calls this function on + * a different core from the one, where the sending is taking + * place, the message might not yet be marked as expecting a + * reply. + */ + spin_lock_irqsave(&sdev->ipc_lock, flags); + /* handle immediate reply from DSP core - ignore ROM messages */ if (hda_dsp_ipc_is_sof(msg)) { hda_dsp_ipc_get_reply(sdev); @@ -187,6 +198,8 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) /* set the done bit */ hda_dsp_ipc_dsp_done(sdev); + spin_unlock_irqrestore(&sdev->ipc_lock, flags); + ret = IRQ_HANDLED; } diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 4671eb6b553d42..2414640a32d18d 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -308,19 +308,8 @@ EXPORT_SYMBOL(sof_ipc_tx_message); int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) { struct snd_sof_ipc_msg *msg = &sdev->ipc->msg; - unsigned long flags; - - /* - * Protect against a theoretical race with sof_ipc_tx_message(): if the - * DSP is fast enough to receive an IPC message, reply to it, and the - * host interrupt processing calls this function on a different core - * from the one, where the sending is taking place, the message might - * not yet be marked as expecting a reply. - */ - spin_lock_irqsave(&sdev->ipc_lock, flags); if (msg->ipc_complete) { - spin_unlock_irqrestore(&sdev->ipc_lock, flags); dev_err(sdev->dev, "error: no reply expected, received 0x%x", msg_id); return -EINVAL; @@ -330,8 +319,6 @@ int snd_sof_ipc_reply(struct snd_sof_dev *sdev, u32 msg_id) msg->ipc_complete = true; wake_up(&msg->waitq); - spin_unlock_irqrestore(&sdev->ipc_lock, flags); - return 0; } EXPORT_SYMBOL(snd_sof_ipc_reply); From 901cd2a52b667b4915f6c50ef2eb7813058bd96c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 14 May 2019 16:08:01 -0500 Subject: [PATCH 1481/1995] ASoC: SOF: pcm: remove warning - initialize workqueue on open If the SOF hw_params() fail, typically with an IPC error thrown by the firmware, the period_elapsed workqueue is not initialized, but we still cancel it in hw_free(), which results in a kernel warning. Move the initialization to the .open callback. Tested on Broadwell (Samus) and IceLake. Fixes: e2803e610ae ("ASoC: SOF: PCM: add period_elapsed work to fix race condition in interrupt context") GitHub issue: https://github.com/thesofproject/linux/issues/932 Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pcm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index e9489205369068..6dc5f97be0bced 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -211,9 +211,6 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, /* save pcm hw_params */ memcpy(&spcm->params[substream->stream], params, sizeof(*params)); - INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work, - sof_pcm_period_elapsed_work); - /* clear hw_params_upon_resume flag */ spcm->hw_params_upon_resume[substream->stream] = 0; @@ -431,6 +428,9 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); + INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work, + sof_pcm_period_elapsed_work); + caps = &spcm->pcm.caps[substream->stream]; /* set any runtime constraints based on topology */ From e3ec7cf10f36b7ddebdf464b7063be41929eebdf Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 15 May 2019 11:28:35 -0500 Subject: [PATCH 1482/1995] ASoC: SOF: trace: move to opt-in with Kconfig and module parameter In a number of debug cases, the DMA-based trace can add problems (e.g. with HDaudio channel allocation). It also generates additional traffic on the bus and if the DMA handling is unreliable will prevent audio use-cases from working normally. Using the trace also requires tools to be installed on the target. The trace can be instead handled as dynamic debug. We can use a Kconfig to force the trace to be enabled in all cases, or use a module parameter to enable it on a need-basis, e.g. by setting "options snd_sof sof_debug=0x1" in a /etc/modprobe.d file. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/Kconfig | 8 ++++++++ sound/soc/sof/core.c | 26 ++++++++++++++++++++------ sound/soc/sof/sof-priv.h | 1 + sound/soc/sof/trace.c | 17 ++++++++++++++++- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index b204c65698f9f7..a468ffc1cfd5bc 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -128,6 +128,14 @@ config SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE Say Y if you want to enable caching the memory windows. If unsure, select "N". +config SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE + bool "SOF enable firmware trace" + help + The firmware trace can be enabled either at build-time with + this option, or dynamically by setting flags in the SOF core + module parameter (similar to dynamic debug) + If unsure, select "N". + endif ## SND_SOC_SOF_DEBUG endif ## SND_SOC_SOF_OPTIONS diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 5beda47cdf9fc7..70b471be07b275 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -16,6 +16,12 @@ #include "sof-priv.h" #include "ops.h" +static int sof_core_debug; +module_param_named(sof_debug, sof_core_debug, int, 0444); +MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)"); + +#define SOF_CORE_ENABLE_TRACE BIT(0) + /* SOF defaults if not provided by the platform in ms */ #define TIMEOUT_DEFAULT_IPC_MS 5 #define TIMEOUT_DEFAULT_BOOT_MS 100 @@ -350,12 +356,20 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) goto fw_run_err; } - /* init DMA trace */ - ret = snd_sof_init_trace(sdev); - if (ret < 0) { - /* non fatal */ - dev_warn(sdev->dev, - "warning: failed to initialize trace %d\n", ret); + if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE) || + (sof_core_debug & SOF_CORE_ENABLE_TRACE)) { + sdev->dtrace_is_supported = true; + + /* init DMA trace */ + ret = snd_sof_init_trace(sdev); + if (ret < 0) { + /* non fatal */ + dev_warn(sdev->dev, + "warning: failed to initialize trace %d\n", + ret); + } + } else { + dev_dbg(sdev->dev, "SOF firmware trace disabled\n"); } /* hereafter all FW boot flows are for PM reasons */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 01a6219c326b7f..03d852293d2794 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -415,6 +415,7 @@ struct snd_sof_dev { int dma_trace_pages; wait_queue_head_t trace_sleep; u32 host_offset; + u32 dtrace_is_supported; /* set with Kconfig or module parameter */ u32 dtrace_is_enabled; u32 dtrace_error; u32 dtrace_draining; diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index befed975161cb7..84d89206a0e0f8 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -167,6 +167,9 @@ int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev) struct sof_ipc_reply ipc_reply; int ret; + if (!sdev->dtrace_is_supported) + return 0; + if (sdev->dtrace_is_enabled || !sdev->dma_trace_pages) return -EINVAL; @@ -227,6 +230,9 @@ int snd_sof_init_trace(struct snd_sof_dev *sdev) { int ret; + if (!sdev->dtrace_is_supported) + return 0; + /* set false before start initialization */ sdev->dtrace_is_enabled = false; @@ -282,6 +288,9 @@ EXPORT_SYMBOL(snd_sof_init_trace); int snd_sof_trace_update_pos(struct snd_sof_dev *sdev, struct sof_ipc_dma_trace_posn *posn) { + if (!sdev->dtrace_is_supported) + return 0; + if (sdev->dtrace_is_enabled && sdev->host_offset != posn->host_offset) { sdev->host_offset = posn->host_offset; wake_up(&sdev->trace_sleep); @@ -298,6 +307,9 @@ int snd_sof_trace_update_pos(struct snd_sof_dev *sdev, /* an error has occurred within the DSP that prevents further trace */ void snd_sof_trace_notify_for_error(struct snd_sof_dev *sdev) { + if (!sdev->dtrace_is_supported) + return; + if (sdev->dtrace_is_enabled) { dev_err(sdev->dev, "error: waking up any trace sleepers\n"); sdev->dtrace_error = true; @@ -310,7 +322,7 @@ void snd_sof_release_trace(struct snd_sof_dev *sdev) { int ret; - if (!sdev->dtrace_is_enabled) + if (!sdev->dtrace_is_supported || !sdev->dtrace_is_enabled) return; ret = snd_sof_dma_trace_trigger(sdev, SNDRV_PCM_TRIGGER_STOP); @@ -331,6 +343,9 @@ EXPORT_SYMBOL(snd_sof_release_trace); void snd_sof_free_trace(struct snd_sof_dev *sdev) { + if (!sdev->dtrace_is_supported) + return; + snd_sof_release_trace(sdev); snd_dma_free_pages(&sdev->dmatb); From 311ceec64b5626d970d7e037369d65e3ee5862bc Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Sun, 21 Apr 2019 23:35:29 -0700 Subject: [PATCH 1483/1995] ASoC: SOF: add mode parameter for snd_sof_debugfs_buf_item Add mode parameter for snd_sof_debugfs_buf_item() to specify the mode while creating debugfs entries. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/debug.c | 4 ++-- sound/soc/sof/loader.c | 4 ++-- sound/soc/sof/sof-priv.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 55f1d808dba04f..219c3becf670fb 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -161,7 +161,7 @@ EXPORT_SYMBOL_GPL(snd_sof_debugfs_io_item); /* create FS entry for debug files to expose kernel memory */ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, void *base, size_t size, - const char *name) + const char *name, mode_t mode) { struct snd_sof_dfsentry *dfse; @@ -177,7 +177,7 @@ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, dfse->size = size; dfse->sdev = sdev; - dfse->dfsentry = debugfs_create_file(name, 0444, sdev->debugfs_root, + dfse->dfsentry = debugfs_create_file(name, mode, sdev->debugfs_root, dfse, &sof_dfs_fops); if (!dfse->dfsentry) { /* can't rely on debugfs, only log error and keep going */ diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 628fae5524424a..1021df12db112f 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -337,11 +337,11 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) init_waitqueue_head(&sdev->boot_wait); sdev->boot_complete = false; - /* create fw_version debugfs to store boot version info */ + /* create read-only fw_version debugfs to store boot version info */ if (sdev->first_boot) { ret = snd_sof_debugfs_buf_item(sdev, &sdev->fw_version, sizeof(sdev->fw_version), - "fw_version"); + "fw_version", 0444); /* errors are only due to memory allocation, not debugfs */ if (ret < 0) { dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n"); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 03d852293d2794..14faf3c4550e08 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -547,7 +547,7 @@ int snd_sof_debugfs_io_item(struct snd_sof_dev *sdev, enum sof_debugfs_access_type access_type); int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, void *base, size_t size, - const char *name); + const char *name, mode_t mode); int snd_sof_trace_update_pos(struct snd_sof_dev *sdev, struct sof_ipc_dma_trace_posn *posn); void snd_sof_trace_notify_for_error(struct snd_sof_dev *sdev); From 9d54322ebc9b55643229ff4a4b086bced6ae234f Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 7 May 2019 22:05:37 -0700 Subject: [PATCH 1484/1995] ASoC: SOF: ipc: Introduce SOF_IPC_GLB_TEST_MSG IPC command Add a new class of IPC command along with the first test type, IPC_FLOOD, which will be used for flooding the DSP with IPCs. Signed-off-by: Ranjani Sridharan --- include/sound/sof/header.h | 6 +++++- sound/soc/sof/ipc.c | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index ab5862d80afedf..12867bbd4372ac 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -49,6 +49,7 @@ #define SOF_IPC_GLB_DAI_MSG SOF_GLB_TYPE(0x8U) #define SOF_IPC_GLB_TRACE_MSG SOF_GLB_TYPE(0x9U) #define SOF_IPC_GLB_GDB_DEBUG SOF_GLB_TYPE(0xAU) +#define SOF_IPC_GLB_TEST_MSG SOF_GLB_TYPE(0xBU) /* * DSP Command Message Types @@ -99,11 +100,14 @@ #define SOF_IPC_STREAM_VORBIS_PARAMS SOF_CMD_TYPE(0x010) #define SOF_IPC_STREAM_VORBIS_FREE SOF_CMD_TYPE(0x011) -/* trace and debug */ +/* trace */ #define SOF_IPC_TRACE_DMA_PARAMS SOF_CMD_TYPE(0x001) #define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002) #define SOF_IPC_TRACE_DMA_PARAMS_EXT SOF_CMD_TYPE(0x003) +/* debug */ +#define SOF_IPC_TEST_IPC_FLOOD SOF_CMD_TYPE(0x001) + /* Get message component id */ #define SOF_IPC_MESSAGE_ID(x) ((x) & 0xffff) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 2414640a32d18d..558b596e2133a4 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -175,6 +175,15 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) break; case SOF_IPC_GLB_TRACE_MSG: str = "GLB_TRACE_MSG"; break; + case SOF_IPC_GLB_TEST_MSG: + str = "GLB_TEST_MSG"; + switch (type) { + case SOF_IPC_TEST_IPC_FLOOD: + str2 = "IPC_FLOOD"; break; + default: + str2 = "unknown type"; break; + } + break; default: str = "unknown GLB command"; break; } From cab8ad55233c58ac5e30fc7ecd0ddeb36e67540a Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 7 May 2019 22:08:19 -0700 Subject: [PATCH 1485/1995] ASoC: SOF: debug: add new debugfs entries for IPC flood test Add a couple of new debugfs entries "ipc_flood_count" and "ipc_flood_duration_ms" that can be used to execute the IPC flood test. "ipc_flood_count" floods the DSP with the number of test IPCs specified and ipc_flood_duration_ms floods the DSP with test IPC's for the duration(in ms) specified. The test stats such as average, min and max IPC response times are logged in the dmesg and saved in the debugfs entry cache buffer. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/Kconfig | 8 ++ sound/soc/sof/debug.c | 243 +++++++++++++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 6 +- 3 files changed, 256 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index a468ffc1cfd5bc..8e2188e5600015 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -136,6 +136,14 @@ config SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE module parameter (similar to dynamic debug) If unsure, select "N". +config SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST + bool "SOF enable IPC flood test" + help + This option enables the IPC flood test which can be used to flood + the DSP with test IPCs and gather stats about response times. + Say Y if you want to enable IPC flood test. + If unsure, select "N". + endif ## SND_SOC_SOF_DEBUG endif ## SND_SOC_SOF_OPTIONS diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 219c3becf670fb..54bb53bfc81bf2 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -17,6 +17,203 @@ #include "sof-priv.h" #include "ops.h" +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) +#define MAX_IPC_FLOOD_DURATION_MS 1000 +#define MAX_IPC_FLOOD_COUNT 10000 +#define IPC_FLOOD_TEST_RESULT_LEN 512 + +static int sof_debug_ipc_flood_test(struct snd_sof_dev *sdev, + struct snd_sof_dfsentry *dfse, + bool flood_duration_test, + unsigned long ipc_duration_ms, + unsigned long ipc_count) +{ + struct sof_ipc_cmd_hdr hdr; + struct sof_ipc_reply reply; + u64 min_response_time = U64_MAX; + ktime_t start, end, test_end; + u64 avg_response_time = 0; + u64 max_response_time = 0; + u64 ipc_response_time; + int i = 0; + int ret; + + /* configure test IPC */ + hdr.cmd = SOF_IPC_GLB_TEST_MSG | SOF_IPC_TEST_IPC_FLOOD; + hdr.size = sizeof(hdr); + + /* set test end time for duration flood test */ + if (flood_duration_test) + test_end = ktime_get_ns() + ipc_duration_ms * NSEC_PER_MSEC; + + /* send test IPC's */ + while (1) { + start = ktime_get(); + ret = sof_ipc_tx_message(sdev->ipc, hdr.cmd, &hdr, hdr.size, + &reply, sizeof(reply)); + end = ktime_get(); + + if (ret < 0) + break; + + /* compute min and max response times */ + ipc_response_time = ktime_to_ns(ktime_sub(end, start)); + min_response_time = min(min_response_time, ipc_response_time); + max_response_time = max(max_response_time, ipc_response_time); + + /* sum up response times */ + avg_response_time += ipc_response_time; + i++; + + /* test complete? */ + if (flood_duration_test) { + if (ktime_to_ns(end) >= test_end) + break; + } else { + if (i == ipc_count) + break; + } + } + + if (ret < 0) + dev_err(sdev->dev, + "error: ipc flood test failed at %d iterations\n", i); + + /* return if the first IPC fails */ + if (!i) + return ret; + + /* compute average response time */ + do_div(avg_response_time, i); + + /* clear previous test output */ + memset(dfse->cache_buf, 0, IPC_FLOOD_TEST_RESULT_LEN); + + if (flood_duration_test) { + dev_dbg(sdev->dev, "IPC Flood test duration: %lums\n", + ipc_duration_ms); + snprintf(dfse->cache_buf, IPC_FLOOD_TEST_RESULT_LEN, + "IPC Flood test duration: %lums\n", ipc_duration_ms); + } + + dev_dbg(sdev->dev, + "IPC Flood count: %d, Avg response time: %lluns\n", + i, avg_response_time); + dev_dbg(sdev->dev, "Max response time: %lluns\n", + max_response_time); + dev_dbg(sdev->dev, "Min response time: %lluns\n", + min_response_time); + + /* format output string */ + snprintf(dfse->cache_buf + strlen(dfse->cache_buf), + IPC_FLOOD_TEST_RESULT_LEN - strlen(dfse->cache_buf), + "IPC Flood count: %d\nAvg response time: %lluns\n", + i, avg_response_time); + + snprintf(dfse->cache_buf + strlen(dfse->cache_buf), + IPC_FLOOD_TEST_RESULT_LEN - strlen(dfse->cache_buf), + "Max response time: %lluns\nMin response time: %lluns\n", + max_response_time, min_response_time); + + return ret; +} +#endif + +static ssize_t sof_dfsentry_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) + struct snd_sof_dfsentry *dfse = file->private_data; + struct snd_sof_dev *sdev = dfse->sdev; + unsigned long ipc_duration_ms = 0; + bool flood_duration_test = false; + unsigned long ipc_count = 0; + int err; +#endif + size_t size; + char *string; + int ret; + + string = kzalloc(count, GFP_KERNEL); + if (!string) + return -ENOMEM; + + size = simple_write_to_buffer(string, count, ppos, buffer, count); + ret = size; + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) + /* + * write op is only supported for ipc_flood_count or + * ipc_flood_duration_ms debugfs entries atm. + * ipc_flood_count floods the DSP with the number of IPC's specified. + * ipc_duration_ms test floods the DSP for the time specified + * in the debugfs entry. + */ + if (strcmp(dfse->dfsentry->d_name.name, "ipc_flood_count") && + strcmp(dfse->dfsentry->d_name.name, "ipc_flood_duration_ms")) + return -EINVAL; + + if (!strcmp(dfse->dfsentry->d_name.name, "ipc_flood_duration_ms")) + flood_duration_test = true; + + /* test completion criterion */ + if (flood_duration_test) + ret = kstrtoul(string, 0, &ipc_duration_ms); + else + ret = kstrtoul(string, 0, &ipc_count); + if (ret < 0) + return ret; + + /* limit max duration/ipc count for flood test */ + if (flood_duration_test) { + if (!ipc_duration_ms) { + ret = size; + goto out; + } + + /* find the minimum. min() is not used to avoid warnings */ + if (ipc_duration_ms > MAX_IPC_FLOOD_DURATION_MS) + ipc_duration_ms = MAX_IPC_FLOOD_DURATION_MS; + } else { + if (!ipc_count) { + ret = size; + goto out; + } + + /* find the minimum. min() is not used to avoid warnings */ + if (ipc_count > MAX_IPC_FLOOD_COUNT) + ipc_count = MAX_IPC_FLOOD_COUNT; + } + + ret = pm_runtime_get_sync(sdev->dev); + if (ret < 0) { + dev_err_ratelimited(sdev->dev, + "error: debugfs write failed to resume %d\n", + ret); + pm_runtime_put_noidle(sdev->dev); + return ret; + } + + /* flood test */ + ret = sof_debug_ipc_flood_test(sdev, dfse, flood_duration_test, + ipc_duration_ms, ipc_count); + + pm_runtime_mark_last_busy(sdev->dev); + err = pm_runtime_put_autosuspend(sdev->dev); + if (err < 0) + dev_err_ratelimited(sdev->dev, + "error: debugfs write failed to idle %d\n", + err); + + /* return size if test is successful */ + if (ret >= 0) + ret = size; +out: +#endif + kfree(string); + return ret; +} + static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { @@ -28,6 +225,22 @@ static ssize_t sof_dfsentry_read(struct file *file, char __user *buffer, int size; u8 *buf; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) + if ((!strcmp(dfse->dfsentry->d_name.name, "ipc_flood_count") || + !strcmp(dfse->dfsentry->d_name.name, "ipc_flood_duration_ms")) && + dfse->cache_buf) { + if (*ppos) + return 0; + + count = strlen(dfse->cache_buf); + size_ret = copy_to_user(buffer, dfse->cache_buf, count); + if (size_ret) + return -EFAULT; + + *ppos += count; + return count; + } +#endif size = dfse->size; /* validate position & count */ @@ -107,6 +320,7 @@ static const struct file_operations sof_dfs_fops = { .open = simple_open, .read = sof_dfsentry_read, .llseek = default_llseek, + .write = sof_dfsentry_write, }; /* create FS entry for debug files that can expose DSP memories, registers */ @@ -177,6 +391,17 @@ int snd_sof_debugfs_buf_item(struct snd_sof_dev *sdev, dfse->size = size; dfse->sdev = sdev; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) + /* + * cache_buf is unused for SOF_DFSENTRY_TYPE_BUF debugfs entries. + * So, use it to save the results of the last IPC flood test. + */ + dfse->cache_buf = devm_kzalloc(sdev->dev, IPC_FLOOD_TEST_RESULT_LEN, + GFP_KERNEL); + if (!dfse->cache_buf) + return -ENOMEM; +#endif + dfse->dfsentry = debugfs_create_file(name, mode, sdev->debugfs_root, dfse, &sof_dfs_fops); if (!dfse->dfsentry) { @@ -221,6 +446,24 @@ int snd_sof_dbg_init(struct snd_sof_dev *sdev) return err; } +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST) + /* create read-write ipc_flood_count debugfs entry */ + err = snd_sof_debugfs_buf_item(sdev, NULL, 0, + "ipc_flood_count", 0666); + + /* errors are only due to memory allocation, not debugfs */ + if (err < 0) + return err; + + /* create read-write ipc_flood_duration_ms debugfs entry */ + err = snd_sof_debugfs_buf_item(sdev, NULL, 0, + "ipc_flood_duration_ms", 0666); + + /* errors are only due to memory allocation, not debugfs */ + if (err < 0) + return err; +#endif + return 0; } EXPORT_SYMBOL_GPL(snd_sof_dbg_init); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 14faf3c4550e08..563623bcaad6e2 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -56,6 +56,10 @@ #define SOF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_FLOAT) +#define ENABLE_DEBUGFS_CACHEBUF \ + (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) || \ + IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST)) + struct snd_sof_dev; struct snd_sof_ipc_msg; struct snd_sof_ipc; @@ -226,7 +230,7 @@ struct snd_sof_dfsentry { * or if it is accessible only when the DSP is in D0. */ enum sof_debugfs_access_type access_type; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) +#if ENABLE_DEBUGFS_CACHEBUF char *cache_buf; /* buffer to cache the contents of debugfs memory */ #endif struct snd_sof_dev *sdev; From cd01004a1a519087e333ad683fff208d2b619cda Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Thu, 25 Apr 2019 13:24:33 +0300 Subject: [PATCH 1486/1995] ASoC: SOF: topology: add support for mux/demux component Add enumerations to support mux/demux processing component. Signed-off-by: Jaska Uimonen --- include/sound/sof/topology.h | 3 +++ sound/soc/sof/topology.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h index 4afed7f1c6b21a..41dcabf89899f9 100644 --- a/include/sound/sof/topology.h +++ b/include/sound/sof/topology.h @@ -35,6 +35,7 @@ enum sof_comp_type { SOF_COMP_KEYWORD_DETECT, SOF_COMP_KPB, /* A key phrase buffer component */ SOF_COMP_SELECTOR, /**< channel selector component */ + SOF_COMP_DEMUX, /* keep FILEREAD/FILEWRITE as the last ones */ SOF_COMP_FILEREAD = 10000, /**< host test based file IO */ SOF_COMP_FILEWRITE = 10001, /**< host test based file IO */ @@ -175,6 +176,8 @@ enum sof_ipc_process_type { SOF_PROCESS_KEYWORD_DETECT, /**< Keyword Detection */ SOF_PROCESS_KPB, /**< KeyPhrase Buffer Manager */ SOF_PROCESS_CHAN_SELECTOR, /**< Channel Selector */ + SOF_PROCESS_MUX, + SOF_PROCESS_DEMUX, }; /* generic "effect", "codec" or proprietary processing component */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index c88afa872a58df..d0179e797d60a9 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -394,6 +394,8 @@ static const struct sof_process_types sof_process[] = { {"KEYWORD_DETECT", SOF_PROCESS_KEYWORD_DETECT, SOF_COMP_KEYWORD_DETECT}, {"KPB", SOF_PROCESS_KPB, SOF_COMP_KPB}, {"CHAN_SELECTOR", SOF_PROCESS_CHAN_SELECTOR, SOF_COMP_SELECTOR}, + {"MUX", SOF_PROCESS_MUX, SOF_COMP_MUX}, + {"DEMUX", SOF_PROCESS_DEMUX, SOF_COMP_DEMUX}, }; static enum sof_ipc_process_type find_process(const char *name) From 0ca91e658304401eaa3b8afd9e8af1e08fd2329f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 21 May 2019 14:04:13 -0500 Subject: [PATCH 1487/1995] ASoC: SOF: acpi: add module param to disable pm_runtime Add debug option to disable pm_runtime. This is not intended for production devices but is very useful for platform bringup. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-acpi-dev.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index e9cf69874b5b1f..38062dd00dd208 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -32,6 +32,12 @@ static char *tplg_path; module_param(tplg_path, charp, 0444); MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); +static int sof_acpi_debug; +module_param_named(sof_debug, sof_acpi_debug, int, 0444); +MODULE_PARM_DESC(sof_debug, "SOF ACPI debug options (0x0 all off)"); + +#define SOF_ACPI_DISABLE_PM_RUNTIME BIT(0) + #if IS_ENABLED(CONFIG_SND_SOC_SOF_HASWELL) static const struct sof_dev_desc sof_acpi_haswell_desc = { .machines = snd_soc_acpi_intel_haswell_machines, @@ -174,6 +180,9 @@ static const struct dev_pm_ops sof_acpi_pm = { static void sof_acpi_probe_complete(struct device *dev) { + if (sof_acpi_debug & SOF_ACPI_DISABLE_PM_RUNTIME) + return; + /* allow runtime_pm */ pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); pm_runtime_use_autosuspend(dev); @@ -274,7 +283,8 @@ static int sof_acpi_probe(struct platform_device *pdev) static int sof_acpi_remove(struct platform_device *pdev) { - pm_runtime_disable(&pdev->dev); + if (!(sof_acpi_debug & SOF_ACPI_DISABLE_PM_RUNTIME)) + pm_runtime_disable(&pdev->dev); /* call sof helper for DSP hardware remove */ snd_sof_device_remove(&pdev->dev); From 853c93877c3992332f7dda7058025b728318c231 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 21 May 2019 14:05:18 -0500 Subject: [PATCH 1488/1995] ASoC: SOF: pci: add module param to disable pm_runtime Add debug option to disable pm_runtime. This is not intended for production devices but is very useful for platform bringup. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-pci-dev.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 5f0eccbafc2204..c144d03244ca06 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -29,6 +29,12 @@ static char *tplg_path; module_param(tplg_path, charp, 0444); MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); +static int sof_pci_debug; +module_param_named(sof_debug, sof_pci_debug, int, 0444); +MODULE_PARM_DESC(sof_debug, "SOF PCI debug options (0x0 all off)"); + +#define SOF_PCI_DISABLE_PM_RUNTIME BIT(0) + #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) static const struct sof_dev_desc bxt_desc = { .machines = snd_soc_acpi_intel_bxt_machines, @@ -193,6 +199,9 @@ static void sof_pci_probe_complete(struct device *dev) { dev_dbg(dev, "Completing SOF PCI probe"); + if (sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME) + return; + /* allow runtime_pm */ pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); pm_runtime_use_autosuspend(dev); @@ -311,7 +320,8 @@ static void sof_pci_remove(struct pci_dev *pci) snd_sof_device_remove(&pci->dev); /* follow recommendation in pci-driver.c to increment usage counter */ - pm_runtime_get_noresume(&pci->dev); + if (!(sof_pci_debug & SOF_PCI_DISABLE_PM_RUNTIME)) + pm_runtime_get_noresume(&pci->dev); /* release pci regions and disable device */ pci_release_regions(pci); From c86e79bb6b0410f01f4195530a4def9ef2027600 Mon Sep 17 00:00:00 2001 From: Dragos Tarcatu Date: Wed, 22 May 2019 18:08:14 +0300 Subject: [PATCH 1489/1995] ASOC: SOF: ipc: prevent logging trace messages If the firmware is set for verbose tracing, the kernel log is flooded with ipc rx/ipc rx done messages. Prevent logging those unless the verbose IPC debugging config option is set. Signed-off-by: Dragos Tarcatu --- sound/soc/sof/ipc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 558b596e2133a4..f3eb46bc808beb 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -196,7 +196,8 @@ static void ipc_log_header(struct device *dev, u8 *text, u32 cmd) #else static inline void ipc_log_header(struct device *dev, u8 *text, u32 cmd) { - dev_dbg(dev, "%s: 0x%x\n", text, cmd); + if ((cmd & SOF_GLB_TYPE_MASK) != SOF_IPC_GLB_TRACE_MSG) + dev_dbg(dev, "%s: 0x%x\n", text, cmd); } #endif From 4d1fc20e3e01f7d91d9414f0265c7342b09931cf Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 23 Jan 2019 22:49:58 +0200 Subject: [PATCH 1490/1995] ASoC: SOF: Do not send cmd via SHIM register We use shim registers only to notify the other side that a message was sent. The actual information for the message is transmitted via mailbox. cmd information inside shim register is not used by the DSP, so we remove it to avoid confusion. Signed-off-by: Daniel Baluta --- sound/soc/sof/intel/byt.c | 5 +---- sound/soc/sof/intel/cnl.c | 4 +--- sound/soc/sof/intel/hda-ipc.c | 4 +--- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 45c4ed73b88210..5afe6ab4d011b2 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -378,13 +378,10 @@ static irqreturn_t byt_irq_thread(int irq, void *context) static int byt_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { - u64 cmd = msg->header; - /* send the message */ sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, msg->msg_size); - snd_sof_dsp_write64(sdev, BYT_DSP_BAR, SHIM_IPCX, - cmd | SHIM_BYT_IPCX_BUSY); + snd_sof_dsp_write64(sdev, BYT_DSP_BAR, SHIM_IPCX, SHIM_BYT_IPCX_BUSY); return 0; } diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 797ba3d4b2e353..72e20e8d3918cf 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -153,13 +153,11 @@ static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev) static int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { - u32 cmd = msg->header; - /* send the message */ sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, msg->msg_size); snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, - cmd | CNL_DSP_REG_HIPCIDR_BUSY); + CNL_DSP_REG_HIPCIDR_BUSY); return 0; } diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index c977a447051d59..8ff61c7890d401 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -56,13 +56,11 @@ static void hda_dsp_ipc_dsp_done(struct snd_sof_dev *sdev) int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { - u32 cmd = msg->header; - /* send IPC message to DSP */ sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, msg->msg_size); snd_sof_dsp_write(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI, - cmd | HDA_DSP_REG_HIPCI_BUSY); + HDA_DSP_REG_HIPCI_BUSY); return 0; } From d63f56884f3219d52f37176c9681beb15d295ea3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 18 May 2019 15:49:33 -0500 Subject: [PATCH 1491/1995] ASoC: SOF: Intel: cnl-ipc: read all IPC registers first Align with hardware recommended sequences, and read all IPC registers before doing any other actions. Playing with BUSY and DONE bits may invalidate values. The values read may not actually be necessary but at least this provides a snapshot of the IPC registers with no consistency issues. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/cnl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 72e20e8d3918cf..93e95e213e0909 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -42,6 +42,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL); hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR); + hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDD); + hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR); /* reenable IPC interrupt */ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, @@ -52,8 +54,6 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) hipcctl & CNL_DSP_REG_HIPCCTL_DONE) { unsigned long flags; - hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, - CNL_DSP_REG_HIPCIDR); msg_ext = hipci & CNL_DSP_REG_HIPCIDR_MSG_MASK; msg = hipcida & CNL_DSP_REG_HIPCIDA_MSG_MASK; @@ -86,8 +86,6 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) /* new message from DSP */ if (hipctdr & CNL_DSP_REG_HIPCTDR_BUSY) { - hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, - CNL_DSP_REG_HIPCTDD); msg = hipctdr & CNL_DSP_REG_HIPCTDR_MSG_MASK; msg_ext = hipctdd & CNL_DSP_REG_HIPCTDD_MSG_MASK; From 146610b0df2d88c2aa57c7983e5ff9b4a9784d1e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 18 May 2019 16:02:41 -0500 Subject: [PATCH 1492/1995] ASoC: SOF: Intel: cnl-ipc: move code around for clarity Move all register access to cnl_ipc_host_done() No functionality change. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/cnl.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 93e95e213e0909..fecab6a5535214 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -101,15 +101,6 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) snd_sof_ipc_msgs_rx(sdev); } - /* - * clear busy interrupt to tell dsp controller this - * interrupt has been accepted, not trigger it again - */ - snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, - CNL_DSP_REG_HIPCTDR, - CNL_DSP_REG_HIPCTDR_BUSY, - CNL_DSP_REG_HIPCTDR_BUSY); - cnl_ipc_host_done(sdev); ret = IRQ_HANDLED; @@ -120,6 +111,14 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) static void cnl_ipc_host_done(struct snd_sof_dev *sdev) { + /* + * clear busy interrupt to tell dsp controller this + * interrupt has been accepted, not trigger it again + */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + CNL_DSP_REG_HIPCTDR, + CNL_DSP_REG_HIPCTDR_BUSY, + CNL_DSP_REG_HIPCTDR_BUSY); /* * set done bit to ack dsp the msg has been * processed and send reply msg to dsp From 849a175690e251f8413ab1a36a8832c615f8a0b5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 18 May 2019 16:07:45 -0500 Subject: [PATCH 1493/1995] ASoC: SOF: Intel: cnl-ipc: re-enable IPC IRQ at end of handler Align with Skylake driver and enable the IRQ at end of handler, instead of at beginning. Also add an error log if we have nothing to do in this handler. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/cnl.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index fecab6a5535214..5b3dd6b5a0db4a 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -37,7 +37,7 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) u32 hipctdd; u32 msg; u32 msg_ext; - irqreturn_t ret = IRQ_NONE; + bool ipc_irq = false; hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL); @@ -45,10 +45,6 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDD); hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR); - /* reenable IPC interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, - HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); - /* reply message from DSP */ if (hipcida & CNL_DSP_REG_HIPCIDA_DONE && hipcctl & CNL_DSP_REG_HIPCCTL_DONE) { @@ -81,7 +77,7 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) spin_unlock_irqrestore(&sdev->ipc_lock, flags); - ret = IRQ_HANDLED; + ipc_irq = true; } /* new message from DSP */ @@ -103,10 +99,22 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) cnl_ipc_host_done(sdev); - ret = IRQ_HANDLED; + ipc_irq = true; + } + + if (!ipc_irq) { + /* + * This interrupt is not shared so no need to return IRQ_NONE. + */ + dev_err_ratelimited(sdev->dev, + "error: nothing to do in IRQ thread\n"); } - return ret; + /* re-enable IPC interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); + + return IRQ_HANDLED; } static void cnl_ipc_host_done(struct snd_sof_dev *sdev) From 3e73d2fec12a90aed91cdf30463569308fd910c2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 18 May 2019 16:11:41 -0500 Subject: [PATCH 1494/1995] ASoC: SOF: Intel: hda-ipc: read all IPC registers first Align with hardware recommended sequences, and read all IPC registers before doing any other actions. Playing with BUSY and DONE bits may invalidate values. The values read may not actually be necessary but at least this provides a snapshot of the IPC registers with no consistency issues. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-ipc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 8ff61c7890d401..a40520b09873f9 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -145,6 +145,8 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) HDA_DSP_REG_HIPCIE); hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT); hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL); + hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI); + hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCTE); /* reenable IPC interrupt */ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, @@ -155,8 +157,6 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) hipcctl & HDA_DSP_REG_HIPCCTL_DONE) { unsigned long flags; - hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_DSP_REG_HIPCI); msg = hipci & HDA_DSP_REG_HIPCI_MSG_MASK; msg_ext = hipcie & HDA_DSP_REG_HIPCIE_MSG_MASK; @@ -205,8 +205,6 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) if (hipct & HDA_DSP_REG_HIPCT_BUSY && hipcctl & HDA_DSP_REG_HIPCCTL_BUSY) { - hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, - HDA_DSP_REG_HIPCTE); msg = hipct & HDA_DSP_REG_HIPCT_MSG_MASK; msg_ext = hipcte & HDA_DSP_REG_HIPCTE_MSG_MASK; From 5e8c6a54dc4e213970ed03bfcfda4b437e3471c7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 18 May 2019 16:15:04 -0500 Subject: [PATCH 1495/1995] ASoC: SOF: Intel: hda-ipc: re-enable IPC IRQ at end of handler Align with Skylake driver and enable the IRQ at end of handler, instead of at beginning. Also add an error log if we have nothing to do in this handler. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-ipc.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index a40520b09873f9..97c88982d2d9f4 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -131,7 +131,6 @@ static bool hda_dsp_ipc_is_sof(uint32_t msg) irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = context; - irqreturn_t ret = IRQ_NONE; u32 hipci; u32 hipcie; u32 hipct; @@ -139,6 +138,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) u32 hipcctl; u32 msg; u32 msg_ext; + bool ipc_irq = false; /* read IPC status */ hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -148,10 +148,6 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI); hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCTE); - /* reenable IPC interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, - HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); - /* is this a reply message from the DSP */ if (hipcie & HDA_DSP_REG_HIPCIE_DONE && hipcctl & HDA_DSP_REG_HIPCCTL_DONE) { @@ -198,7 +194,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) spin_unlock_irqrestore(&sdev->ipc_lock, flags); - ret = IRQ_HANDLED; + ipc_irq = true; } /* is this a new message from DSP */ @@ -228,10 +224,22 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) hda_dsp_ipc_host_done(sdev); - ret = IRQ_HANDLED; + ipc_irq = true; } - return ret; + if (!ipc_irq) { + /* + * This interrupt is not shared so no need to return IRQ_NONE. + */ + dev_err_ratelimited(sdev->dev, + "error: nothing to do in IRQ thread\n"); + } + + /* re-enable IPC interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, + HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); + + return IRQ_HANDLED; } /* is this IRQ for ADSP ? - we only care about IPC here */ From d807d30dcf405d808784e8df1380afe047746e82 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 18 May 2019 15:40:57 -0500 Subject: [PATCH 1496/1995] ASoC: SOF: Intel: ipc: don't check for HIPCCTL register value The HIPCCTL register controls the IPC interrupts. It can be set or cleared to mask or enable these interrupts, but it makes no sense to read and test its fields in an interrupt (which can only executed if its fields are set). Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/cnl.c | 5 +---- sound/soc/sof/intel/hda-ipc.c | 8 ++------ 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 5b3dd6b5a0db4a..906a6e46d76451 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -31,7 +31,6 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) { struct snd_sof_dev *sdev = context; u32 hipci; - u32 hipcctl; u32 hipcida; u32 hipctdr; u32 hipctdd; @@ -40,14 +39,12 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) bool ipc_irq = false; hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); - hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL); hipctdr = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDR); hipctdd = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCTDD); hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR); /* reply message from DSP */ - if (hipcida & CNL_DSP_REG_HIPCIDA_DONE && - hipcctl & CNL_DSP_REG_HIPCCTL_DONE) { + if (hipcida & CNL_DSP_REG_HIPCIDA_DONE) { unsigned long flags; msg_ext = hipci & CNL_DSP_REG_HIPCIDR_MSG_MASK; diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 97c88982d2d9f4..ad2b4c64570a4b 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -135,7 +135,6 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) u32 hipcie; u32 hipct; u32 hipcte; - u32 hipcctl; u32 msg; u32 msg_ext; bool ipc_irq = false; @@ -144,13 +143,11 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE); hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT); - hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL); hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI); hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCTE); /* is this a reply message from the DSP */ - if (hipcie & HDA_DSP_REG_HIPCIE_DONE && - hipcctl & HDA_DSP_REG_HIPCCTL_DONE) { + if (hipcie & HDA_DSP_REG_HIPCIE_DONE) { unsigned long flags; msg = hipci & HDA_DSP_REG_HIPCI_MSG_MASK; @@ -198,8 +195,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) } /* is this a new message from DSP */ - if (hipct & HDA_DSP_REG_HIPCT_BUSY && - hipcctl & HDA_DSP_REG_HIPCCTL_BUSY) { + if (hipct & HDA_DSP_REG_HIPCT_BUSY) { msg = hipct & HDA_DSP_REG_HIPCT_MSG_MASK; msg_ext = hipcte & HDA_DSP_REG_HIPCTE_MSG_MASK; From 924347de73e488fa21772af90566821694dcce55 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 24 May 2019 13:13:24 -0500 Subject: [PATCH 1497/1995] ASoC: SOF: Intel: ipc: simplify spin-lock usage spin_lock_irqsave is not required, feedback from Takashi Iwai. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/bdw.c | 6 ++---- sound/soc/sof/intel/byt.c | 6 ++---- sound/soc/sof/intel/cnl.c | 6 ++---- sound/soc/sof/intel/hda-ipc.c | 7 ++----- 4 files changed, 8 insertions(+), 17 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 4c06332b4de3e6..70d524ef9bc07d 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -281,14 +281,12 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) /* reply message from DSP */ if (ipcx & SHIM_IPCX_DONE && !(imrx & SHIM_IMRX_DONE)) { - unsigned long flags; - /* Mask Done interrupt before return */ snd_sof_dsp_update_bits_unlocked(sdev, BDW_DSP_BAR, SHIM_IMRX, SHIM_IMRX_DONE, SHIM_IMRX_DONE); - spin_lock_irqsave(&sdev->ipc_lock, flags); + spin_lock_irq(&sdev->ipc_lock); /* * handle immediate reply from DSP core. If the msg is @@ -302,7 +300,7 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) bdw_dsp_done(sdev); - spin_unlock_irqrestore(&sdev->ipc_lock, flags); + spin_unlock_irq(&sdev->ipc_lock); } ipcd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 5afe6ab4d011b2..107d711efc3f05 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -327,15 +327,13 @@ static irqreturn_t byt_irq_thread(int irq, void *context) /* reply message from DSP */ if (ipcx & SHIM_BYT_IPCX_DONE && !(imrx & SHIM_IMRX_DONE)) { - unsigned long flags; - /* Mask Done interrupt before first */ snd_sof_dsp_update_bits64_unlocked(sdev, BYT_DSP_BAR, SHIM_IMRX, SHIM_IMRX_DONE, SHIM_IMRX_DONE); - spin_lock_irqsave(&sdev->ipc_lock, flags); + spin_lock_irq(&sdev->ipc_lock); /* * handle immediate reply from DSP core. If the msg is @@ -349,7 +347,7 @@ static irqreturn_t byt_irq_thread(int irq, void *context) byt_dsp_done(sdev); - spin_unlock_irqrestore(&sdev->ipc_lock, flags); + spin_unlock_irq(&sdev->ipc_lock); } /* new message from DSP */ diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 906a6e46d76451..9a4927b6b6ae54 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -45,8 +45,6 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) /* reply message from DSP */ if (hipcida & CNL_DSP_REG_HIPCIDA_DONE) { - unsigned long flags; - msg_ext = hipci & CNL_DSP_REG_HIPCIDR_MSG_MASK; msg = hipcida & CNL_DSP_REG_HIPCIDA_MSG_MASK; @@ -59,7 +57,7 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) CNL_DSP_REG_HIPCCTL, CNL_DSP_REG_HIPCCTL_DONE, 0); - spin_lock_irqsave(&sdev->ipc_lock, flags); + spin_lock_irq(&sdev->ipc_lock); /* handle immediate reply from DSP core */ hda_dsp_ipc_get_reply(sdev); @@ -72,7 +70,7 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) cnl_ipc_dsp_done(sdev); - spin_unlock_irqrestore(&sdev->ipc_lock, flags); + spin_unlock_irq(&sdev->ipc_lock); ipc_irq = true; } diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index ad2b4c64570a4b..50244b82600c01 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -148,8 +148,6 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) /* is this a reply message from the DSP */ if (hipcie & HDA_DSP_REG_HIPCIE_DONE) { - unsigned long flags; - msg = hipci & HDA_DSP_REG_HIPCI_MSG_MASK; msg_ext = hipcie & HDA_DSP_REG_HIPCIE_MSG_MASK; @@ -172,7 +170,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) * place, the message might not yet be marked as expecting a * reply. */ - spin_lock_irqsave(&sdev->ipc_lock, flags); + spin_lock_irq(&sdev->ipc_lock); /* handle immediate reply from DSP core - ignore ROM messages */ if (hda_dsp_ipc_is_sof(msg)) { @@ -189,14 +187,13 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) /* set the done bit */ hda_dsp_ipc_dsp_done(sdev); - spin_unlock_irqrestore(&sdev->ipc_lock, flags); + spin_unlock_irq(&sdev->ipc_lock); ipc_irq = true; } /* is this a new message from DSP */ if (hipct & HDA_DSP_REG_HIPCT_BUSY) { - msg = hipct & HDA_DSP_REG_HIPCT_MSG_MASK; msg_ext = hipcte & HDA_DSP_REG_HIPCTE_MSG_MASK; From 56684c4eceece28fec4fbbd02b88e2fbbc238859 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Thu, 16 May 2019 16:10:44 +0800 Subject: [PATCH 1498/1995] ALSA: hda/realtek - Check headset type by unplug and resume When system enable HDA power save mode. This issue will happen on new platform which DMIC connect to PCH. In Dell headset mode, it will recheck during runtime resume when headset was plugged. This patch will move check headset type on unplug and system resume. [ A few minor code cleanups by tiwai ] Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai (cherry picked from commit aeac1a0dadb4ab699a61136a5729d048abe6ee5f) --- sound/pci/hda/patch_realtek.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f83f21d64dd42a..b984bd1d19716f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -834,6 +834,8 @@ static void alc_pre_init(struct hda_codec *codec) alc_fill_eapd_coef(codec); } +#define is_s3_resume(codec) \ + ((codec)->core.dev.power.power_state.event == PM_EVENT_RESUME) #define is_s4_resume(codec) \ ((codec)->core.dev.power.power_state.event == PM_EVENT_RESTORE) @@ -4901,6 +4903,8 @@ static void alc_update_headset_mode(struct hda_codec *codec) switch (new_headset_mode) { case ALC_HEADSET_MODE_UNPLUGGED: alc_headset_mode_unplugged(codec); + spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN; + spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN; spec->gen.hp_jack_present = false; break; case ALC_HEADSET_MODE_HEADSET: @@ -4943,8 +4947,6 @@ static void alc_update_headset_mode_hook(struct hda_codec *codec, static void alc_update_headset_jack_cb(struct hda_codec *codec, struct hda_jack_callback *jack) { - struct alc_spec *spec = codec->spec; - spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN; snd_hda_gen_hp_automute(codec, jack); } @@ -4981,7 +4983,10 @@ static void alc_fixup_headset_mode(struct hda_codec *codec, alc_probe_headset_mode(codec); break; case HDA_FIXUP_ACT_INIT: - spec->current_headset_mode = 0; + if (is_s3_resume(codec) || is_s4_resume(codec)) { + spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN; + spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN; + } alc_update_headset_mode(codec); break; } From b729f9a07caa957562e76e3fe3a27706be52a5c4 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 24 May 2019 15:47:44 +0800 Subject: [PATCH 1499/1995] ALSA: hda - Force polling mode on CNL for fixing codec communication We observed the same issue as reported by commit a8d7bde23e7130686b7662 ("ALSA: hda - Force polling mode on CFL for fixing codec communication") We don't have a better solution. So apply the same workaround to CNL. Signed-off-by: Bard Liao --- sound/pci/hda/hda_intel.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 0741eae23f1053..a4b0414dda3bd9 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -375,6 +375,7 @@ enum { #define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) #define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348) +#define IS_CNL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9dc8) static char *driver_short_names[] = { [AZX_DRIVER_ICH] = "HDA Intel", @@ -1700,8 +1701,8 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, else chip->bdl_pos_adj = bdl_pos_adj[dev]; - /* Workaround for a communication error on CFL (bko#199007) */ - if (IS_CFL(pci)) + /* Workaround for a communication error on CFL (bko#199007) and CNL */ + if (IS_CFL(pci) || IS_CNL(pci)) chip->polling_mode = 1; err = azx_bus_init(chip, model[dev], &pci_hda_io_ops); From dc9d4395034a68a8d9e5056f7727e8cb6dab1033 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 27 May 2019 09:38:18 +0800 Subject: [PATCH 1500/1995] ALSA: hda: assign polling_mode after azx_bus_init We will move the polling_mode flag from struct azx to struct hdac_bus, and the flag should be assigned after bus init. Signed-off-by: Bard Liao --- sound/pci/hda/hda_intel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index a4b0414dda3bd9..489fb53c9b067f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1701,10 +1701,6 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, else chip->bdl_pos_adj = bdl_pos_adj[dev]; - /* Workaround for a communication error on CFL (bko#199007) and CNL */ - if (IS_CFL(pci) || IS_CNL(pci)) - chip->polling_mode = 1; - err = azx_bus_init(chip, model[dev], &pci_hda_io_ops); if (err < 0) { kfree(hda); @@ -1712,6 +1708,10 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, return err; } + /* Workaround for a communication error on CFL (bko#199007) and CNL */ + if (IS_CFL(pci) || IS_CNL(pci)) + chip->polling_mode = 1; + if (chip->driver_type == AZX_DRIVER_NVIDIA) { dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n"); chip->bus.needs_damn_long_delay = 1; From 0e8518f8cd58914ca1f78c852af009a9fd36eb2c Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 27 May 2019 09:27:52 +0800 Subject: [PATCH 1501/1995] ALSA: hda: move polling_mode flag to struct hdac_bus polling mode is a useful function in the get_response function. Move polling_mode flag from struct azx to struct hdac_bus so people can implement polling mode in their own get_response function without adding a polling_mode flag in their local chip structure. Signed-off-by: Bard Liao --- include/sound/hdaudio.h | 3 +++ sound/pci/hda/hda_controller.c | 12 ++++++------ sound/pci/hda/hda_controller.h | 2 -- sound/pci/hda/hda_intel.c | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index e8346784cf3f8d..f49af557bdb0e8 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -358,6 +358,9 @@ struct hdac_bus { bool align_bdle_4k:1; /* BDLE align 4K boundary */ bool reverse_assign:1; /* assign devices in reverse order */ bool corbrp_self_clear:1; /* CORBRP clears itself after reset */ + bool polling_mode:1; + + int poll_count; int bdl_pos_adj; /* BDL position adjustment */ diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 532e081f8b8a24..53feaeef155314 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -806,11 +806,11 @@ static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr, for (loopcounter = 0;; loopcounter++) { spin_lock_irq(&bus->reg_lock); - if (chip->polling_mode || do_poll) + if (bus->polling_mode || do_poll) snd_hdac_bus_update_rirb(bus); if (!bus->rirb.cmds[addr]) { if (!do_poll) - chip->poll_count = 0; + bus->poll_count = 0; if (res) *res = bus->rirb.res[addr]; /* the last value */ spin_unlock_irq(&bus->reg_lock); @@ -830,21 +830,21 @@ static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr, if (hbus->no_response_fallback) return -EIO; - if (!chip->polling_mode && chip->poll_count < 2) { + if (!bus->polling_mode && bus->poll_count < 2) { dev_dbg(chip->card->dev, "azx_get_response timeout, polling the codec once: last cmd=0x%08x\n", bus->last_cmd[addr]); do_poll = 1; - chip->poll_count++; + bus->poll_count++; goto again; } - if (!chip->polling_mode) { + if (!bus->polling_mode) { dev_warn(chip->card->dev, "azx_get_response timeout, switching to polling mode: last cmd=0x%08x\n", bus->last_cmd[addr]); - chip->polling_mode = 1; + bus->polling_mode = 1; goto again; } diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 7185ed574b412f..8d886791cf0fc1 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -142,11 +142,9 @@ struct azx { /* flags */ int bdl_pos_adj; - int poll_count; unsigned int running:1; unsigned int fallback_to_single_cmd:1; unsigned int single_cmd:1; - unsigned int polling_mode:1; unsigned int msi:1; unsigned int probing:1; /* codec probing phase */ unsigned int snoop:1; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 489fb53c9b067f..c0b466c9634089 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1710,7 +1710,7 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, /* Workaround for a communication error on CFL (bko#199007) and CNL */ if (IS_CFL(pci) || IS_CNL(pci)) - chip->polling_mode = 1; + azx_bus(chip)->polling_mode = 1; if (chip->driver_type == AZX_DRIVER_NVIDIA) { dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n"); From 78f3e2b747493365f9f6c3afda6e942f3b137946 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 27 May 2019 10:53:50 +0800 Subject: [PATCH 1502/1995] ALSA: hda: add polling mode in snd_hdac_bus_get_response Polling mode is useful if a machine somehow missed an expected IRQ. Signed-off-by: Bard Liao --- sound/hda/hdac_controller.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index b2e9454f5816a0..a16ac31bda8354 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -239,6 +239,8 @@ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr, timeout = jiffies + msecs_to_jiffies(1000); for (loopcounter = 0;; loopcounter++) { + if (bus->polling_mode) + snd_hdac_bus_update_rirb(bus); spin_lock_irq(&bus->reg_lock); if (!bus->rirb.cmds[addr]) { if (res) From d1008d1458a27f3e8ddcdd4610234a0917a91247 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 24 May 2019 14:52:24 +0800 Subject: [PATCH 1503/1995] ASoC: SOF: Force polling mode on CFL and CNL There is a workaround in legacy HDA codec for too long time respone with CFL machine. We need the same workaround on SOF driver. The same issue is also seen on CNL machine. Signed-off-by: Bard Liao --- sound/soc/sof/intel/hda.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 5c78f4dde6f529..b9f3c802924b1f 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -32,6 +32,9 @@ /* platform specific devices */ #include "shim.h" +#define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348) +#define IS_CNL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9dc8) + /* * Debug */ @@ -217,6 +220,11 @@ static int hda_init(struct snd_sof_dev *sdev) ext_ops = snd_soc_hdac_hda_get_ops(); #endif sof_hda_bus_init(bus, &pci->dev, ext_ops); + + /* Workaround for a communication error on CFL (bko#199007) and CNL */ + if (IS_CFL(pci) || IS_CNL(pci)) + bus->polling_mode = 1; + bus->use_posbuf = 1; bus->bdl_pos_adj = 0; From 959f44464e45746dd20a5189aeca3397efe27e53 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 10 May 2019 18:06:32 -0700 Subject: [PATCH 1504/1995] ASoC: SOF: hda: save handle to sdev in sof_intel_hda_stream Add a snd_sof_dev member to sof_intel_hda_stream. This will be used to access the snd_sof_dev during link hw_params callback. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-stream.c | 4 ++++ sound/soc/sof/intel/hda.h | 1 + 2 files changed, 5 insertions(+) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index c92006f894992a..1cd94e7631a844 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -564,6 +564,8 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) if (!hda_stream) return -ENOMEM; + hda_stream->sdev = sdev; + stream = &hda_stream->hda_stream; stream->pphc_addr = sdev->bar[HDA_DSP_PP_BAR] + @@ -617,6 +619,8 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev) if (!hda_stream) return -ENOMEM; + hda_stream->sdev = sdev; + stream = &hda_stream->hda_stream; /* we always have DSP support */ diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 455046612b9494..aae568f01c07c4 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -408,6 +408,7 @@ static inline struct hda_bus *sof_to_hbus(struct snd_sof_dev *s) } struct sof_intel_hda_stream { + struct snd_sof_dev *sdev; struct hdac_ext_stream hda_stream; struct sof_intel_stream stream; int hw_params_upon_resume; /* set up hw_params upon resume */ From bb1ea3b31c28a131a5f5a50dd325198645526b19 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 10 May 2019 18:08:07 -0700 Subject: [PATCH 1505/1995] ASoC: SOF: topology: add cpu_dai_name for DAIs Add the cpu_dai_name member to snd_sof_dai and save the cpu_dai_name while setting the DAI config. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/sof-priv.h | 1 + sound/soc/sof/topology.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 563623bcaad6e2..ba6556ecc8bab3 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -335,6 +335,7 @@ struct snd_sof_route { struct snd_sof_dai { struct snd_sof_dev *sdev; const char *name; + const char *cpu_dai_name; struct sof_ipc_comp_dai comp_dai; struct sof_ipc_dai_config *dai_config; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index d0179e797d60a9..b1bc186d4e9066 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2342,6 +2342,9 @@ static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size, if (!dai->dai_config) return -ENOMEM; + /* set cpu_dai_name */ + dai->cpu_dai_name = link->cpu_dai_name; + found = 1; } } @@ -2606,6 +2609,8 @@ static int sof_link_hda_process(struct snd_sof_dev *sdev, if (!sof_dai->dai_config) return -ENOMEM; + sof_dai->cpu_dai_name = link->cpu_dai_name; + /* send message to DSP */ ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, size, From 353419f8ebb25a8b581c240ac9fd579160626c92 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 28 May 2019 14:42:01 -0700 Subject: [PATCH 1506/1995] ASoC: SOF: Intel: hda: add new macro hstream_to_sof_hda_stream() Add a new macro to get sof_intel_hda_stream from hdac_ext_stream. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index aae568f01c07c4..53f9cdad809892 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -414,6 +414,9 @@ struct sof_intel_hda_stream { int hw_params_upon_resume; /* set up hw_params upon resume */ }; +#define hstream_to_sof_hda_stream(hstream) \ + container_of(hstream, struct sof_intel_hda_stream, hda_stream) + #define bus_to_sof_hda(bus) \ container_of(bus, struct sof_intel_hda_dev, hbus.core) From 64632de9140e52b72781fefe542314db7cd29d8c Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 10 May 2019 18:12:31 -0700 Subject: [PATCH 1507/1995] ASoC: SOF: assign link DMA channel at run-time The recommended HDA HW programming sequence for setting the DMA format requires that the link DMA and host DMA channels be coupled before setting the format. This change means that host DMA or link DMA channels be reserved even if only one is used. Statically assigned link DMA channels would mean that all the corresponding host DMA channels will need to be reserved, leaving only a few channels available at run-time. So, the suggestion here is to switch to dynamically assigning both host DMA channels and link DMA channels are run-time. The host DMA channel is assigned when the pcm is opened as before. While choosing the link DMA channel, if the host DMA channel corresponding to the link DMA channel is already taken, the proposed method checks to make sure that the BE is connected to the FE that has been assigned this host DMA channel. Once the link DMA channel is assigned, an IPC is sent to the DSP to set the link DMA channel. The link DMA channel is freed during hw_free() and also in the SUSPEND trigger callback. It will be re-assigned when hw_params are set upon resume. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dai.c | 284 ++++++++++++++++++++++------------ sound/soc/sof/sof-priv.h | 2 + sound/soc/sof/topology.c | 51 +----- 3 files changed, 189 insertions(+), 148 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index e1decf25aeace3..c270fd7a08784c 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -30,62 +30,84 @@ struct hda_pipe_params { }; /* - * Unlike GP dma, there is a set of stream registers in hda controller - * to control the link dma channels. Each register controls one link - * dma channel and the relation is fixed. To make sure FW uses correct - * link dma channels, host allocates stream registers and sends the - * corresponding link dma channels to FW to allocate link dma channel - * - * FIXME: this API is abused in the sense that tx_num and rx_num are - * passed as arguments, not returned. We need to find a better way to - * retrieve the stream tag allocated for the link DMA + * This function checks if the host dma channel corresponding + * to the link DMA stream_tag argument is assigned to one + * of the FEs connected to the BE DAI. */ -static int hda_link_dma_get_channels(struct snd_soc_dai *dai, - unsigned int *tx_num, - unsigned int *tx_slot, - unsigned int *rx_num, - unsigned int *rx_slot) +static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd, + int dir, int stream_tag) { - struct hdac_bus *bus; - struct hdac_ext_stream *stream; - struct snd_pcm_substream substream; - struct snd_sof_dev *sdev = - snd_soc_component_get_drvdata(dai->component); - - bus = sof_to_bus(sdev); - - memset(&substream, 0, sizeof(substream)); - if (*tx_num == 1) { - substream.stream = SNDRV_PCM_STREAM_PLAYBACK; - stream = snd_hdac_ext_stream_assign(bus, &substream, - HDAC_EXT_STREAM_TYPE_LINK); - if (!stream) { - dev_err(bus->dev, "error: failed to find a free hda ext stream for playback"); - return -EBUSY; - } + struct snd_pcm_substream *fe_substream; + struct hdac_stream *fe_hstream; + struct snd_soc_dpcm *dpcm; + + for_each_dpcm_fe(rtd, dir, dpcm) { + fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, dir); + fe_hstream = fe_substream->runtime->private_data; + if (fe_hstream->stream_tag == stream_tag) + return true; + } - snd_soc_dai_set_dma_data(dai, &substream, stream); - *tx_slot = hdac_stream(stream)->stream_tag - 1; + return false; +} + +static struct hdac_ext_stream * + hda_link_stream_assign(struct hdac_bus *bus, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sof_intel_hda_stream *hda_stream; + struct hdac_ext_stream *res = NULL; + struct hdac_stream *stream = NULL; - dev_dbg(bus->dev, "link dma channel %d for playback", *tx_slot); + int stream_dir = substream->stream; + + if (!bus->ppcap) { + dev_err(bus->dev, "stream type not supported\n"); + return NULL; } - if (*rx_num == 1) { - substream.stream = SNDRV_PCM_STREAM_CAPTURE; - stream = snd_hdac_ext_stream_assign(bus, &substream, - HDAC_EXT_STREAM_TYPE_LINK); - if (!stream) { - dev_err(bus->dev, "error: failed to find a free hda ext stream for capture"); - return -EBUSY; + list_for_each_entry(stream, &bus->stream_list, list) { + struct hdac_ext_stream *hstream = + stream_to_hdac_ext_stream(stream); + if (stream->direction != substream->stream) + continue; + + hda_stream = hstream_to_sof_hda_stream(hstream); + + /* check if available */ + if (!hstream->link_locked) { + if (stream->opened) { + /* + * check if the stream tag matches the stream + * tag of one of the connected FEs + */ + if (hda_check_fes(rtd, stream_dir, + stream->stream_tag)) { + res = hstream; + break; + } + } else { + res = hstream; + break; + } } + } - snd_soc_dai_set_dma_data(dai, &substream, stream); - *rx_slot = hdac_stream(stream)->stream_tag - 1; - - dev_dbg(bus->dev, "link dma channel %d for capture", *rx_slot); + if (res) { + /* + * Decouple host and link DMA. The decoupled flag + * is updated in snd_hdac_ext_stream_decouple(). + */ + if (!res->decoupled) + snd_hdac_ext_stream_decouple(bus, res, true); + spin_lock_irq(&bus->reg_lock); + res->link_locked = 1; + res->link_substream = substream; + spin_unlock_irq(&bus->reg_lock); } - return 0; + return res; } static int hda_link_dma_params(struct hdac_ext_stream *stream, @@ -122,6 +144,51 @@ static int hda_link_dma_params(struct hdac_ext_stream *stream, return 0; } +/* Send DAI_CONFIG IPC to the DAI that matches the dai_name and direction */ +static int hda_link_config_ipc(struct sof_intel_hda_stream *hda_stream, + const char *dai_name, int channel, int dir) +{ + struct sof_ipc_dai_config *config; + struct snd_sof_dai *sof_dai; + struct sof_ipc_reply reply; + int ret = 0; + + list_for_each_entry(sof_dai, &hda_stream->sdev->dai_list, list) { + if (!sof_dai->cpu_dai_name) + continue; + + if (!strcmp(dai_name, sof_dai->cpu_dai_name) && + dir == sof_dai->comp_dai.direction) { + config = sof_dai->dai_config; + + if (!config) { + dev_err(hda_stream->sdev->dev, + "error: no config for DAI %s\n", + sof_dai->name); + return -EINVAL; + } + + /* update config with stream tag */ + config->hda.link_dma_ch = channel; + + /* send IPC */ + ret = sof_ipc_tx_message(hda_stream->sdev->ipc, + config->hdr.cmd, + config, + config->hdr.size, + &reply, sizeof(reply)); + + if (ret < 0) + dev_err(hda_stream->sdev->dev, + "error: failed to set dai config for %s\n", + sof_dai->name); + return ret; + } + } + + return -EINVAL; +} + static int hda_link_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -135,20 +202,31 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream, struct hda_pipe_params p_params = {0}; struct hdac_ext_link *link; int stream_tag; + int ret; - link_dev = snd_soc_dai_get_dma_data(dai, substream); + link_dev = hda_link_stream_assign(bus, substream); + if (!link_dev) + return -EBUSY; + + stream_tag = hdac_stream(link_dev)->stream_tag; + + hda_stream = hstream_to_sof_hda_stream(link_dev); + + /* update the DSP with the new tag */ + ret = hda_link_config_ipc(hda_stream, dai->name, stream_tag - 1, + substream->stream); + if (ret < 0) + return ret; + + snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); - hda_stream = container_of(link_dev, struct sof_intel_hda_stream, - hda_stream); hda_stream->hw_params_upon_resume = 0; link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name); if (!link) return -EINVAL; - stream_tag = hdac_stream(link_dev)->stream_tag; - - /* set the stream tag in the codec dai dma params */ + /* set the stream tag in the codec dai dma params */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0); else @@ -181,8 +259,7 @@ static int hda_link_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); int stream = substream->stream; - hda_stream = container_of(link_dev, struct sof_intel_hda_stream, - hda_stream); + hda_stream = hstream_to_sof_hda_stream(link_dev); /* setup hw_params again only if resuming from system suspend */ if (!hda_stream->hw_params_upon_resume) @@ -199,8 +276,24 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, { struct hdac_ext_stream *link_dev = snd_soc_dai_get_dma_data(dai, substream); + struct sof_intel_hda_stream *hda_stream; + struct snd_soc_pcm_runtime *rtd; + struct hdac_ext_link *link; + struct hdac_stream *hstream; + struct hdac_bus *bus; + int stream_tag; int ret; + hstream = substream->runtime->private_data; + bus = hstream->bus; + rtd = snd_pcm_substream_chip(substream); + + link = snd_hdac_ext_bus_get_link(bus, rtd->codec_dai->component->name); + if (!link) + return -EINVAL; + + hda_stream = hstream_to_sof_hda_stream(link_dev); + dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: @@ -217,8 +310,22 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: snd_hdac_ext_link_stream_start(link_dev); break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: + /* + * clear and release link DMA channel. It will be assigned when + * hw_params is set up again after resume. + */ + ret = hda_link_config_ipc(hda_stream, dai->name, + DMA_CHAN_INVALID, substream->stream); + if (ret < 0) + return ret; + stream_tag = hdac_stream(link_dev)->stream_tag; + snd_hdac_ext_link_clear_stream_id(link, stream_tag); + snd_hdac_ext_stream_release(link_dev, + HDAC_EXT_STREAM_TYPE_LINK); + + /* fallthrough */ + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_STOP: snd_hdac_ext_link_stream_clear(link_dev); break; @@ -228,62 +335,38 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, return 0; } -/* - * FIXME: This API is also abused since it's used for two purposes. - * when the substream argument is NULL this function is used for cleanups - * that aren't necessarily required, and called explicitly by handling - * ASoC core structures, which is not recommended. - * This part will be reworked in follow-up patches. - */ static int hda_link_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - const char *name; unsigned int stream_tag; + struct sof_intel_hda_stream *hda_stream; struct hdac_bus *bus; struct hdac_ext_link *link; struct hdac_stream *hstream; - struct hdac_ext_stream *stream; struct snd_soc_pcm_runtime *rtd; struct hdac_ext_stream *link_dev; - struct snd_pcm_substream pcm_substream; - - memset(&pcm_substream, 0, sizeof(pcm_substream)); - if (substream) { - hstream = substream->runtime->private_data; - bus = hstream->bus; - rtd = snd_pcm_substream_chip(substream); - link_dev = snd_soc_dai_get_dma_data(dai, substream); - snd_hdac_ext_stream_decouple(bus, link_dev, false); - name = rtd->codec_dai->component->name; - link = snd_hdac_ext_bus_get_link(bus, name); - if (!link) - return -EINVAL; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - stream_tag = hdac_stream(link_dev)->stream_tag; - snd_hdac_ext_link_clear_stream_id(link, stream_tag); - } + int ret; - link_dev->link_prepared = 0; - } else { - /* release all hda streams when dai link is unloaded */ - pcm_substream.stream = SNDRV_PCM_STREAM_PLAYBACK; - stream = snd_soc_dai_get_dma_data(dai, &pcm_substream); - if (stream) { - snd_soc_dai_set_dma_data(dai, &pcm_substream, NULL); - snd_hdac_ext_stream_release(stream, - HDAC_EXT_STREAM_TYPE_LINK); - } + hstream = substream->runtime->private_data; + bus = hstream->bus; + rtd = snd_pcm_substream_chip(substream); + link_dev = snd_soc_dai_get_dma_data(dai, substream); + hda_stream = hstream_to_sof_hda_stream(link_dev); - pcm_substream.stream = SNDRV_PCM_STREAM_CAPTURE; - stream = snd_soc_dai_get_dma_data(dai, &pcm_substream); - if (stream) { - snd_soc_dai_set_dma_data(dai, &pcm_substream, NULL); - snd_hdac_ext_stream_release(stream, - HDAC_EXT_STREAM_TYPE_LINK); - } - } + /* free the link DMA channel in the FW */ + ret = hda_link_config_ipc(hda_stream, dai->name, DMA_CHAN_INVALID, + substream->stream); + if (ret < 0) + return ret; + + link = snd_hdac_ext_bus_get_link(bus, rtd->codec_dai->component->name); + if (!link) + return -EINVAL; + + stream_tag = hdac_stream(link_dev)->stream_tag; + snd_hdac_ext_link_clear_stream_id(link, stream_tag); + snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); + link_dev->link_prepared = 0; return 0; } @@ -293,7 +376,6 @@ static const struct snd_soc_dai_ops hda_link_dai_ops = { .hw_free = hda_link_hw_free, .trigger = hda_link_pcm_trigger, .prepare = hda_link_pcm_prepare, - .get_channel_map = hda_link_dma_get_channels, }; #endif diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index ba6556ecc8bab3..0ef8d88db00682 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -60,6 +60,8 @@ (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) || \ IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST)) +#define DMA_CHAN_INVALID 0xFFFFFFFF + struct snd_sof_dev; struct snd_sof_ipc_msg; struct snd_sof_ipc; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index b1bc186d4e9066..51eb500b5d00d4 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2573,9 +2573,7 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, */ static int sof_link_hda_process(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link, - struct sof_ipc_dai_config *config, - int tx_slot, - int rx_slot) + struct sof_ipc_dai_config *config) { struct sof_ipc_reply reply; u32 size = sizeof(*config); @@ -2588,22 +2586,11 @@ static int sof_link_hda_process(struct snd_sof_dev *sdev, continue; if (strcmp(link->name, sof_dai->name) == 0) { - if (sof_dai->comp_dai.direction == - SNDRV_PCM_STREAM_PLAYBACK) { - if (!link->dpcm_playback) - return -EINVAL; - - config->hda.link_dma_ch = tx_slot; - } else { - if (!link->dpcm_capture) - return -EINVAL; - - config->hda.link_dma_ch = rx_slot; - } - config->dai_index = sof_dai->comp_dai.dai_index; found = 1; + config->hda.link_dma_ch = DMA_CHAN_INVALID; + /* save config in dai component */ sof_dai->dai_config = kmemdup(config, size, GFP_KERNEL); if (!sof_dai->dai_config) @@ -2650,10 +2637,6 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_private *private = &cfg->priv; struct snd_soc_dai *dai; u32 size = sizeof(*config); - u32 tx_num = 0; - u32 tx_slot = 0; - u32 rx_num = 0; - u32 rx_slot = 0; int ret; /* init IPC */ @@ -2679,22 +2662,7 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index, return -EINVAL; } - if (link->dpcm_playback) - tx_num = 1; - - if (link->dpcm_capture) - rx_num = 1; - - ret = snd_soc_dai_get_channel_map(dai, &tx_num, &tx_slot, - &rx_num, &rx_slot); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to get dma channel for HDA%d\n", - config->dai_index); - - return ret; - } - - ret = sof_link_hda_process(sdev, link, config, tx_slot, rx_slot); + ret = sof_link_hda_process(sdev, link, config); if (ret < 0) dev_err(sdev->dev, "error: failed to process hda dai link %s", link->name); @@ -2821,17 +2789,6 @@ static int sof_link_hda_unload(struct snd_sof_dev *sdev, return -EINVAL; } - /* - * FIXME: this call to hw_free is mainly to release the link DMA ID. - * This is abusing the API and handling SOC internals is not - * recommended. This part will be reworked. - */ - if (dai->driver->ops->hw_free) - ret = dai->driver->ops->hw_free(NULL, dai); - if (ret < 0) - dev_err(sdev->dev, "error: failed to free hda resource for %s\n", - link->name); - return ret; } From cd6792df954d2ae2df99b64208e8bdc9c6fc0662 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 10 May 2019 18:13:38 -0700 Subject: [PATCH 1508/1995] ASoC: SOF: hda: reserve host DMA channel for hostless streams Due to the HW programming sequence requirement that the host and link DMA channels need to be coupled/decoupled during pcm hw_params, the host DMA channel corresponding to the link DMA channel in use for hostless streams needs to be reserved. This is achieved by adding a host_reserved flag in the sof_intel_hda_stream structure which is checked when assigning a host DMA channel. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dai.c | 11 ++++++++++- sound/soc/sof/intel/hda-stream.c | 10 +++++++++- sound/soc/sof/intel/hda.h | 1 + 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index c270fd7a08784c..a514f9cf5c9a1b 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -75,7 +75,7 @@ static struct hdac_ext_stream * hda_stream = hstream_to_sof_hda_stream(hstream); - /* check if available */ + /* check if link is available */ if (!hstream->link_locked) { if (stream->opened) { /* @@ -89,6 +89,12 @@ static struct hdac_ext_stream * } } else { res = hstream; + + /* + * This must be a hostless stream. + * So reserve the host DMA channel. + */ + hda_stream->host_reserved = 1; break; } } @@ -368,6 +374,9 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream, snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); link_dev->link_prepared = 0; + /* free the host DMA channel reserved by hostless streams */ + hda_stream->host_reserved = 0; + return 0; } diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 1cd94e7631a844..a3f7c91469ece9 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -155,6 +155,7 @@ struct hdac_ext_stream * hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction) { struct hdac_bus *bus = sof_to_bus(sdev); + struct sof_intel_hda_stream *hda_stream; struct hdac_ext_stream *stream = NULL; struct hdac_stream *s; @@ -163,8 +164,15 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction) /* get an unused stream */ list_for_each_entry(s, &bus->stream_list, list) { if (s->direction == direction && !s->opened) { - s->opened = true; stream = stream_to_hdac_ext_stream(s); + hda_stream = container_of(stream, + struct sof_intel_hda_stream, + hda_stream); + /* check if the host DMA channel is reserved */ + if (hda_stream->host_reserved) + continue; + + s->opened = true; break; } } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 53f9cdad809892..d50db46d98b5d9 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -412,6 +412,7 @@ struct sof_intel_hda_stream { struct hdac_ext_stream hda_stream; struct sof_intel_stream stream; int hw_params_upon_resume; /* set up hw_params upon resume */ + int host_reserved; /* reserve host DMA channel */ }; #define hstream_to_sof_hda_stream(hstream) \ From bf705eaa7ce07f9c132f8e367fc2fc46b7842528 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 20 May 2019 11:16:38 -0700 Subject: [PATCH 1509/1995] ASoC: SOF: Intel: hda: release link DMA for paused streams during suspend Paused streams do not get suspended when the system enters S3. So, clear and release link DMA channel for such streams in the hda_dsp_set_hw_params_upon_resume() callback. Also, invalidate the link DMA channel in the DAI config before restoring the dai config upon resume. Also, modify the signature for the set_hw_params_upon_resume() op to return an int. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dsp.c | 29 ++++++++++++++++++++++++++++- sound/soc/sof/intel/hda.h | 2 +- sound/soc/sof/ops.h | 5 +++-- sound/soc/sof/pm.c | 24 ++++++++++++++++++++---- sound/soc/sof/sof-priv.h | 2 +- 5 files changed, 53 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 5b73115a0b7873..17f6054d3d68bd 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -454,18 +454,45 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state) return 0; } -void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) +int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); struct sof_intel_hda_stream *hda_stream; struct hdac_ext_stream *stream; struct hdac_stream *s; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + struct snd_soc_pcm_runtime *rtd; + struct hdac_ext_link *link; + const char *name; +#endif + int stream_tag; + /* set internal flag for BE */ list_for_each_entry(s, &bus->stream_list, list) { stream = stream_to_hdac_ext_stream(s); hda_stream = container_of(stream, struct sof_intel_hda_stream, hda_stream); hda_stream->hw_params_upon_resume = 1; + stream_tag = hdac_stream(stream)->stream_tag; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* + * clear and release stream. This should already be taken care + * for running streams when the SUSPEND trigger is called. + * But paused streams do not get suspended, so this needs to be + * done explicitly during suspend. + */ + if (stream->link_substream) { + rtd = snd_pcm_substream_chip(stream->link_substream); + name = rtd->codec_dai->component->name; + link = snd_hdac_ext_bus_get_link(bus, name); + if (!link) + return -EINVAL; + snd_hdac_ext_link_clear_stream_id(link, stream_tag); + snd_hdac_ext_stream_release(stream, + HDAC_EXT_STREAM_TYPE_LINK); + } +#endif } + return 0; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index d50db46d98b5d9..9126757aa4323a 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -450,7 +450,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state); int hda_dsp_resume(struct snd_sof_dev *sdev); int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state); int hda_dsp_runtime_resume(struct snd_sof_dev *sdev); -void hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev); +int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev); void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags); void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags); void hda_ipc_dump(struct snd_sof_dev *sdev); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 80fc3b374c2b3b..a2329735375096 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -134,10 +134,11 @@ static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev, return 0; } -static inline void snd_sof_dsp_hw_params_upon_resume(struct snd_sof_dev *sdev) +static inline int snd_sof_dsp_hw_params_upon_resume(struct snd_sof_dev *sdev) { if (sof_ops(sdev)->set_hw_params_upon_resume) - sof_ops(sdev)->set_hw_params_upon_resume(sdev); + return sof_ops(sdev)->set_hw_params_upon_resume(sdev); + return 0; } static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 8ef1d51025d8bb..a42f9a45d21b0f 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -153,6 +153,15 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev) continue; } + /* + * The link DMA channel would be invalidated for running + * streams but not for streams that were in the PAUSED + * state during suspend. So invalidate it here before setting + * the dai config in the DSP. + */ + if (config->type == SOF_DAI_INTEL_HDA) + config->hda.link_dma_ch = DMA_CHAN_INVALID; + ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size, @@ -204,7 +213,7 @@ static int sof_send_pm_ipc(struct snd_sof_dev *sdev, int cmd) sizeof(pm_ctx), &reply, sizeof(reply)); } -static void sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev) +static int sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev) { struct snd_pcm_substream *substream; struct snd_sof_pcm *spcm; @@ -229,7 +238,7 @@ static void sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev) } /* set internal flag for BE */ - snd_sof_dsp_hw_params_upon_resume(sdev); + return snd_sof_dsp_hw_params_upon_resume(sdev); } #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) @@ -333,8 +342,15 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) snd_sof_release_trace(sdev); /* set restore_stream for all streams during system suspend */ - if (!runtime_suspend) - sof_set_hw_params_upon_resume(sdev); + if (!runtime_suspend) { + ret = sof_set_hw_params_upon_resume(sdev); + if (ret < 0) { + dev_err(sdev->dev, + "error: setting hw_params flag during suspend %d\n", + ret); + return ret; + } + } #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) /* cache debugfs contents during runtime suspend */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 0ef8d88db00682..b4afe7a9bc415a 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -172,7 +172,7 @@ struct snd_sof_dsp_ops { int (*runtime_suspend)(struct snd_sof_dev *sof_dev, int state); /* optional */ int (*runtime_resume)(struct snd_sof_dev *sof_dev); /* optional */ - void (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */ + int (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */ /* DSP clocking */ int (*set_clk)(struct snd_sof_dev *sof_dev, u32 freq); /* optional */ From c6cc9ca1e14a8601886b8acdbbfb05e05b20ddf6 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 21 May 2019 00:08:15 -0700 Subject: [PATCH 1510/1995] ASoC: SOF: hda: couple host and link DMA during FE hw_free Host and link DMA are decoupled during FE hw_params. So, they must be coupled in hw_free if the link DMA channel is idle. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/apl.c | 1 + sound/soc/sof/intel/cnl.c | 1 + sound/soc/sof/intel/hda-stream.c | 20 ++++++++++++++++++++ sound/soc/sof/intel/hda.h | 2 ++ sound/soc/sof/ops.h | 11 +++++++++++ sound/soc/sof/pcm.c | 7 +++++++ sound/soc/sof/sof-priv.h | 4 ++++ 7 files changed, 46 insertions(+) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index f215d80dce2c3e..43d1c9f31ec4c8 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -61,6 +61,7 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .pcm_open = hda_dsp_pcm_open, .pcm_close = hda_dsp_pcm_close, .pcm_hw_params = hda_dsp_pcm_hw_params, + .pcm_hw_free = hda_dsp_stream_hw_free, .pcm_trigger = hda_dsp_pcm_trigger, .pcm_pointer = hda_dsp_pcm_pointer, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 9a4927b6b6ae54..35f854d33f0695 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -217,6 +217,7 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .pcm_open = hda_dsp_pcm_open, .pcm_close = hda_dsp_pcm_close, .pcm_hw_params = hda_dsp_pcm_hw_params, + .pcm_hw_free = hda_dsp_stream_hw_free, .pcm_trigger = hda_dsp_pcm_trigger, .pcm_pointer = hda_dsp_pcm_pointer, diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index a3f7c91469ece9..ff6ab0c45d8ea2 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -438,6 +438,26 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, return ret; } +int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct hdac_stream *stream = substream->runtime->private_data; + struct hdac_ext_stream *link_dev = container_of(stream, + struct hdac_ext_stream, + hstream); + struct hdac_bus *bus = sof_to_bus(sdev); + u32 mask = 0x1 << stream->index; + + spin_lock(&bus->reg_lock); + /* couple host and link DMA if link DMA channel is idle */ + if (!link_dev->link_locked) + snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, + SOF_HDA_REG_PP_PPCTL, mask, 0); + spin_unlock(&bus->reg_lock); + + return 0; +} + irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) { struct hdac_bus *bus = context; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 9126757aa4323a..430e84e6c8c608 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -466,6 +466,8 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct sof_ipc_stream_params *ipc_params); +int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, int cmd); snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index a2329735375096..45a3d10911634a 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -287,6 +287,17 @@ snd_sof_pcm_platform_hw_params(struct snd_sof_dev *sdev, return 0; } +/* host stream hw free */ +static inline int +snd_sof_pcm_platform_hw_free(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + if (sof_ops(sdev) && sof_ops(sdev)->pcm_hw_free) + return sof_ops(sdev)->pcm_hw_free(sdev, substream); + + return 0; +} + /* host stream trigger */ static inline int snd_sof_pcm_platform_trigger(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 6dc5f97be0bced..334e9d59b1bafa 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -251,6 +251,13 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work); + if (ret < 0) + return ret; + + ret = snd_sof_pcm_platform_hw_free(sdev, substream); + if (ret < 0) + dev_err(sdev->dev, "error: platform hw free failed\n"); + return ret; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index b4afe7a9bc415a..95be40f9c79dca 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -143,6 +143,10 @@ struct snd_sof_dsp_ops { struct snd_pcm_hw_params *params, struct sof_ipc_stream_params *ipc_params); /* optional */ + /* host stream hw_free */ + int (*pcm_hw_free)(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); /* optional */ + /* host stream trigger */ int (*pcm_trigger)(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, From a29b7af934854c0f754d772833300c3f0bfec157 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 29 May 2019 08:49:40 -0500 Subject: [PATCH 1511/1995] ASoC: SOF: Intel: hda-dsp: fix compilation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sound/soc/sof/intel/hda-dsp.c: In function ‘hda_dsp_set_hw_params_upon_resume’: sound/soc/sof/intel/hda-dsp.c:469:6: error: variable ‘stream_tag’ set but not used [-Werror=unused-but-set-variable] int stream_tag; Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-dsp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 17f6054d3d68bd..c6eea3079ab747 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -465,8 +465,8 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) struct snd_soc_pcm_runtime *rtd; struct hdac_ext_link *link; const char *name; -#endif int stream_tag; +#endif /* set internal flag for BE */ list_for_each_entry(s, &bus->stream_list, list) { @@ -474,7 +474,6 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) hda_stream = container_of(stream, struct sof_intel_hda_stream, hda_stream); hda_stream->hw_params_upon_resume = 1; - stream_tag = hdac_stream(stream)->stream_tag; #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* * clear and release stream. This should already be taken care @@ -488,6 +487,7 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) link = snd_hdac_ext_bus_get_link(bus, name); if (!link) return -EINVAL; + stream_tag = hdac_stream(stream)->stream_tag; snd_hdac_ext_link_clear_stream_id(link, stream_tag); snd_hdac_ext_stream_release(stream, HDAC_EXT_STREAM_TYPE_LINK); From 97e9ff9c6ff083ec690347561b7ba45c651035c5 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 22 May 2019 17:24:43 +0100 Subject: [PATCH 1512/1995] soundwire: stream: fix out of boundary access on port properties Assigning local iterator to array element and using it again for indexing would cross the array boundary. Fix this by directly referring array element without using the local variable. Signed-off-by: Srinivas Kandagatla Acked-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/stream.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index d01060dbee9625..544925ff0b4001 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1406,9 +1406,7 @@ struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave, } for (i = 0; i < num_ports; i++) { - dpn_prop = &dpn_prop[i]; - - if (dpn_prop->num == port_num) + if (dpn_prop[i].num == port_num) return &dpn_prop[i]; } From f1ff65dfe92c518d56261d16659c8df0f56df894 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 4 Apr 2019 09:12:21 +0100 Subject: [PATCH 1513/1995] soundwire: cdns: Fix compilation error on arm64 On arm64 the cadence_master.c file doesn't compile. readl and writel are undefined. This patch fixes that by including io.h. Signed-off-by: Jan Kotas Reviewed-by: Mukesh Ojha Signed-off-by: Vinod Koul --- drivers/soundwire/cadence_master.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 682789bb8ab30b..d56237bb351f3f 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include From d8fc2ed4c9e55af43479fd431ca7ce86e3456561 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 May 2019 14:47:17 -0500 Subject: [PATCH 1514/1995] soundwire: intel: filter SoundWire controller device search The convention is that the SoundWire controller device is a child of the HDAudio controller. However there can be more than one child exposed in the DSDT table, and the current namespace walk returns the last (incorrect) device. Intel documentation states that bits 28..31 of the _ADR field represent the link type, with SoundWire assigned the value 4. Add a filter and terminate early when a valid _ADR is provided, otherwise keep iterating to find the next child. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/intel_init.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index d3d6b54c57914c..771a53a5c033b7 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -14,6 +14,7 @@ #include #include "intel.h" +#define SDW_LINK_TYPE 4 /* from Intel ACPI documentation */ #define SDW_MAX_LINKS 4 #define SDW_SHIM_LCAP 0x0 #define SDW_SHIM_BASE 0x2C000 @@ -150,6 +151,12 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, { struct sdw_intel_res *res = cdata; struct acpi_device *adev; + acpi_status status; + u64 adr; + + status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); + if (ACPI_FAILURE(status)) + return AE_OK; /* keep going */ if (acpi_bus_get_device(handle, &adev)) { pr_err("%s: Couldn't find ACPI handle\n", __func__); @@ -157,7 +164,19 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, } res->handle = handle; - return AE_OK; + + /* + * On some Intel platforms, multiple children of the HDAS + * device can be found, but only one of them is the SoundWire + * controller. The SNDW device is always exposed with + * Name(_ADR, 0x40000000), with bits 31..28 representing the + * SoundWire link so filter accordingly + */ + if ((adr & GENMASK(31, 28)) >> 28 != SDW_LINK_TYPE) + return AE_OK; /* keep going */ + + /* device found, stop namespace walk */ + return AE_CTRL_TERMINATE; } /** From 741ee1baaa51306ad212fc444d997dab95c30360 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 May 2019 14:47:18 -0500 Subject: [PATCH 1515/1995] soundwire: mipi_disco: fix master/link error The MIPI DisCo specification for SoundWire defines the "mipi-sdw-link-N-subproperties" for slaves and "mipi-sdw-master-N-subproperties" for controllers. This is a mistake that was not identified until now. Existing Intel DSDT tables use 'link' everywhere, and the MIPI spec will be updated to deprecate "mipi-sdw-master-N-subproperties" Fix to parse firmware information on existing devices. If we ever see a system with 'master-N-subproperties' I guess we'll have to try both. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/mipi_disco.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soundwire/mipi_disco.c b/drivers/soundwire/mipi_disco.c index c1f51d6a23d22b..6df68584c963e4 100644 --- a/drivers/soundwire/mipi_disco.c +++ b/drivers/soundwire/mipi_disco.c @@ -40,7 +40,7 @@ int sdw_master_read_prop(struct sdw_bus *bus) /* Find master handle */ snprintf(name, sizeof(name), - "mipi-sdw-master-%d-subproperties", bus->link_id); + "mipi-sdw-link-%d-subproperties", bus->link_id); link = device_get_named_child_node(bus->dev, name); if (!link) { From 421a130706c1c130d5864e25c326936ee7d99e50 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 May 2019 14:47:19 -0500 Subject: [PATCH 1516/1995] soundwire: add port-related definitions Somehow previous header files did not include definition for sink/source, flow and grouping. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- include/linux/soundwire/sdw.h | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 35662d9c2c62d7..69ae680a5a218d 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -41,6 +41,31 @@ struct sdw_slave; #define SDW_DAI_ID_RANGE_START 100 #define SDW_DAI_ID_RANGE_END 200 +enum { + SDW_PORT_DIRN_SINK = 0, + SDW_PORT_DIRN_SOURCE, + SDW_PORT_DIRN_MAX, +}; + +/* + * constants for flow control, ports and transport + * + * these are bit masks as devices can have multiple capabilities + */ + +/* + * flow modes for SDW port. These can be isochronous, tx controlled, + * rx controlled or async + */ +#define SDW_PORT_FLOW_MODE_ISOCH 0 +#define SDW_PORT_FLOW_MODE_TX_CNTRL BIT(0) +#define SDW_PORT_FLOW_MODE_RX_CNTRL BIT(1) +#define SDW_PORT_FLOW_MODE_ASYNC GENMASK(1, 0) + +/* sample packaging for block. It can be per port or per channel */ +#define SDW_BLOCK_PACKG_PER_PORT BIT(0) +#define SDW_BLOCK_PACKG_PER_CH BIT(1) + /** * enum sdw_slave_status - Slave status * @SDW_SLAVE_UNATTACHED: Slave is not attached with the bus. @@ -76,6 +101,14 @@ enum sdw_command_response { SDW_CMD_FAIL_OTHER = 4, }; +/* block group count enum */ +enum sdw_dpn_grouping { + SDW_BLK_GRP_CNT_1 = 0, + SDW_BLK_GRP_CNT_2 = 1, + SDW_BLK_GRP_CNT_3 = 2, + SDW_BLK_GRP_CNT_4 = 3, +}; + /** * enum sdw_stream_type: data stream type * @@ -100,6 +133,26 @@ enum sdw_data_direction { SDW_DATA_DIR_TX = 1, }; +/** + * enum sdw_port_data_mode: Data Port mode + * + * @SDW_PORT_DATA_MODE_NORMAL: Normal data mode where audio data is received + * and transmitted. + * @SDW_PORT_DATA_MODE_STATIC_1: Simple test mode which uses static value of + * logic 1. The encoding will result in signal transitions at every bitslot + * owned by this Port + * @SDW_PORT_DATA_MODE_STATIC_0: Simple test mode which uses static value of + * logic 0. The encoding will result in no signal transitions + * @SDW_PORT_DATA_MODE_PRBS: Test mode which uses a PRBS generator to produce + * a pseudo random data pattern that is transferred + */ +enum sdw_port_data_mode { + SDW_PORT_DATA_MODE_NORMAL = 0, + SDW_PORT_DATA_MODE_STATIC_1 = 1, + SDW_PORT_DATA_MODE_STATIC_0 = 2, + SDW_PORT_DATA_MODE_PRBS = 3, +}; + /* * SDW properties, defined in MIPI DisCo spec v1.0 */ From d81bbedb888692b57e2e4d3922435dffb34f05db Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 May 2019 14:47:20 -0500 Subject: [PATCH 1517/1995] soundwire: remove master data port properties The SoundWire and DisCo specifications do not define Master data ports or related properties. Data ports are only defined for Slave devices, so remove the unused member in properties. Credits: this patch is based on an earlier internal contribution by Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- include/linux/soundwire/sdw.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 69ae680a5a218d..831a370eaedd58 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -377,7 +377,6 @@ struct sdw_slave_prop { * @dynamic_frame: Dynamic frame supported * @err_threshold: Number of times that software may retry sending a single * command - * @dpn_prop: Data Port N properties */ struct sdw_master_prop { u32 revision; @@ -393,7 +392,6 @@ struct sdw_master_prop { u32 default_col; bool dynamic_frame; u32 err_threshold; - struct sdw_dpn_prop *dpn_prop; }; int sdw_master_read_prop(struct sdw_bus *bus); From c809af85b7c4c69b685f8bf554fa10d0e7dac5c4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 May 2019 14:47:21 -0500 Subject: [PATCH 1518/1995] soundwire: mipi-disco: remove master_count property for masters The master_count is only defined for a Controller or a Slave in the MIPI DisCo for SoundWire document. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- include/linux/soundwire/sdw.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 831a370eaedd58..14376d8458c353 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -364,7 +364,6 @@ struct sdw_slave_prop { /** * struct sdw_master_prop - Master properties * @revision: MIPI spec version of the implementation - * @master_count: Number of masters * @clk_stop_mode: Bitmap for Clock Stop modes supported * @max_freq: Maximum Bus clock frequency, in Hz * @num_clk_gears: Number of clock gears supported @@ -380,7 +379,6 @@ struct sdw_slave_prop { */ struct sdw_master_prop { u32 revision; - u32 master_count; enum sdw_clk_stop_mode clk_stop_mode; u32 max_freq; u32 num_clk_gears; From 9624143f45c287f2d5ed04cccc50adb11700960b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 May 2019 14:47:22 -0500 Subject: [PATCH 1519/1995] soundwire: rename 'freq' fields Rename all fields with 'freq' as 'clk_freq' to follow the MIPI specification and avoid confusion between bus clock and audio clocks. No functionality change. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 4 ++-- drivers/soundwire/intel.c | 11 ++++++----- drivers/soundwire/mipi_disco.c | 23 ++++++++++++----------- drivers/soundwire/stream.c | 2 +- include/linux/soundwire/sdw.h | 12 ++++++------ 5 files changed, 27 insertions(+), 25 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index aac35fc3cf22c4..96e42df8f4582e 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -87,7 +87,7 @@ int sdw_add_bus_master(struct sdw_bus *bus) /* * Initialize clock values based on Master properties. The max - * frequency is read from max_freq property. Current assumption + * frequency is read from max_clk_freq property. Current assumption * is that the bus will start at highest clock frequency when * powered on. * @@ -95,7 +95,7 @@ int sdw_add_bus_master(struct sdw_bus *bus) * to start with bank 0 (Table 40 of Spec) */ prop = &bus->prop; - bus->params.max_dr_freq = prop->max_freq * SDW_DOUBLE_RATE_FACTOR; + bus->params.max_dr_freq = prop->max_clk_freq * SDW_DOUBLE_RATE_FACTOR; bus->params.curr_dr_freq = bus->params.max_dr_freq; bus->params.curr_bank = SDW_BANK0; bus->params.next_bank = SDW_BANK1; diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 31336b0271b076..4ac141730b130e 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -796,13 +796,14 @@ static int intel_prop_read(struct sdw_bus *bus) sdw_master_read_prop(bus); /* BIOS is not giving some values correctly. So, lets override them */ - bus->prop.num_freq = 1; - bus->prop.freq = devm_kcalloc(bus->dev, bus->prop.num_freq, - sizeof(*bus->prop.freq), GFP_KERNEL); - if (!bus->prop.freq) + bus->prop.num_clk_freq = 1; + bus->prop.clk_freq = devm_kcalloc(bus->dev, bus->prop.num_clk_freq, + sizeof(*bus->prop.clk_freq), + GFP_KERNEL); + if (!bus->prop.clk_freq) return -ENOMEM; - bus->prop.freq[0] = bus->prop.max_freq; + bus->prop.clk_freq[0] = bus->prop.max_clk_freq; bus->prop.err_threshold = 5; return 0; diff --git a/drivers/soundwire/mipi_disco.c b/drivers/soundwire/mipi_disco.c index 6df68584c963e4..b1770af43fa8c5 100644 --- a/drivers/soundwire/mipi_disco.c +++ b/drivers/soundwire/mipi_disco.c @@ -58,31 +58,32 @@ int sdw_master_read_prop(struct sdw_bus *bus) fwnode_property_read_u32(link, "mipi-sdw-max-clock-frequency", - &prop->max_freq); + &prop->max_clk_freq); nval = fwnode_property_read_u32_array(link, "mipi-sdw-clock-frequencies-supported", NULL, 0); if (nval > 0) { - prop->num_freq = nval; - prop->freq = devm_kcalloc(bus->dev, prop->num_freq, - sizeof(*prop->freq), GFP_KERNEL); - if (!prop->freq) + prop->num_clk_freq = nval; + prop->clk_freq = devm_kcalloc(bus->dev, prop->num_clk_freq, + sizeof(*prop->clk_freq), + GFP_KERNEL); + if (!prop->clk_freq) return -ENOMEM; fwnode_property_read_u32_array(link, "mipi-sdw-clock-frequencies-supported", - prop->freq, prop->num_freq); + prop->clk_freq, prop->num_clk_freq); } /* * Check the frequencies supported. If FW doesn't provide max * freq, then populate here by checking values. */ - if (!prop->max_freq && prop->freq) { - prop->max_freq = prop->freq[0]; - for (i = 1; i < prop->num_freq; i++) { - if (prop->freq[i] > prop->max_freq) - prop->max_freq = prop->freq[i]; + if (!prop->max_clk_freq && prop->clk_freq) { + prop->max_clk_freq = prop->clk_freq[0]; + for (i = 1; i < prop->num_clk_freq; i++) { + if (prop->clk_freq[i] > prop->max_clk_freq) + prop->max_clk_freq = prop->clk_freq[i]; } } diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 544925ff0b4001..755fca57955429 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1472,7 +1472,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream) memcpy(¶ms, &bus->params, sizeof(params)); /* TODO: Support Asynchronous mode */ - if ((prop->max_freq % stream->params.rate) != 0) { + if ((prop->max_clk_freq % stream->params.rate) != 0) { dev_err(bus->dev, "Async mode not supported\n"); return -EINVAL; } diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 14376d8458c353..c6ded0d7a9f298 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -365,11 +365,11 @@ struct sdw_slave_prop { * struct sdw_master_prop - Master properties * @revision: MIPI spec version of the implementation * @clk_stop_mode: Bitmap for Clock Stop modes supported - * @max_freq: Maximum Bus clock frequency, in Hz + * @max_clk_freq: Maximum Bus clock frequency, in Hz * @num_clk_gears: Number of clock gears supported * @clk_gears: Clock gears supported - * @num_freq: Number of clock frequencies supported, in Hz - * @freq: Clock frequencies supported, in Hz + * @num_clk_freq: Number of clock frequencies supported, in Hz + * @clk_freq: Clock frequencies supported, in Hz * @default_frame_rate: Controller default Frame rate, in Hz * @default_row: Number of rows * @default_col: Number of columns @@ -380,11 +380,11 @@ struct sdw_slave_prop { struct sdw_master_prop { u32 revision; enum sdw_clk_stop_mode clk_stop_mode; - u32 max_freq; + u32 max_clk_freq; u32 num_clk_gears; u32 *clk_gears; - u32 num_freq; - u32 *freq; + u32 num_clk_freq; + u32 *clk_freq; u32 default_frame_rate; u32 default_row; u32 default_col; From 447b1ce65e7d3f271180c7aa41abbbfb9b46bdc4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 May 2019 14:47:23 -0500 Subject: [PATCH 1520/1995] soundwire: mipi-disco: fix clock stop modes Fix support for clock_stop_mode0 and 1. The existing code uses a bitmask between enums, one of which being zero. Or-ing with zero is not very useful in general...Fix by or-ing with a BIT dependent on the enum value. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/mipi_disco.c | 4 ++-- include/linux/soundwire/sdw.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/soundwire/mipi_disco.c b/drivers/soundwire/mipi_disco.c index b1770af43fa8c5..efb87ee0e7fc37 100644 --- a/drivers/soundwire/mipi_disco.c +++ b/drivers/soundwire/mipi_disco.c @@ -50,11 +50,11 @@ int sdw_master_read_prop(struct sdw_bus *bus) if (fwnode_property_read_bool(link, "mipi-sdw-clock-stop-mode0-supported")) - prop->clk_stop_mode = SDW_CLK_STOP_MODE0; + prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE0); if (fwnode_property_read_bool(link, "mipi-sdw-clock-stop-mode1-supported")) - prop->clk_stop_mode |= SDW_CLK_STOP_MODE1; + prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE1); fwnode_property_read_u32(link, "mipi-sdw-max-clock-frequency", diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index c6ded0d7a9f298..0e3fdd03e589b7 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -364,7 +364,7 @@ struct sdw_slave_prop { /** * struct sdw_master_prop - Master properties * @revision: MIPI spec version of the implementation - * @clk_stop_mode: Bitmap for Clock Stop modes supported + * @clk_stop_modes: Bitmap, bit N set when clock-stop-modeN supported * @max_clk_freq: Maximum Bus clock frequency, in Hz * @num_clk_gears: Number of clock gears supported * @clk_gears: Clock gears supported @@ -379,7 +379,7 @@ struct sdw_slave_prop { */ struct sdw_master_prop { u32 revision; - enum sdw_clk_stop_mode clk_stop_mode; + u32 clk_stop_modes; u32 max_clk_freq; u32 num_clk_gears; u32 *clk_gears; From 66f57f3e165d33f5df013e32cdd4f9cc80a820eb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 May 2019 14:47:24 -0500 Subject: [PATCH 1521/1995] soundwire: clarify comment The MIPI DisCo spec refers to dynamic frame shape, not to dynamic shape. Clarify. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- include/linux/soundwire/sdw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 0e3fdd03e589b7..b7efa819d425b1 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -373,7 +373,7 @@ struct sdw_slave_prop { * @default_frame_rate: Controller default Frame rate, in Hz * @default_row: Number of rows * @default_col: Number of columns - * @dynamic_frame: Dynamic frame supported + * @dynamic_frame: Dynamic frame shape supported * @err_threshold: Number of times that software may retry sending a single * command */ From f8d6c290996981de1e92df40500dc04c6135b35e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 May 2019 14:47:25 -0500 Subject: [PATCH 1522/1995] soundwire: rename/clarify MIPI DisCo properties The existing definitions are ambiguous and possibly misleading. For DP0, 'flow-control' is only relevant for the BRA protocol and should not be confused with async modes explicitly not supported for DP0, add prefix to follow MIPI DisCo definition The use of 'device_interrupts' is also questionable. The MIPI SoundWire spec defines Slave-, DP0- and DPN-level implementation-defined interrupts. Using the 'device' prefix in the last two cases is misleading, not only is the term 'device' overloaded but these properties are only valid at the DP0 and DPn levels. Rename to follow the MIPI definitions, no need to be creative here. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 2 +- drivers/soundwire/mipi_disco.c | 6 +++--- drivers/soundwire/stream.c | 6 +++--- include/linux/soundwire/sdw.h | 13 +++++++------ 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 96e42df8f4582e..fe745830a261a7 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -648,7 +648,7 @@ static int sdw_initialize_slave(struct sdw_slave *slave) return 0; /* Enable DP0 interrupts */ - val = prop->dp0_prop->device_interrupts; + val = prop->dp0_prop->imp_def_interrupts; val |= SDW_DP0_INT_PORT_READY | SDW_DP0_INT_BRA_FAILURE; ret = sdw_update(slave, SDW_DP0_INTMASK, val, val); diff --git a/drivers/soundwire/mipi_disco.c b/drivers/soundwire/mipi_disco.c index efb87ee0e7fc37..79fee1b21ab6e6 100644 --- a/drivers/soundwire/mipi_disco.c +++ b/drivers/soundwire/mipi_disco.c @@ -150,13 +150,13 @@ static int sdw_slave_read_dp0(struct sdw_slave *slave, dp0->words, dp0->num_words); } - dp0->flow_controlled = fwnode_property_read_bool(port, + dp0->BRA_flow_controlled = fwnode_property_read_bool(port, "mipi-sdw-bra-flow-controlled"); dp0->simple_ch_prep_sm = fwnode_property_read_bool(port, "mipi-sdw-simplified-channel-prepare-sm"); - dp0->device_interrupts = fwnode_property_read_bool(port, + dp0->imp_def_interrupts = fwnode_property_read_bool(port, "mipi-sdw-imp-def-dp0-interrupts-supported"); return 0; @@ -225,7 +225,7 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave, fwnode_property_read_u32(node, "mipi-sdw-imp-def-dpn-interrupts-supported", - &dpn[i].device_interrupts); + &dpn[i].imp_def_interrupts); fwnode_property_read_u32(node, "mipi-sdw-min-channel-number", &dpn[i].min_ch); diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 755fca57955429..c3cdef6b789e22 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -439,7 +439,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus, prep_ch.bank = bus->params.next_bank; - if (dpn_prop->device_interrupts || !dpn_prop->simple_ch_prep_sm) + if (dpn_prop->imp_def_interrupts || !dpn_prop->simple_ch_prep_sm) intr = true; /* @@ -449,7 +449,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus, */ if (prep && intr) { ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep, - dpn_prop->device_interrupts); + dpn_prop->imp_def_interrupts); if (ret < 0) return ret; } @@ -493,7 +493,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus, /* Disable interrupt after Port de-prepare */ if (!prep && intr) ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep, - dpn_prop->device_interrupts); + dpn_prop->imp_def_interrupts); return ret; } diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index b7efa819d425b1..bea46bd8b6ce9e 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -206,10 +206,11 @@ enum sdw_clk_stop_mode { * (inclusive) * @num_words: number of wordlengths supported * @words: wordlengths supported - * @flow_controlled: Slave implementation results in an OK_NotReady + * @BRA_flow_controlled: Slave implementation results in an OK_NotReady * response * @simple_ch_prep_sm: If channel prepare sequence is required - * @device_interrupts: If implementation-defined interrupts are supported + * @imp_def_interrupts: If set, each bit corresponds to support for + * implementation-defined interrupts * * The wordlengths are specified by Spec as max, min AND number of * discrete values, implementation can define based on the wordlengths they @@ -220,9 +221,9 @@ struct sdw_dp0_prop { u32 min_word; u32 num_words; u32 *words; - bool flow_controlled; + bool BRA_flow_controlled; bool simple_ch_prep_sm; - bool device_interrupts; + bool imp_def_interrupts; }; /** @@ -272,7 +273,7 @@ struct sdw_dpn_audio_mode { * @simple_ch_prep_sm: If the port supports simplified channel prepare state * machine * @ch_prep_timeout: Port-specific timeout value, in milliseconds - * @device_interrupts: If set, each bit corresponds to support for + * @imp_def_interrupts: If set, each bit corresponds to support for * implementation-defined interrupts * @max_ch: Maximum channels supported * @min_ch: Minimum channels supported @@ -297,7 +298,7 @@ struct sdw_dpn_prop { u32 max_grouping; bool simple_ch_prep_sm; u32 ch_prep_timeout; - u32 device_interrupts; + u32 imp_def_interrupts; u32 max_ch; u32 min_ch; u32 num_ch; From 303143e110e7f07d7144423df6dcc260721a6e0e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 May 2019 14:47:26 -0500 Subject: [PATCH 1523/1995] soundwire: cadence_master: use rate_limited dynamic debug When commands start failing, e.g. due to a bad electrical connection or bus conflicts, the dmesg log is flooded. This should not happen for production devices but it's quite frequent when bringing-up a new platform. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/cadence_master.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index d56237bb351f3f..e3b78768886b53 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -237,19 +237,19 @@ cdns_fill_msg_resp(struct sdw_cdns *cdns, for (i = 0; i < count; i++) { if (!(cdns->response_buf[i] & CDNS_MCP_RESP_ACK)) { no_ack = 1; - dev_dbg(cdns->dev, "Msg Ack not received\n"); + dev_dbg_ratelimited(cdns->dev, "Msg Ack not received\n"); if (cdns->response_buf[i] & CDNS_MCP_RESP_NACK) { nack = 1; - dev_err(cdns->dev, "Msg NACK received\n"); + dev_err_ratelimited(cdns->dev, "Msg NACK received\n"); } } } if (nack) { - dev_err(cdns->dev, "Msg NACKed for Slave %d\n", msg->dev_num); + dev_err_ratelimited(cdns->dev, "Msg NACKed for Slave %d\n", msg->dev_num); return SDW_CMD_FAIL; } else if (no_ack) { - dev_dbg(cdns->dev, "Msg ignored for Slave %d\n", msg->dev_num); + dev_dbg_ratelimited(cdns->dev, "Msg ignored for Slave %d\n", msg->dev_num); return SDW_CMD_IGNORED; } @@ -357,12 +357,12 @@ cdns_program_scp_addr(struct sdw_cdns *cdns, struct sdw_msg *msg) /* For NACK, NO ack, don't return err if we are in Broadcast mode */ if (nack) { - dev_err(cdns->dev, - "SCP_addrpage NACKed for Slave %d\n", msg->dev_num); + dev_err_ratelimited(cdns->dev, + "SCP_addrpage NACKed for Slave %d\n", msg->dev_num); return SDW_CMD_FAIL; } else if (no_ack) { - dev_dbg(cdns->dev, - "SCP_addrpage ignored for Slave %d\n", msg->dev_num); + dev_dbg_ratelimited(cdns->dev, + "SCP_addrpage ignored for Slave %d\n", msg->dev_num); return SDW_CMD_IGNORED; } @@ -525,9 +525,9 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns, /* first check if Slave reported multiple status */ if (set_status > 1) { - dev_warn(cdns->dev, - "Slave reported multiple Status: %d\n", - status[i]); + dev_warn_ratelimited(cdns->dev, + "Slave reported multiple Status: %d\n", + status[i]); /* * TODO: we need to reread the status here by * issuing a PING cmd @@ -613,7 +613,7 @@ irqreturn_t sdw_cdns_thread(int irq, void *dev_id) struct sdw_cdns *cdns = dev_id; u32 slave0, slave1; - dev_dbg(cdns->dev, "Slave status change\n"); + dev_dbg_ratelimited(cdns->dev, "Slave status change\n"); slave0 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0); slave1 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1); From a9f61cadffbaed215f20f87db081dea8d9453ccd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 May 2019 14:47:27 -0500 Subject: [PATCH 1524/1995] soundwire: cadence_master: log Slave status mask on errors The Slave status mask exposes 4 sticky bits. When the device loses sync, the IP will report two status but the log will only show that the device lost sync. The status mask has all the information needed so let's report it instead. Also change the resolution of the mask, using 64 bits is not needed when you need 4. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/cadence_master.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index e3b78768886b53..d76dd24a6eaead 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -487,7 +487,8 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns, { enum sdw_slave_status status[SDW_MAX_DEVICES + 1]; bool is_slave = false; - u64 slave, mask; + u64 slave; + u32 mask; int i, set_status; /* combine the two status */ @@ -527,7 +528,7 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns, if (set_status > 1) { dev_warn_ratelimited(cdns->dev, "Slave reported multiple Status: %d\n", - status[i]); + mask); /* * TODO: we need to reread the status here by * issuing a PING cmd From b10eb75eee3130ba7432ca1394a0ea2a9787a4d0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 May 2019 14:47:28 -0500 Subject: [PATCH 1525/1995] soundwire: cadence_master: check the number of bidir PDIs There is an assumption that the first two PDIs are reserved for Bulk, so we need to make sure the number of bidir PDIs is indeed larger than two. If the configuration provided is incorrect, this could lead to allocating a huge amount of memory. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/cadence_master.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index d76dd24a6eaead..ff4badc9b3dec5 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -718,6 +718,8 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns, stream = &cdns->pcm; /* First two PDIs are reserved for bulk transfers */ + if (stream->num_bd < CDNS_PCM_PDI_OFFSET) + return -EINVAL; stream->num_bd -= CDNS_PCM_PDI_OFFSET; offset = CDNS_PCM_PDI_OFFSET; From 8d51b45d8033ec28d7894668ff993c50844494c7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 May 2019 14:47:29 -0500 Subject: [PATCH 1526/1995] soundwire: Intel: add log for number of PCM and PDM PDIs This information will be reflected in debugfs but it's easier to see as a dmesg log. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/intel.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 4ac141730b130e..92be6ad84e8ddb 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -263,6 +263,9 @@ static void intel_pdi_init(struct sdw_intel *sdw, config->pcm_out = (pcm_cap & SDW_SHIM_PCMSCAP_OSS) >> SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_OSS); + dev_dbg(sdw->cdns.dev, "PCM cap bd:%d in:%d out:%d\n", + config->pcm_bd, config->pcm_in, config->pcm_out); + /* PDM Stream Capability */ pdm_cap = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id)); @@ -272,6 +275,9 @@ static void intel_pdi_init(struct sdw_intel *sdw, SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_ISS); config->pdm_out = (pdm_cap & SDW_SHIM_PDMSCAP_OSS) >> SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_OSS); + + dev_dbg(sdw->cdns.dev, "PDM cap bd:%d in:%d out:%d\n", + config->pdm_bd, config->pdm_in, config->pdm_out); } static int From 303ae6cd0e2ef7c31fce01d4f7f092834a21786d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 May 2019 14:47:30 -0500 Subject: [PATCH 1527/1995] soundwire: fix typo in comments Copy/paste of sdw_intel_res Signed-off-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/intel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soundwire/intel.h b/drivers/soundwire/intel.h index 71050e5f643d0f..d923b626233026 100644 --- a/drivers/soundwire/intel.h +++ b/drivers/soundwire/intel.h @@ -5,7 +5,7 @@ #define __SDW_INTEL_LOCAL_H /** - * struct sdw_intel_res - Soundwire link resources + * struct sdw_intel_link_res - Soundwire link resources * @registers: Link IO registers base * @shim: Audio shim pointer * @alh: ALH (Audio Link Hub) pointer From 80a2cb895f4b72756891a6fca2d965a9a6ce9891 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 22 May 2019 14:47:31 -0500 Subject: [PATCH 1528/1995] soundwire: intel_init: add checks on link numbers Add mask to correctly read the SoundWire SHIM LCAP register. Only bits 2..0 are meaningful, the rest is about link synchronization and stream channel mapping. Without this mask, the hardware information would always be larger than whatever the BIOS would report. Also trap the case with zero links. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul --- drivers/soundwire/intel_init.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 771a53a5c033b7..70637a0383d2a1 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -81,6 +81,7 @@ static struct sdw_intel_ctx /* Check SNDWLCAP.LCOUNT */ caps = ioread32(res->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP); + caps &= GENMASK(2, 0); /* Check HW supported vs property value and use min of two */ count = min_t(u8, caps, count); @@ -90,6 +91,9 @@ static struct sdw_intel_ctx dev_err(&adev->dev, "Link count %d exceeds max %d\n", count, SDW_MAX_LINKS); return NULL; + } else if (!count) { + dev_warn(&adev->dev, "No SoundWire links detected\n"); + return NULL; } dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count); From 0a6d0d85cc37616a59bc87a8614798dbed48ad5a Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Thu, 30 May 2019 16:21:15 +0800 Subject: [PATCH 1529/1995] ASoC: SOF: intel: hda-stream: fix a deadlock with bus->reg_lock We should use irq disabled mode when read/write hda registers from thread context, as we need to hold the same bus->reg_lock in interrupt context hda_dsp_stream_interrupt(), otherwise, when we are holding the lock in hda_dsp_stream_hw_free() and the interrupt arrives, we will get deadlock in the interrupt handler. Error logs like this: [ 5.603606] CPU0 [ 5.603606] ---- [ 5.603607] lock(&(&bus->reg_lock)->rlock); [ 5.603608] [ 5.603609] lock(&(&bus->reg_lock)->rlock); [ 5.603610] *** DEADLOCK *** [ 5.603611] 2 locks held by pulseaudio/2329: [ 5.603612] #0: 000000005fcf26c6 (&card->mutex/1){+.+.}, at: dpcm_fe_dai_hw_free+0x2b/0x110 [snd_soc_core] [ 5.603619] #1: 00000000ef369faf (&rtd->pcm_mutex){+.+.}, at: soc_pcm_hw_free+0x2e/0x1c0 [snd_soc_core] The fix is simple, let's switch to use spin_lock/unlock_irq(). Reported-by: Xun Zhang Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-stream.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index ff6ab0c45d8ea2..ddfd80b44e6e8c 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -448,12 +448,12 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, struct hdac_bus *bus = sof_to_bus(sdev); u32 mask = 0x1 << stream->index; - spin_lock(&bus->reg_lock); + spin_lock_irq(&bus->reg_lock); /* couple host and link DMA if link DMA channel is idle */ if (!link_dev->link_locked) snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, mask, 0); - spin_unlock(&bus->reg_lock); + spin_unlock_irq(&bus->reg_lock); return 0; } From 0a747dc2f1ca837c543607b42c991beb186bc4c6 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 30 May 2019 16:26:11 +0800 Subject: [PATCH 1530/1995] ALSA: hda: fix: lock reg_lock before calling snd_hdac_bus_update_rirb The patch is to fix commit 5e13cf6cd64c (ALSA: hda: add polling mode in snd_hdac_bus_get_response) spin_lock_irq should be called before snd_hdac_bus_update_rirb. Signed-off-by: Bard Liao --- sound/hda/hdac_controller.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index a16ac31bda8354..d6a91429c058cd 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -239,9 +239,9 @@ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr, timeout = jiffies + msecs_to_jiffies(1000); for (loopcounter = 0;; loopcounter++) { + spin_lock_irq(&bus->reg_lock); if (bus->polling_mode) snd_hdac_bus_update_rirb(bus); - spin_lock_irq(&bus->reg_lock); if (!bus->rirb.cmds[addr]) { if (res) *res = bus->rirb.res[addr]; /* the last value */ From a5221da21556187530a18e7095a611838b66b1c8 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Tue, 21 May 2019 17:04:48 +0800 Subject: [PATCH 1531/1995] ASoC: SOF: Intel: hda: use the SOF defined ppcap functions Unify ppcap function setup by using SOF common functions for both HDA and non-HDA cases. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-dsp.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index c6eea3079ab747..883134d535b3a3 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -307,18 +307,14 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state) return ret; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* disable ppcap interrupt */ - snd_hdac_ext_bus_ppcap_int_enable(bus, false); - snd_hdac_ext_bus_ppcap_enable(bus, false); + hda_dsp_ctrl_ppcap_enable(sdev, false); + hda_dsp_ctrl_ppcap_int_enable(sdev, false); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* disable hda bus irq and i/o */ snd_hdac_bus_stop_chip(bus); #else - /* disable ppcap interrupt */ - hda_dsp_ctrl_ppcap_enable(sdev, false); - hda_dsp_ctrl_ppcap_int_enable(sdev, false); - /* disable hda bus irq */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, @@ -370,10 +366,6 @@ static int hda_resume(struct snd_sof_dev *sdev) bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); hda_dsp_ctrl_misc_clock_gating(sdev, true); - - /* enable ppcap interrupt */ - snd_hdac_ext_bus_ppcap_enable(bus, true); - snd_hdac_ext_bus_ppcap_int_enable(bus, true); #else hda_dsp_ctrl_misc_clock_gating(sdev, false); @@ -400,11 +392,11 @@ static int hda_resume(struct snd_sof_dev *sdev) SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); hda_dsp_ctrl_misc_clock_gating(sdev, true); +#endif /* enable ppcap interrupt */ hda_dsp_ctrl_ppcap_enable(sdev, true); hda_dsp_ctrl_ppcap_int_enable(sdev, true); -#endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* turn off the links that were off before suspend */ From 80aa6c56fe7be2d1d8defb9059af6fbab518578e Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Tue, 21 May 2019 16:50:39 +0800 Subject: [PATCH 1532/1995] ASoC: SOF: Intel: hda: add function for hda stop chip Add common hda_dsp_ctrl_stop_chip() function to stop controller with the same function handling both HDA and non-HDA cases. This function disables IRQs and clears status masks. When CONFIG_SND_SOC_SOF_HDA is defined, also disables the CORB/RIRB, and stops i/o. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-ctrl.c | 67 ++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 2 +- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 07bc123112c9ba..688ab8d895a974 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -263,3 +263,70 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) return ret; } + +void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct hdac_stream *stream; + int sd_offset; + + if (!bus->chip_init) + return; + + /* disable interrupts in stream descriptor */ + list_for_each_entry(stream, &bus->stream_list, list) { + sd_offset = SOF_STREAM_SD_OFFSET(stream); + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + + SOF_HDA_ADSP_REG_CL_SD_CTL, + SOF_HDA_CL_DMA_SD_INT_MASK, + 0); + } + + /* disable SIE for all streams */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + SOF_HDA_INT_ALL_STREAM, 0); + + /* disable controller CIE and GIE */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, + 0); + + /* clear stream status */ + list_for_each_entry(stream, &bus->stream_list, list) { + sd_offset = SOF_STREAM_SD_OFFSET(stream); + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + sd_offset + + SOF_HDA_ADSP_REG_CL_SD_STS, + SOF_HDA_CL_DMA_SD_INT_MASK, + SOF_HDA_CL_DMA_SD_INT_MASK); + } + + /* clear WAKESTS */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, + SOF_HDA_WAKESTS_INT_MASK, + SOF_HDA_WAKESTS_INT_MASK); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* clear rirb status */ + snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); +#endif + + /* clear interrupt status register */ + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS, + SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_ALL_STREAM); + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* disable CORB/RIRB */ + snd_hdac_bus_stop_cmd_io(bus); +#endif + /* disable position buffer */ + if (bus->posbuf.addr) { + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + SOF_HDA_ADSP_DPLBASE, 0); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + SOF_HDA_ADSP_DPUBASE, 0); + } + + bus->chip_init = false; +} diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 430e84e6c8c608..774ac9794aa1bc 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -536,7 +536,7 @@ int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset); void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable); int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable); int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset); - +void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev); /* * HDA bus operations. */ From 7f300c73179c2a5c98d52d91371dc591584f219e Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Tue, 21 May 2019 17:42:05 +0800 Subject: [PATCH 1533/1995] ASoC: SOF: Intel: hda: use the defined stop chip in suspend Unify suspend code by using SOF common function hda_dsp_ctrl_stop_chip() which can handle both HDA and non-HDA cases. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-dsp.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 883134d535b3a3..f2c5a12db930a4 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -311,15 +311,8 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state) hda_dsp_ctrl_ppcap_enable(sdev, false); hda_dsp_ctrl_ppcap_int_enable(sdev, false); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* disable hda bus irq and i/o */ - snd_hdac_bus_stop_chip(bus); -#else - /* disable hda bus irq */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, - 0); -#endif + /* disable hda bus irq and streams */ + hda_dsp_ctrl_stop_chip(sdev); /* disable LP retention mode */ snd_sof_pci_update_bits(sdev, PCI_PGCTL, From 4a9f1991f282ee701f8bda3fb0cec190d73b6595 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 5 Jun 2019 21:29:30 +0300 Subject: [PATCH 1534/1995] ASoC: SOF: intel: extend IPC dump information Extend the HDA IPC dump implementation with status of key IRQ registers. This is useful to debug IPC timeouts and similar issues. Signed-off-by: Kai Vehmanen --- sound/soc/sof/intel/cnl.c | 2 ++ sound/soc/sof/intel/hda.c | 29 +++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 2 ++ 3 files changed, 33 insertions(+) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 35f854d33f0695..3840f81767fab1 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -168,6 +168,8 @@ static void cnl_ipc_dump(struct snd_sof_dev *sdev) u32 hipcida; u32 hipctdr; + hda_ipc_irq_dump(sdev); + /* read IPC status */ hipcida = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDA); hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCCTL); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 5b6c21565b96e8..9ddefda37692a1 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -15,6 +15,9 @@ * Hardware interface for generic Intel audio DSP HDA IP */ +#include +#include + #include #include #include @@ -186,12 +189,38 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) } } +void hda_ipc_irq_dump(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + u32 adspis; + u32 intsts; + u32 intctl; + u32 ppsts; + u8 rirbsts; + + /* read key IRQ stats and config registers */ + adspis = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS); + intsts = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS); + intctl = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL); + ppsts = snd_sof_dsp_read(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPSTS); + rirbsts = snd_hdac_chip_readb(bus, RIRBSTS); + + dev_err(sdev->dev, + "error: hda irq intsts 0x%8.8x intlctl 0x%8.8x rirb %2.2x\n", + intsts, intctl, rirbsts); + dev_err(sdev->dev, + "error: dsp irq ppsts 0x%8.8x adspis 0x%8.8x\n", + ppsts, adspis); +} + void hda_ipc_dump(struct snd_sof_dev *sdev) { u32 hipcie; u32 hipct; u32 hipcctl; + hda_ipc_irq_dump(sdev); + /* read IPC status */ hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE); hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 774ac9794aa1bc..50653859e0a044 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -61,6 +61,7 @@ #define SOF_HDA_PP_CAP_ID 0x3 #define SOF_HDA_REG_PP_PPCH 0x10 #define SOF_HDA_REG_PP_PPCTL 0x04 +#define SOF_HDA_REG_PP_PPSTS 0x08 #define SOF_HDA_PPCTL_PIE BIT(31) #define SOF_HDA_PPCTL_GPROCEN BIT(30) @@ -454,6 +455,7 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev); void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags); void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags); void hda_ipc_dump(struct snd_sof_dev *sdev); +void hda_ipc_irq_dump(struct snd_sof_dev *sdev); /* * DSP PCM Operations. From d303110038a04fd7f379a41b12470e67181409d6 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 6 Jun 2019 11:29:56 -0700 Subject: [PATCH 1535/1995] ASoC: SOF: Intel: hda: clear stream status and wakests properly Stream status and WAKESTS registers need to be cleared by writing to them with snd_sof_dsp_write(). snd_sof_dsp_update_bits() only writes if the value is changed and will result in not clearing the status. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-ctrl.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 688ab8d895a974..ea63f83a509bb5 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -217,17 +217,14 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) /* clear stream status */ list_for_each_entry(stream, &bus->stream_list, list) { sd_offset = SOF_STREAM_SD_OFFSET(stream); - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - sd_offset + - SOF_HDA_ADSP_REG_CL_SD_STS, - SOF_HDA_CL_DMA_SD_INT_MASK, - SOF_HDA_CL_DMA_SD_INT_MASK); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, + SOF_HDA_CL_DMA_SD_INT_MASK); } /* clear WAKESTS */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, - SOF_HDA_WAKESTS_INT_MASK, - SOF_HDA_WAKESTS_INT_MASK); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, + SOF_HDA_WAKESTS_INT_MASK); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* clear rirb status */ @@ -295,17 +292,14 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev) /* clear stream status */ list_for_each_entry(stream, &bus->stream_list, list) { sd_offset = SOF_STREAM_SD_OFFSET(stream); - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, - sd_offset + - SOF_HDA_ADSP_REG_CL_SD_STS, - SOF_HDA_CL_DMA_SD_INT_MASK, - SOF_HDA_CL_DMA_SD_INT_MASK); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, + sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, + SOF_HDA_CL_DMA_SD_INT_MASK); } /* clear WAKESTS */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, - SOF_HDA_WAKESTS_INT_MASK, - SOF_HDA_WAKESTS_INT_MASK); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, + SOF_HDA_WAKESTS_INT_MASK); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* clear rirb status */ From c760776089f147c4d28875619f3a917c02d42307 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 17 Apr 2019 12:10:39 +0300 Subject: [PATCH 1536/1995] ASoC: SOF: ignore unrecoverable CTX_SAVE IPC errors at suspend As part of the suspend flow, a context save IPC message is sent to the firmware before powering down the DSP. If errors are met, the suspend flow is aborted with current code. Change the behaviour such that if firmware returns -EBUSY or -EAGAIN, return the error codes to PM core as before. The device is left in active state in this case. If other errors are reported, print a warning but do not block the suspend flow. As per interface specification, no valid error can be returned in this scenario. If the hardware has hit a fatal error and is not able to respond successfully, best recovery method is to proceed with suspend and power off the DSP. Signed-off-by: Kai Vehmanen --- sound/soc/sof/pm.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index a42f9a45d21b0f..8eeb3a1029f24d 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -359,11 +359,20 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) #endif /* notify DSP of upcoming power down */ ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_SAVE); - if (ret < 0) { + if (ret == -EBUSY || ret == -EAGAIN) { + /* + * runtime PM has logic to handle -EBUSY/-EAGAIN so + * pass these errors up + */ dev_err(sdev->dev, "error: ctx_save ipc error during suspend %d\n", ret); return ret; + } else if (ret < 0) { + /* FW in unexpected state, continue to power down */ + dev_warn(sdev->dev, + "ctx_save ipc error %d, proceeding with suspend\n", + ret); } /* power down all DSP cores */ From a2c461c85c31eb3a8de1a972f7add9a3214be997 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 24 May 2019 10:33:30 -0500 Subject: [PATCH 1537/1995] ASoC: Intel: bxt_da7219_max98357a: fix conflict with upstream Patches from Keyon for DMIC16k is not upstream yet. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 2467849e494631..c0d865a940dce4 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -404,6 +404,10 @@ SND_SOC_DAILINK_DEF(ssp1_codec, SND_SOC_DAILINK_DEF(dmic_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); + +SND_SOC_DAILINK_DEF(dmic16k_pin, + DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); + SND_SOC_DAILINK_DEF(dmic_codec, DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); @@ -581,13 +585,10 @@ static struct snd_soc_dai_link broxton_dais[] = { { .name = "dmic16k", .id = 6, - .cpu_dai_name = "DMIC16k Pin", - .codec_name = "dmic-codec", - .codec_dai_name = "dmic-hifi", - .platform_name = "0000:00:1f.3", .be_hw_params_fixup = broxton_dmic_fixup, .dpcm_capture = 1, .no_pcm = 1, + SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform), }, }; From f67be60a6b5ec2512a7b057bde430db70edc5ce8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 29 May 2019 10:48:11 -0500 Subject: [PATCH 1538/1995] ASoC: Intel: bxt_pcm512x: move to modern dailink Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bxt_pcm512x.c | 56 ++++++++++++++-------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/sound/soc/intel/boards/bxt_pcm512x.c b/sound/soc/intel/boards/bxt_pcm512x.c index 848b83729ac55d..2e3e8bee751ce4 100644 --- a/sound/soc/intel/boards/bxt_pcm512x.c +++ b/sound/soc/intel/boards/bxt_pcm512x.c @@ -166,11 +166,29 @@ static const struct snd_soc_ops aif1_ops = { .shutdown = aif1_shutdown, }; -static struct snd_soc_dai_link_component platform_component[] = { - { - .name = "0000:00:0e.0" - } -}; +SND_SOC_DAILINK_DEF(ssp5_pin, + DAILINK_COMP_ARRAY(COMP_CPU("SSP5 Pin"))); + +SND_SOC_DAILINK_DEF(ssp5_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-104C5122:00", "pcm512x-hifi"))); + +SND_SOC_DAILINK_DEF(platform, + DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:0e.0"))); + +SND_SOC_DAILINK_DEF(idisp1_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); +SND_SOC_DAILINK_DEF(idisp1_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); + +SND_SOC_DAILINK_DEF(idisp2_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); +SND_SOC_DAILINK_DEF(idisp2_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); + +SND_SOC_DAILINK_DEF(idisp3_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); +SND_SOC_DAILINK_DEF(idisp3_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); static struct snd_soc_dai_link dailink[] = { /* CODEC<->CODEC link */ @@ -178,12 +196,7 @@ static struct snd_soc_dai_link dailink[] = { { .name = "SSP5-Codec", .id = 0, - .cpu_dai_name = "SSP5 Pin", - .platforms = platform_component, - .num_platforms = ARRAY_SIZE(platform_component), .no_pcm = 1, - .codec_dai_name = "pcm512x-hifi", - .codec_name = "i2c-104C5122:00", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, .init = init, @@ -191,43 +204,32 @@ static struct snd_soc_dai_link dailink[] = { .nonatomic = true, .dpcm_playback = 1, .dpcm_capture = 1, + SND_SOC_DAILINK_REG(ssp5_pin, ssp5_codec, platform), }, #if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) { .name = "iDisp1", .id = 1, - .cpu_dai_name = "iDisp1 Pin", - .codec_name = "ehdaudio0D2", - .codec_dai_name = "intel-hdmi-hifi1", - .platforms = platform_component, - .num_platforms = ARRAY_SIZE(platform_component), .init = broxton_hdmi_init, .dpcm_playback = 1, .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), }, { .name = "iDisp2", .id = 2, - .cpu_dai_name = "iDisp2 Pin", - .codec_name = "ehdaudio0D2", - .codec_dai_name = "intel-hdmi-hifi2", - .platforms = platform_component, - .num_platforms = ARRAY_SIZE(platform_component), .init = broxton_hdmi_init, .dpcm_playback = 1, .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), }, { .name = "iDisp3", .id = 3, - .cpu_dai_name = "iDisp3 Pin", - .codec_name = "ehdaudio0D2", - .codec_dai_name = "intel-hdmi-hifi3", - .platforms = platform_component, - .num_platforms = ARRAY_SIZE(platform_component), .init = broxton_hdmi_init, .dpcm_playback = 1, .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), }, #endif }; @@ -277,7 +279,7 @@ static int bxt_pcm512x_probe(struct platform_device *pdev) /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(dailink); i++) { - if (!strcmp(dailink[i].codec_name, "i2c-104C5122:00")) { + if (!strcmp(dailink[i].codecs->name, "i2c-104C5122:00")) { dai_index = i; break; } @@ -289,7 +291,7 @@ static int bxt_pcm512x_probe(struct platform_device *pdev) snprintf(codec_name, sizeof(codec_name), "%s%s", "i2c-", acpi_dev_name(adev)); put_device(&adev->dev); - dailink[dai_index].codec_name = codec_name; + dailink[dai_index].codecs->name = codec_name; } snd_soc_card_set_drvdata(card, ctx); From f1f5e68eedb2c4354171b45f578a4f100ab26941 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 29 May 2019 10:48:47 -0500 Subject: [PATCH 1539/1995] ASoC: Intel: bxt_wm8804: move to modern dailink Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bxt_wm8804.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sound/soc/intel/boards/bxt_wm8804.c b/sound/soc/intel/boards/bxt_wm8804.c index 0506ab7c43a740..b93fbae5a66004 100644 --- a/sound/soc/intel/boards/bxt_wm8804.c +++ b/sound/soc/intel/boards/bxt_wm8804.c @@ -179,23 +179,29 @@ static struct snd_soc_ops snd_rpi_hifiberry_digi_ops = { .shutdown = snd_rpi_hifiberry_digi_shutdown, }; +SND_SOC_DAILINK_DEF(ssp5_pin, + DAILINK_COMP_ARRAY(COMP_CPU("SSP5 Pin"))); + +SND_SOC_DAILINK_DEF(ssp5_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-1AEC8804:00", "wm8804-spdif"))); + +SND_SOC_DAILINK_DEF(platform, + DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:0e.0"))); + static struct snd_soc_dai_link dailink[] = { /* CODEC<->CODEC link */ /* back ends */ { .name = "SSP5-Codec", .id = 0, - .cpu_dai_name = "SSP5 Pin", - .platform_name = "sof-audio", .no_pcm = 1, - .codec_dai_name = "wm8804-spdif", - .codec_name = "i2c-1AEC8804:00", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM, .nonatomic = true, .dpcm_playback = 1, .ops = &snd_rpi_hifiberry_digi_ops, .init = snd_rpi_hifiberry_digi_init, + SND_SOC_DAILINK_REG(ssp5_pin, ssp5_codec, platform), }, }; @@ -225,7 +231,7 @@ static int bxt_wm8804_probe(struct platform_device *pdev) /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(dailink); i++) { - if (!strcmp(dailink[i].codec_name, "i2c-1AEC8804:00")) { + if (!strcmp(dailink[i].codecs->name, "i2c-1AEC8804:00")) { dai_index = i; break; } @@ -237,7 +243,7 @@ static int bxt_wm8804_probe(struct platform_device *pdev) snprintf(codec_name, sizeof(codec_name), "%s%s", "i2c-", acpi_dev_name(adev)); put_device(&adev->dev); - dailink[dai_index].codec_name = codec_name; + dailink[dai_index].codecs->name = codec_name; } ret_val = devm_snd_soc_register_card(&pdev->dev, card); From a50a20a4464f56ca8402f3298f1d502f7a78183a Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 7 Jun 2019 12:30:12 +0200 Subject: [PATCH 1540/1995] sound: HDA: remove an unused field from struct hda_codec The .jacks field in struct hda_codec is unused and seems to be a duplicate of .jacktbl, remove it. Signed-off-by: Guennadi Liakhovetski --- include/sound/hda_codec.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index cc7c8d42d4fd9a..2a1d1ad44d661a 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -281,9 +281,6 @@ struct hda_codec { unsigned long jackpoll_interval; /* In jiffies. Zero means no poll, rely on unsol events */ struct delayed_work jackpoll_work; - /* jack detection */ - struct snd_array jacks; - int depop_delay; /* depop delay in ms, -1 for default delay time */ /* fix-up list */ From 943a60ecc3124bcf85c79a8ba3b289eb219121d2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 10 Jun 2019 13:15:50 -0500 Subject: [PATCH 1541/1995] ASoC: SOF: ipc: clarify operator precedence Cppcheck complains about the following warning, fix by adding parentheses [sound/soc/sof/ipc.c:783]: (style) Clarify calculation precedence for '&' and '?'. [sound/soc/sof/ipc.c:785]: (style) Clarify calculation precedence for '&' and '?'. [sound/soc/sof/ipc.c:787]: (style) Clarify calculation precedence for '&' and '?'. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/ipc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index f3eb46bc808beb..20dfca9c93b76d 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -780,11 +780,11 @@ int snd_sof_ipc_valid(struct snd_sof_dev *sdev) " lock debug: %s\n" " lock vdebug: %s\n", v->build, v->date, v->time, - ready->flags & SOF_IPC_INFO_GDB ? + (ready->flags & SOF_IPC_INFO_GDB) ? "enabled" : "disabled", - ready->flags & SOF_IPC_INFO_LOCKS ? + (ready->flags & SOF_IPC_INFO_LOCKS) ? "enabled" : "disabled", - ready->flags & SOF_IPC_INFO_LOCKSV ? + (ready->flags & SOF_IPC_INFO_LOCKSV) ? "enabled" : "disabled"); } From 3c78dda583abc7871213e6fcb76537d6dc927563 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Fri, 31 May 2019 11:17:54 +0800 Subject: [PATCH 1542/1995] ASoC: SOF: Intel: hda: make sure DMA is start/stop by read the RUN bit As per the HW recommendation, after setting the RUN bit (start as 1, stop as 0), software must read the bit back to make sure the bit is set right, before modifying related control registers/re-starting the DMA engine. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-stream.c | 22 ++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 6 ++++++ 2 files changed, 28 insertions(+) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index ddfd80b44e6e8c..74f086056cae6d 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -217,6 +217,9 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, { struct hdac_stream *hstream = &stream->hstream; int sd_offset = SOF_STREAM_SD_OFFSET(hstream); + u32 dma_start = SOF_HDA_SD_CTL_DMA_START; + int ret; + u32 run; /* cmd must be for audio stream */ switch (cmd) { @@ -234,6 +237,16 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, SOF_HDA_SD_CTL_DMA_START | SOF_HDA_CL_DMA_SD_INT_MASK); + ret = snd_sof_dsp_read_poll_timeout(sdev, + HDA_DSP_HDA_BAR, + sd_offset, run, + ((run & dma_start) == dma_start), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_STREAM_RUN_TIMEOUT); + + if (ret) + return ret; + hstream->running = true; break; case SNDRV_PCM_TRIGGER_SUSPEND: @@ -244,6 +257,15 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, SOF_HDA_SD_CTL_DMA_START | SOF_HDA_CL_DMA_SD_INT_MASK, 0x0); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_HDA_BAR, + sd_offset, run, + !(run & dma_start), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_STREAM_RUN_TIMEOUT); + + if (ret) + return ret; + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, SOF_HDA_CL_DMA_SD_INT_MASK); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 50653859e0a044..73d7cc08afc225 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -159,6 +159,12 @@ #define HDA_DSP_MBOX_UPLINK_OFFSET 0x81000 #define HDA_DSP_STREAM_RESET_TIMEOUT 300 +/* + * Timeout in us, for setting the stream RUN bit, during + * start/stop the stream. The timeout expires if new RUN bit + * value cannot be read back within the specified time. + */ +#define HDA_DSP_STREAM_RUN_TIMEOUT 300 #define HDA_DSP_CL_TRIGGER_TIMEOUT 300 #define HDA_DSP_SPIB_ENABLE 1 From 3db5c23ab938903e2df52dce6cf406db6ee96f7d Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Fri, 31 May 2019 11:21:03 +0800 Subject: [PATCH 1543/1995] ASoC: SOF: Intel: hda: make sure RUN bit setting to 0 during clear stream status Beforing clearing stream statuses, ensure RUN bit update has taken effect by reading the value back. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-stream.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 74f086056cae6d..0d2815eefd3cdc 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -295,7 +295,9 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_stream *hstream = &stream->hstream; int sd_offset = SOF_STREAM_SD_OFFSET(hstream); int ret, timeout = HDA_DSP_STREAM_RESET_TIMEOUT; + u32 dma_start = SOF_HDA_SD_CTL_DMA_START; u32 val, mask; + u32 run; if (!stream) { dev_err(sdev->dev, "error: no stream available\n"); @@ -316,6 +318,16 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, SOF_HDA_CL_DMA_SD_INT_MASK | SOF_HDA_SD_CTL_DMA_START, 0); + + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_HDA_BAR, + sd_offset, run, + !(run & dma_start), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_STREAM_RUN_TIMEOUT); + + if (ret) + return ret; + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, SOF_HDA_CL_DMA_SD_INT_MASK, @@ -368,6 +380,16 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, SOF_HDA_CL_DMA_SD_INT_MASK | SOF_HDA_SD_CTL_DMA_START, 0); + + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_HDA_BAR, + sd_offset, run, + !(run & dma_start), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_STREAM_RUN_TIMEOUT); + + if (ret) + return ret; + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, SOF_HDA_CL_DMA_SD_INT_MASK, From b57d514e0c81b54f9d4c41f80ca1db651df67de9 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Tue, 4 Jun 2019 09:35:15 +0800 Subject: [PATCH 1544/1995] ASoC: SOF: topology: add min/max step for volume_table add two units min_volume_step and max_volume_step to the snd_sof_control struct, for the min and max step of the volume_table. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/sof-priv.h | 2 ++ sound/soc/sof/topology.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 95be40f9c79dca..e0441861512926 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -303,6 +303,8 @@ struct snd_sof_pcm { struct snd_sof_control { struct snd_sof_dev *sdev; int comp_id; + int min_volume_step; /* min volume step for volume_table */ + int max_volume_step; /* max volume step for volume_table */ int num_channels; u32 readback_offset; /* offset to mmaped data if used */ struct sof_ipc_ctrl_data *control_data; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 9ac43cb86e383e..6ee6f9c077ace4 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -451,6 +451,8 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, return -ENOMEM; scontrol->comp_id = sdev->next_comp_id; + scontrol->min_volume_step = le32_to_cpu(mc->min); + scontrol->max_volume_step = le32_to_cpu(mc->max); scontrol->num_channels = le32_to_cpu(mc->num_channels); /* set cmd for mixer control */ From 24d854a516aae5d4df763713db3b27186781fa52 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Wed, 5 Jun 2019 12:12:57 +0800 Subject: [PATCH 1545/1995] ASoC: SOF: topology: pass volume min/max linear value to FW The driver currently passes the volume ramp type and length topology tokens to firmware, but the min and max volume are not set. This patch provides a correction to convert the information from the topology file and pass the linear volume min/max value to the firmware to improve transitions. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/topology.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 6ee6f9c077ace4..ead1d5055c9e3c 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1552,6 +1552,9 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &tw->priv; struct sof_ipc_comp_volume *volume; + struct snd_sof_control *scontrol; + int min_step; + int max_step; int ret; volume = kzalloc(sizeof(*volume), GFP_KERNEL); @@ -1594,6 +1597,17 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, swidget->private = volume; + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + if (scontrol->comp_id == swidget->comp_id) { + min_step = scontrol->min_volume_step; + max_step = scontrol->max_volume_step; + volume->min_value = scontrol->volume_table[min_step]; + volume->max_value = scontrol->volume_table[max_step]; + volume->channels = scontrol->num_channels; + break; + } + } + ret = sof_ipc_tx_message(sdev->ipc, volume->comp.hdr.cmd, volume, sizeof(*volume), r, sizeof(*r)); if (ret >= 0) From e15cab2e35eea8480fdf6c9885162994f991ddb1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 7 Jun 2019 15:49:35 -0500 Subject: [PATCH 1546/1995] [SQUASH BEFORE UPSTREAM] ASoC: SOF: topology: use modern dailink representation Change link representation. The internal SOF representation will have to change at a later point as well when we have multiple CPU dais. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/topology.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 80dba00c252150..437d1c27a0be5c 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2341,7 +2341,7 @@ static int sof_set_dai_config(struct snd_sof_dev *sdev, u32 size, return -ENOMEM; /* set cpu_dai_name */ - dai->cpu_dai_name = link->cpu_dai_name; + dai->cpu_dai_name = link->cpus->dai_name; found = 1; } @@ -2594,7 +2594,7 @@ static int sof_link_hda_process(struct snd_sof_dev *sdev, if (!sof_dai->dai_config) return -ENOMEM; - sof_dai->cpu_dai_name = link->cpu_dai_name; + sof_dai->cpu_dai_name = link->cpus->dai_name; /* send message to DSP */ ret = sof_ipc_tx_message(sdev->ipc, From d2cf4c496d13962a4999678934e2bc2c2de5c073 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 11 Jun 2019 16:12:50 -0500 Subject: [PATCH 1547/1995] ASoC: soc-topology: fix modern dai link style The topology code can create a FE DAI link but did not allocate the memory for a platform component - whose name can be overridden at a later time. Fixes: 23b946ce2808b ("ASoC: soc-topology: use modern dai_link style") Signed-off-by: Pierre-Louis Bossart --- sound/soc/soc-topology.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index f485f7f751a1dd..b538412e4bcff3 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1882,8 +1882,8 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, struct snd_soc_dai_link_component *dlc; int ret; - /* link + cpu + codec */ - link = kzalloc(sizeof(*link) + (2 * sizeof(*dlc)), GFP_KERNEL); + /* link + cpu + codec + platform */ + link = kzalloc(sizeof(*link) + (3 * sizeof(*dlc)), GFP_KERNEL); if (link == NULL) return -ENOMEM; @@ -1891,9 +1891,11 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, link->cpus = &dlc[0]; link->codecs = &dlc[1]; + link->platforms = &dlc[2]; link->num_cpus = 1; link->num_codecs = 1; + link->num_platforms = 1; if (strlen(pcm->pcm_name)) { link->name = kstrdup(pcm->pcm_name, GFP_KERNEL); @@ -1907,6 +1909,8 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, link->codecs->name = "snd-soc-dummy"; link->codecs->dai_name = "snd-soc-dummy-dai"; + link->platforms->name = "snd-soc-dummy"; + /* enable DPCM */ link->dynamic = 1; link->dpcm_playback = le32_to_cpu(pcm->playback); From 38d0e9fc227c7876d09754863adc88aeca6dd205 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 4 Jun 2019 13:57:16 +0800 Subject: [PATCH 1548/1995] ASoC: SOF: dont wake dsp up in kcontrol IO Always get kcontrol value from cache, set kcontrol value to DSP when DSP is active. Kcontrol values will be restored when DSP boot up. We will set the default value of kcontrol in sof_complete to make sure the value is align with firmware. Signed-off-by: Bard Liao --- sound/soc/sof/control.c | 270 ++++++--------------------------------- sound/soc/sof/topology.c | 48 +++++++ 2 files changed, 86 insertions(+), 232 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 84e2cbfbbcbb3c..a4983f90ff5b31 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -39,26 +39,8 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int err, ret; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: volume get failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - - /* get all the mixer data from DSP */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_GET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_VOLUME, - false); /* read back each channel */ for (i = 0; i < channels; i++) @@ -66,12 +48,6 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, ipc_to_mixer(cdata->chanv[i].value, scontrol->volume_table, sm->max + 1); - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: volume get failed to idle %d\n", - err); return 0; } @@ -84,16 +60,6 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int ret, err; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: volume put failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } /* update each channel */ for (i = 0; i < channels; i++) { @@ -104,18 +70,13 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, } /* notify DSP of mixer updates */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_VOLUME, - true); - - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: volume put failed to idle %d\n", - err); + if (pm_runtime_active(sdev->dev)) + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_VOLUME, + true); + return 0; } @@ -125,37 +86,13 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol, struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int err, ret; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: switch get failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - - /* get all the mixer data from DSP */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_GET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_SWITCH, - false); /* read back each channel */ for (i = 0; i < channels; i++) ucontrol->value.integer.value[i] = cdata->chanv[i].value; - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: switch get failed to idle %d\n", - err); return 0; } @@ -168,16 +105,6 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int ret, err; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: switch put failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } /* update each channel */ for (i = 0; i < channels; i++) { @@ -186,18 +113,13 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, } /* notify DSP of mixer updates */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_SWITCH, - true); - - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: switch put failed to idle %d\n", - err); + if (pm_runtime_active(sdev->dev)) + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_SWITCH, + true); + return 0; } @@ -207,37 +129,13 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, struct soc_enum *se = (struct soc_enum *)kcontrol->private_value; struct snd_sof_control *scontrol = se->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int err, ret; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: enum get failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - - /* get all the enum data from DSP */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_GET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_ENUM, - false); /* read back each channel */ for (i = 0; i < channels; i++) ucontrol->value.enumerated.item[i] = cdata->chanv[i].value; - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: enum get failed to idle %d\n", - err); return 0; } @@ -250,16 +148,6 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; - int ret, err; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: enum put failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } /* update each channel */ for (i = 0; i < channels; i++) { @@ -268,18 +156,13 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, } /* notify DSP of enum updates */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_SET_VALUE, - SOF_CTRL_TYPE_VALUE_CHAN_GET, - SOF_CTRL_CMD_ENUM, - true); - - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: enum put failed to idle %d\n", - err); + if (pm_runtime_active(sdev->dev)) + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_VALUE, + SOF_CTRL_TYPE_VALUE_CHAN_GET, + SOF_CTRL_CMD_ENUM, + true); + return 0; } @@ -293,7 +176,7 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_abi_hdr *data = cdata->data; size_t size; - int ret, err; + int ret = 0; if (be->max > sizeof(ucontrol->value.bytes.data)) { dev_err_ratelimited(sdev->dev, @@ -302,22 +185,6 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, return -EINVAL; } - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: bytes get failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - - /* get all the binary data from DSP */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_GET_DATA, - SOF_CTRL_TYPE_DATA_GET, - scontrol->cmd, - false); - size = data->size + sizeof(*data); if (size > be->max) { dev_err_ratelimited(sdev->dev, @@ -331,12 +198,6 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, memcpy(ucontrol->value.bytes.data, data, size); out: - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: bytes get failed to idle %d\n", - err); return ret; } @@ -350,7 +211,6 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_abi_hdr *data = cdata->data; size_t size = data->size + sizeof(*data); - int ret, err; if (be->max > sizeof(ucontrol->value.bytes.data)) { dev_err_ratelimited(sdev->dev, @@ -366,32 +226,18 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, return -EINVAL; } - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: bytes put failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - /* copy from kcontrol */ memcpy(data, ucontrol->value.bytes.data, size); /* notify DSP of byte control updates */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_SET_DATA, - SOF_CTRL_TYPE_DATA_SET, - scontrol->cmd, - true); - - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: bytes put failed to idle %d\n", - err); - return ret; + if (pm_runtime_active(sdev->dev)) + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_DATA, + SOF_CTRL_TYPE_DATA_SET, + scontrol->cmd, + true); + + return 0; } int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, @@ -406,8 +252,6 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, struct snd_ctl_tlv header; const struct snd_ctl_tlv __user *tlvd = (const struct snd_ctl_tlv __user *)binary_data; - int ret; - int err; /* * The beginning of bytes data contains a header from where @@ -453,30 +297,15 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, return -EINVAL; } - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: bytes_ext put failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } - /* notify DSP of byte control updates */ - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_SET_DATA, - SOF_CTRL_TYPE_DATA_SET, - scontrol->cmd, - true); - - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: bytes_ext put failed to idle %d\n", - err); + if (pm_runtime_active(sdev->dev)) + snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + SOF_IPC_COMP_SET_DATA, + SOF_CTRL_TYPE_DATA_SET, + scontrol->cmd, + true); - return ret; + return 0; } int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, @@ -492,17 +321,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data; int data_size; - int err; - int ret; - - ret = pm_runtime_get_sync(sdev->dev); - if (ret < 0) { - dev_err_ratelimited(sdev->dev, - "error: bytes_ext get failed to resume %d\n", - ret); - pm_runtime_put_noidle(sdev->dev); - return ret; - } + int ret = 0; /* * Decrement the limit by ext bytes header size to @@ -514,13 +333,6 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, cdata->data->magic = SOF_ABI_MAGIC; cdata->data->abi = SOF_ABI_VERSION; - /* get all the component data from DSP */ - ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - SOF_IPC_COMP_GET_DATA, - SOF_CTRL_TYPE_DATA_GET, - scontrol->cmd, - false); - /* Prevent read of other kernel data or possibly corrupt response */ data_size = cdata->data->size + sizeof(const struct sof_abi_hdr); @@ -543,11 +355,5 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, ret = -EFAULT; out: - pm_runtime_mark_last_busy(sdev->dev); - err = pm_runtime_put_autosuspend(sdev->dev); - if (err < 0) - dev_err_ratelimited(sdev->dev, - "error: bytes_ext get failed to idle %d\n", - err); return ret; } diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index ead1d5055c9e3c..8b531bd2c7298d 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2976,6 +2976,49 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, return ret; } +/* Function to set the initial value of SOF kcontrols. + * The value will be stored in scontrol->control_data + */ +static int snd_sof_cache_kcontrol_val(struct snd_sof_dev *sdev) +{ + struct snd_sof_control *scontrol = NULL; + int ipc_cmd, ctrl_type; + int ret = 0; + + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + + /* notify DSP of kcontrol values */ + switch (scontrol->cmd) { + case SOF_CTRL_CMD_VOLUME: + case SOF_CTRL_CMD_ENUM: + case SOF_CTRL_CMD_SWITCH: + ipc_cmd = SOF_IPC_COMP_GET_VALUE; + ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_GET; + break; + case SOF_CTRL_CMD_BINARY: + ipc_cmd = SOF_IPC_COMP_GET_DATA; + ctrl_type = SOF_CTRL_TYPE_DATA_GET; + break; + default: + dev_err(sdev->dev, + "error: Invalid scontrol->cmd: %d\n", + scontrol->cmd); + return -EINVAL; + } + ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + ipc_cmd, ctrl_type, + scontrol->cmd, + false); + if (ret < 0) { + dev_warn(sdev->dev, + "error: kcontrol value get for widget: %d\n", + scontrol->comp_id); + } + } + + return ret; +} + int snd_sof_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget) { @@ -3019,6 +3062,11 @@ static void sof_complete(struct snd_soc_component *scomp) break; } } + /* + * cache initial values of SOF kcontrols by reading DSP value over + * IPC. It may be overwritten by alsa-mixer after booting up + */ + snd_sof_cache_kcontrol_val(sdev); } /* manifest - optional to inform component of manifest */ From a330b98772694db320eaa8aef17021cdf2829d9a Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 11 Jun 2019 09:53:08 +0800 Subject: [PATCH 1549/1995] ASoC: SOF: Intel: hda: reduce ifdef usage for hda Move the code for hda to one point Signed-off-by: Rander Wang --- sound/soc/sof/intel/hda-dsp.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index f2c5a12db930a4..481cfa0b225e3b 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -359,6 +359,16 @@ static int hda_resume(struct snd_sof_dev *sdev) bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); hda_dsp_ctrl_misc_clock_gating(sdev, true); + + /* turn off the links that were off before suspend */ + list_for_each_entry(hlink, &bus->hlink_list, list) { + if (!hlink->ref_count) + snd_hdac_ext_bus_link_power_down(hlink); + } + + /* check dma status and clean up CORB/RIRB buffers */ + if (!bus->cmd_dma_state) + snd_hdac_bus_stop_cmd_io(bus); #else hda_dsp_ctrl_misc_clock_gating(sdev, false); @@ -391,18 +401,6 @@ static int hda_resume(struct snd_sof_dev *sdev) hda_dsp_ctrl_ppcap_enable(sdev, true); hda_dsp_ctrl_ppcap_int_enable(sdev, true); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* turn off the links that were off before suspend */ - list_for_each_entry(hlink, &bus->hlink_list, list) { - if (!hlink->ref_count) - snd_hdac_ext_bus_link_power_down(hlink); - } - - /* check dma status and clean up CORB/RIRB buffers */ - if (!bus->cmd_dma_state) - snd_hdac_bus_stop_cmd_io(bus); -#endif - return 0; } From 7e43c6c0bfb838129627f2897f3cd7ffe5231276 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 27 May 2019 16:50:22 +0800 Subject: [PATCH 1550/1995] ASoC: SOF: Intel: hda: Enable jack detection in sof hda driver In commit 7d4f606c50ff ("ALSA: hda - WAKEEN feature enabling for runtime pm"), legacy HD-A driver sets hda controller in reset mode after entering runtime-suspend. And when resuming from suspend mode, it checks hda controller & codec status to detect headphone hotplug event. Now this patch does the same job in SOF runtime pm functions. And we need to check all the non-hdmi codecs for some cases like playback with HDMI or capture with DMIC connected to dsp. In these cases, only controller is active and codecs are suspended, so codecs can't send unsolicited event to controller. The jack polling operation will activate codecs and unsolicited event can work even codecs become suspended later. Tested on whiskylake with hda codecs. Signed-off-by: Rander Wang --- sound/soc/sof/intel/hda-codec.c | 45 +++++++++++++++++++++++++++++++-- sound/soc/sof/intel/hda-dsp.c | 29 ++++++++++++++++----- sound/soc/sof/intel/hda.h | 4 +++ 3 files changed, 70 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 0d8437b080bfa5..5882f1bfd906ca 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -37,16 +38,55 @@ static void hda_codec_load_module(struct hda_codec *codec) static void hda_codec_load_module(struct hda_codec *codec) {} #endif +/* check jack status after resuming from suspend mode */ +void hda_codec_jack_check(struct snd_sof_dev *sdev, int status) +{ + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; + struct hda_bus *hbus = sof_to_hbus(sdev); + struct hdac_bus *bus = sof_to_bus(sdev); + struct hda_codec *codec; + int mask; + + /* + * there are two reasons for runtime resume + * (1) waken up by interrupt triggered by WAKEEN feature + * (2) waken up by pm get functions for some audio operations + * For case (1), the bits in status mean which codec triggers + * the interrupt and jacks will be checked on these codecs. + * For case (2), we need to check all the non-hdmi codecs for some + * cases like playback with HDMI or capture with DMIC. In these + * cases, only controller is active and codecs are suspended, so + * codecs can't send unsolicited event to controller. The jack polling + * operation will activate codecs and unsolicited event can work + * even codecs become suspended later. + */ + mask = status ? status : hda->hda_codec_mask; + + list_for_each_codec(codec, hbus) + if (mask & BIT(codec->core.addr)) + schedule_delayed_work(&codec->jackpoll_work, + codec->jackpoll_interval); + + /* disable controller Wake Up event*/ + snd_hdac_chip_writew(bus, WAKEEN, + snd_hdac_chip_readw(bus, WAKEEN) & + ~hda->hda_codec_mask); +} +#else +void hda_codec_jack_check(struct snd_sof_dev *sdev, int status) {} #endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ +EXPORT_SYMBOL(hda_codec_jack_check); /* probe individual codec */ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) { - struct hda_bus *hbus = sof_to_hbus(sdev); - struct hdac_device *hdev; #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct hdac_hda_priv *hda_priv; #endif + struct hda_bus *hbus = sof_to_hbus(sdev); + struct hdac_device *hdev; + u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) | (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; u32 resp = -1; @@ -76,6 +116,7 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) /* use legacy bus only for HDA codecs, idisp uses ext bus */ if ((resp & 0xFFFF0000) != IDISP_VID_INTEL) { hdev->type = HDA_DEV_LEGACY; + hda->hda_codec_mask |= BIT(address); hda_codec_load_module(&hda_priv->codec); } diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 481cfa0b225e3b..f8ed8a4a60b789 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -282,7 +282,8 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0); } -static int hda_suspend(struct snd_sof_dev *sdev, int state) +static int hda_suspend(struct snd_sof_dev *sdev, int state, + bool runtime_suspend) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; @@ -295,6 +296,12 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state) hda_dsp_ipc_int_disable(sdev); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + if (IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) && runtime_suspend) + /* enable controller wake up event */ + snd_hdac_chip_writew(bus, WAKEEN, + snd_hdac_chip_readw(bus, WAKEEN) | + hda->hda_codec_mask); + /* power down all hda link */ snd_hdac_ext_bus_link_power_down_all(bus); #endif @@ -329,11 +336,12 @@ static int hda_suspend(struct snd_sof_dev *sdev, int state) return 0; } -static int hda_resume(struct snd_sof_dev *sdev) +static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) { #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_ext_link *hlink = NULL; + int status; #endif int ret; @@ -344,6 +352,11 @@ static int hda_resume(struct snd_sof_dev *sdev) snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + if (runtime_resume) { + /* read STATESTS before controller reset */ + status = snd_hdac_chip_readw(bus, STATESTS); + } + /* reset and start hda controller */ ret = hda_dsp_ctrl_init_chip(sdev, true); if (ret < 0) { @@ -360,6 +373,10 @@ static int hda_resume(struct snd_sof_dev *sdev) hda_dsp_ctrl_misc_clock_gating(sdev, true); + /* check jack status based on controller status */ + if (runtime_resume) + hda_codec_jack_check(sdev, status); + /* turn off the links that were off before suspend */ list_for_each_entry(hlink, &bus->hlink_list, list) { if (!hlink->ref_count) @@ -407,19 +424,19 @@ static int hda_resume(struct snd_sof_dev *sdev) int hda_dsp_resume(struct snd_sof_dev *sdev) { /* init hda controller. DSP cores will be powered up during fw boot */ - return hda_resume(sdev); + return hda_resume(sdev, false); } int hda_dsp_runtime_resume(struct snd_sof_dev *sdev) { /* init hda controller. DSP cores will be powered up during fw boot */ - return hda_resume(sdev); + return hda_resume(sdev, true); } int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state) { /* stop hda controller and power dsp off */ - return hda_suspend(sdev, state); + return hda_suspend(sdev, state, true); } int hda_dsp_suspend(struct snd_sof_dev *sdev, int state) @@ -428,7 +445,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, int state) int ret; /* stop hda controller and power dsp off */ - ret = hda_suspend(sdev, state); + ret = hda_suspend(sdev, state, false); if (ret < 0) { dev_err(bus->dev, "error: suspending dsp\n"); return ret; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 73d7cc08afc225..dd476d3a745d1e 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -398,6 +398,9 @@ struct sof_intel_hda_dev { /* DMIC device */ struct platform_device *dmic_dev; + + /* hda codec mask excluding hdmi */ + u32 hda_codec_mask; }; static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s) @@ -556,6 +559,7 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, * HDA Codec operations. */ int hda_codec_probe_bus(struct snd_sof_dev *sdev); +void hda_codec_jack_check(struct snd_sof_dev *sdev, int status); #endif /* CONFIG_SND_SOC_SOF_HDA */ From dec1616a8441ae8408831a56817352a7f63d9650 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 5 Jun 2019 22:08:05 -0700 Subject: [PATCH 1551/1995] ASoC: SOF: Intel: hda: modify stream interrupt handler Modify the stream interrupt handler to always wake up the IRQ thread if the status register is valid. The IRQ thread performs the check for stream interrupts and RIRB interrupts in a loop to handle the case of missed interrupts when an unsolicited response from the codec is received just before the stream interrupt handler is completed. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-stream.c | 77 ++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 28 deletions(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 0d2815eefd3cdc..196f89d5cbee18 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -505,57 +505,40 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) { struct hdac_bus *bus = context; - struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); - u32 stream_mask; + int ret = IRQ_WAKE_THREAD; u32 status; - if (!pm_runtime_active(bus->dev)) - return IRQ_NONE; - spin_lock(&bus->reg_lock); status = snd_hdac_chip_readl(bus, INTSTS); - stream_mask = GENMASK(sof_hda->stream_max - 1, 0) | AZX_INT_CTRL_EN; - - /* Not stream interrupt or register inaccessible, ignore it.*/ - if (!(status & stream_mask) || status == 0xffffffff) { - spin_unlock(&bus->reg_lock); - return IRQ_NONE; - } + dev_vdbg(bus->dev, "stream irq, INTSTS status: 0x%x\n", status); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* clear rirb int */ - status = snd_hdac_chip_readb(bus, RIRBSTS); - if (status & RIRB_INT_MASK) { - if (status & RIRB_INT_RESPONSE) - snd_hdac_bus_update_rirb(bus); - snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); - } -#endif + /* Register inaccessible, ignore it.*/ + if (status == 0xffffffff) + ret = IRQ_NONE; spin_unlock(&bus->reg_lock); - return snd_hdac_chip_readl(bus, INTSTS) ? IRQ_WAKE_THREAD : IRQ_HANDLED; + return ret; } -irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) +static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status) { - struct hdac_bus *bus = context; struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus); - u32 status = snd_hdac_chip_readl(bus, INTSTS); struct hdac_stream *s; + bool active = false; u32 sd_status; - /* check streams */ list_for_each_entry(s, &bus->stream_list, list) { - if (status & (1 << s->index) && s->opened) { + if (status & BIT(s->index) && s->opened) { sd_status = snd_hdac_stream_readb(s, SD_STS); dev_vdbg(bus->dev, "stream %d status 0x%x\n", s->index, sd_status); - snd_hdac_stream_writeb(s, SD_STS, SD_INT_MASK); + snd_hdac_stream_writeb(s, SD_STS, sd_status); + active = true; if (!s->substream || !s->running || (sd_status & SOF_HDA_CL_DMA_SD_INT_COMPLETE) == 0) @@ -564,8 +547,46 @@ irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) /* Inform ALSA only in case not do that with IPC */ if (sof_hda->no_ipc_position) snd_sof_pcm_period_elapsed(s->substream); + } + } + + return active; +} +irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) +{ + struct hdac_bus *bus = context; + u32 rirb_status; + bool active; + u32 status; + int i; + + /* + * Loop 10 times to handle missed interrupts caused by + * unsolicited responses from the codec + */ + for (i = 0, active = true; i < 10 && active; i++) { + spin_lock_irq(&bus->reg_lock); + + status = snd_hdac_chip_readl(bus, INTSTS); + + /* check streams */ + active = hda_dsp_stream_check(bus, status); + + /* check and clear RIRB interrupt */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + if (status & AZX_INT_CTRL_EN) { + rirb_status = snd_hdac_chip_readb(bus, RIRBSTS); + if (rirb_status & RIRB_INT_MASK) { + active = true; + if (rirb_status & RIRB_INT_RESPONSE) + snd_hdac_bus_update_rirb(bus); + snd_hdac_chip_writeb(bus, RIRBSTS, + RIRB_INT_MASK); + } } +#endif + spin_unlock_irq(&bus->reg_lock); } return IRQ_HANDLED; From dd9faeff45bfd4ab61af24ae43755c20fbb28a3e Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Wed, 29 May 2019 18:23:48 +0300 Subject: [PATCH 1552/1995] ASoC: SOF: Add DMIC token for unmute gain ramp time The settling time of DMIC DC level is both platform and used microphone model specific. The unmute gain ramp is used to conceal most of the large DC level seen in beginning of capture. This patch adds into the DMIC DAI IPC struct a new field called unmute_ramp_time and a new token SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME. The value is the ramp length in milliseconds (ms). The ABI minor version is incremented for this backwards compatible change. Signed-off-by: Seppo Ingalsuo --- include/sound/sof/dai-intel.h | 3 ++- include/uapi/sound/sof/abi.h | 2 +- include/uapi/sound/sof/tokens.h | 1 + sound/soc/sof/topology.c | 4 ++++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h index 4bd83f7adddf65..4bb8ee138ba7f2 100644 --- a/include/sound/sof/dai-intel.h +++ b/include/sound/sof/dai-intel.h @@ -167,9 +167,10 @@ struct sof_ipc_dai_dmic_params { uint32_t wake_up_time; /**< Time from clock start to data (us) */ uint32_t min_clock_on_time; /**< Min. time that clk is kept on (us) */ + uint32_t unmute_ramp_time; /**< Length of logarithmic gain ramp (ms) */ /* reserved for future use */ - uint32_t reserved[6]; + uint32_t reserved[5]; /**< variable number of pdm controller config */ struct sof_ipc_dai_dmic_pdm_ctrl pdm[0]; diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index 92eee681bc6286..4a9c24434f4259 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 7 +#define SOF_ABI_MINOR 8 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 53ea94bf1c08d3..dc1b27daaac622 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -85,6 +85,7 @@ #define SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE 605 #define SOF_TKN_INTEL_DMIC_SAMPLE_RATE 608 #define SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH 609 +#define SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME_MS 610 /* DMIC PDM */ #define SOF_TKN_INTEL_DMIC_PDM_CTRL_ID 700 diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 8b531bd2c7298d..c9053ded8c5f50 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -779,6 +779,10 @@ static const struct sof_topology_token dmic_tokens[] = { {SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, offsetof(struct sof_ipc_dai_dmic_params, fifo_bits), 0}, + {SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME_MS, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_dai_dmic_params, unmute_ramp_time), 0}, + }; /* From 5458391efd839356bc9707b47c6e0b9c90d4a594 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 12 Jun 2019 15:02:20 +0300 Subject: [PATCH 1553/1995] ASoC: SOF: Intel: fix warning for unused variable in non-HDA builds Fix unused variables when CONFIG_SND_SOC_SOF_HDA is not defined. Signed-off-by: Kai Vehmanen --- sound/soc/sof/intel/hda-stream.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 196f89d5cbee18..ad8d41f22e92dd 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -556,7 +556,9 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status) irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) { struct hdac_bus *bus = context; +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) u32 rirb_status; +#endif bool active; u32 status; int i; From 06dc9f8ccee90b03bde99d2b001ac0ce5ba2c97e Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 11 Jun 2019 17:38:19 +0300 Subject: [PATCH 1554/1995] ASoC: codec: hdac_hdmi: fix pin connections at cvt enable In display codecs supported by hdac_hdmi, the connection indices are shared by all converters. At boot and resume from suspend, the connection state may be reset to default values. In case of multiple connected pins (multiple monitors connected with audio capability), routing and mute status of pins that are not connected to any PCM, may interfere with other pins. E.g. after resume from S3 with multiple monitors, unless all converters are in active use, playback to some PCMs may be muted due to the default settings of unrelated converters. Avoid this by ensuring all pin:cvt selections are correct in codec whenever a converter is enabled for playback. Signed-off-by: Kai Vehmanen --- sound/soc/codecs/hdac_hdmi.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 660e0587f39993..7eba57157bb948 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -546,6 +546,29 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt( return NULL; } +/* + * Go through all converters and ensure connection is set to + * the correct pin as set via kcontrols. + */ +static void hdac_hdmi_verify_connect_sel_all_pins(struct hdac_device *hdev) +{ + struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); + struct hdac_hdmi_port *port; + struct hdac_hdmi_cvt *cvt; + int cvt_idx = 0; + + list_for_each_entry(cvt, &hdmi->cvt_list, head) { + port = hdac_hdmi_get_port_from_cvt(hdev, hdmi, cvt); + if (port && port->pin) { + snd_hdac_codec_write(hdev, port->pin->nid, 0, + AC_VERB_SET_CONNECT_SEL, cvt_idx); + dev_dbg(&hdev->dev, "%s: %s set connect %d -> %d\n", + __func__, cvt->name, port->pin->nid, cvt_idx); + } + ++cvt_idx; + } +} + /* * This tries to get a valid pin and set the HW constraints based on the * ELD. Even if a valid pin is not found return success so that device open @@ -806,6 +829,14 @@ static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w, AC_VERB_SET_CHANNEL_STREAMID, pcm->stream_tag); snd_hdac_codec_write(hdev, cvt->nid, 0, AC_VERB_SET_STREAM_FORMAT, pcm->format); + + /* + * The connection indices are shared by all converters and + * may interfere with each other. Ensure correct + * routing for all converters at stream start. + */ + hdac_hdmi_verify_connect_sel_all_pins(hdev); + break; case SND_SOC_DAPM_POST_PMD: From ab5d97b897e0e7fff938c9bb3e09bcf3773215e2 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Tue, 18 Jun 2019 01:36:59 +0800 Subject: [PATCH 1555/1995] ASoC: sof: mark last_busy value at runtime PM init If last_busy value is not set at runtime PM enable, the device will be suspend immediately after usage counter is 0. Set the last_busy value to make sure delay is working at first boot up. Signed-off-by: Pan Xiuli --- sound/soc/sof/sof-pci-dev.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index ffe485f4ba717e..3e3ee9c9aefd52 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -232,6 +232,9 @@ static void sof_pci_probe_complete(struct device *dev) */ pm_runtime_allow(dev); + /* mark last_busy for pm_runtime to make sure not suspend immediately */ + pm_runtime_mark_last_busy(dev); + /* follow recommendation in pci-driver.c to decrement usage counter */ pm_runtime_put_noidle(dev); } From 0cd05559757acd14175f697aab20223b1834e5ac Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Thu, 13 Jun 2019 17:52:03 +0800 Subject: [PATCH 1556/1995] ASoC: Intel: sof-rt5682: correct naming for dmic16k Change the link name to be "dmic16k", the cpu_dai_name to be "DMIC16k Pin", to be aligned with other machine drivers. Signed-off-by: Keyon Jie --- sound/soc/intel/boards/sof_rt5682.c | 37 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index e2e5f97d99204c..64671e934f3a80 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -327,7 +327,7 @@ static struct snd_soc_dai_link_component max98357a_component[] = { static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, int ssp_codec, int ssp_amp, - int dmic_num, + int dmic_be_num, int hdmi_num) { struct snd_soc_dai_link_component *idisp_components; @@ -387,20 +387,23 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, id++; /* dmic */ - for (i = 1; i <= dmic_num; i++) { - links[id].name = devm_kasprintf(dev, GFP_KERNEL, - "dmic%02d", i); - if (!links[id].name) - goto devm_err; + if (dmic_be_num > 0) { + /* at least we have dmic01 */ + links[id].name = "dmic01"; + links[id].cpus = &cpus[id]; + links[id].cpus->dai_name = "DMIC01 Pin"; + if (dmic_be_num > 1) { + /* set up 2 BE links at most */ + links[id + 1].name = "dmic16k"; + links[id + 1].cpus = &cpus[id + 1]; + links[id + 1].cpus->dai_name = "DMIC16k Pin"; + dmic_be_num = 2; + } + } + for (i = 0; i < dmic_be_num; i++) { links[id].id = id; - links[id].cpus = &cpus[id]; links[id].num_cpus = 1; - links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, - "DMIC%02d Pin", i); - if (!links[id].cpus->dai_name) - goto devm_err; - links[id].codecs = dmic_component; links[id].num_codecs = ARRAY_SIZE(dmic_component); links[id].platforms = platform_component; @@ -495,7 +498,7 @@ static int sof_audio_probe(struct platform_device *pdev) struct snd_soc_dai_link *dai_links; struct snd_soc_acpi_mach *mach; struct sof_card_private *ctx; - int dmic_num, hdmi_num; + int dmic_be_num, hdmi_num; int ret, ssp_amp, ssp_codec; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); @@ -504,12 +507,12 @@ static int sof_audio_probe(struct platform_device *pdev) if (soc_intel_is_byt() || soc_intel_is_cht()) { is_legacy_cpu = 1; - dmic_num = 0; + dmic_be_num = 0; hdmi_num = 0; /* default quirk for legacy cpu */ sof_rt5682_quirk = SOF_RT5682_SSP_CODEC(2); } else { - dmic_num = 1; + dmic_be_num = 2; hdmi_num = 3; } @@ -523,13 +526,13 @@ static int sof_audio_probe(struct platform_device *pdev) ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK; /* compute number of dai links */ - sof_audio_card_rt5682.num_links = 1 + dmic_num + hdmi_num; + sof_audio_card_rt5682.num_links = 1 + dmic_be_num + hdmi_num; if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) sof_audio_card_rt5682.num_links++; dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp, - dmic_num, hdmi_num); + dmic_be_num, hdmi_num); if (!dai_links) return -ENOMEM; From 26c2aa758338ae273c60b9db620916f96c083b25 Mon Sep 17 00:00:00 2001 From: Xun Zhang Date: Mon, 17 Jun 2019 13:49:26 +0800 Subject: [PATCH 1557/1995] ASoC: Intel: sof-rt5682: add MCLK support for BYT platform The sof-rt5682 machine driver currently uses BCLK on BYT/Minnowboard platform. The MCLK signal is available since the Turbot revision, so enable MCLK on BYT/Minnowboard Turbot platform. Signed-off-by: Xun Zhang --- sound/soc/intel/boards/sof_rt5682.c | 65 ++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 64671e934f3a80..64db00353e187a 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6)) #define SOF_RT5682_SSP_AMP(quirk) \ (((quirk) << SOF_RT5682_SSP_AMP_SHIFT) & SOF_RT5682_SSP_AMP_MASK) +#define SOF_RT5682_MCLK_BYTCHT_EN BIT(9) /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | @@ -48,6 +50,7 @@ struct sof_hdmi_pcm { }; struct sof_card_private { + struct clk *mclk; struct snd_soc_jack sof_headset; struct list_head hdmi_pcm_list; }; @@ -59,6 +62,22 @@ static int sof_rt5682_quirk_cb(const struct dmi_system_id *id) } static const struct dmi_system_id sof_rt5682_quirk_table[] = { + { + .callback = sof_rt5682_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), + DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max"), + }, + .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)), + }, + { + .callback = sof_rt5682_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), + DMI_MATCH(DMI_PRODUCT_NAME, "UP-CHT01"), + }, + .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)), + }, { .callback = sof_rt5682_quirk_cb, .matches = { @@ -127,6 +146,27 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) RT5682_CLK_SEL_I2S1_ASRC); } + if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { + /* + * The firmware might enable the clock at + * boot (this information may or may not + * be reflected in the enable clock register). + * To change the rate we must disable the clock + * first to cover these cases. Due to common + * clock framework restrictions that do not allow + * to disable a clock that has not been enabled, + * we need to enable the clock first. + */ + ret = clk_prepare_enable(ctx->mclk); + if (!ret) + clk_disable_unprepare(ctx->mclk); + + ret = clk_set_rate(ctx->mclk, 19200000); + + if (ret) + dev_err(rtd->dev, "unable to set MCLK rate\n"); + } + /* * Headset buttons map to the google Reference headset. * These can be configured by userspace. @@ -161,10 +201,20 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *codec_dai = rtd->codec_dai; int clk_id, clk_freq, pll_out, ret; if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) { + if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { + ret = clk_prepare_enable(ctx->mclk); + if (ret < 0) { + dev_err(rtd->dev, + "could not configure MCLK state"); + return ret; + } + } + clk_id = RT5682_PLL1_S_MCLK; if (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ) clk_freq = 24000000; @@ -510,7 +560,9 @@ static int sof_audio_probe(struct platform_device *pdev) dmic_be_num = 0; hdmi_num = 0; /* default quirk for legacy cpu */ - sof_rt5682_quirk = SOF_RT5682_SSP_CODEC(2); + sof_rt5682_quirk = SOF_RT5682_MCLK_EN | + SOF_RT5682_MCLK_BYTCHT_EN | + SOF_RT5682_SSP_CODEC(2); } else { dmic_be_num = 2; hdmi_num = 3; @@ -518,6 +570,17 @@ static int sof_audio_probe(struct platform_device *pdev) dmi_check_system(sof_rt5682_quirk_table); + /* need to get main clock from pmc */ + if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { + ctx->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + ret = clk_prepare_enable(ctx->mclk); + if (ret < 0) { + dev_err(&pdev->dev, + "could not configure MCLK state"); + return ret; + } + } + dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk); ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >> From 08d3631c44da53bc101b299c7fd849f3dfee3ca1 Mon Sep 17 00:00:00 2001 From: Xun Zhang Date: Tue, 18 Jun 2019 15:17:18 +0800 Subject: [PATCH 1558/1995] ASoC: Intel: sof-rt5682: fix kernel memory allocation flag In "sof_audio_probe", we should use GFP_KERNEL instead of GFP_ATOMIC for memory allocation because the device can sleep. Signed-off-by: Xun Zhang --- sound/soc/intel/boards/sof_rt5682.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 64db00353e187a..daeaa396d92817 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -551,7 +551,7 @@ static int sof_audio_probe(struct platform_device *pdev) int dmic_be_num, hdmi_num; int ret, ssp_amp, ssp_codec; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; From 0087d4afe31bad40a0f365b774547fd69124d58c Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Tue, 18 Jun 2019 19:34:14 +0800 Subject: [PATCH 1559/1995] [DEBUG][CI]travis: add coccinelle check for SOF Add coccinelle check for SOF part code in Travis CI. Build coccinelle 1.0.7 from source in Travis CI. Update make command forom SUBDIRS to M. Signed-off-by: Pan Xiuli --- .travis.yml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3ad3d6b9a18ddc..d226c5e6e38d14 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,8 @@ language: c +dist: xenial git: - depth: false + depth: 20 before_install: - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test @@ -18,20 +19,26 @@ jobs: - SHA_PR=`git log --oneline -1 | sed -rn "s/.*Merge (.*) into.*/\1/p"` - SHA_MAIN=`git log --oneline -1 | sed -rn "s/.*Merge .* into (.*)/\1/p"` - scripts/checkpatch.pl --strict --codespell -g $SHA_MAIN..$SHA_PR - - name: "sparse check" + - name: "Code Scan" script: + - sudo apt-get install automake ocaml-native-compilers ocaml-findlib + - wget https://github.com/coccinelle/coccinelle/archive/1.0.7.tar.gz + - tar -xf 1.0.7.tar.gz + - cd coccinelle-1.0.7 && ./autogen && ./configure && make && sudo make install + - cd - - export ARCH=x86_64 - make defconfig - scripts/kconfig/merge_config.sh .config kconfig/base-defconfig kconfig/sof-defconfig kconfig/hdaudio-codecs-defconfig - make modules_prepare - - make SUBDIRS=sound/soc/sof C=2 + - make M=sound/soc/sof C=2 + - make coccicheck MODE=report M=sound/soc/sof - name: "BUILD SOF Kernel x86_64" script: - export ARCH=x86_64 - make defconfig - scripts/kconfig/merge_config.sh .config kconfig/base-defconfig kconfig/sof-defconfig - make modules_prepare - - KCFLAGS="-Wall -Werror" make -j`getconf _NPROCESSORS_ONLN` SUBDIRS=sound/soc/sof W=1 + - KCFLAGS="-Wall -Werror" make -j`getconf _NPROCESSORS_ONLN` M=sound/soc/sof W=1 - KCFLAGS="-Wall -Werror" make -j`getconf _NPROCESSORS_ONLN` - make bindeb-pkg -j`getconf _NPROCESSORS_ONLN` - name: "BUILD SST Kernel x86_64" From 67e5fa8c39c33089711a567b45e1b7568197044a Mon Sep 17 00:00:00 2001 From: Fred Oh Date: Mon, 24 Jun 2019 10:41:10 -0700 Subject: [PATCH 1560/1995] ASoC: SOF: remove unused state variable in suspend function Remove unused and no plan to use variable from suspend function. Signed-off-by: Fred Oh --- sound/soc/sof/intel/hda-dsp.c | 11 +++++------ sound/soc/sof/intel/hda.h | 4 ++-- sound/soc/sof/ops.h | 9 ++++----- sound/soc/sof/pm.c | 4 ++-- sound/soc/sof/sof-priv.h | 5 ++--- 5 files changed, 15 insertions(+), 18 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index f8ed8a4a60b789..611c130a7ca253 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -282,8 +282,7 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0); } -static int hda_suspend(struct snd_sof_dev *sdev, int state, - bool runtime_suspend) +static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; const struct sof_intel_dsp_desc *chip = hda->desc; @@ -433,19 +432,19 @@ int hda_dsp_runtime_resume(struct snd_sof_dev *sdev) return hda_resume(sdev, true); } -int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state) +int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev) { /* stop hda controller and power dsp off */ - return hda_suspend(sdev, state, true); + return hda_suspend(sdev, true); } -int hda_dsp_suspend(struct snd_sof_dev *sdev, int state) +int hda_dsp_suspend(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); int ret; /* stop hda controller and power dsp off */ - ret = hda_suspend(sdev, state, false); + ret = hda_suspend(sdev, false); if (ret < 0) { dev_err(bus->dev, "error: suspending dsp\n"); return ret; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index dd476d3a745d1e..dd57cedc5cddd9 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -456,9 +456,9 @@ int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev); void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev); -int hda_dsp_suspend(struct snd_sof_dev *sdev, int state); +int hda_dsp_suspend(struct snd_sof_dev *sdev); int hda_dsp_resume(struct snd_sof_dev *sdev); -int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev, int state); +int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev); int hda_dsp_runtime_resume(struct snd_sof_dev *sdev); int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev); void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags); diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 45a3d10911634a..80092541430d32 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -109,10 +109,10 @@ static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev) return 0; } -static inline int snd_sof_dsp_suspend(struct snd_sof_dev *sdev, int state) +static inline int snd_sof_dsp_suspend(struct snd_sof_dev *sdev) { if (sof_ops(sdev)->suspend) - return sof_ops(sdev)->suspend(sdev, state); + return sof_ops(sdev)->suspend(sdev); return 0; } @@ -125,11 +125,10 @@ static inline int snd_sof_dsp_runtime_resume(struct snd_sof_dev *sdev) return 0; } -static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev, - int state) +static inline int snd_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev) { if (sof_ops(sdev)->runtime_suspend) - return sof_ops(sdev)->runtime_suspend(sdev, state); + return sof_ops(sdev)->runtime_suspend(sdev); return 0; } diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 8eeb3a1029f24d..70b1b5989c8267 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -377,9 +377,9 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) /* power down all DSP cores */ if (runtime_suspend) - ret = snd_sof_dsp_runtime_suspend(sdev, 0); + ret = snd_sof_dsp_runtime_suspend(sdev); else - ret = snd_sof_dsp_suspend(sdev, 0); + ret = snd_sof_dsp_suspend(sdev); if (ret < 0) dev_err(sdev->dev, "error: failed to power down DSP during suspend %d\n", diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index e0441861512926..24cc75f3f6e218 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -171,10 +171,9 @@ struct snd_sof_dsp_ops { int (*post_fw_run)(struct snd_sof_dev *sof_dev); /* optional */ /* DSP PM */ - int (*suspend)(struct snd_sof_dev *sof_dev, int state); /* optional */ + int (*suspend)(struct snd_sof_dev *sof_dev); /* optional */ int (*resume)(struct snd_sof_dev *sof_dev); /* optional */ - int (*runtime_suspend)(struct snd_sof_dev *sof_dev, - int state); /* optional */ + int (*runtime_suspend)(struct snd_sof_dev *sof_dev); /* optional */ int (*runtime_resume)(struct snd_sof_dev *sof_dev); /* optional */ int (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */ From 6ca18cb4441e017d806006103a21df3a8ffa1b6b Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Mon, 27 May 2019 16:40:59 +0800 Subject: [PATCH 1561/1995] ASoC: SOF: Intel: hda: set position buffer in init chip Set the HDA stream position buffer during init chip. The position buffer needs to be set in both HDA codec and nocodec cases. Using SOF defined function and move it to common code. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-ctrl.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index ea63f83a509bb5..015760284969b1 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -245,14 +245,13 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* program the position buffer */ if (bus->use_posbuf && bus->posbuf.addr) { - snd_hdac_chip_writel(bus, DPLBASE, (u32)bus->posbuf.addr); - snd_hdac_chip_writel(bus, DPUBASE, - upper_32_bits(bus->posbuf.addr)); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPLBASE, + (u32)bus->posbuf.addr); + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, SOF_HDA_ADSP_DPUBASE, + upper_32_bits(bus->posbuf.addr)); } -#endif bus->chip_init = true; From 41fb6317effe68a52e4d50c3bc3493ec5be36a28 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Thu, 13 Jun 2019 15:51:21 +0800 Subject: [PATCH 1562/1995] ASoC: SOF: Intel: hda: use SOF defined init chip in resume Unify resume code by using SOF common function hda_dsp_ctrl_init_chip() which can handle both HDA and non-HDA cases. Move code to reset stream-to-link mapping into hda_dsp_ctrl_init_chip(). Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-ctrl.c | 9 +++++++++ sound/soc/sof/intel/hda-dsp.c | 36 ++-------------------------------- 2 files changed, 11 insertions(+), 34 deletions(-) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 015760284969b1..8b856dc35e20ed 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -164,6 +164,9 @@ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) { struct hdac_bus *bus = sof_to_bus(sdev); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + struct hdac_ext_link *hlink; +#endif struct hdac_stream *stream; int sd_offset, ret = 0; @@ -253,6 +256,12 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) upper_32_bits(bus->posbuf.addr)); } +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* Reset stream-to-link mapping */ + list_for_each_entry(hlink, &bus->hlink_list, list) + bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); +#endif + bus->chip_init = true; hda_dsp_ctrl_misc_clock_gating(sdev, true); diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 611c130a7ca253..1215504233d6d8 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -355,6 +355,7 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) /* read STATESTS before controller reset */ status = snd_hdac_chip_readw(bus, STATESTS); } +#endif /* reset and start hda controller */ ret = hda_dsp_ctrl_init_chip(sdev, true); @@ -364,14 +365,7 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) return ret; } - hda_dsp_ctrl_misc_clock_gating(sdev, false); - - /* Reset stream-to-link mapping */ - list_for_each_entry(hlink, &bus->hlink_list, list) - bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); - - hda_dsp_ctrl_misc_clock_gating(sdev, true); - +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* check jack status based on controller status */ if (runtime_resume) hda_codec_jack_check(sdev, status); @@ -385,32 +379,6 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) /* check dma status and clean up CORB/RIRB buffers */ if (!bus->cmd_dma_state) snd_hdac_bus_stop_cmd_io(bus); -#else - - hda_dsp_ctrl_misc_clock_gating(sdev, false); - - /* reset controller */ - ret = hda_dsp_ctrl_link_reset(sdev, true); - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to reset controller during resume\n"); - return ret; - } - - /* take controller out of reset */ - ret = hda_dsp_ctrl_link_reset(sdev, false); - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to ready controller during resume\n"); - return ret; - } - - /* enable hda bus irq */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); - - hda_dsp_ctrl_misc_clock_gating(sdev, true); #endif /* enable ppcap interrupt */ From 6ec3295826d8c11141c970cf3fd68d77d3452adb Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Thu, 13 Jun 2019 16:17:32 +0800 Subject: [PATCH 1563/1995] ASoC: SOF: Intel: hda: remove duplicated clear WAKESTS Remove the first clear WAKESTS, only one clear is needed during init chip. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-ctrl.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 8b856dc35e20ed..a7fee403cb9088 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -176,11 +176,6 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) hda_dsp_ctrl_misc_clock_gating(sdev, false); if (full_reset) { - /* clear WAKESTS */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_WAKESTS, - SOF_HDA_WAKESTS_INT_MASK, - SOF_HDA_WAKESTS_INT_MASK); - /* reset HDA controller */ ret = hda_dsp_ctrl_link_reset(sdev, true); if (ret < 0) { From 7fa1499cfaf591b39d7015f610d64fad666df944 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 25 Jun 2019 11:13:55 +0200 Subject: [PATCH 1564/1995] ASoC: SOF: Intel: HDA: add a parameter to disable MSI Enabling MSI on HDA can fail, in which case the legacy PCI IRQ mode will be used. To make testing this mode easier add an "enable_msi" module parameter, which is only enabled if debugging is enabled too. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/hda.c | 28 +++++++++++++++++----------- sound/soc/sof/sof-priv.h | 2 +- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 7f665392618f64..79cce20666b6cd 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -46,6 +46,12 @@ struct hda_dsp_msg_code { const char *msg; }; +static bool hda_use_msi = IS_ENABLED(CONFIG_PCI); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG) +module_param_named(use_msi, hda_use_msi, bool, 0444); +MODULE_PARM_DESC(use_msi, "SOF HDA use PCI MSI mode"); +#endif + static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = { {HDA_DSP_ROM_FW_MANIFEST_LOADED, "status: manifest loaded"}, {HDA_DSP_ROM_FW_FW_LOADED, "status: fw loaded"}, @@ -529,11 +535,18 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) * register our IRQ * let's try to enable msi firstly * if it fails, use legacy interrupt mode - * TODO: support interrupt mode selection with kernel parameter - * support msi multiple vectors + * TODO: support msi multiple vectors */ - ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI); - if (ret < 0) { + if (hda_use_msi && !pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI)) { + dev_info(sdev->dev, "use msi interrupt mode\n"); + hdev->irq = pci_irq_vector(pci, 0); + /* ipc irq number is the same of hda irq */ + sdev->ipc_irq = hdev->irq; + /* initialised to "false" by kzalloc() */ + sdev->msi_enabled = true; + } + + if (!sdev->msi_enabled) { dev_info(sdev->dev, "use legacy interrupt mode\n"); /* * in IO-APIC mode, hda->irq and ipc_irq are using the same @@ -541,13 +554,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) */ hdev->irq = pci->irq; sdev->ipc_irq = pci->irq; - sdev->msi_enabled = 0; - } else { - dev_info(sdev->dev, "use msi interrupt mode\n"); - hdev->irq = pci_irq_vector(pci, 0); - /* ipc irq number is the same of hda irq */ - sdev->ipc_irq = hdev->irq; - sdev->msi_enabled = 1; } dev_dbg(sdev->dev, "using HDA IRQ %d\n", hdev->irq); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 24cc75f3f6e218..21204fd9c9c109 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -432,7 +432,7 @@ struct snd_sof_dev { u32 dtrace_error; u32 dtrace_draining; - u32 msi_enabled; + bool msi_enabled; void *private; /* core does not touch this */ }; From 86b820f25258db8ff8298d92b8665116b2bf673e Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 3 Jul 2019 11:09:43 -0700 Subject: [PATCH 1565/1995] ASoC: SOF: Intel: hda: Initialize HDA controller after i915 init On some platforms, sound card registration fails when a HDMI monitor is not connected. This is caused by a recent commit that switched the order in which the HDA controller and the i915 are initialized. Initializing the i915 before initializing the HDA controller fixes the problem. Fixes: be1b577d01787c ("ASoC: SOF: Intel: hda: fix the hda init chip" Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 79cce20666b6cd..724a494702fa4f 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -335,10 +335,23 @@ static int hda_init_caps(struct snd_sof_dev *sdev) if (bus->ppcap) dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n"); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* init i915 and HDMI codecs */ + ret = hda_codec_i915_init(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: init i915 and HDMI codec failed\n"); + return ret; + } +#endif + + /* Init HDA controller after i915 init */ ret = hda_dsp_ctrl_init_chip(sdev, true); if (ret < 0) { dev_err(bus->dev, "error: init chip failed with ret: %d\n", ret); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + hda_codec_i915_exit(sdev); +#endif return ret; } @@ -346,13 +359,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) if (bus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(bus); - /* init i915 and HDMI codecs */ - ret = hda_codec_i915_init(sdev); - if (ret < 0) { - dev_err(sdev->dev, "error: no HDMI audio devices found\n"); - return ret; - } - /* codec detection */ if (!bus->codec_mask) { dev_info(bus->dev, "no hda codecs found!\n"); From c29d96c3b9b4b8db417222d9444265ceb076b772 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 19 Jun 2019 15:27:23 +0300 Subject: [PATCH 1566/1995] ASoC: SOF: reset DMA state in prepare When application goes through SUSPEND/STOP->PREPARE->START cycle, we should always reprogram the SOF device to start DMA from a known state so that hw_ptr/appl_ptrs remain valid. This is expected by ALSA core as it resets the buffer state as part of prepare (see snd_pcm_do_prepare()). Fix the issue by forcing reconfiguration of the FW with STREAM_PCM_PARAMS in prepare(). Use combined logic to handle prepare and the existing flow to reprogram hw-params after system suspend. Without the fix, first call to pcm pointer() will return an invalid hw_ptr and application may immediately observe XRUN status, unless "start_threshold" SW parameter is set to maximum value by the application. Signed-off-by: Kai Vehmanen --- sound/soc/sof/pcm.c | 27 +++++++++++++++------------ sound/soc/sof/pm.c | 2 +- sound/soc/sof/sof-priv.h | 2 +- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 334e9d59b1bafa..3b8955e755b241 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -208,12 +208,11 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; + spcm->prepared[substream->stream] = true; + /* save pcm hw_params */ memcpy(&spcm->params[substream->stream], params, sizeof(*params)); - /* clear hw_params_upon_resume flag */ - spcm->hw_params_upon_resume[substream->stream] = 0; - return ret; } @@ -236,6 +235,9 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) if (!spcm) return -EINVAL; + if (!spcm->prepared[substream->stream]) + return 0; + dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); @@ -258,6 +260,8 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) if (ret < 0) dev_err(sdev->dev, "error: platform hw free failed\n"); + spcm->prepared[substream->stream] = false; + return ret; } @@ -278,11 +282,7 @@ static int sof_pcm_prepare(struct snd_pcm_substream *substream) if (!spcm) return -EINVAL; - /* - * check if hw_params needs to be set-up again. - * This is only needed when resuming from system sleep. - */ - if (!spcm->hw_params_upon_resume[substream->stream]) + if (spcm->prepared[substream->stream]) return 0; dev_dbg(sdev->dev, "pcm: prepare stream %d dir %d\n", spcm->pcm.pcm_id, @@ -311,6 +311,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_sof_pcm *spcm; struct sof_ipc_stream stream; struct sof_ipc_reply reply; + bool reset_hw_params = false; int ret; /* nothing to do for BE */ @@ -351,6 +352,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; + reset_hw_params = true; break; default: dev_err(sdev->dev, "error: unhandled trigger cmd %d\n", cmd); @@ -363,17 +365,17 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, sizeof(stream), &reply, sizeof(reply)); - if (ret < 0 || cmd != SNDRV_PCM_TRIGGER_SUSPEND) + if (ret < 0 || !reset_hw_params) return ret; /* - * The hw_free op is usually called when the pcm stream is closed. - * Since the stream is not closed during suspend, the DSP needs to be - * notified explicitly to free pcm to prevent errors upon resume. + * In case of stream is stopped, DSP must be reprogrammed upon + * restart, so free PCM here. */ stream.hdr.size = sizeof(stream); stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE; stream.comp_id = spcm->stream[substream->stream].comp_id; + spcm->prepared[substream->stream] = false; /* send IPC to the DSP */ return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, @@ -481,6 +483,7 @@ static int sof_pcm_open(struct snd_pcm_substream *substream) spcm->stream[substream->stream].posn.host_posn = 0; spcm->stream[substream->stream].posn.dai_posn = 0; spcm->stream[substream->stream].substream = substream; + spcm->prepared[substream->stream] = false; ret = snd_sof_pcm_platform_open(sdev, substream); if (ret < 0) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 70b1b5989c8267..16e92648e0d307 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -233,7 +233,7 @@ static int sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev) state = substream->runtime->status->state; if (state == SNDRV_PCM_STATE_SUSPENDED) - spcm->hw_params_upon_resume[dir] = 1; + spcm->prepared[dir] = false; } } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 21204fd9c9c109..d5e7562eb922d1 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -295,7 +295,7 @@ struct snd_sof_pcm { struct snd_sof_pcm_stream stream[2]; struct list_head list; /* list in sdev pcm list */ struct snd_pcm_hw_params params[2]; - int hw_params_upon_resume[2]; /* set up hw_params upon resume */ + bool prepared[2]; /* PCM_PARAMS set successfully */ }; /* ALSA SOF Kcontrol device */ From 4158eab73a1285477b76be933e9c2ad308d9bfc1 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Thu, 27 Jun 2019 18:11:35 +0300 Subject: [PATCH 1567/1995] ASoC: SOF: use common code to send PCM_FREE IPC Remove duplicated code by using a common helper function to send the PCM_FREE IPC message to FW. Signed-off-by: Kai Vehmanen --- sound/soc/sof/pcm.c | 50 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 3b8955e755b241..8612896673a5bf 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -216,6 +216,27 @@ static int sof_pcm_hw_params(struct snd_pcm_substream *substream, return ret; } +static int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, + struct snd_sof_dev *sdev, + struct snd_sof_pcm *spcm) +{ + struct sof_ipc_stream stream; + struct sof_ipc_reply reply; + int ret; + + stream.hdr.size = sizeof(stream); + stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE; + stream.comp_id = spcm->stream[substream->stream].comp_id; + + /* send IPC to the DSP */ + ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, + sizeof(stream), &reply, sizeof(reply)); + if (!ret) + spcm->prepared[substream->stream] = false; + + return ret; +} + static int sof_pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -223,8 +244,6 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; - struct sof_ipc_stream stream; - struct sof_ipc_reply reply; int ret; /* nothing to do for BE */ @@ -241,13 +260,7 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); - stream.hdr.size = sizeof(stream); - stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE; - stream.comp_id = spcm->stream[substream->stream].comp_id; - - /* send IPC to the DSP */ - ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, - sizeof(stream), &reply, sizeof(reply)); + ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); snd_pcm_lib_free_pages(substream); @@ -260,8 +273,6 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) if (ret < 0) dev_err(sdev->dev, "error: platform hw free failed\n"); - spcm->prepared[substream->stream] = false; - return ret; } @@ -365,21 +376,10 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, sizeof(stream), &reply, sizeof(reply)); - if (ret < 0 || !reset_hw_params) - return ret; - - /* - * In case of stream is stopped, DSP must be reprogrammed upon - * restart, so free PCM here. - */ - stream.hdr.size = sizeof(stream); - stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_FREE; - stream.comp_id = spcm->stream[substream->stream].comp_id; - spcm->prepared[substream->stream] = false; + if (!ret && reset_hw_params) + ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); - /* send IPC to the DSP */ - return sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, - sizeof(stream), &reply, sizeof(reply)); + return ret; } static snd_pcm_uframes_t sof_pcm_pointer(struct snd_pcm_substream *substream) From fdfcca4c7700f156c716ca2e9dcd9fdbce328157 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 1 Jul 2019 17:23:47 +0300 Subject: [PATCH 1568/1995] ASoC: SOF: Intel: reset link DMA state in prepare When application goes through SUSPEND/STOP->PREPARE->START cycle, we should always reprogram the DAI link DMA to ensure it is in sync with the host PCM DMA. Use same state tracking logic to handle both restart and system resume flows. Use link_prepared field of 'struct hdac_ext_stream' to store the state, instead of adding redundant fields to SOF specific structs. Signed-off-by: Kai Vehmanen --- sound/soc/sof/intel/hda-dai.c | 8 +++----- sound/soc/sof/intel/hda-dsp.c | 17 ++++++----------- sound/soc/sof/intel/hda.h | 1 - 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index a514f9cf5c9a1b..a448be60f6ddf1 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -226,8 +226,6 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream, snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); - hda_stream->hw_params_upon_resume = 0; - link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name); if (!link) return -EINVAL; @@ -267,8 +265,7 @@ static int hda_link_pcm_prepare(struct snd_pcm_substream *substream, hda_stream = hstream_to_sof_hda_stream(link_dev); - /* setup hw_params again only if resuming from system suspend */ - if (!hda_stream->hw_params_upon_resume) + if (link_dev->link_prepared) return 0; dev_dbg(sdev->dev, "hda: prepare stream dir %d\n", substream->stream); @@ -317,6 +314,7 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, snd_hdac_ext_link_stream_start(link_dev); break; case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: /* * clear and release link DMA channel. It will be assigned when * hw_params is set up again after resume. @@ -329,10 +327,10 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, snd_hdac_ext_link_clear_stream_id(link, stream_tag); snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); + link_dev->link_prepared = 0; /* fallthrough */ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_STOP: snd_hdac_ext_link_stream_clear(link_dev); break; default: diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 1215504233d6d8..fe143bb000e373 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -423,25 +423,19 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev) int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) { - struct hdac_bus *bus = sof_to_bus(sdev); - struct sof_intel_hda_stream *hda_stream; - struct hdac_ext_stream *stream; - struct hdac_stream *s; - #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + struct hdac_bus *bus = sof_to_bus(sdev); struct snd_soc_pcm_runtime *rtd; + struct hdac_ext_stream *stream; struct hdac_ext_link *link; + struct hdac_stream *s; const char *name; int stream_tag; -#endif /* set internal flag for BE */ list_for_each_entry(s, &bus->stream_list, list) { stream = stream_to_hdac_ext_stream(s); - hda_stream = container_of(stream, struct sof_intel_hda_stream, - hda_stream); - hda_stream->hw_params_upon_resume = 1; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) + /* * clear and release stream. This should already be taken care * for running streams when the SUSPEND trigger is called. @@ -458,8 +452,9 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) snd_hdac_ext_link_clear_stream_id(link, stream_tag); snd_hdac_ext_stream_release(stream, HDAC_EXT_STREAM_TYPE_LINK); + stream->link_prepared = 0; } -#endif } +#endif return 0; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index dd57cedc5cddd9..3df15012279b19 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -421,7 +421,6 @@ struct sof_intel_hda_stream { struct snd_sof_dev *sdev; struct hdac_ext_stream hda_stream; struct sof_intel_stream stream; - int hw_params_upon_resume; /* set up hw_params upon resume */ int host_reserved; /* reserve host DMA channel */ }; From 2840c809c40892cb00c7924463eed3ed2a074d3f Mon Sep 17 00:00:00 2001 From: Janusz Jankowski Date: Wed, 3 Jul 2019 13:30:06 +0200 Subject: [PATCH 1569/1995] ASoC: SOF: Intel: ssp: BCLK delay parameter Some codecs require BCLK to be on for some time, before sending any data. SOF can enable BCLK and then wait for guaranteed time, before starting DMA on SSP start. Signed-off-by: Janusz Jankowski --- include/sound/sof/dai-intel.h | 3 +++ include/uapi/sound/sof/abi.h | 2 +- include/uapi/sound/sof/tokens.h | 1 + sound/soc/sof/topology.c | 3 +++ 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h index 4bb8ee138ba7f2..a81afd3fbd41e4 100644 --- a/include/sound/sof/dai-intel.h +++ b/include/sound/sof/dai-intel.h @@ -76,6 +76,9 @@ struct sof_ipc_dai_ssp_params { uint16_t tdm_per_slot_padding_flag; uint32_t clks_control; uint32_t quirks; + uint32_t bclk_delay; /* guaranteed time (ms) for which BCLK + * will be driven, before sending data + */ } __packed; /* HDA Configuration Request - SOF_IPC_DAI_HDA_CONFIG */ diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index 4a9c24434f4259..dff70a42445a17 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 8 +#define SOF_ABI_MINOR 9 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index dc1b27daaac622..6435240cef1351 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -75,6 +75,7 @@ #define SOF_TKN_INTEL_SSP_FRAME_PULSE_WIDTH 503 #define SOF_TKN_INTEL_SSP_QUIRKS 504 #define SOF_TKN_INTEL_SSP_TDM_PADDING_PER_SLOT 505 +#define SOF_TKN_INTEL_SSP_BCLK_DELAY 506 /* DMIC */ #define SOF_TKN_INTEL_DMIC_DRIVER_VERSION 600 diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 432ae343f96024..12b7d900b9c245 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -748,6 +748,9 @@ static const struct sof_topology_token ssp_tokens[] = { get_token_u16, offsetof(struct sof_ipc_dai_ssp_params, tdm_per_slot_padding_flag), 0}, + {SOF_TKN_INTEL_SSP_BCLK_DELAY, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, + offsetof(struct sof_ipc_dai_ssp_params, bclk_delay), 0}, }; From 5ff87ceba9bc7c815a94970bea67d4d4136ee4d1 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 14 Jun 2019 17:33:04 +0300 Subject: [PATCH 1570/1995] ASoC: SOF: ipc: use timeout configured at probe Do not hardcode IPC timeout value in ipc.c, but rather use the timeout value configured during device probe. For platforms that do not override the IPC timeout, default value TIMEOUT_DEFAULT_IPC_MS has already been defined in core.c. Signed-off-by: Kai Vehmanen --- sound/soc/sof/ipc.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 20dfca9c93b76d..b2f359d2f7e530 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -17,12 +17,6 @@ #include "sof-priv.h" #include "ops.h" -/* - * IPC message default size and timeout (ms). - * TODO: allow platforms to set size and timeout. - */ -#define IPC_TIMEOUT_MS 300 - static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id); static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd); @@ -211,7 +205,7 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, /* wait for DSP IPC completion */ ret = wait_event_timeout(msg->waitq, msg->ipc_complete, - msecs_to_jiffies(IPC_TIMEOUT_MS)); + msecs_to_jiffies(sdev->ipc_timeout)); if (ret == 0) { dev_err(sdev->dev, "error: ipc timed out for 0x%x size %d\n", From 092404a48179112a0283c90a64763a2345df944f Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Thu, 13 Jun 2019 17:19:23 +0300 Subject: [PATCH 1571/1995] ASoC: SOF: core: increase default IPC timeouts Increase the default timeout values for boot (100ms to 2sec) and IPC message sending (5ms to 500ms). The values should be overridden with values from platform data. There is no functional need to have such short timeouts as both boot and IPC send errors are considered fatal errors. More relaxed timeouts are convenient when running the driver on top of emulation such as QEMU. Signed-off-by: Kai Vehmanen --- sound/soc/sof/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 70b471be07b275..15200841a12a12 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -23,8 +23,8 @@ MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)"); #define SOF_CORE_ENABLE_TRACE BIT(0) /* SOF defaults if not provided by the platform in ms */ -#define TIMEOUT_DEFAULT_IPC_MS 5 -#define TIMEOUT_DEFAULT_BOOT_MS 100 +#define TIMEOUT_DEFAULT_IPC_MS 500 +#define TIMEOUT_DEFAULT_BOOT_MS 2000 /* * Generic object lookup APIs. From 291b5ca873cfa8864d5d88d5db4a12b1befa30c2 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 1 Jul 2019 16:25:47 +0200 Subject: [PATCH 1572/1995] ASoC: SOF: Intel: use snd_hdac_chip_updatew() for WAKEEN Use snd_hdac_chip_updatew() to update WAKEEN instead of open-coding. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/hda-codec.c | 4 +--- sound/soc/sof/intel/hda-dsp.c | 5 ++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 5882f1bfd906ca..95e8bab8f8bf60 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -68,9 +68,7 @@ void hda_codec_jack_check(struct snd_sof_dev *sdev, int status) codec->jackpoll_interval); /* disable controller Wake Up event*/ - snd_hdac_chip_writew(bus, WAKEEN, - snd_hdac_chip_readw(bus, WAKEEN) & - ~hda->hda_codec_mask); + snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0); } #else void hda_codec_jack_check(struct snd_sof_dev *sdev, int status) {} diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index fe143bb000e373..6ce4f3dd74d146 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -297,9 +297,8 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) if (IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) && runtime_suspend) /* enable controller wake up event */ - snd_hdac_chip_writew(bus, WAKEEN, - snd_hdac_chip_readw(bus, WAKEEN) | - hda->hda_codec_mask); + snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, + hda->hda_codec_mask); /* power down all hda link */ snd_hdac_ext_bus_link_power_down_all(bus); From 1da8b5fa69a114a8a493cec7f5df2213436d287f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 12 Jun 2019 12:34:53 +0200 Subject: [PATCH 1573/1995] ASoC: SOF: Intel: optimise jack detection 1. The additional HDA codec mask isn't needed, just check the codec jack table. 2. Remove the "status" parameter. Signed-off-by: Guennadi Liakhovetski --- sound/soc/sof/intel/hda-codec.c | 53 +++++++++++++++++---------------- sound/soc/sof/intel/hda-dsp.c | 18 +++-------- sound/soc/sof/intel/hda.h | 6 ++-- 3 files changed, 33 insertions(+), 44 deletions(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 95e8bab8f8bf60..3ca6795a89ba3a 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -38,53 +38,55 @@ static void hda_codec_load_module(struct hda_codec *codec) static void hda_codec_load_module(struct hda_codec *codec) {} #endif -/* check jack status after resuming from suspend mode */ -void hda_codec_jack_check(struct snd_sof_dev *sdev, int status) +/* enable controller wake up event for all codecs with jack connectors */ +void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev) { - struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct hda_bus *hbus = sof_to_hbus(sdev); struct hdac_bus *bus = sof_to_bus(sdev); struct hda_codec *codec; - int mask; - - /* - * there are two reasons for runtime resume - * (1) waken up by interrupt triggered by WAKEEN feature - * (2) waken up by pm get functions for some audio operations - * For case (1), the bits in status mean which codec triggers - * the interrupt and jacks will be checked on these codecs. - * For case (2), we need to check all the non-hdmi codecs for some - * cases like playback with HDMI or capture with DMIC. In these - * cases, only controller is active and codecs are suspended, so - * codecs can't send unsolicited event to controller. The jack polling - * operation will activate codecs and unsolicited event can work - * even codecs become suspended later. - */ - mask = status ? status : hda->hda_codec_mask; + unsigned int mask = 0; list_for_each_codec(codec, hbus) - if (mask & BIT(codec->core.addr)) - schedule_delayed_work(&codec->jackpoll_work, - codec->jackpoll_interval); + if (codec->jacktbl.used) + mask |= BIT(codec->core.addr); + + snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, mask); +} + +/* check jack status after resuming from suspend mode */ +void hda_codec_jack_check(struct snd_sof_dev *sdev) +{ + struct hda_bus *hbus = sof_to_hbus(sdev); + struct hdac_bus *bus = sof_to_bus(sdev); + struct hda_codec *codec; /* disable controller Wake Up event*/ snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0); + + list_for_each_codec(codec, hbus) + /* + * Wake up all jack-detecting codecs regardless whether an event + * has been recorded in STATESTS + */ + if (codec->jacktbl.used) + schedule_delayed_work(&codec->jackpoll_work, + codec->jackpoll_interval); } #else -void hda_codec_jack_check(struct snd_sof_dev *sdev, int status) {} +void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev) {} +void hda_codec_jack_check(struct snd_sof_dev *sdev) {} #endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */ +EXPORT_SYMBOL(hda_codec_jack_wake_enable); EXPORT_SYMBOL(hda_codec_jack_check); /* probe individual codec */ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) { #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) - struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct hdac_hda_priv *hda_priv; #endif struct hda_bus *hbus = sof_to_hbus(sdev); struct hdac_device *hdev; - u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) | (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; u32 resp = -1; @@ -114,7 +116,6 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) /* use legacy bus only for HDA codecs, idisp uses ext bus */ if ((resp & 0xFFFF0000) != IDISP_VID_INTEL) { hdev->type = HDA_DEV_LEGACY; - hda->hda_codec_mask |= BIT(address); hda_codec_load_module(&hda_priv->codec); } diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 6ce4f3dd74d146..938b4f99218837 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -295,10 +295,8 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) hda_dsp_ipc_int_disable(sdev); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - if (IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) && runtime_suspend) - /* enable controller wake up event */ - snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, - hda->hda_codec_mask); + if (runtime_suspend) + hda_codec_jack_wake_enable(sdev); /* power down all hda link */ snd_hdac_ext_bus_link_power_down_all(bus); @@ -339,7 +337,6 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_ext_link *hlink = NULL; - int status; #endif int ret; @@ -349,13 +346,6 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) */ snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - if (runtime_resume) { - /* read STATESTS before controller reset */ - status = snd_hdac_chip_readw(bus, STATESTS); - } -#endif - /* reset and start hda controller */ ret = hda_dsp_ctrl_init_chip(sdev, true); if (ret < 0) { @@ -365,9 +355,9 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) } #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* check jack status based on controller status */ + /* check jack status */ if (runtime_resume) - hda_codec_jack_check(sdev, status); + hda_codec_jack_check(sdev); /* turn off the links that were off before suspend */ list_for_each_entry(hlink, &bus->hlink_list, list) { diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 3df15012279b19..aa11df4ff7f72a 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -398,9 +398,6 @@ struct sof_intel_hda_dev { /* DMIC device */ struct platform_device *dmic_dev; - - /* hda codec mask excluding hdmi */ - u32 hda_codec_mask; }; static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s) @@ -558,7 +555,8 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev, * HDA Codec operations. */ int hda_codec_probe_bus(struct snd_sof_dev *sdev); -void hda_codec_jack_check(struct snd_sof_dev *sdev, int status); +void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev); +void hda_codec_jack_check(struct snd_sof_dev *sdev); #endif /* CONFIG_SND_SOC_SOF_HDA */ From c7f1b858a69feaabb3c52bb4f1e111670a447220 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 3 Jul 2019 10:16:23 +0800 Subject: [PATCH 1574/1995] ASoC: SOF: hda: fix link DMA config For this bug, there are two capture pcm streams active, with one stream and its related stream tag released before suspend. Later when system suspend is done, the stream tag for the remaining active stream is released by SOF driver. After system resume, hda codec driver restores the stream tag for the active pcm stream, but SOF goes to assign a new one, which now doesn't match with the stream tag used by codec driver, and this causes DMA to fail receiving data, leading to unrecoverable XRUN condition in FW. For stream tag is stored in both hda codec and SOF driver, it shouldn't be released only in SOF driver. This patch just keeps the stream information in dma data and checks whether there is a stored DMA data for stream resuming from S3 and restores it. And it also removes DMA data when the stream is released. Tested on Whiskey Lake platform. GitHub issue: https://github.com/thesofproject/sof/issues/1594 Signed-off-by: Rander Wang --- sound/soc/sof/intel/hda-dai.c | 15 +++++++++------ sound/soc/sof/intel/hda-dsp.c | 10 ++++------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index a448be60f6ddf1..2b5e2b8c69c28f 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -210,9 +210,13 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream, int stream_tag; int ret; - link_dev = hda_link_stream_assign(bus, substream); - if (!link_dev) - return -EBUSY; + /* get stored dma data if resuming from system suspend */ + link_dev = snd_soc_dai_get_dma_data(dai, substream); + if (!link_dev) { + link_dev = hda_link_stream_assign(bus, substream); + if (!link_dev) + return -EBUSY; + } stream_tag = hdac_stream(link_dev)->stream_tag; @@ -316,7 +320,7 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: /* - * clear and release link DMA channel. It will be assigned when + * clear link DMA channel. It will be assigned when * hw_params is set up again after resume. */ ret = hda_link_config_ipc(hda_stream, dai->name, @@ -325,8 +329,6 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, return ret; stream_tag = hdac_stream(link_dev)->stream_tag; snd_hdac_ext_link_clear_stream_id(link, stream_tag); - snd_hdac_ext_stream_release(link_dev, - HDAC_EXT_STREAM_TYPE_LINK); link_dev->link_prepared = 0; /* fallthrough */ @@ -369,6 +371,7 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream, stream_tag = hdac_stream(link_dev)->stream_tag; snd_hdac_ext_link_clear_stream_id(link, stream_tag); + snd_soc_dai_set_dma_data(dai, substream, NULL); snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); link_dev->link_prepared = 0; diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 938b4f99218837..4689b5fe55eaf0 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -426,10 +426,10 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) stream = stream_to_hdac_ext_stream(s); /* - * clear and release stream. This should already be taken care - * for running streams when the SUSPEND trigger is called. - * But paused streams do not get suspended, so this needs to be - * done explicitly during suspend. + * clear stream. This should already be taken care for running + * streams when the SUSPEND trigger is called. But paused + * streams do not get suspended, so this needs to be done + * explicitly during suspend. */ if (stream->link_substream) { rtd = snd_pcm_substream_chip(stream->link_substream); @@ -439,8 +439,6 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) return -EINVAL; stream_tag = hdac_stream(stream)->stream_tag; snd_hdac_ext_link_clear_stream_id(link, stream_tag); - snd_hdac_ext_stream_release(stream, - HDAC_EXT_STREAM_TYPE_LINK); stream->link_prepared = 0; } } From 01373cf705829874e5bc037e9487717c8f0f39a7 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 8 Jul 2019 13:49:39 +0800 Subject: [PATCH 1575/1995] ASoC: SOF: hda: fix stream id setting snd_hdac_ext_link_clear_stream_id maps stream id to link output, which is for playback, not capture. Tested on Whiskey Lake platform. Signed-off-by: Rander Wang --- sound/soc/sof/intel/hda-dai.c | 15 +++++++++++---- sound/soc/sof/intel/hda-dsp.c | 8 +++++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 2b5e2b8c69c28f..8796f385be76c1 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -327,8 +327,12 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream, DMA_CHAN_INVALID, substream->stream); if (ret < 0) return ret; - stream_tag = hdac_stream(link_dev)->stream_tag; - snd_hdac_ext_link_clear_stream_id(link, stream_tag); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + stream_tag = hdac_stream(link_dev)->stream_tag; + snd_hdac_ext_link_clear_stream_id(link, stream_tag); + } + link_dev->link_prepared = 0; /* fallthrough */ @@ -369,8 +373,11 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream, if (!link) return -EINVAL; - stream_tag = hdac_stream(link_dev)->stream_tag; - snd_hdac_ext_link_clear_stream_id(link, stream_tag); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + stream_tag = hdac_stream(link_dev)->stream_tag; + snd_hdac_ext_link_clear_stream_id(link, stream_tag); + } + snd_soc_dai_set_dma_data(dai, substream, NULL); snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); link_dev->link_prepared = 0; diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 4689b5fe55eaf0..bc3edbcad01aa7 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -437,9 +437,15 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev) link = snd_hdac_ext_bus_get_link(bus, name); if (!link) return -EINVAL; + + stream->link_prepared = 0; + + if (hdac_stream(stream)->direction == + SNDRV_PCM_STREAM_CAPTURE) + continue; + stream_tag = hdac_stream(stream)->stream_tag; snd_hdac_ext_link_clear_stream_id(link, stream_tag); - stream->link_prepared = 0; } } #endif From 5a9fa02791aaf66c83bbfbe53b235222ca6e0cd0 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Mon, 8 Jul 2019 18:53:20 +0300 Subject: [PATCH 1576/1995] ASoC: SOF: Introduce snd_sof_dsp_get_bar_index ops FW encapsulates information about section types (e.g DRAM, IRAM) inside module block header. This information can be used in order to correctly load the section to the appropriate place in memory. SOF Linux driver needs to know for each platform how to map the section type with the corresponding memory BAR. So, this patch introduces get_bar_index, a new operation inside snd_sof_dsp_ops. Intel platforms, usually load all the section in a contiguous memory area (usually denoted by sdev->mmio_bar) so things are relatively simple there. Anyhow, on i.MX8 IRAM and DRAM for example are mapped to distinct BARs. By default, if no get_bar function is provided the core implementation will always return sdev->mmio_bar so that there will be no need for a change to existing Intel code. Signed-off-by: Daniel Baluta --- sound/soc/sof/ops.h | 19 +++++++++++++++++++ sound/soc/sof/sof-priv.h | 3 +++ 2 files changed, 22 insertions(+) diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 80092541430d32..4d1591937d3e70 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -100,6 +100,25 @@ static inline int snd_sof_dsp_post_fw_run(struct snd_sof_dev *sdev) return 0; } +/* misc */ + +/** + * snd_sof_dsp_get_bar_index - Maps a section type with a BAR index + * + * @sdev: sof device + * @type: section type as described by snd_sof_fw_blk_type + * + * Returns the corresponding BAR index (a positive integer) or -EINVAL + * in case there is no mapping + */ +static inline int snd_sof_dsp_get_bar_index(struct snd_sof_dev *sdev, u32 type) +{ + if (sof_ops(sdev)->get_bar_index) + return sof_ops(sdev)->get_bar_index(sdev, type); + + return sdev->mmio_bar; +} + /* power management */ static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index d5e7562eb922d1..b5a03a9f983cd4 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -194,6 +194,9 @@ struct snd_sof_dsp_ops { int (*trace_trigger)(struct snd_sof_dev *sdev, int cmd); /* optional */ + /* misc */ + int (*get_bar_index)(struct snd_sof_dev *sdev, + u32 type); /* optional */ /* DAI ops */ struct snd_soc_dai_driver *drv; int num_drv; From 0e8235e1ac516226f30b0413e2b31defc2730477 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 12 Apr 2019 16:26:30 +0300 Subject: [PATCH 1577/1995] ASoC: SOF: loader: Use the BAR provided by FW Make sure to use the newly introduced function snd_sof_dsp_get_bar_index that converts the section type to appropriate BAR index. Signed-off-by: Daniel Baluta --- sound/soc/sof/loader.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 952a19091c5821..e75da8aa7d4a1b 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -92,7 +92,7 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, struct snd_sof_mod_hdr *module) { struct snd_sof_blk_hdr *block; - int count; + int count, bar; u32 offset; size_t remaining; @@ -128,6 +128,13 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, case SOF_FW_BLK_TYPE_IRAM: case SOF_FW_BLK_TYPE_DRAM: offset = block->offset; + bar = snd_sof_dsp_get_bar_index(sdev, block->type); + if (bar < 0) { + dev_err(sdev->dev, + "error: no BAR mapping for block type 0x%x\n", + block->type); + return bar; + } break; default: dev_err(sdev->dev, "error: bad type 0x%x for block 0x%x\n", @@ -145,7 +152,7 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, block->size); return -EINVAL; } - snd_sof_dsp_block_write(sdev, sdev->mmio_bar, offset, + snd_sof_dsp_block_write(sdev, bar, offset, block + 1, block->size); if (remaining < block->size) { From 4a8b4fbf5643554bc7915f02bc6650056fb378fc Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 5 Jun 2019 15:55:51 +0300 Subject: [PATCH 1578/1995] ASoC: SOF: loader: Don't ignore SRAM block types On i.MX8 data/heap/stack is kept in System RAM so do not ignore SRAM block types received from FW. Signed-off-by: Daniel Baluta --- sound/soc/sof/loader.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index e75da8aa7d4a1b..93cb8fd0844fa6 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -123,10 +123,11 @@ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, switch (block->type) { case SOF_FW_BLK_TYPE_RSRVD0: - case SOF_FW_BLK_TYPE_SRAM...SOF_FW_BLK_TYPE_RSRVD14: + case SOF_FW_BLK_TYPE_ROM...SOF_FW_BLK_TYPE_RSRVD14: continue; /* not handled atm */ case SOF_FW_BLK_TYPE_IRAM: case SOF_FW_BLK_TYPE_DRAM: + case SOF_FW_BLK_TYPE_SRAM: offset = block->offset; bar = snd_sof_dsp_get_bar_index(sdev, block->type); if (bar < 0) { From 04b9bfe5d1e99ef5cac06dd15a9488b2a1643d96 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 9 Jul 2019 17:58:54 +0300 Subject: [PATCH 1579/1995] ASoC: SOF: Intel: remove misleading error trace from IRQ thread Downgrade "nothing to do in IRQ thread" message from error to a debug message in the IPC interrupt handler thread. The spurious wake-up can happen if a HDA stream interrupt is raised while the IPC interrupt thread is running. IPC functionality is not impacted by this condition, so debug is a more appropriate trace level. Signed-off-by: Kai Vehmanen --- sound/soc/sof/intel/cnl.c | 4 ++-- sound/soc/sof/intel/hda-ipc.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 3840f81767fab1..7b12ff37c820d0 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -101,8 +101,8 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) /* * This interrupt is not shared so no need to return IRQ_NONE. */ - dev_err_ratelimited(sdev->dev, - "error: nothing to do in IRQ thread\n"); + dev_dbg_ratelimited(sdev->dev, + "nothing to do in IPC IRQ thread\n"); } /* re-enable IPC interrupt */ diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 50244b82600c01..2ecba91f5219d6 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -224,8 +224,8 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) /* * This interrupt is not shared so no need to return IRQ_NONE. */ - dev_err_ratelimited(sdev->dev, - "error: nothing to do in IRQ thread\n"); + dev_dbg_ratelimited(sdev->dev, + "nothing to do in IPC IRQ thread\n"); } /* re-enable IPC interrupt */ From f745362cc60dd62b825a4afacf7457430dce3565 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 17 Jul 2019 17:39:01 +0800 Subject: [PATCH 1580/1995] ASoC: SOF: Intel: HDA: correct ROM state mask The ROM state is represented by the 24 LSB bits in the ROM status register, so the mask should be 0xffffff instead of 0xf. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 8568f9ceb6ee69..ceaaa8d467f4cf 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -175,7 +175,7 @@ #define HDA_DSP_STACK_DUMP_SIZE 32 /* ROM status/error values */ -#define HDA_DSP_ROM_STS_MASK 0xf +#define HDA_DSP_ROM_STS_MASK GENMASK(23, 0) #define HDA_DSP_ROM_INIT 0x1 #define HDA_DSP_ROM_FW_MANIFEST_LOADED 0x3 #define HDA_DSP_ROM_FW_FW_LOADED 0x4 From e79eda1019281d7298cb8a37ef460abeeba517ac Mon Sep 17 00:00:00 2001 From: Thomas Voegtle Date: Sat, 20 Jul 2019 19:01:22 +0200 Subject: [PATCH 1581/1995] r8169: fix RTL8168g PHY init This fixes a copy&paste error in the original patch. Setting the wrong register resulted in massive packet loss on some systems. Fixes: a2928d28643e ("r8169: use paged versions of phylib MDIO access functions") Tested-by: Thomas Voegtle Signed-off-by: Thomas Voegtle Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 0637c6752a78e7..6272115b28480a 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -3251,9 +3251,9 @@ static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp) ret = phy_read_paged(tp->phydev, 0x0a46, 0x13); if (ret & BIT(8)) - phy_modify_paged(tp->phydev, 0x0c41, 0x12, 0, BIT(1)); + phy_modify_paged(tp->phydev, 0x0c41, 0x15, 0, BIT(1)); else - phy_modify_paged(tp->phydev, 0x0c41, 0x12, BIT(1), 0); + phy_modify_paged(tp->phydev, 0x0c41, 0x15, BIT(1), 0); /* Enable PHY auto speed down */ phy_modify_paged(tp->phydev, 0x0a44, 0x11, 0, BIT(3) | BIT(2)); From 8b8f4377316961d5689ba509fc175f3b1498bea3 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 26 Jul 2019 18:10:51 +0800 Subject: [PATCH 1582/1995] ASoC: hdac_hda: fix page fault issue via removing race There is race between hda codec device removing and the jack-detecting work, which will lead to page fault issue as the latter work is accessing codec device which could be already removed. Here adding cancellation of jack-detecting work before codecs are actually removed to avoid the race and fix the issue. Bug: https://github.com/thesofproject/linux/issues/1067 Signed-off-by: Keyon Jie --- sound/soc/codecs/hdac_hda.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 7d494025691498..91242b6f8ea7ad 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -495,6 +495,10 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev) static int hdac_hda_dev_remove(struct hdac_device *hdev) { + struct hdac_hda_priv *hda_pvt; + + hda_pvt = dev_get_drvdata(&hdev->dev); + cancel_delayed_work_sync(&hda_pvt->codec.jackpoll_work); return 0; } From 94acc9921001cf2da78c26f4889e8b629d071e99 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 1 Aug 2019 13:09:51 +0300 Subject: [PATCH 1583/1995] ASoC: SOF: Remove call to snd_sof_dsp_mailbox_init This is reserved for some historical reason, we didn't enable memory windows for byt/bdw at the beginning, to make it compatible, we get those mailbox offsets from fw_ready struct firstly, and then update them if they existed in the following memory windows, to make sure the mailbox still can be used if no memory windows are created. With this change all platforms have the same implementation for xxx_fw_ready function so that we can refactor it in a common file. Suggested-by: Keyon Jie Signed-off-by: Daniel Baluta --- sound/soc/sof/intel/bdw.c | 5 ----- sound/soc/sof/intel/byt.c | 5 ----- 2 files changed, 10 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 70d524ef9bc07d..39f7ffefbef2e1 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -455,11 +455,6 @@ static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, sizeof(*fw_ready)); - snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, - fw_ready->dspbox_size, - fw_ready->hostbox_offset, - fw_ready->hostbox_size); - /* make sure ABI version is compatible */ ret = snd_sof_ipc_valid(sdev); if (ret < 0) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 107d711efc3f05..21a089f4b104dd 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -237,11 +237,6 @@ static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, sizeof(*fw_ready)); - snd_sof_dsp_mailbox_init(sdev, fw_ready->dspbox_offset, - fw_ready->dspbox_size, - fw_ready->hostbox_offset, - fw_ready->hostbox_size); - /* make sure ABI version is compatible */ ret = snd_sof_ipc_valid(sdev); if (ret < 0) From cd9a4d5e5802704bd01429659e16f79e384ef071 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 30 Jul 2019 22:37:49 +0300 Subject: [PATCH 1584/1995] ASoC: SOF: Introduce snd_sof_dsp_get_mailbox_offset This will allow us to export mailbox offset in order to read the fw_ready message from. Signed-off-by: Daniel Baluta --- sound/soc/sof/ops.h | 9 +++++++++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 793c1aea0c53b3..c820606f19a176 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -119,6 +119,15 @@ static inline int snd_sof_dsp_get_bar_index(struct snd_sof_dev *sdev, u32 type) return sdev->mmio_bar; } +static inline int snd_sof_dsp_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + if (sof_ops(sdev)->get_mailbox_offset) + return sof_ops(sdev)->get_mailbox_offset(sdev); + + dev_err(sdev->dev, "error: %s not defined\n", __func__); + return -ENOTSUPP; +} + /* power management */ static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index b4243a4e877e55..d4e063ffc5152c 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -198,6 +198,8 @@ struct snd_sof_dsp_ops { /* misc */ int (*get_bar_index)(struct snd_sof_dev *sdev, u32 type); /* optional */ + int (*get_mailbox_offset)(struct snd_sof_dev *sdev);/* mandatory for common loader code */ + /* DAI ops */ struct snd_soc_dai_driver *drv; int num_drv; From af4fef217149105e122d76f13332dfac80aa8b93 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 2 Aug 2019 00:29:45 +0300 Subject: [PATCH 1585/1995] ASoC: SOF: Introduce snd_sof_dsp_get_window_offset This will allow us to export the offset for a memory window. Signed-off-by: Daniel Baluta --- sound/soc/sof/ops.h | 9 +++++++++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index c820606f19a176..824d36fe59fd0d 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -128,6 +128,15 @@ static inline int snd_sof_dsp_get_mailbox_offset(struct snd_sof_dev *sdev) return -ENOTSUPP; } +static inline int snd_sof_dsp_get_window_offset(struct snd_sof_dev *sdev, + u32 id) +{ + if (sof_ops(sdev)->get_window_offset) + return sof_ops(sdev)->get_window_offset(sdev, id); + + dev_err(sdev->dev, "error: %s not defined\n", __func__); + return -ENOTSUPP; +} /* power management */ static inline int snd_sof_dsp_resume(struct snd_sof_dev *sdev) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index d4e063ffc5152c..1949cf1fbe34f3 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -199,6 +199,8 @@ struct snd_sof_dsp_ops { int (*get_bar_index)(struct snd_sof_dev *sdev, u32 type); /* optional */ int (*get_mailbox_offset)(struct snd_sof_dev *sdev);/* mandatory for common loader code */ + int (*get_window_offset)(struct snd_sof_dev *sdev, + u32 id);/* mandatory for common loader code */ /* DAI ops */ struct snd_soc_dai_driver *drv; From 91ba196c17ce8202b8554e9ad12efd2a2e74f21a Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 30 Jul 2019 17:59:42 +0300 Subject: [PATCH 1586/1995] ASoC: SOF: Intel: byt: Refactor fw ready / mem windows creation There is a lot of duplicate code when processing IPC firmware ready notification and creating memory windows. First step in reducing the code duplication is to introduce generic functions: * sof_get_windows * sof_fw_ready that will replace, in the first step, the specific implementation related to baytrail related platforms: * byt_get_windows * byt_fw_ready So we are basically moving code from intel/byt.c to loader.c keeping in mind that mbox_offset is a per platform constant so we need to use newly introduced snd_sof_dsp_get_mailbox_offset / snd_sof_dsp_get_window_offset in order to get the correct mbox offset / window offset value. Also, bar is a per platform constant so we use snd_sof_dsp_get_bar_index instead of the hardcoded BYT_DSP_BAR. Signed-off-by: Daniel Baluta --- sound/soc/sof/intel/byt.c | 164 +++++-------------------------------- sound/soc/sof/loader.c | 168 ++++++++++++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 2 + 3 files changed, 189 insertions(+), 145 deletions(-) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 21a089f4b104dd..3c5229aa46dd45 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -109,148 +109,6 @@ static void byt_host_done(struct snd_sof_dev *sdev); static void byt_dsp_done(struct snd_sof_dev *sdev); static void byt_get_reply(struct snd_sof_dev *sdev); -/* - * IPC Firmware ready. - */ -static void byt_get_windows(struct snd_sof_dev *sdev) -{ - struct sof_ipc_window_elem *elem; - u32 outbox_offset = 0; - u32 stream_offset = 0; - u32 inbox_offset = 0; - u32 outbox_size = 0; - u32 stream_size = 0; - u32 inbox_size = 0; - int i; - - if (!sdev->info_window) { - dev_err(sdev->dev, "error: have no window info\n"); - return; - } - - for (i = 0; i < sdev->info_window->num_windows; i++) { - elem = &sdev->info_window->window[i]; - - switch (elem->type) { - case SOF_IPC_REGION_UPBOX: - inbox_offset = elem->offset + MBOX_OFFSET; - inbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - inbox_offset, - elem->size, "inbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DOWNBOX: - outbox_offset = elem->offset + MBOX_OFFSET; - outbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - outbox_offset, - elem->size, "outbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "etrace", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "debug", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_STREAM: - stream_offset = elem->offset + MBOX_OFFSET; - stream_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - stream_offset, - elem->size, "stream", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_REGS: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "regs", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_EXCEPTION: - sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BYT_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "exception", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - default: - dev_err(sdev->dev, "error: get illegal window info\n"); - return; - } - } - - if (outbox_size == 0 || inbox_size == 0) { - dev_err(sdev->dev, "error: get illegal mailbox window\n"); - return; - } - - snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, - outbox_offset, outbox_size); - sdev->stream_box.offset = stream_offset; - sdev->stream_box.size = stream_size; - - dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", - inbox_offset, inbox_size); - dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", - outbox_offset, outbox_size); - dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", - stream_offset, stream_size); -} - -/* check for ABI compatibility and create memory windows on first boot */ -static int byt_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) -{ - struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; - u32 offset; - int ret; - - /* mailbox must be on 4k boundary */ - offset = MBOX_OFFSET; - - dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n", - msg_id, offset); - - /* no need to re-check version/ABI for subsequent boots */ - if (!sdev->first_boot) - return 0; - - /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, - sizeof(*fw_ready)); - - /* make sure ABI version is compatible */ - ret = snd_sof_ipc_valid(sdev); - if (ret < 0) - return ret; - - /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + - sizeof(struct sof_ipc_fw_ready)); - - byt_get_windows(sdev); - - return 0; -} - /* * Debug */ @@ -418,6 +276,16 @@ static void byt_get_reply(struct snd_sof_dev *sdev) msg->reply_error = ret; } +static int byt_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return MBOX_OFFSET; +} + +static int byt_get_window_offset(struct snd_sof_dev *sdev, u32 id) +{ + return MBOX_OFFSET; +} + static void byt_host_done(struct snd_sof_dev *sdev) { /* clear BUSY bit and set DONE bit - accept new messages */ @@ -612,7 +480,9 @@ const struct snd_sof_dsp_ops sof_tng_ops = { /* ipc */ .send_msg = byt_send_msg, - .fw_ready = byt_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = byt_get_mailbox_offset, + .get_window_offset = byt_get_window_offset, .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, @@ -774,7 +644,9 @@ const struct snd_sof_dsp_ops sof_byt_ops = { /* ipc */ .send_msg = byt_send_msg, - .fw_ready = byt_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = byt_get_mailbox_offset, + .get_window_offset = byt_get_window_offset, .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, @@ -831,7 +703,9 @@ const struct snd_sof_dsp_ops sof_cht_ops = { /* ipc */ .send_msg = byt_send_msg, - .fw_ready = byt_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = byt_get_mailbox_offset, + .get_window_offset = byt_get_window_offset, .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 93cb8fd0844fa6..d7f32745fefe42 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -87,6 +87,174 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) } EXPORT_SYMBOL(snd_sof_fw_parse_ext_data); +/* + * IPC Firmware ready. + */ +static void sof_get_windows(struct snd_sof_dev *sdev) +{ + struct sof_ipc_window_elem *elem; + u32 outbox_offset = 0; + u32 stream_offset = 0; + u32 inbox_offset = 0; + u32 outbox_size = 0; + u32 stream_size = 0; + u32 inbox_size = 0; + int window_offset; + int bar; + int i; + + if (!sdev->info_window) { + dev_err(sdev->dev, "error: have no window info\n"); + return; + } + + bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM); + if (bar < 0) { + dev_err(sdev->dev, "error: have no bar mapping\n"); + return; + } + + for (i = 0; i < sdev->info_window->num_windows; i++) { + elem = &sdev->info_window->window[i]; + + window_offset = snd_sof_dsp_get_window_offset(sdev, elem->id); + if (window_offset < 0) { + dev_warn(sdev->dev, "warn: no offset for window %d\n", + elem->id); + continue; + } + + switch (elem->type) { + case SOF_IPC_REGION_UPBOX: + inbox_offset = window_offset + elem->offset; + inbox_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + inbox_offset, + elem->size, "inbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_DOWNBOX: + outbox_offset = window_offset + elem->offset; + outbox_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + outbox_offset, + elem->size, "outbox", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_TRACE: + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + window_offset + + elem->offset, + elem->size, "etrace", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_DEBUG: + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + window_offset + + elem->offset, + elem->size, "debug", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_STREAM: + stream_offset = window_offset + elem->offset; + stream_size = elem->size; + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + stream_offset, + elem->size, "stream", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_REGS: + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + window_offset + + elem->offset, + elem->size, "regs", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + case SOF_IPC_REGION_EXCEPTION: + sdev->dsp_oops_offset = window_offset + elem->offset; + snd_sof_debugfs_io_item(sdev, + sdev->bar[bar] + + window_offset + + elem->offset, + elem->size, "exception", + SOF_DEBUGFS_ACCESS_D0_ONLY); + break; + default: + dev_err(sdev->dev, "error: get illegal window info\n"); + return; + } + } + + if (outbox_size == 0 || inbox_size == 0) { + dev_err(sdev->dev, "error: get illegal mailbox window\n"); + return; + } + + snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, + outbox_offset, outbox_size); + sdev->stream_box.offset = stream_offset; + sdev->stream_box.size = stream_size; + + dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", + inbox_offset, inbox_size); + dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", + outbox_offset, outbox_size); + dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", + stream_offset, stream_size); +} + +/* check for ABI compatibility and create memory windows on first boot */ +int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) +{ + struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; + int offset; + int bar; + int ret; + + /* mailbox must be on 4k boundary */ + offset = snd_sof_dsp_get_mailbox_offset(sdev); + if (offset < 0) { + dev_err(sdev->dev, "error: have no mailbox offset\n"); + return offset; + } + + bar = snd_sof_dsp_get_bar_index(sdev, SOF_FW_BLK_TYPE_SRAM); + if (bar < 0) { + dev_err(sdev->dev, "error: have no bar mapping\n"); + return -EINVAL; + } + + dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n", + msg_id, offset); + + /* no need to re-check version/ABI for subsequent boots */ + if (!sdev->first_boot) + return 0; + + /* copy data from the DSP FW ready offset */ + sof_block_read(sdev, bar, offset, fw_ready, sizeof(*fw_ready)); + + /* make sure ABI version is compatible */ + ret = snd_sof_ipc_valid(sdev); + if (ret < 0) + return ret; + + /* now check for extended data */ + snd_sof_fw_parse_ext_data(sdev, bar, offset + + sizeof(struct sof_ipc_fw_ready)); + + sof_get_windows(sdev); + + return 0; +} +EXPORT_SYMBOL(sof_fw_ready); + /* generic module parser for mmaped DSPs */ int snd_sof_parse_module_memcpy(struct snd_sof_dev *sdev, struct snd_sof_mod_hdr *module) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 1949cf1fbe34f3..467b49530b4888 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -644,6 +644,8 @@ void sof_block_write(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *src, void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, size_t size); +int sof_fw_ready(struct snd_sof_dev *sdev, u32 msg_id); + void intel_ipc_msg_data(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, void *p, size_t sz); From 6235f9f1c78d120859e9e87d4c5ebf3f7ae92d63 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 30 Jul 2019 21:31:18 +0300 Subject: [PATCH 1587/1995] ASoC: SOF: Intel: bdw: Use generic function for fw ready / mem windows creation bdw_get_windows / bdw_fw_ready is identical with the generic implementation introduced in a previous patch. So remove bdw_get_windows / bdw_fw_ready and use the generic sof_get_windows version. Do not forget to implement get_mailbox_offset/get_window_offset so that we export the correct mailbox/memory window offset to the outside world. Signed-off-by: Daniel Baluta --- sound/soc/sof/intel/bdw.c | 156 ++++---------------------------------- 1 file changed, 13 insertions(+), 143 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 39f7ffefbef2e1..1c53c0e230143c 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -327,148 +327,6 @@ static irqreturn_t bdw_irq_thread(int irq, void *context) return IRQ_HANDLED; } -/* - * IPC Firmware ready. - */ -static void bdw_get_windows(struct snd_sof_dev *sdev) -{ - struct sof_ipc_window_elem *elem; - u32 outbox_offset = 0; - u32 stream_offset = 0; - u32 inbox_offset = 0; - u32 outbox_size = 0; - u32 stream_size = 0; - u32 inbox_size = 0; - int i; - - if (!sdev->info_window) { - dev_err(sdev->dev, "error: have no window info\n"); - return; - } - - for (i = 0; i < sdev->info_window->num_windows; i++) { - elem = &sdev->info_window->window[i]; - - switch (elem->type) { - case SOF_IPC_REGION_UPBOX: - inbox_offset = elem->offset + MBOX_OFFSET; - inbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - inbox_offset, - elem->size, "inbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DOWNBOX: - outbox_offset = elem->offset + MBOX_OFFSET; - outbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - outbox_offset, - elem->size, "outbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "etrace", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "debug", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_STREAM: - stream_offset = elem->offset + MBOX_OFFSET; - stream_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - stream_offset, - elem->size, "stream", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_REGS: - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "regs", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_EXCEPTION: - sdev->dsp_oops_offset = elem->offset + MBOX_OFFSET; - snd_sof_debugfs_io_item(sdev, - sdev->bar[BDW_DSP_BAR] + - elem->offset + - MBOX_OFFSET, - elem->size, "exception", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - default: - dev_err(sdev->dev, "error: get illegal window info\n"); - return; - } - } - - if (outbox_size == 0 || inbox_size == 0) { - dev_err(sdev->dev, "error: get illegal mailbox window\n"); - return; - } - - snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, - outbox_offset, outbox_size); - sdev->stream_box.offset = stream_offset; - sdev->stream_box.size = stream_size; - - dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", - inbox_offset, inbox_size); - dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", - outbox_offset, outbox_size); - dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", - stream_offset, stream_size); -} - -/* check for ABI compatibility and create memory windows on first boot */ -static int bdw_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) -{ - struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; - u32 offset; - int ret; - - /* mailbox must be on 4k boundary */ - offset = MBOX_OFFSET; - - dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset %d\n", - msg_id, offset); - - /* no need to re-check version/ABI for subsequent boots */ - if (!sdev->first_boot) - return 0; - - /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, - sizeof(*fw_ready)); - - /* make sure ABI version is compatible */ - ret = snd_sof_ipc_valid(sdev); - if (ret < 0) - return ret; - - /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, MBOX_OFFSET + - sizeof(struct sof_ipc_fw_ready)); - - bdw_get_windows(sdev); - - return 0; -} - /* * IPC Mailbox IO */ @@ -522,6 +380,16 @@ static void bdw_get_reply(struct snd_sof_dev *sdev) msg->reply_error = ret; } +static int bdw_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return MBOX_OFFSET; +} + +static int bdw_get_window_offset(struct snd_sof_dev *sdev, u32 id) +{ + return MBOX_OFFSET; +} + static void bdw_host_done(struct snd_sof_dev *sdev) { /* clear BUSY bit and set DONE bit - accept new messages */ @@ -675,7 +543,9 @@ const struct snd_sof_dsp_ops sof_bdw_ops = { /* ipc */ .send_msg = bdw_send_msg, - .fw_ready = bdw_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = bdw_get_mailbox_offset, + .get_window_offset = bdw_get_window_offset, .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, From ad938a41967f265e58bb55fd0ce19fb32d25118d Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 1 Aug 2019 15:52:51 +0300 Subject: [PATCH 1588/1995] ASoC: SOF: Intel: hda: Use generic function for fw ready / mem windows creation We can use generic sof_fw_ready function and reduce code duplication. Careful here that we need to provide the implementation for get_mailbox_offset and get_window_offset. Signed-off-by: Daniel Baluta --- sound/soc/sof/intel/apl.c | 4 +- sound/soc/sof/intel/cnl.c | 4 +- sound/soc/sof/intel/hda-ipc.c | 150 +--------------------------------- sound/soc/sof/intel/hda.h | 4 +- 4 files changed, 13 insertions(+), 149 deletions(-) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index fd2e26d7979619..8dc7a5558da4da 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -46,7 +46,9 @@ const struct snd_sof_dsp_ops sof_apl_ops = { /* ipc */ .send_msg = hda_dsp_ipc_send_msg, - .fw_ready = hda_dsp_ipc_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset, + .get_window_offset = hda_dsp_ipc_get_window_offset, .ipc_msg_data = hda_ipc_msg_data, .ipc_pcm_params = hda_ipc_pcm_params, diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index ffd8d43945374c..6d7d9c93252c81 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -204,7 +204,9 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { /* ipc */ .send_msg = cnl_ipc_send_msg, - .fw_ready = hda_dsp_ipc_fw_ready, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = hda_dsp_ipc_get_mailbox_offset, + .get_window_offset = hda_dsp_ipc_get_window_offset, .ipc_msg_data = hda_ipc_msg_data, .ipc_pcm_params = hda_ipc_pcm_params, diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 2ecba91f5219d6..6aae6f18b3dcaa 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -266,156 +266,14 @@ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) return ret; } -/* IPC Firmware ready */ - -static void ipc_get_windows(struct snd_sof_dev *sdev) +int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) { - struct sof_ipc_window_elem *elem; - u32 outbox_offset = 0; - u32 stream_offset = 0; - u32 inbox_offset = 0; - u32 outbox_size = 0; - u32 stream_size = 0; - u32 inbox_size = 0; - int i; - - if (!sdev->info_window) { - dev_err(sdev->dev, "error: have no window info\n"); - return; - } - - for (i = 0; i < sdev->info_window->num_windows; i++) { - elem = &sdev->info_window->window[i]; - - switch (elem->type) { - case SOF_IPC_REGION_UPBOX: - inbox_offset = - elem->offset + SRAM_WINDOW_OFFSET(elem->id); - inbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - inbox_offset, - elem->size, "inbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DOWNBOX: - outbox_offset = - elem->offset + SRAM_WINDOW_OFFSET(elem->id); - outbox_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - outbox_offset, - elem->size, "outbox", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_TRACE: - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "etrace", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_DEBUG: - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "debug", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_STREAM: - stream_offset = - elem->offset + SRAM_WINDOW_OFFSET(elem->id); - stream_size = elem->size; - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "stream", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_REGS: - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "regs", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - case SOF_IPC_REGION_EXCEPTION: - sdev->dsp_oops_offset = elem->offset + - SRAM_WINDOW_OFFSET(elem->id); - snd_sof_debugfs_io_item(sdev, - sdev->bar[HDA_DSP_BAR] + - elem->offset + - SRAM_WINDOW_OFFSET - (elem->id), - elem->size, "exception", - SOF_DEBUGFS_ACCESS_D0_ONLY); - break; - default: - dev_err(sdev->dev, "error: get illegal window info\n"); - return; - } - } - - if (outbox_size == 0 || inbox_size == 0) { - dev_err(sdev->dev, "error: get illegal mailbox window\n"); - return; - } - - snd_sof_dsp_mailbox_init(sdev, inbox_offset, inbox_size, - outbox_offset, outbox_size); - sdev->stream_box.offset = stream_offset; - sdev->stream_box.size = stream_size; - - dev_dbg(sdev->dev, " mailbox upstream 0x%x - size 0x%x\n", - inbox_offset, inbox_size); - dev_dbg(sdev->dev, " mailbox downstream 0x%x - size 0x%x\n", - outbox_offset, outbox_size); - dev_dbg(sdev->dev, " stream region 0x%x - size 0x%x\n", - stream_offset, stream_size); + return HDA_DSP_MBOX_UPLINK_OFFSET; } -/* check for ABI compatibility and create memory windows on first boot */ -int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id) +int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) { - struct sof_ipc_fw_ready *fw_ready = &sdev->fw_ready; - u32 offset; - int ret; - - /* mailbox must be on 4k boundary */ - offset = HDA_DSP_MBOX_UPLINK_OFFSET; - - dev_dbg(sdev->dev, "ipc: DSP is ready 0x%8.8x offset 0x%x\n", - msg_id, offset); - - /* no need to re-check version/ABI for subsequent boots */ - if (!sdev->first_boot) - return 0; - - /* copy data from the DSP FW ready offset */ - sof_block_read(sdev, sdev->mmio_bar, offset, fw_ready, - sizeof(*fw_ready)); - - /* make sure ABI version is compatible */ - ret = snd_sof_ipc_valid(sdev); - if (ret < 0) - return ret; - - /* now check for extended data */ - snd_sof_fw_parse_ext_data(sdev, sdev->mmio_bar, - HDA_DSP_MBOX_UPLINK_OFFSET + - sizeof(struct sof_ipc_fw_ready)); - - ipc_get_windows(sdev); - - return 0; + return SRAM_WINDOW_OFFSET(id); } void hda_ipc_msg_data(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index ceaaa8d467f4cf..9246ba776d68e8 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -519,7 +519,9 @@ int hda_ipc_pcm_params(struct snd_sof_dev *sdev, int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev); -int hda_dsp_ipc_fw_ready(struct snd_sof_dev *sdev, u32 msg_id); +int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev); +int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id); + irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context); irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context); int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); From dda8df4a84c7aceec2a63acfcd2400517237ccc7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 2 Aug 2019 13:04:36 -0500 Subject: [PATCH 1589/1995] ASoC: SOF: Intel: hda: fix MSI handling The addition of a kernel module parameter to optionally disable MSI had the side effect of permanently disabling it. The return value of pci_alloc_irq_vectors() is the number of allocated vectors or a negative number on error, so testing with the ! operator is not quite right. It was one optimization too far. Restore previous behavior to use MSI by default, unless the user selects not to do so or the allocation of irq_vectors fails. Fixes: 672ff5e3596ee ('ASoC: SOF: Intel: hda: add a parameter to disable MSI') Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 724a494702fa4f..c7de5065b96119 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -543,7 +543,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) * if it fails, use legacy interrupt mode * TODO: support msi multiple vectors */ - if (hda_use_msi && !pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI)) { + if (hda_use_msi && pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI) > 0) { dev_info(sdev->dev, "use msi interrupt mode\n"); hdev->irq = pci_irq_vector(pci, 0); /* ipc irq number is the same of hda irq */ From 53d775409a9df519a8f6bd3149e66a5ccb118d4c Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Wed, 22 May 2019 23:48:33 +0300 Subject: [PATCH 1590/1995] ASoC: SOF: topology: use set_get_data in process load Currently when loading sof process components there's a check if binary control data is associated with it. If found the data is extracted to be part of component loading and initialization. If binary data exceeds the ipc max size, loading fails with error as large message support is only implemented in set_get_data method. So make the process loading use set_get_data to enable large parameters in component initialization. Also refactor the process component loading function as it digs out 3 times almost identical information of related controls. This is redundant, looks ugly and makes it difficult to understand the mechanism. So make a function out of fetching the control data and use it in process loading. Signed-off-by: Jaska Uimonen --- sound/soc/sof/topology.c | 204 +++++++++++++++++++++++++-------------- 1 file changed, 130 insertions(+), 74 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 12b7d900b9c245..30b5638622ddd0 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -42,6 +42,13 @@ /* size of tplg abi in byte */ #define SOF_TPLG_ABI_SIZE 3 +struct sof_widget_data { + int ctrl_type; + int ipc_cmd; + struct sof_abi_hdr *pdata; + struct snd_sof_control *control; +}; + /* send pcm params ipc */ static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir) { @@ -1742,51 +1749,32 @@ static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index, return ret; } -static int sof_process_load(struct snd_soc_component *scomp, int index, - struct snd_sof_widget *swidget, - struct snd_soc_tplg_dapm_widget *tw, - struct sof_ipc_comp_reply *r, - int type) +static size_t sof_get_control_data(struct snd_sof_dev *sdev, + struct snd_soc_dapm_widget *widget, + struct sof_widget_data *wdata) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_tplg_private *private = &tw->priv; - struct snd_soc_dapm_widget *widget = swidget->widget; const struct snd_kcontrol_new *kc; - struct soc_bytes_ext *sbe; struct soc_mixer_control *sm; + struct soc_bytes_ext *sbe; struct soc_enum *se; - struct snd_sof_control *scontrol = NULL; - struct sof_abi_hdr *pdata = NULL; - struct sof_ipc_comp_process *process; - size_t ipc_size, ipc_data_size = 0; - int ret, i, offset = 0; - - if (type == SOF_COMP_NONE) { - dev_err(sdev->dev, "error: invalid process comp type %d\n", - type); - return -EINVAL; - } + size_t size = 0; + int i; - /* - * get possible component controls - get size of all pdata, - * then memcpy with headers - */ for (i = 0; i < widget->num_kcontrols; i++) { - kc = &widget->kcontrol_news[i]; switch (widget->dobj.widget.kcontrol_type) { case SND_SOC_TPLG_TYPE_MIXER: sm = (struct soc_mixer_control *)kc->private_value; - scontrol = sm->dobj.private; + wdata[i].control = sm->dobj.private; break; case SND_SOC_TPLG_TYPE_BYTES: sbe = (struct soc_bytes_ext *)kc->private_value; - scontrol = sbe->dobj.private; + wdata[i].control = sbe->dobj.private; break; case SND_SOC_TPLG_TYPE_ENUM: se = (struct soc_enum *)kc->private_value; - scontrol = se->dobj.private; + wdata[i].control = se->dobj.private; break; default: dev_err(sdev->dev, "error: unknown kcontrol type %d in widget %s\n", @@ -1795,31 +1783,98 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, return -EINVAL; } - if (!scontrol) { + if (!wdata[i].control) { dev_err(sdev->dev, "error: no scontrol for widget %s\n", widget->name); return -EINVAL; } - /* don't include if no private data */ - pdata = scontrol->control_data->data; - if (!pdata) - continue; + wdata[i].pdata = wdata[i].control->control_data->data; + if (!wdata[i].pdata) + return -EINVAL; /* make sure data is valid - data can be updated at runtime */ - if (pdata->magic != SOF_ABI_MAGIC) - continue; + if (wdata[i].pdata->magic != SOF_ABI_MAGIC) + return -EINVAL; + + size += wdata[i].pdata->size; - ipc_data_size += pdata->size; + /* get data type */ + switch (wdata[i].control->cmd) { + case SOF_CTRL_CMD_VOLUME: + case SOF_CTRL_CMD_ENUM: + case SOF_CTRL_CMD_SWITCH: + wdata[i].ipc_cmd = SOF_IPC_COMP_SET_VALUE; + wdata[i].ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET; + break; + case SOF_CTRL_CMD_BINARY: + wdata[i].ipc_cmd = SOF_IPC_COMP_SET_DATA; + wdata[i].ctrl_type = SOF_CTRL_TYPE_DATA_SET; + break; + default: + break; + } + } + + return size; +} + +static int sof_process_load(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r, + int type) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_dapm_widget *widget = swidget->widget; + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_process *process = NULL; + struct sof_widget_data *wdata = NULL; + size_t ipc_data_size = 0; + size_t ipc_size; + int offset = 0; + int ret = 0; + int i; + + if (type == SOF_COMP_NONE) { + dev_err(sdev->dev, "error: invalid process comp type %d\n", + type); + return -EINVAL; + } + + /* allocate struct for widget control data sizes and types */ + if (widget->num_kcontrols) { + wdata = kcalloc(widget->num_kcontrols, + sizeof(*wdata), + GFP_KERNEL); + + if (!wdata) + return -ENOMEM; + + /* get possible component controls and get size of all pdata */ + ipc_data_size = sof_get_control_data(sdev, widget, wdata); + + if (ipc_data_size <= 0) { + kfree(wdata); + return ipc_data_size; + } } ipc_size = sizeof(struct sof_ipc_comp_process) + le32_to_cpu(private->size) + ipc_data_size; + /* we are exceeding max ipc size, config needs to be sent separately */ + if (ipc_size > SOF_IPC_MSG_MAX_SIZE) { + ipc_size -= ipc_data_size; + ipc_data_size = 0; + } + process = kzalloc(ipc_size, GFP_KERNEL); - if (!process) + if (!process) { + kfree(wdata); return -ENOMEM; + } /* configure iir IPC message */ process->comp.hdr.size = ipc_size; @@ -1835,7 +1890,9 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, if (ret != 0) { dev_err(sdev->dev, "error: parse process.cfg tokens failed %d\n", le32_to_cpu(private->size)); - goto err; + kfree(wdata); + kfree(process); + return ret; } sof_dbg_comp_config(scomp, &process->config); @@ -1845,40 +1902,13 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, * get possible component controls - get size of all pdata, * then memcpy with headers */ - for (i = 0; i < widget->num_kcontrols; i++) { - kc = &widget->kcontrol_news[i]; - - switch (widget->dobj.widget.kcontrol_type) { - case SND_SOC_TPLG_TYPE_MIXER: - sm = (struct soc_mixer_control *)kc->private_value; - scontrol = sm->dobj.private; - break; - case SND_SOC_TPLG_TYPE_BYTES: - sbe = (struct soc_bytes_ext *)kc->private_value; - scontrol = sbe->dobj.private; - break; - case SND_SOC_TPLG_TYPE_ENUM: - se = (struct soc_enum *)kc->private_value; - scontrol = se->dobj.private; - break; - default: - dev_err(sdev->dev, "error: unknown kcontrol type %d in widget %s\n", - widget->dobj.widget.kcontrol_type, - widget->name); - return -EINVAL; + if (ipc_data_size) { + for (i = 0; i < widget->num_kcontrols; i++) { + memcpy(&process->data + offset, + wdata[i].pdata->data, + wdata[i].pdata->size); + offset += wdata[i].pdata->size; } - - /* don't include if no private data */ - pdata = scontrol->control_data->data; - if (!pdata) - continue; - - /* make sure data is valid - data can be updated at runtime */ - if (pdata->magic != SOF_ABI_MAGIC) - continue; - - memcpy(&process->data + offset, pdata->data, pdata->size); - offset += pdata->size; } process->size = ipc_data_size; @@ -1886,10 +1916,36 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, ret = sof_ipc_tx_message(sdev->ipc, process->comp.hdr.cmd, process, ipc_size, r, sizeof(*r)); - if (ret >= 0) + + if (ret < 0) { + dev_err(sdev->dev, "error: create process failed\n"); + kfree(wdata); + kfree(process); return ret; -err: - kfree(process); + } + + /* we sent the data in single message so return */ + if (ipc_data_size) { + kfree(wdata); + return ret; + } + + /* send control data with large message supported method */ + for (i = 0; i < widget->num_kcontrols; i++) { + wdata[i].control->readback_offset = 0; + ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, wdata[i].control, + wdata[i].ipc_cmd, + wdata[i].ctrl_type, + wdata[i].control->cmd, + true); + if (ret != 0) { + dev_err(sdev->dev, "error: send control failed\n"); + kfree(process); + break; + } + } + + kfree(wdata); return ret; } From c936ca7629ae18592690203bea33157be5ea7df8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 7 Aug 2019 21:35:28 -0500 Subject: [PATCH 1591/1995] ASoC: soc-core: fix module_put() warning in soc_cleanup_component The recent changes introduce warnings in the SOF load/unload module tests. The code does not seem balanced with a confusion between _close() and _remove() macros. Using _remove() fixes the issue and removes the warning. Suggested-by: Ranjani Sridharan Fixes: 4a81e8f30d0b4 ('ASoC: soc-component: add snd_soc_component_get/put()') Signed-off-by: Pierre-Louis Bossart --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index bb1e9e2c4ff464..00e8ad122ce727 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -924,7 +924,7 @@ static void soc_cleanup_component(struct snd_soc_component *component) snd_soc_dapm_free(snd_soc_component_get_dapm(component)); soc_cleanup_component_debugfs(component); component->card = NULL; - snd_soc_component_module_put_when_close(component); + snd_soc_component_module_put_when_remove(component); } static void soc_remove_component(struct snd_soc_component *component) From c1dcaba9c6d1a7d34891abd1025526c47ea71c33 Mon Sep 17 00:00:00 2001 From: Sathya Prakash M R Date: Tue, 23 Jul 2019 09:13:56 +0530 Subject: [PATCH 1592/1995] ASoC: Intel: boards: Match Product Family instead of product The generic machine driver of sof_rt5682 supports more platforms of same product family. hence match the product family instead of product name. Signed-off-by: Sathya Prakash M R --- sound/soc/intel/boards/sof_rt5682.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index daeaa396d92817..c1181bc0119e82 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -91,8 +91,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { { .callback = sof_rt5682_quirk_cb, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), - DMI_MATCH(DMI_PRODUCT_NAME, "Hatch"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Hatch"), }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | SOF_RT5682_MCLK_24MHZ | From ac1153f9dac643a52246b0abee44ae415113ea1e Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Thu, 8 Aug 2019 17:08:32 +0800 Subject: [PATCH 1593/1995] ASoC: Intel: sof-rt5682: add dmic dapm widget to support dmic PCM We need add DAPM MIC endpoint widget "SoC DMIC" and route, to enable DMIC PCM DAPM support. Signed-off-by: Keyon Jie --- sound/soc/intel/boards/sof_rt5682.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index c1181bc0119e82..a437567b8cee23 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -308,6 +308,7 @@ static const struct snd_soc_dapm_widget sof_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Spk", NULL), + SND_SOC_DAPM_MIC("SoC DMIC", NULL), }; static const struct snd_soc_dapm_route sof_map[] = { @@ -318,6 +319,9 @@ static const struct snd_soc_dapm_route sof_map[] = { /* other jacks */ { "IN1P", NULL, "Headset Mic" }, + /* digital mics */ + {"DMic", NULL, "SoC DMIC"}, + }; static const struct snd_soc_dapm_route speaker_map[] = { From e6773a7ccf1a7a74bc117e6b96a72a6aa5aebc85 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 9 Aug 2019 09:36:52 +0800 Subject: [PATCH 1594/1995] ASoC: Intel: skl-hda-dsp-generic: add dependency to dmic driver The hda generic machine actually has dependency on the dmic driver, select SND_SOC_DMIC at the machine selected to fix it. Signed-off-by: Keyon Jie --- sound/soc/intel/boards/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 755e884a475447..b651f91069dc5b 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -411,6 +411,7 @@ if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH tristate "SKL/KBL/BXT/APL with HDA Codecs" select SND_SOC_HDAC_HDMI + select SND_SOC_DMIC # SND_SOC_HDAC_HDA is already selected help This adds support for ASoC machine driver for Intel platforms From d284494b2676f415e073f059db434ea65a0a27f3 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 9 Aug 2019 09:54:43 +0800 Subject: [PATCH 1595/1995] ASoC: Intel: skl-hda-dsp-generic: add dmic dapm widget and route Adding DAPM MIC endpoint widget "SoC DMIC" and route, to enable DMIC DAPM support with hda generic machine. Signed-off-by: Keyon Jie --- sound/soc/intel/boards/skl_hda_dsp_generic.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 9ed68eb4f058ca..1778acdc367c4e 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -23,6 +23,7 @@ static const struct snd_soc_dapm_widget skl_hda_widgets[] = { SND_SOC_DAPM_MIC("Alt Analog In", NULL), SND_SOC_DAPM_SPK("Digital Out", NULL), SND_SOC_DAPM_MIC("Digital In", NULL), + SND_SOC_DAPM_MIC("SoC DMIC", NULL), }; static const struct snd_soc_dapm_route skl_hda_map[] = { @@ -41,6 +42,9 @@ static const struct snd_soc_dapm_route skl_hda_map[] = { { "Codec Input Pin2", NULL, "Digital In" }, { "Codec Input Pin3", NULL, "Alt Analog In" }, + /* digital mics */ + {"DMic", NULL, "SoC DMIC"}, + /* CODEC BE connections */ { "Analog Codec Playback", NULL, "Analog CPU Playback" }, { "Analog CPU Playback", NULL, "codec0_out" }, From 4730d842646f8cd22c0bc397b5f41202fa4a997b Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 7 Aug 2019 13:25:53 -0700 Subject: [PATCH 1596/1995] ASoC: SOF: topology: Improve error handling in sof_process_load() Improve the error handling paths in sof_process_load() by moving the freeing of wdata and process to the end. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/topology.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 30b5638622ddd0..9cffea1423954e 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1855,8 +1855,8 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, ipc_data_size = sof_get_control_data(sdev, widget, wdata); if (ipc_data_size <= 0) { - kfree(wdata); - return ipc_data_size; + ret = ipc_data_size; + goto out; } } @@ -1872,8 +1872,8 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, process = kzalloc(ipc_size, GFP_KERNEL); if (!process) { - kfree(wdata); - return -ENOMEM; + ret = -ENOMEM; + goto out; } /* configure iir IPC message */ @@ -1890,9 +1890,7 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, if (ret != 0) { dev_err(sdev->dev, "error: parse process.cfg tokens failed %d\n", le32_to_cpu(private->size)); - kfree(wdata); - kfree(process); - return ret; + goto err; } sof_dbg_comp_config(scomp, &process->config); @@ -1919,16 +1917,12 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, if (ret < 0) { dev_err(sdev->dev, "error: create process failed\n"); - kfree(wdata); - kfree(process); - return ret; + goto err; } /* we sent the data in single message so return */ - if (ipc_data_size) { - kfree(wdata); - return ret; - } + if (ipc_data_size) + goto out; /* send control data with large message supported method */ for (i = 0; i < widget->num_kcontrols; i++) { @@ -1940,11 +1934,14 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, true); if (ret != 0) { dev_err(sdev->dev, "error: send control failed\n"); - kfree(process); break; } } +err: + if (ret < 0) + kfree(process); +out: kfree(wdata); return ret; } From 58296cedfc03254a0dbca57bb5bfed6345b39db3 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 7 Aug 2019 13:36:22 +0300 Subject: [PATCH 1597/1995] ASoC: SOF: Add OF DSP device support Add support for device tree based SOF DSP devices. Signed-off-by: Daniel Baluta --- sound/soc/sof/Kconfig | 10 +++ sound/soc/sof/Makefile | 3 + sound/soc/sof/sof-of-dev.c | 143 +++++++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 sound/soc/sof/sof-of-dev.c diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 5b41628ad72229..73c455dacab55c 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -36,6 +36,16 @@ config SND_SOC_SOF_ACPI Say Y if you need this option If unsure select "N". +config SND_SOC_SOF_OF + tristate "SOF OF enumeration support" + depends on OF || COMPILE_TEST + select SND_SOC_SOF + select SND_SOC_SOF_OPTIONS + help + This adds support for Device Tree enumeration. This option is + required to enable i.MX8 devices. + Say Y if you need this option. If unsure select "N". + config SND_SOC_SOF_OPTIONS tristate help diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 474474a4c7884d..051569079248d8 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -7,6 +7,8 @@ snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ snd-sof-pci-objs := sof-pci-dev.o snd-sof-acpi-objs := sof-acpi-dev.o +snd-sof-of-objs := sof-of-dev.o + snd-sof-nocodec-objs := nocodec.o obj-$(CONFIG_SND_SOC_SOF) += snd-sof.o @@ -14,6 +16,7 @@ obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o obj-$(CONFIG_SND_SOC_SOF_ACPI) += snd-sof-acpi.o +obj-$(CONFIG_SND_SOC_SOF_OF) += snd-sof-of.o obj-$(CONFIG_SND_SOC_SOF_PCI) += snd-sof-pci.o obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/ diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c new file mode 100644 index 00000000000000..28a9692974e51d --- /dev/null +++ b/sound/soc/sof/sof-of-dev.c @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// Copyright 2019 NXP +// +// Author: Daniel Baluta +// + +#include +#include +#include +#include + +#include "ops.h" + +extern struct snd_sof_dsp_ops sof_imx8_ops; + +/* platform specific devices */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8) +static struct sof_dev_desc sof_of_imx8qxp_desc = { + .default_fw_path = "imx/sof", + .default_tplg_path = "imx/sof-tplg", + .nocodec_fw_filename = "sof-imx8.ri", + .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", + .ops = &sof_imx8_ops, +}; +#endif + +static const struct dev_pm_ops sof_of_pm = { + SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) + SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, + NULL) +}; + +static void sof_of_probe_complete(struct device *dev) +{ + /* allow runtime_pm */ + pm_runtime_set_autosuspend_delay(dev, SND_SOF_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); +} + +static int sof_of_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct sof_dev_desc *desc; + /*TODO: create a generic snd_soc_xxx_mach */ + struct snd_soc_acpi_mach *mach; + struct snd_sof_pdata *sof_pdata; + const struct snd_sof_dsp_ops *ops; + int ret; + + dev_info(&pdev->dev, "DT DSP detected"); + + sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); + if (!sof_pdata) + return -ENOMEM; + + desc = device_get_match_data(dev); + if (!desc) + return -ENODEV; + + /* get ops for platform */ + ops = desc->ops; + if (!ops) { + dev_err(dev, "error: no matching DT descriptor ops\n"); + return -ENODEV; + } + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) + /* force nocodec mode */ + dev_warn(dev, "Force to use nocodec mode\n"); + mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); + if (!mach) + return -ENOMEM; + ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); + if (ret < 0) + return ret; +#else + /* TODO: implement case where we actually have a codec */ + return -ENODEV; +#endif + + if (mach) + mach->mach_params.platform = dev_name(dev); + + sof_pdata->machine = mach; + sof_pdata->desc = desc; + sof_pdata->dev = &pdev->dev; + sof_pdata->platform = dev_name(dev); + + /* TODO: read alternate fw and tplg filenames from DT */ + sof_pdata->fw_filename_prefix = sof_pdata->desc->default_fw_path; + sof_pdata->tplg_filename_prefix = sof_pdata->desc->default_tplg_path; + +#if IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) + /* set callback to enable runtime_pm */ + sof_pdata->sof_probe_complete = sof_of_probe_complete; +#endif + /* call sof helper for DSP hardware probe */ + ret = snd_sof_device_probe(dev, sof_pdata); + if (ret) { + dev_err(dev, "error: failed to probe DSP hardware\n"); + return ret; + } + +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_PROBE_WORK_QUEUE) + sof_of_probe_complete(dev); +#endif + + return ret; +} + +static int sof_of_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + /* call sof helper for DSP hardware remove */ + snd_sof_device_remove(&pdev->dev); + + return 0; +} + +static const struct of_device_id sof_of_ids[] = { +#if IS_ENABLED(CONFIG_SND_SOC_SOF_IMX8) + { .compatible = "fsl,imx8qxp-dsp", .data = &sof_of_imx8qxp_desc}, +#endif + { } +}; +MODULE_DEVICE_TABLE(of, sof_of_ids); + +/* DT driver definition */ +static struct platform_driver snd_sof_of_driver = { + .probe = sof_of_probe, + .remove = sof_of_remove, + .driver = { + .name = "sof-audio-of", + .pm = &sof_of_pm, + .of_match_table = sof_of_ids, + }, +}; +module_platform_driver(snd_sof_of_driver); + +MODULE_LICENSE("Dual BSD/GPL"); From a2d424bee2ded26a26907c4363f5c7b1e2647625 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 7 Aug 2019 13:38:46 +0300 Subject: [PATCH 1598/1995] ASoC: SOF: imx: Add i.MX8 HW support Add support for the audio DSP hardware found on NXP i.MX8 platform. Signed-off-by: Daniel Baluta --- sound/soc/sof/Kconfig | 1 + sound/soc/sof/Makefile | 1 + sound/soc/sof/imx/Kconfig | 22 +++ sound/soc/sof/imx/Makefile | 4 + sound/soc/sof/imx/imx8.c | 394 +++++++++++++++++++++++++++++++++++++ 5 files changed, 422 insertions(+) create mode 100644 sound/soc/sof/imx/Kconfig create mode 100644 sound/soc/sof/imx/Makefile create mode 100644 sound/soc/sof/imx/imx8.c diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 73c455dacab55c..cc592bcadae710 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -181,6 +181,7 @@ config SND_SOC_SOF_PROBE_WORK_QUEUE When selected, the probe is handled in two steps, for example to avoid lockdeps if request_module is used in the probe. +source "sound/soc/sof/imx/Kconfig" source "sound/soc/sof/intel/Kconfig" source "sound/soc/sof/xtensa/Kconfig" diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 051569079248d8..3639f7c006600b 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -20,4 +20,5 @@ obj-$(CONFIG_SND_SOC_SOF_OF) += snd-sof-of.o obj-$(CONFIG_SND_SOC_SOF_PCI) += snd-sof-pci.o obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/ +obj-$(CONFIG_SND_SOC_SOF_IMX_TOPLEVEL) += imx/ obj-$(CONFIG_SND_SOC_SOF_XTENSA) += xtensa/ diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig new file mode 100644 index 00000000000000..fd73d8402dbf1c --- /dev/null +++ b/sound/soc/sof/imx/Kconfig @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) + +config SND_SOC_SOF_IMX_TOPLEVEL + bool "SOF support for NXP i.MX audio DSPs" + depends on ARM64 && SND_SOC_SOF_OF || COMPILE_TEST + help + This adds support for Sound Open Firmware for NXP i.MX platforms. + Say Y if you have such a device. + If unsure select "N". + +if SND_SOC_SOF_IMX_TOPLEVEL + +config SND_SOC_SOF_IMX8 + tristate "SOF support for i.MX8" + depends on IMX_SCU + depends on IMX_DSP + help + This adds support for Sound Open Firmware for NXP i.MX8 platforms + Say Y if you have such a device. + If unsure select "N". + +endif ## SND_SOC_SOF_IMX_IMX_TOPLEVEL diff --git a/sound/soc/sof/imx/Makefile b/sound/soc/sof/imx/Makefile new file mode 100644 index 00000000000000..6ef908e8c807cc --- /dev/null +++ b/sound/soc/sof/imx/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +snd-sof-imx8-objs := imx8.o + +obj-$(CONFIG_SND_SOC_SOF_IMX8) += snd-sof-imx8.o diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c new file mode 100644 index 00000000000000..e502f584207fa4 --- /dev/null +++ b/sound/soc/sof/imx/imx8.c @@ -0,0 +1,394 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// Copyright 2019 NXP +// +// Author: Daniel Baluta +// +// Hardware interface for audio DSP on i.MX8 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include "../ops.h" + +/* DSP memories */ +#define IRAM_OFFSET 0x10000 +#define IRAM_SIZE (2 * 1024) +#define DRAM0_OFFSET 0x0 +#define DRAM0_SIZE (32 * 1024) +#define DRAM1_OFFSET 0x8000 +#define DRAM1_SIZE (32 * 1024) +#define SYSRAM_OFFSET 0x18000 +#define SYSRAM_SIZE (256 * 1024) +#define SYSROM_OFFSET 0x58000 +#define SYSROM_SIZE (192 * 1024) + +#define RESET_VECTOR_VADDR 0x596f8000 + +#define MBOX_OFFSET 0x800000 +#define MBOX_SIZE 0x1000 + +struct imx8_priv { + struct device *dev; + struct snd_sof_dev *sdev; + + /* DSP IPC handler */ + struct imx_dsp_ipc *dsp_ipc; + struct platform_device *ipc_dev; + + /* System Controller IPC handler */ + struct imx_sc_ipc *sc_ipc; + + /* Power domain handling */ + int num_domains; + struct device **pd_dev; + struct device_link **link; + +}; + +static void imx8_get_reply(struct snd_sof_dev *sdev) +{ + struct snd_sof_ipc_msg *msg = sdev->msg; + struct sof_ipc_reply reply; + int ret = 0; + + if (!msg) { + dev_warn(sdev->dev, "unexpected ipc interrupt\n"); + return; + } + + /* get reply */ + sof_mailbox_read(sdev, sdev->host_box.offset, &reply, sizeof(reply)); + + if (reply.error < 0) { + memcpy(msg->reply_data, &reply, sizeof(reply)); + ret = reply.error; + } else { + /* reply has correct size? */ + if (reply.hdr.size != msg->reply_size) { + dev_err(sdev->dev, "error: reply expected %zu got %u bytes\n", + msg->reply_size, reply.hdr.size); + ret = -EINVAL; + } + + /* read the message */ + if (msg->reply_size > 0) + sof_mailbox_read(sdev, sdev->host_box.offset, + msg->reply_data, msg->reply_size); + } + + msg->reply_error = ret; +} + +static int imx8_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return MBOX_OFFSET; +} + +static int imx8_get_window_offset(struct snd_sof_dev *sdev, u32 id) +{ + return MBOX_OFFSET; +} + +void imx8_dsp_handle_reply(struct imx_dsp_ipc *ipc) +{ + struct imx8_priv *priv = imx_dsp_get_data(ipc); + unsigned long flags; + + spin_lock_irqsave(&priv->sdev->ipc_lock, flags); + imx8_get_reply(priv->sdev); + snd_sof_ipc_reply(priv->sdev, 0); + spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); +} + +void imx8_dsp_handle_request(struct imx_dsp_ipc *ipc) +{ + struct imx8_priv *priv = imx_dsp_get_data(ipc); + + snd_sof_ipc_msgs_rx(priv->sdev); +} + +struct imx_dsp_ops dsp_ops = { + .handle_reply = imx8_dsp_handle_reply, + .handle_request = imx8_dsp_handle_request, +}; + +static int imx8_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + struct imx8_priv *priv = (struct imx8_priv *)sdev->private; + + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + imx_dsp_ring_doorbell(priv->dsp_ipc, 0); + + return 0; +} + +/* + * DSP control. + */ +static int imx8_run(struct snd_sof_dev *sdev) +{ + struct imx8_priv *dsp_priv = (struct imx8_priv *)sdev->private; + int ret; + + ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, + IMX_SC_C_OFS_SEL, 1); + if (ret < 0) { + dev_err(sdev->dev, "Error system address offset source select\n"); + return ret; + } + + ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, + IMX_SC_C_OFS_AUDIO, 0x80); + if (ret < 0) { + dev_err(sdev->dev, "Error system address offset of AUDIO\n"); + return ret; + } + + ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, + IMX_SC_C_OFS_PERIPH, 0x5A); + if (ret < 0) { + dev_err(sdev->dev, "Error system address offset of PERIPH %d\n", + ret); + return ret; + } + + ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, + IMX_SC_C_OFS_IRQ, 0x51); + if (ret < 0) { + dev_err(sdev->dev, "Error system address offset of IRQ\n"); + return ret; + } + + imx_sc_pm_cpu_start(dsp_priv->sc_ipc, IMX_SC_R_DSP, true, + RESET_VECTOR_VADDR); + + return 0; +} + +static int imx8_probe(struct snd_sof_dev *sdev) +{ + struct platform_device *pdev = + container_of(sdev->dev, struct platform_device, dev); + struct device_node *np = pdev->dev.of_node; + struct device_node *res_node; + struct resource *mmio; + struct imx8_priv *priv; + struct resource res; + u32 base, size; + int ret = 0; + int i; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + sdev->private = priv; + priv->dev = sdev->dev; + priv->sdev = sdev; + + /* power up device associated power domains */ + priv->num_domains = of_count_phandle_with_args(np, "power-domains", + "#power-domain-cells"); + if (priv->num_domains < 0) { + dev_err(sdev->dev, "no power-domains property in %pOF\n", np); + return priv->num_domains; + } + + priv->pd_dev = devm_kmalloc_array(&pdev->dev, priv->num_domains, + sizeof(*priv->pd_dev), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->link = devm_kmalloc_array(&pdev->dev, priv->num_domains, + sizeof(*priv->link), GFP_KERNEL); + if (!priv->link) + return -ENOMEM; + + for (i = 0; i < priv->num_domains; i++) { + priv->pd_dev[i] = dev_pm_domain_attach_by_id(&pdev->dev, i); + if (IS_ERR(priv->pd_dev[i])) { + ret = PTR_ERR(priv->pd_dev[i]); + goto exit_unroll_pm; + } + priv->link[i] = device_link_add(&pdev->dev, priv->pd_dev[i], + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (IS_ERR(priv->link[i])) { + ret = PTR_ERR(priv->link[i]); + dev_pm_domain_detach(priv->pd_dev[i], false); + goto exit_unroll_pm; + } + } + + ret = imx_scu_get_handle(&priv->sc_ipc); + if (ret) { + dev_err(sdev->dev, "Cannot obtain SCU handle (err = %d)\n", + ret); + goto exit_unroll_pm; + } + + priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp", + PLATFORM_DEVID_NONE, + pdev, sizeof(*pdev)); + if (IS_ERR(priv->ipc_dev)) { + ret = PTR_ERR(priv->ipc_dev); + goto exit_unroll_pm; + } + + priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev); + if (!priv->dsp_ipc) { + /* DSP IPC driver not probed yet, try later */ + ret = -EPROBE_DEFER; + dev_err(sdev->dev, "Failed to get drvdata\n"); + goto exit_pdev_unregister; + } + + imx_dsp_set_data(priv->dsp_ipc, priv); + priv->dsp_ipc->ops = &dsp_ops; + + /* DSP base */ + mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (mmio) { + base = mmio->start; + size = resource_size(mmio); + } else { + dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n"); + ret = -EINVAL; + goto exit_pdev_unregister; + } + + sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size); + if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) { + dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n", + base, size); + ret = -ENODEV; + goto exit_pdev_unregister; + } + sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM; + + res_node = of_parse_phandle(np, "memory-region", 0); + if (!res_node) { + dev_err(&pdev->dev, "failed to get memory region node\n"); + ret = -ENODEV; + goto exit_pdev_unregister; + } + + ret = of_address_to_resource(res_node, 0, &res); + if (ret) { + dev_err(&pdev->dev, "failed to get reserved region address\n"); + goto exit_pdev_unregister; + } + + sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start, + res.end - res.start + + 1); + if (IS_ERR(sdev->bar[SOF_FW_BLK_TYPE_SRAM])) { + dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n", + base, size); + ret = PTR_ERR(sdev->bar[SOF_FW_BLK_TYPE_SRAM]); + goto exit_pdev_unregister; + } + sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM; + + return 0; + +exit_pdev_unregister: + platform_device_unregister(priv->ipc_dev); +exit_unroll_pm: + while (--i >= 0) { + device_link_del(priv->link[i]); + dev_pm_domain_detach(priv->pd_dev[i], false); + } + + return ret; +} + +static int imx8_remove(struct snd_sof_dev *sdev) +{ + struct imx8_priv *priv = (struct imx8_priv *)sdev->private; + int i; + + platform_device_unregister(priv->ipc_dev); + + for (i = 0; i < priv->num_domains; i++) { + device_link_del(priv->link[i]); + dev_pm_domain_detach(priv->pd_dev[i], false); + } + + return 0; +} + +/* on i.MX8 there is 1 to 1 match between type and BAR idx */ +int imx8_get_bar_index(struct snd_sof_dev *sdev, u32 type) +{ + return type; +} + +void imx8_ipc_msg_data(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + void *p, size_t sz) +{ + sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); +} + +int imx8_ipc_pcm_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + const struct sof_ipc_pcm_params_reply *reply) +{ + return 0; +} + +static struct snd_soc_dai_driver imx8_dai[] = { +{ + .name = "esai-port", +}, +}; + +/* i.MX8 ops */ +struct snd_sof_dsp_ops sof_imx8_ops = { + /* probe and remove */ + .probe = imx8_probe, + .remove = imx8_remove, + /* DSP core boot */ + .run = imx8_run, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* ipc */ + .send_msg = imx8_send_msg, + .fw_ready = sof_fw_ready, + .get_mailbox_offset = imx8_get_mailbox_offset, + .get_window_offset = imx8_get_window_offset, + + .ipc_msg_data = imx8_ipc_msg_data, + .ipc_pcm_params = imx8_ipc_pcm_params, + + /* module loading */ + .load_module = snd_sof_parse_module_memcpy, + .get_bar_index = imx8_get_bar_index, + /* firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + + /* DAI drivers */ + .drv = imx8_dai, + .num_drv = 1, /* we have only 1 ESAI interface on i.MX8 */ +}; +EXPORT_SYMBOL(sof_imx8_ops); + +MODULE_LICENSE("Dual BSD/GPL"); From c9da397e36cac35fcf50291677a07c7d63beebba Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 5 Jun 2019 16:28:15 +0300 Subject: [PATCH 1599/1995] ASoC: SOF: topology: Add dummy support for i.MX8 DAIs Add dummy support for SAI/ESAI digital audio interface IPs found on i.MX8 boards. Signed-off-by: Daniel Baluta --- include/sound/sof/dai.h | 2 ++ include/uapi/sound/sof/tokens.h | 8 ++++++++ sound/soc/sof/topology.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 5b8de1b1983c29..7a84f7fb460a3e 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -50,6 +50,8 @@ enum sof_ipc_dai_type { SOF_DAI_INTEL_DMIC, /**< Intel DMIC */ SOF_DAI_INTEL_HDA, /**< Intel HD/A */ SOF_DAI_INTEL_SOUNDWIRE, /**< Intel SoundWire */ + SOF_DAI_IMX_SAI, /**< i.MX SAI */ + SOF_DAI_IMX_ESAI, /**< i.MX ESAI */ }; /* general purpose DAI configuration */ diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 6435240cef1351..8f996857fb2427 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -106,4 +106,12 @@ /* for backward compatibility */ #define SOF_TKN_EFFECT_TYPE SOF_TKN_PROCESS_TYPE +/* SAI */ +#define SOF_TKN_IMX_SAI_FIRST_TOKEN 1000 +/* TODO: Add SAI tokens */ + +/* ESAI */ +#define SOF_TKN_IMX_ESAI_FIRST_TOKEN 1100 +/* TODO: Add ESAI tokens */ + #endif diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 9cffea1423954e..a215bf58b138f7 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -346,6 +346,8 @@ static const struct sof_dai_types sof_dais[] = { {"SSP", SOF_DAI_INTEL_SSP}, {"HDA", SOF_DAI_INTEL_HDA}, {"DMIC", SOF_DAI_INTEL_DMIC}, + {"SAI", SOF_DAI_IMX_SAI}, + {"ESAI", SOF_DAI_IMX_ESAI}, }; static enum sof_ipc_dai_type find_dai(const char *name) @@ -2513,6 +2515,26 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, return ret; } +static int sof_link_sai_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + /*TODO: Add implementation */ + return 0; +} + +static int sof_link_esai_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + /*TODO: Add implementation */ + return 0; +} + static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg, @@ -2837,6 +2859,14 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, ret = sof_link_hda_load(scomp, index, link, cfg, hw_config, &config); break; + case SOF_DAI_IMX_SAI: + ret = sof_link_sai_load(scomp, index, link, cfg, hw_config, + &config); + break; + case SOF_DAI_IMX_ESAI: + ret = sof_link_esai_load(scomp, index, link, cfg, hw_config, + &config); + break; default: dev_err(sdev->dev, "error: invalid DAI type %d\n", config.type); ret = -EINVAL; From d5cbc3c89ac649591412be98b0d7ad6f025c7fcb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 8 Aug 2019 19:51:35 -0500 Subject: [PATCH 1600/1995] ASoC: SOF: Intel: hda: fixup HDaudio topology name with DMIC number The SOF project maintains 6 topologies for HDaudio (iDisp or HDaudio+iDisp, no DMIC, 2 DMICs, 4 DMICs). The user is currently required to manually rename the topology file used in /lib/firmware/intel/sof-tplg. We can do better to avoid such renames and use logic to select the relevant file. The NHLT information can be used to figure out which topology file should be used. Alternatively, when NHLT is not present in ACPI tables or is possibly incorrect, a module parameter can provide that information, e.g. on Up^2 board with the test DMIC kit. Tested on Up^2 board and Acer Swift-SF314-55 Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/Kconfig | 1 + sound/soc/sof/intel/hda.c | 75 +++++++++++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index dd14ce92fe102f..545071afbe18af 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -254,6 +254,7 @@ config SND_SOC_SOF_HDA tristate select SND_HDA_EXT_CORE if SND_SOC_SOF_HDA_LINK select SND_SOC_HDAC_HDA if SND_SOC_SOF_HDA_AUDIO_CODEC + select SND_INTEL_NHLT help This option is not user-selectable but automagically handled by 'select' statements at a higher level diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index c7de5065b96119..cf395e816fee31 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include "../ops.h" @@ -52,6 +53,12 @@ module_param_named(use_msi, hda_use_msi, bool, 0444); MODULE_PARM_DESC(use_msi, "SOF HDA use PCI MSI mode"); #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +static int hda_dmic_num = -1; +module_param_named(dmic_num, hda_dmic_num, int, 0444); +MODULE_PARM_DESC(dmic_num, "SOF HDA DMIC number"); +#endif + static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = { {HDA_DSP_ROM_FW_MANIFEST_LOADED, "status: manifest loaded"}, {HDA_DSP_ROM_FW_FW_LOADED, "status: fw loaded"}, @@ -290,8 +297,26 @@ static int hda_init(struct snd_sof_dev *sdev) #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +static int check_nhlt_dmic(struct snd_sof_dev *sdev) +{ + struct nhlt_acpi_table *nhlt; + int dmic_num; + + nhlt = intel_nhlt_init(sdev->dev); + if (nhlt) { + dmic_num = intel_nhlt_get_dmic_geo(sdev->dev, nhlt); + intel_nhlt_free(nhlt); + if (dmic_num == 2 || dmic_num == 4) + return dmic_num; + } + + return 0; +} + static const char *fixup_tplg_name(struct snd_sof_dev *sdev, - const char *sof_tplg_filename) + const char *sof_tplg_filename, + const char *idisp_str, + const char *dmic_str) { const char *tplg_filename = NULL; char *filename; @@ -305,7 +330,8 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev, split_ext = strsep(&filename, "."); if (split_ext) { tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, - "%s-idisp.tplg", split_ext); + "%s%s%s.tplg", + split_ext, idisp_str, dmic_str); if (!tplg_filename) return NULL; } @@ -324,6 +350,9 @@ static int hda_init_caps(struct snd_sof_dev *sdev) struct snd_sof_pdata *pdata = sdev->pdata; struct snd_soc_acpi_mach *mach; const char *tplg_filename; + const char *idisp_str; + const char *dmic_str; + int dmic_num; int codec_num = 0; int i; #endif @@ -394,17 +423,39 @@ static int hda_init_caps(struct snd_sof_dev *sdev) dev_info(bus->dev, "using HDA machine driver %s now\n", hda_mach->drv_name); - /* fixup topology file for HDMI only platforms */ - if (codec_num == 1) { - /* use local variable for readability */ - tplg_filename = pdata->tplg_filename; - tplg_filename = fixup_tplg_name(sdev, tplg_filename); - if (!tplg_filename) { - hda_codec_i915_exit(sdev); - return ret; - } - pdata->tplg_filename = tplg_filename; + if (codec_num == 1) + idisp_str = "-idisp"; + else + idisp_str = ""; + + /* first check NHLT for DMICs */ + dmic_num = check_nhlt_dmic(sdev); + + /* allow for module parameter override */ + if (hda_dmic_num != -1) + dmic_num = hda_dmic_num; + + switch (dmic_num) { + case 2: + dmic_str = "-2ch"; + break; + case 4: + dmic_str = "-4ch"; + break; + default: + dmic_num = 0; + dmic_str = ""; + break; + } + + tplg_filename = pdata->tplg_filename; + tplg_filename = fixup_tplg_name(sdev, tplg_filename, + idisp_str, dmic_str); + if (!tplg_filename) { + hda_codec_i915_exit(sdev); + return ret; } + pdata->tplg_filename = tplg_filename; } } From acb0412df06e036c81c89de6600a74e7de52779e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 12 Aug 2019 12:33:33 -0500 Subject: [PATCH 1601/1995] ASoC: SOF: fix HDA direct MMIO access The recent change to remove the bus->io_ops callbacks used an older version of the SOF code base, and when merged into Mark's for-next it invalidated changes, resulting in broken compilation. Restore SOF code and apply Takashi's intended change in the 'right' location. Fixes: c2f16a94a8049 ("Merge branch 'topic/hda-bus-ops-cleanup'") Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-ctrl.c | 2 +- sound/soc/sof/intel/hda-dsp.c | 39 ---------------------------------- 2 files changed, 1 insertion(+), 40 deletions(-) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index a7fee403cb9088..bc41028a7a01de 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -254,7 +254,7 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* Reset stream-to-link mapping */ list_for_each_entry(hlink, &bus->hlink_list, list) - bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); + writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); #endif bus->chip_init = true; diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 097727cda5cb3c..fb55a3c5afd0d5 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -354,45 +354,6 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) return ret; } - hda_dsp_ctrl_misc_clock_gating(sdev, false); - - /* Reset stream-to-link mapping */ - list_for_each_entry(hlink, &bus->hlink_list, list) - writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); - - hda_dsp_ctrl_misc_clock_gating(sdev, true); -#else - - hda_dsp_ctrl_misc_clock_gating(sdev, false); - - /* reset controller */ - ret = hda_dsp_ctrl_link_reset(sdev, true); - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to reset controller during resume\n"); - return ret; - } - - /* take controller out of reset */ - ret = hda_dsp_ctrl_link_reset(sdev, false); - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to ready controller during resume\n"); - return ret; - } - - /* enable hda bus irq */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, - SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN); - - hda_dsp_ctrl_misc_clock_gating(sdev, true); -#endif - - /* enable ppcap interrupt */ - hda_dsp_ctrl_ppcap_enable(sdev, true); - hda_dsp_ctrl_ppcap_int_enable(sdev, true); - #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) /* check jack status */ if (runtime_resume) From b45315d57e2ab6fce1de8bd6391d925143b4fbda Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 1 Aug 2019 12:56:36 +0300 Subject: [PATCH 1602/1995] firmware: imx: Add DSP IPC protocol interface Some of i.MX8 processors (e.g i.MX8QM, i.MX8QXP) contain the Tensilica HiFi4 DSP for advanced pre- and post-audio processing. The communication between Host CPU and DSP firmware is taking place using a shared memory area for message passing and a dedicated Messaging Unit for notifications. DSP IPC protocol offers a doorbell interface using imx-mailbox API. We use 4 MU channels (2 x TXDB, 2 x RXDB) to implement a request-reply protocol. Connection 0 (txdb0, rxdb0): - Host writes messasge to shared memory [SHMEM] - Host sends a request [MU] - DSP handles request [SHMEM] - DSP sends reply [MU] Connection 1 (txdb1, rxdb1): - DSP writes a message to shared memory [SHMEM] - DSP sends a request [MU] - Host handles request [SHMEM] - Host sends reply [MU] The protocol interface will be used by a Host client to communicate with the DSP. First client will be the i.MX8 part from Sound Open Firmware infrastructure. The protocol offers the following interface: On Tx: - imx_dsp_ring_doorbell, will be called to notify the DSP that it needs to handle a request. On Rx: - clients need to provide two callbacks: .handle_reply .handle_request - the callbacks will be used by the protocol on notification arrival from DSP. Signed-off-by: Daniel Baluta Reviewed-by: Oleksij Rempel Signed-off-by: Shawn Guo --- drivers/firmware/imx/Kconfig | 11 +++ drivers/firmware/imx/Makefile | 1 + drivers/firmware/imx/imx-dsp.c | 155 +++++++++++++++++++++++++++++++ include/linux/firmware/imx/dsp.h | 67 +++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 drivers/firmware/imx/imx-dsp.c create mode 100644 include/linux/firmware/imx/dsp.h diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig index 42b566f8903fad..0dbee32da4c6d5 100644 --- a/drivers/firmware/imx/Kconfig +++ b/drivers/firmware/imx/Kconfig @@ -1,4 +1,15 @@ # SPDX-License-Identifier: GPL-2.0-only +config IMX_DSP + bool "IMX DSP Protocol driver" + depends on IMX_MBOX + help + This enables DSP IPC protocol between host AP (Linux) + and the firmware running on DSP. + DSP exists on some i.MX8 processors (e.g i.MX8QM, i.MX8QXP). + + It acts like a doorbell. Client might use shared memory to + exchange information with DSP side. + config IMX_SCU bool "IMX SCU Protocol driver" depends on IMX_MBOX diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile index 802c4ad8e8f967..08bc9ddfbdfb51 100644 --- a/drivers/firmware/imx/Makefile +++ b/drivers/firmware/imx/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_IMX_DSP) += imx-dsp.o obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o diff --git a/drivers/firmware/imx/imx-dsp.c b/drivers/firmware/imx/imx-dsp.c new file mode 100644 index 00000000000000..a43d2db5cbdb4c --- /dev/null +++ b/drivers/firmware/imx/imx-dsp.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 NXP + * Author: Daniel Baluta + * + * Implementation of the DSP IPC interface (host side) + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * imx_dsp_ring_doorbell - triggers an interrupt on the other side (DSP) + * + * @dsp: DSP IPC handle + * @chan_idx: index of the channel where to trigger the interrupt + * + * Returns non-negative value for success, negative value for error + */ +int imx_dsp_ring_doorbell(struct imx_dsp_ipc *ipc, unsigned int idx) +{ + int ret; + struct imx_dsp_chan *dsp_chan; + + if (idx >= DSP_MU_CHAN_NUM) + return -EINVAL; + + dsp_chan = &ipc->chans[idx]; + ret = mbox_send_message(dsp_chan->ch, NULL); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL(imx_dsp_ring_doorbell); + +/* + * imx_dsp_handle_rx - rx callback used by imx mailbox + * + * @c: mbox client + * @msg: message received + * + * Users of DSP IPC will need to privde handle_reply and handle_request + * callbacks. + */ +static void imx_dsp_handle_rx(struct mbox_client *c, void *msg) +{ + struct imx_dsp_chan *chan = container_of(c, struct imx_dsp_chan, cl); + + if (chan->idx == 0) { + chan->ipc->ops->handle_reply(chan->ipc); + } else { + chan->ipc->ops->handle_request(chan->ipc); + imx_dsp_ring_doorbell(chan->ipc, 1); + } +} + +static int imx_dsp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct imx_dsp_ipc *dsp_ipc; + struct imx_dsp_chan *dsp_chan; + struct mbox_client *cl; + char *chan_name; + int ret; + int i, j; + + device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent); + + dsp_ipc = devm_kzalloc(dev, sizeof(*dsp_ipc), GFP_KERNEL); + if (!dsp_ipc) + return -ENOMEM; + + for (i = 0; i < DSP_MU_CHAN_NUM; i++) { + if (i < 2) + chan_name = kasprintf(GFP_KERNEL, "txdb%d", i); + else + chan_name = kasprintf(GFP_KERNEL, "rxdb%d", i - 2); + + if (!chan_name) + return -ENOMEM; + + dsp_chan = &dsp_ipc->chans[i]; + cl = &dsp_chan->cl; + cl->dev = dev; + cl->tx_block = false; + cl->knows_txdone = true; + cl->rx_callback = imx_dsp_handle_rx; + + dsp_chan->ipc = dsp_ipc; + dsp_chan->idx = i % 2; + dsp_chan->ch = mbox_request_channel_byname(cl, chan_name); + if (IS_ERR(dsp_chan->ch)) { + ret = PTR_ERR(dsp_chan->ch); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Failed to request mbox chan %s ret %d\n", + chan_name, ret); + goto out; + } + + dev_dbg(dev, "request mbox chan %s\n", chan_name); + /* chan_name is not used anymore by framework */ + kfree(chan_name); + } + + dsp_ipc->dev = dev; + + dev_set_drvdata(dev, dsp_ipc); + + dev_info(dev, "NXP i.MX DSP IPC initialized\n"); + + return devm_of_platform_populate(dev); +out: + kfree(chan_name); + for (j = 0; j < i; j++) { + dsp_chan = &dsp_ipc->chans[j]; + mbox_free_channel(dsp_chan->ch); + } + + return ret; +} + +static int imx_dsp_remove(struct platform_device *pdev) +{ + struct imx_dsp_chan *dsp_chan; + struct imx_dsp_ipc *dsp_ipc; + int i; + + dsp_ipc = dev_get_drvdata(&pdev->dev); + + for (i = 0; i < DSP_MU_CHAN_NUM; i++) { + dsp_chan = &dsp_ipc->chans[i]; + mbox_free_channel(dsp_chan->ch); + } + + return 0; +} + +static struct platform_driver imx_dsp_driver = { + .driver = { + .name = "imx-dsp", + }, + .probe = imx_dsp_probe, + .remove = imx_dsp_remove, +}; +builtin_platform_driver(imx_dsp_driver); + +MODULE_AUTHOR("Daniel Baluta "); +MODULE_DESCRIPTION("IMX DSP IPC protocol driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/firmware/imx/dsp.h b/include/linux/firmware/imx/dsp.h new file mode 100644 index 00000000000000..7562099c9e4644 --- /dev/null +++ b/include/linux/firmware/imx/dsp.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2019 NXP + * + * Header file for the DSP IPC implementation + */ + +#ifndef _IMX_DSP_IPC_H +#define _IMX_DSP_IPC_H + +#include +#include +#include + +#define DSP_MU_CHAN_NUM 4 + +struct imx_dsp_chan { + struct imx_dsp_ipc *ipc; + struct mbox_client cl; + struct mbox_chan *ch; + char *name; + int idx; +}; + +struct imx_dsp_ops { + void (*handle_reply)(struct imx_dsp_ipc *ipc); + void (*handle_request)(struct imx_dsp_ipc *ipc); +}; + +struct imx_dsp_ipc { + /* Host <-> DSP communication uses 2 txdb and 2 rxdb channels */ + struct imx_dsp_chan chans[DSP_MU_CHAN_NUM]; + struct device *dev; + struct imx_dsp_ops *ops; + void *private_data; +}; + +static inline void imx_dsp_set_data(struct imx_dsp_ipc *ipc, void *data) +{ + if (!ipc) + return; + + ipc->private_data = data; +} + +static inline void *imx_dsp_get_data(struct imx_dsp_ipc *ipc) +{ + if (!ipc) + return NULL; + + return ipc->private_data; +} + +#if IS_ENABLED(CONFIG_IMX_DSP) + +int imx_dsp_ring_doorbell(struct imx_dsp_ipc *dsp, unsigned int chan_idx); + +#else + +static inline int imx_dsp_ring_doorbell(struct imx_dsp_ipc *ipc, + unsigned int chan_idx) +{ + return -ENOTSUPP; +} + +#endif +#endif /* _IMX_DSP_IPC_H */ From 34d3085768d2ba00408b36aceea155cce7a2ae29 Mon Sep 17 00:00:00 2001 From: Bard liao Date: Tue, 25 Jun 2019 03:56:58 +0800 Subject: [PATCH 1603/1995] ASoC: SOF: rename SOUNDWIRE to ALH Rename SOUNDWIRE to ALH. Signed-off-by: Bard liao Signed-off-by: Pierre-Louis Bossart --- include/sound/sof/dai.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 7a84f7fb460a3e..6b296df242bd52 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -49,7 +49,7 @@ enum sof_ipc_dai_type { SOF_DAI_INTEL_SSP, /**< Intel SSP */ SOF_DAI_INTEL_DMIC, /**< Intel DMIC */ SOF_DAI_INTEL_HDA, /**< Intel HD/A */ - SOF_DAI_INTEL_SOUNDWIRE, /**< Intel SoundWire */ + SOF_DAI_INTEL_ALH, /**< Intel ALH */ SOF_DAI_IMX_SAI, /**< i.MX SAI */ SOF_DAI_IMX_ESAI, /**< i.MX ESAI */ }; From d2ffb221728be444e7828ac672b3193a5d7f83a6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 24 Jun 2019 09:13:06 -0500 Subject: [PATCH 1604/1995] ASoC: SOF: ipc: add ALH parameters The only configuration parameter is the ALH stream ID. No range checking is done by the driver, the firmware should check that the stream is valid for a specific hardware. Bump the ABI Minor number to keep the alignment with SOF firmware Signed-off-by: Pierre-Louis Bossart --- include/sound/sof/dai-intel.h | 9 +++++++++ include/sound/sof/dai.h | 1 + include/uapi/sound/sof/abi.h | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h index 1ab52fd63ceb98..5f1ef5565be69f 100644 --- a/include/sound/sof/dai-intel.h +++ b/include/sound/sof/dai-intel.h @@ -179,4 +179,13 @@ struct sof_ipc_dai_dmic_params { struct sof_ipc_dai_dmic_pdm_ctrl pdm[0]; } __packed; +/* ALH Configuration Request - SOF_IPC_DAI_ALH_CONFIG */ +struct sof_ipc_dai_alh_params { + struct sof_ipc_hdr hdr; + uint32_t stream_id; + + /* reserved for future use */ + uint32_t reserved[15]; +} __packed; + #endif diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 6b296df242bd52..0f123502214647 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -72,6 +72,7 @@ struct sof_ipc_dai_config { struct sof_ipc_dai_ssp_params ssp; struct sof_ipc_dai_dmic_params dmic; struct sof_ipc_dai_hda_params hda; + struct sof_ipc_dai_alh_params alh; }; } __packed; diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index dff70a42445a17..a0fe0d4c4b6657 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 9 +#define SOF_ABI_MINOR 10 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ From 3af56e4625921890511a0119057401cc98f5eb13 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 25 Jun 2019 04:19:38 -0500 Subject: [PATCH 1605/1995] ASoC: SOF: topology: initial support for Intel ALH DAI type The Audio Link Hub DAI does not require any static configuration from topology for now. We still need to pass the frame rate and format to firmware. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/topology.c | 42 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index a215bf58b138f7..28a7a6e06a5395 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -346,6 +346,7 @@ static const struct sof_dai_types sof_dais[] = { {"SSP", SOF_DAI_INTEL_SSP}, {"HDA", SOF_DAI_INTEL_HDA}, {"DMIC", SOF_DAI_INTEL_DMIC}, + {"ALH", SOF_DAI_INTEL_ALH}, {"SAI", SOF_DAI_IMX_SAI}, {"ESAI", SOF_DAI_IMX_ESAI}, }; @@ -2763,6 +2764,40 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index, return ret; } +static int sof_link_alh_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg, + struct snd_soc_tplg_hw_config *hw_config, + struct sof_ipc_dai_config *config) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc_reply reply; + u32 size = sizeof(*config); + int ret; + + /* init IPC */ + config->hdr.size = size; + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + config->hdr.cmd, config, size, &reply, + sizeof(reply)); + + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DAI config for ALH %d\n", + config->dai_index); + return ret; + } + + /* set config for all DAI's with name matching the link name */ + ret = sof_set_dai_config(sdev, size, link, config); + if (ret < 0) + dev_err(sdev->dev, "error: failed to save DAI config for ALH %d\n", + config->dai_index); + + return ret; +} + /* DAI link - used for any driver specific init */ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link *link, @@ -2859,6 +2894,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, ret = sof_link_hda_load(scomp, index, link, cfg, hw_config, &config); break; + case SOF_DAI_INTEL_ALH: + ret = sof_link_alh_load(scomp, index, link, cfg, hw_config, + &config); + break; case SOF_DAI_IMX_SAI: ret = sof_link_sai_load(scomp, index, link, cfg, hw_config, &config); @@ -2924,7 +2963,8 @@ static int sof_link_unload(struct snd_soc_component *scomp, switch (sof_dai->dai_config->type) { case SOF_DAI_INTEL_SSP: case SOF_DAI_INTEL_DMIC: - /* no resource needs to be released for SSP and DMIC */ + case SOF_DAI_INTEL_ALH: + /* no resource needs to be released for SSP, DMIC and ALH */ break; case SOF_DAI_INTEL_HDA: ret = sof_link_hda_unload(sdev, link); From b5e0a0dd4276a04d8ac664de8f7a11e518a34d1b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 25 Jun 2019 10:33:41 -0500 Subject: [PATCH 1606/1995] ASoC: SOF: pcm: add ALH support Even if ALH has no specific configuration, we still need to handle the common parameters for all DAIs Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pcm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 8612896673a5bf..e3f6a6dc0f368a 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -675,6 +675,9 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, case SOF_DAI_INTEL_HDA: /* do nothing for HDA dai_link */ break; + case SOF_DAI_INTEL_ALH: + /* do nothing for ALH dai_link */ + break; default: dev_err(sdev->dev, "error: invalid DAI type %d\n", dai->dai_config->type); From e66536eb1ea7826af8cd7d27221872c67c4a604d Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Wed, 24 Jul 2019 22:14:42 +0800 Subject: [PATCH 1607/1995] ASoC: Intel: common: add ACPI matching tables for Tiger Lake Initial support for TGL w/ RT1308 Signed-off-by: Pan Xiuli Signed-off-by: Pierre-Louis Bossart --- include/sound/soc-acpi-intel-match.h | 1 + sound/soc/intel/common/Makefile | 1 + .../intel/common/soc-acpi-intel-tgl-match.c | 24 +++++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 sound/soc/intel/common/soc-acpi-intel-tgl-match.c diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index bb5e1e4ce8bf91..ce6c4a97093997 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -25,6 +25,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[]; /* * generic table used for HDA codec-based platforms, possibly with diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 56c81e20b5bf8d..a14aca62ff9671 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -8,6 +8,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \ + soc-acpi-intel-tgl-match.o \ soc-acpi-intel-hda-match.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c new file mode 100644 index 00000000000000..57a6298d6dca31 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-apci-intel-tgl-match.c - tables and support for ICL ACPI enumeration. + * + * Copyright (c) 2019, Intel Corporation. + * + */ + +#include +#include + +struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { + { + .id = "10EC1308", + .drv_name = "tgl_rt1308", + .sof_fw_filename = "sof-tgl.ri", + .sof_tplg_filename = "sof-tgl-rt1308.tplg", + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); From e6eada59a87b2212fde40c5c4e5bb967b7c0bb30 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Wed, 24 Jul 2019 22:05:47 +0800 Subject: [PATCH 1608/1995] ASoC: SOF: Intel: initial support for Tiger Lake. Add Kconfig, PCI ID and chip info for Tiger Lake platform. Note that the core mask is different from previous platforms, only Core0 can be controlled by the host. Additional patches will be required for multi-core functionality. Signed-off-by: Pan Xiuli Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/Kconfig | 16 ++++++++++++++++ sound/soc/sof/intel/cnl.c | 16 ++++++++++++++++ sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/sof-pci-dev.c | 22 ++++++++++++++++++++++ 4 files changed, 55 insertions(+) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 545071afbe18af..0dc5da661b6188 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -27,6 +27,7 @@ config SND_SOC_SOF_INTEL_PCI select SND_SOC_SOF_ICELAKE if SND_SOC_SOF_ICELAKE_SUPPORT select SND_SOC_SOF_COMETLAKE_LP if SND_SOC_SOF_COMETLAKE_LP_SUPPORT select SND_SOC_SOF_COMETLAKE_H if SND_SOC_SOF_COMETLAKE_H_SUPPORT + select SND_SOC_SOF_TIGERLAKE if SND_SOC_SOF_TIGERLAKE_SUPPORT help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -212,6 +213,21 @@ config SND_SOC_SOF_COMETLAKE_H_SUPPORT Say Y if you have such a device. If unsure select "N". +config SND_SOC_SOF_TIGERLAKE_SUPPORT + bool "SOF support for Tigerlake" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Tigerlake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_TIGERLAKE + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + config SND_SOC_SOF_HDA_COMMON tristate select SND_SOC_SOF_INTEL_COMMON diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 6d7d9c93252c81..5de281fcc1221f 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -295,3 +295,19 @@ const struct sof_intel_dsp_desc icl_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, }; EXPORT_SYMBOL(icl_chip_info); + +const struct sof_intel_dsp_desc tgl_chip_info = { + /* Tigerlake */ + .cores_num = 4, + .init_core_mask = 1, + .cores_mask = HDA_DSP_CORE_MASK(0), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .rom_init_timeout = 300, + .ssp_count = ICL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, +}; +EXPORT_SYMBOL(tgl_chip_info); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 6db3dcbab3bdff..cbb431f7835ddd 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -599,5 +599,6 @@ extern const struct sof_intel_dsp_desc apl_chip_info; extern const struct sof_intel_dsp_desc cnl_chip_info; extern const struct sof_intel_dsp_desc skl_chip_info; extern const struct sof_intel_dsp_desc icl_chip_info; +extern const struct sof_intel_dsp_desc tgl_chip_info; #endif diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 9363316b86fc6b..8bf15b72d94fc4 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -209,6 +209,24 @@ static const struct sof_dev_desc kbl_desc = { }; #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) +static const struct sof_dev_desc tgl_desc = { + .machines = snd_soc_acpi_intel_tgl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &tgl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-tgl.ri", + .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", + .ops = &sof_cnl_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + static const struct dev_pm_ops sof_pci_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, @@ -394,6 +412,10 @@ static const struct pci_device_id sof_pci_ids[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) { PCI_DEVICE(0x8086, 0x06c8), .driver_data = (unsigned long)&cml_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) + { PCI_DEVICE(0x8086, 0xa0c8), + .driver_data = (unsigned long)&tgl_desc}, #endif { 0, } }; From 14168205a160d297938b18be128e788d1c95e20d Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Mon, 5 Aug 2019 16:32:52 +0800 Subject: [PATCH 1609/1995] ASoC: Intel: common: add ACPI matching tables for EHL There are no upstream machine drivers just yet so just add dummy table for compilation in nocodec-mode. Signed-off-by: Pan Xiuli Signed-off-by: Pierre-Louis Bossart --- include/sound/soc-acpi-intel-match.h | 1 + sound/soc/intel/common/Makefile | 2 +- .../intel/common/soc-acpi-intel-ehl-match.c | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/common/soc-acpi-intel-ehl-match.c diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index ce6c4a97093997..6c9929abd90b84 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -26,6 +26,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[]; /* * generic table used for HDA codec-based platforms, possibly with diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index a14aca62ff9671..18d9630ae9a232 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -8,7 +8,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \ - soc-acpi-intel-tgl-match.o \ + soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \ soc-acpi-intel-hda-match.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o diff --git a/sound/soc/intel/common/soc-acpi-intel-ehl-match.c b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c new file mode 100644 index 00000000000000..a1290c3fa99f34 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-apci-intel-ehl-match.c - tables and support for EHL ACPI enumeration. + * + * Copyright (c) 2019, Intel Corporation. + * + */ + +#include +#include + +struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[] = { + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ehl_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); From 61c94225a540d3809f4592ed5e9b7e5f53a0ddc0 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Mon, 5 Aug 2019 16:29:34 +0800 Subject: [PATCH 1610/1995] ASoC: SOF: Intel: initial support for Elkhart Lake Add Kconfig, PCI ID and chip info for EHL platform. Note that the core mask is different from previous platforms, only Core0 can be controlled by the host. Additional patches will be required for multi-core functionality. Signed-off-by: Pan Xiuli Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/Kconfig | 16 ++++++++++++++++ sound/soc/sof/intel/cnl.c | 16 ++++++++++++++++ sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/sof-pci-dev.c | 22 ++++++++++++++++++++++ 4 files changed, 55 insertions(+) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 0dc5da661b6188..889b6202d054b0 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -28,6 +28,7 @@ config SND_SOC_SOF_INTEL_PCI select SND_SOC_SOF_COMETLAKE_LP if SND_SOC_SOF_COMETLAKE_LP_SUPPORT select SND_SOC_SOF_COMETLAKE_H if SND_SOC_SOF_COMETLAKE_H_SUPPORT select SND_SOC_SOF_TIGERLAKE if SND_SOC_SOF_TIGERLAKE_SUPPORT + select SND_SOC_SOF_ELKHARTLAKE if SND_SOC_SOF_ELKHARTLAKE_SUPPORT help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -228,6 +229,21 @@ config SND_SOC_SOF_TIGERLAKE This option is not user-selectable but automagically handled by 'select' statements at a higher level +config SND_SOC_SOF_ELKHARTLAKE_SUPPORT + bool "SOF support for ElkhartLake" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the ElkhartLake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_ELKHARTLAKE + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + config SND_SOC_SOF_HDA_COMMON tristate select SND_SOC_SOF_INTEL_COMMON diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 5de281fcc1221f..4ddd73762d813a 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -311,3 +311,19 @@ const struct sof_intel_dsp_desc tgl_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, }; EXPORT_SYMBOL(tgl_chip_info); + +const struct sof_intel_dsp_desc ehl_chip_info = { + /* Elkhartlake */ + .cores_num = 4, + .init_core_mask = 1, + .cores_mask = HDA_DSP_CORE_MASK(0), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .rom_init_timeout = 300, + .ssp_count = ICL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, +}; +EXPORT_SYMBOL(ehl_chip_info); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index cbb431f7835ddd..5591841a1b6faf 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -600,5 +600,6 @@ extern const struct sof_intel_dsp_desc cnl_chip_info; extern const struct sof_intel_dsp_desc skl_chip_info; extern const struct sof_intel_dsp_desc icl_chip_info; extern const struct sof_intel_dsp_desc tgl_chip_info; +extern const struct sof_intel_dsp_desc ehl_chip_info; #endif diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 8bf15b72d94fc4..25537e23ec4bf3 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -227,6 +227,24 @@ static const struct sof_dev_desc tgl_desc = { }; #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) +static const struct sof_dev_desc ehl_desc = { + .machines = snd_soc_acpi_intel_ehl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &ehl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-ehl.ri", + .nocodec_tplg_filename = "sof-ehl-nocodec.tplg", + .ops = &sof_cnl_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + static const struct dev_pm_ops sof_pci_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, @@ -416,6 +434,10 @@ static const struct pci_device_id sof_pci_ids[] = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) { PCI_DEVICE(0x8086, 0xa0c8), .driver_data = (unsigned long)&tgl_desc}, +#endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) + { PCI_DEVICE(0x8086, 0x4b55), + .driver_data = (unsigned long)&ehl_desc}, #endif { 0, } }; From 6fefc993b203d558090406a86ef8f5179843693c Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Wed, 24 Jul 2019 22:26:18 +0800 Subject: [PATCH 1611/1995] ASoC: Intel: tgl: add tgl-rt1308 machine driver New machine driver based on RT1308 + DMIC. HDMI is supported conditionally and needs a follow-up patch for iDISP to handle 4 converters. Signed-off-by: Pan Xiuli Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 17 ++ sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/tgl_rt1308.c | 305 ++++++++++++++++++++++++++++ 3 files changed, 324 insertions(+) create mode 100644 sound/soc/intel/boards/tgl_rt1308.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index b651f91069dc5b..dd3125cb8ca4c2 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -437,4 +437,21 @@ config SND_SOC_INTEL_SOF_RT5682_MACH If unsure select "N". endif ## SND_SOC_SOF_HDA_COMMON || SND_SOC_SOF_BAYTRAIL +if SND_SOC_SOF_TIGERLAKE + +config SND_SOC_INTEL_TGL_RT1308_MACH + tristate "TGL with RT1308 in I2S Mode" + depends on I2C && ACPI + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_RT1308 + select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI if SND_SOC_SOF_HDA_COMMON + help + This adds support for ASoC machine driver for Tigerlake platforms + with RT1308 I2S audio codec. + Say Y if you have such a device. + If unsure select "N". + +endif ## SND_SOC_SOF_TIGERLAKE + endif ## SND_SOC_INTEL_MACH diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index cb6c1356d70673..14b257d8413aaa 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -29,6 +29,7 @@ snd-soc-skl_rt286-objs := skl_rt286.o snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o +snd-soc-tgl-rt1308-objs := tgl_rt1308.o obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o @@ -60,3 +61,4 @@ obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o +obj-$(CONFIG_SND_SOC_INTEL_TGL_RT1308_MACH) += snd-soc-tgl-rt1308.o diff --git a/sound/soc/intel/boards/tgl_rt1308.c b/sound/soc/intel/boards/tgl_rt1308.c new file mode 100644 index 00000000000000..c6b6e4a5215a82 --- /dev/null +++ b/sound/soc/intel/boards/tgl_rt1308.c @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright(c) 2019 Intel Corporation. All rights reserved. + +/* + * tgl_rt1308.c - ASoc Machine driver for Intel platforms + * with RT1308 codec. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../../codecs/rt1308.h" +#include "../../codecs/hdac_hdmi.h" + +struct tgl_card_private { + struct list_head hdmi_pcm_list; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) +static struct snd_soc_jack tgl_hdmi[4]; + +struct tgl_hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +static int tgl_hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct tgl_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct tgl_hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + /* dai_link id is 1:1 mapped to the PCM device */ + pcm->device = rtd->dai_link->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +#define NAME_SIZE 32 +static int tgl_card_late_probe(struct snd_soc_card *card) +{ + struct tgl_card_private *ctx = snd_soc_card_get_drvdata(card); + struct tgl_hdmi_pcm *pcm; + struct snd_soc_component *component = NULL; + int err, i = 0; + char jack_name[NAME_SIZE]; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &tgl_hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &tgl_hdmi[i]); + if (err < 0) + return err; + + i++; + } + + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); +} +#else +static int tgl_card_late_probe(struct snd_soc_card *card) +{ + return 0; +} +#endif + +static int tgl_rt1308_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_card *card = rtd->card; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int clk_id, clk_freq, pll_out; + int err; + + clk_id = RT1308_PLL_S_MCLK; + clk_freq = 38400000; + + pll_out = params_rate(params) * 512; + + /* Set rt1308 pll */ + err = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); + if (err < 0) { + dev_err(card->dev, "Failed to set RT1308 PLL: %d\n", err); + return err; + } + + /* Set rt1308 sysclk */ + err = snd_soc_dai_set_sysclk(codec_dai, RT1308_FS_SYS_S_PLL, pll_out, + SND_SOC_CLOCK_IN); + if (err < 0) { + dev_err(card->dev, "Failed to set RT1308 SYSCLK: %d\n", err); + return err; + } + + return 0; +} + +/* machine stream operations */ +static struct snd_soc_ops tgl_rt1308_ops = { + .hw_params = tgl_rt1308_hw_params, +}; + +static const struct snd_soc_dapm_widget tgl_rt1308_dapm_widgets[] = { + SND_SOC_DAPM_SPK("Speakers", NULL), + SND_SOC_DAPM_MIC("SoC DMIC", NULL), +}; + +static const struct snd_kcontrol_new tgl_rt1308_controls[] = { + SOC_DAPM_PIN_SWITCH("Speakers"), +}; + +static const struct snd_soc_dapm_route tgl_rt1308_dapm_routes[] = { + { "Speakers", NULL, "SPOL" }, + { "Speakers", NULL, "SPOR" }, + + /* digital mics */ + {"DMic", NULL, "SoC DMIC"}, +}; + +SND_SOC_DAILINK_DEF(ssp2_pin, + DAILINK_COMP_ARRAY(COMP_CPU("SSP2 Pin"))); + +SND_SOC_DAILINK_DEF(ssp2_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1308:00", "rt1308-aif"))); + +SND_SOC_DAILINK_DEF(platform, + DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); + +SND_SOC_DAILINK_DEF(dmic_pin, + DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); +SND_SOC_DAILINK_DEF(dmic_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); +SND_SOC_DAILINK_DEF(dmic16k, + DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); + +SND_SOC_DAILINK_DEF(idisp1_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); +SND_SOC_DAILINK_DEF(idisp1_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); + +SND_SOC_DAILINK_DEF(idisp2_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); +SND_SOC_DAILINK_DEF(idisp2_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); + +SND_SOC_DAILINK_DEF(idisp3_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); +SND_SOC_DAILINK_DEF(idisp3_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); + +SND_SOC_DAILINK_DEF(idisp4_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp4 Pin"))); +SND_SOC_DAILINK_DEF(idisp4_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi4"))); + +static struct snd_soc_dai_link tgl_rt1308_dailink[] = { + { + .name = "SSP2-Codec", + .id = 0, + .no_pcm = 1, + .ops = &tgl_rt1308_ops, + .dpcm_playback = 1, + .nonatomic = true, + SND_SOC_DAILINK_REG(ssp2_pin, ssp2_codec, platform), + }, + { + .name = "dmic01", + .id = 1, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), + }, + { + .name = "dmic16k", + .id = 2, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform), + }, +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) + { + .name = "iDisp1", + .id = 3, + .init = tgl_hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), + }, + { + .name = "iDisp2", + .id = 4, + .init = tgl_hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), + }, + { + .name = "iDisp3", + .id = 5, + .init = tgl_hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), + }, + { + .name = "iDisp4", + .id = 6, + .init = tgl_hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp4_pin, idisp4_codec, platform), + }, +#endif +}; + +/* audio machine driver */ +static struct snd_soc_card tgl_rt1308_card = { + .name = "tgl_rt1308", + .owner = THIS_MODULE, + .dai_link = tgl_rt1308_dailink, + .num_links = ARRAY_SIZE(tgl_rt1308_dailink), + .controls = tgl_rt1308_controls, + .num_controls = ARRAY_SIZE(tgl_rt1308_controls), + .dapm_widgets = tgl_rt1308_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tgl_rt1308_dapm_widgets), + .dapm_routes = tgl_rt1308_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(tgl_rt1308_dapm_routes), + .late_probe = tgl_card_late_probe, +}; + +static int tgl_rt1308_probe(struct platform_device *pdev) +{ + struct snd_soc_acpi_mach *mach; + struct tgl_card_private *ctx; + struct snd_soc_card *card = &tgl_rt1308_card; + int ret; + + card->dev = &pdev->dev; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + + mach = (&pdev->dev)->platform_data; + + ret = snd_soc_fixup_dai_links_platform_name(card, + mach->mach_params.platform); + if (ret) + return ret; + + snd_soc_card_set_drvdata(card, ctx); + + return devm_snd_soc_register_card(&pdev->dev, card); +} + +static struct platform_driver tgl_rt1308_driver = { + .driver = { + .name = "tgl_rt1308", + .pm = &snd_soc_pm_ops, + }, + .probe = tgl_rt1308_probe, +}; + +module_platform_driver(tgl_rt1308_driver); + +MODULE_AUTHOR("Xiuli Pan"); +MODULE_DESCRIPTION("ASoC Intel(R) Tiger Lake + RT1308 Machine driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:tgl_rt1308"); From 69a175e9b0bfa717cd0df2bfa16d6352a805d468 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 7 Aug 2019 19:42:58 +0300 Subject: [PATCH 1612/1995] dt-bindings: dsp: fsl: Add DSP core binding support This describes the DSP device tree node. Signed-off-by: Daniel Baluta Reviewed-by: Rob Herring --- .../devicetree/bindings/dsp/fsl,dsp.yaml | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 Documentation/devicetree/bindings/dsp/fsl,dsp.yaml diff --git a/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml b/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml new file mode 100644 index 00000000000000..24b9fd64e3ebdc --- /dev/null +++ b/Documentation/devicetree/bindings/dsp/fsl,dsp.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dsp/fsl,dsp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP i.MX8 DSP core + +maintainers: + - Daniel Baluta + +description: | + Some boards from i.MX8 family contain a DSP core used for + advanced pre- and post- audio processing. + +properties: + compatible: + enum: + - fsl,imx8qxp-dsp + + reg: + description: Should contain register location and length + + clocks: + items: + - description: ipg clock + - description: ocram clock + - description: core clock + + clock-names: + items: + - const: ipg + - const: ocram + - const: core + + power-domains: + description: + List of phandle and PM domain specifier as documented in + Documentation/devicetree/bindings/power/power_domain.txt + maxItems: 4 + + mboxes: + description: + List of <&phandle type channel> - 2 channels for TXDB, 2 channels for RXDB + (see mailbox/fsl,mu.txt) + maxItems: 4 + + mbox-names: + items: + - const: txdb0 + - const: txdb1 + - const: rxdb0 + - const: rxdb1 + + memory-region: + description: + phandle to a node describing reserved memory (System RAM memory) + used by DSP (see bindings/reserved-memory/reserved-memory.txt) + maxItems: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - power-domains + - mboxes + - mbox-names + - memory-region + +examples: + - | + #include + #include + dsp@596e8000 { + compatbile = "fsl,imx8qxp-dsp"; + reg = <0x596e8000 0x88000>; + clocks = <&adma_lpcg IMX_ADMA_LPCG_DSP_IPG_CLK>, + <&adma_lpcg IMX_ADMA_LPCG_OCRAM_IPG_CLK>, + <&adma_lpcg IMX_ADMA_LPCG_DSP_CORE_CLK>; + clock-names = "ipg", "ocram", "core"; + power-domains = <&pd IMX_SC_R_MU_13A>, + <&pd IMX_SC_R_MU_13B>, + <&pd IMX_SC_R_DSP>, + <&pd IMX_SC_R_DSP_RAM>; + mbox-names = "txdb0", "txdb1", "rxdb0", "rxdb1"; + mboxes = <&lsio_mu13 2 0>, <&lsio_mu13 2 1>, <&lsio_mu13 3 0>, <&lsio_mu13 3 1>; + }; From 747a461537dd346ad8795c650ffda11c0d358e07 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 7 Aug 2019 19:42:57 +0300 Subject: [PATCH 1613/1995] arm64: dts: imx8qxp: Add DSP DT node This includes DSP reserved memory, ADMA DSP device and DSP MU communication channels description. Signed-off-by: Daniel Baluta Signed-off-by: Shawn Guo --- arch/arm64/boot/dts/freescale/imx8qxp-mek.dts | 4 +++ arch/arm64/boot/dts/freescale/imx8qxp.dtsi | 32 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts index bfdada2db176ca..19468058e6ae4d 100644 --- a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts +++ b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts @@ -230,3 +230,7 @@ >; }; }; + +&adma_dsp { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8qxp.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp.dtsi index 05fa0b7f36bb18..b6c408fb2b7f12 100644 --- a/arch/arm64/boot/dts/freescale/imx8qxp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8qxp.dtsi @@ -113,6 +113,17 @@ interrupts = ; }; + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + dsp_reserved: dsp@92400000 { + reg = <0 0x92400000 0 0x2000000>; + no-map; + }; + }; + pmu { compatible = "arm,armv8-pmuv3"; interrupts = ; @@ -204,6 +215,27 @@ #clock-cells = <1>; }; + adma_dsp: dsp@596e8000 { + compatible = "fsl,imx8qxp-dsp"; + reg = <0x596e8000 0x88000>; + clocks = <&adma_lpcg IMX_ADMA_LPCG_DSP_IPG_CLK>, + <&adma_lpcg IMX_ADMA_LPCG_OCRAM_IPG_CLK>, + <&adma_lpcg IMX_ADMA_LPCG_DSP_CORE_CLK>; + clock-names = "ipg", "ocram", "core"; + power-domains = <&pd IMX_SC_R_MU_13A>, + <&pd IMX_SC_R_MU_13B>, + <&pd IMX_SC_R_DSP>, + <&pd IMX_SC_R_DSP_RAM>; + mbox-names = "txdb0", "txdb1", + "rxdb0", "rxdb1"; + mboxes = <&lsio_mu13 2 0>, + <&lsio_mu13 2 1>, + <&lsio_mu13 3 0>, + <&lsio_mu13 3 1>; + memory-region = <&dsp_reserved>; + status = "disabled"; + }; + adma_lpuart0: serial@5a060000 { compatible = "fsl,imx8qxp-lpuart", "fsl,imx7ulp-lpuart"; reg = <0x5a060000 0x1000>; From 2a22b942ea414328b4e40331c09d72264331a7a1 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 15 Aug 2019 20:42:08 +0800 Subject: [PATCH 1614/1995] ASoC: intel: sof_rt5682: use separate route map for dmic dmic map can only be added when dmic dai link is present. Signed-off-by: Bard Liao --- sound/soc/intel/boards/sof_rt5682.c | 35 +++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index a437567b8cee23..57b4ef75be1598 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -308,6 +308,9 @@ static const struct snd_soc_dapm_widget sof_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Spk", NULL), +}; + +static const struct snd_soc_dapm_widget dmic_widgets[] = { SND_SOC_DAPM_MIC("SoC DMIC", NULL), }; @@ -318,10 +321,6 @@ static const struct snd_soc_dapm_route sof_map[] = { /* other jacks */ { "IN1P", NULL, "Headset Mic" }, - - /* digital mics */ - {"DMic", NULL, "SoC DMIC"}, - }; static const struct snd_soc_dapm_route speaker_map[] = { @@ -329,6 +328,11 @@ static const struct snd_soc_dapm_route speaker_map[] = { { "Spk", NULL, "Speaker" }, }; +static const struct snd_soc_dapm_route dmic_map[] = { + /* digital mics */ + {"DMic", NULL, "SoC DMIC"}, +}; + static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; @@ -342,6 +346,28 @@ static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd) return ret; } +static int dmic_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets, + ARRAY_SIZE(dmic_widgets)); + if (ret) { + dev_err(card->dev, "DMic widget addition failed: %d\n", ret); + /* Don't need to add routes if widget addition failed */ + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map, + ARRAY_SIZE(dmic_map)); + + if (ret) + dev_err(card->dev, "DMic map addition failed: %d\n", ret); + + return ret; +} + /* sof audio machine driver for rt5682 codec */ static struct snd_soc_card sof_audio_card_rt5682 = { .name = "sof_rt5682", @@ -445,6 +471,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].name = "dmic01"; links[id].cpus = &cpus[id]; links[id].cpus->dai_name = "DMIC01 Pin"; + links[id].init = dmic_init; if (dmic_be_num > 1) { /* set up 2 BE links at most */ links[id + 1].name = "dmic16k"; From a342dd89886652550c061f00b10130705a6fb37f Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Wed, 21 Aug 2019 13:32:05 +0300 Subject: [PATCH 1615/1995] ASoC: rt5682: add NULL handler to set_jack function Implement NULL handler in set_jack function to disable irq's. Signed-off-by: Jaska Uimonen --- sound/soc/codecs/rt5682.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 1ef470700ed5fe..c50b75ce82e0b7 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -995,6 +995,16 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component, { struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); + rt5682->hs_jack = hs_jack; + + if (!hs_jack) { + regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2, + RT5682_JD1_EN_MASK, RT5682_JD1_DIS); + regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL, + RT5682_POW_JDH | RT5682_POW_JDL, 0); + return 0; + } + switch (rt5682->pdata.jd_src) { case RT5682_JD1: snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_2, @@ -1032,8 +1042,6 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component, break; } - rt5682->hs_jack = hs_jack; - return 0; } From 03e99c2ef3c595b7f5264f09da4c9f1f06963256 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Wed, 21 Aug 2019 13:32:16 +0300 Subject: [PATCH 1616/1995] ASoC: intel: sof_rt5682: add remove function to disable jack When removing sof module the rt5682 jack handler will oops if jack detection is not disabled. So add remove function, which disables the jack detection. Signed-off-by: Jaska Uimonen --- sound/soc/intel/boards/sof_rt5682.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 57b4ef75be1598..5ce643d62faf22 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -648,8 +648,24 @@ static int sof_audio_probe(struct platform_device *pdev) &sof_audio_card_rt5682); } +static int sof_rt5682_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct snd_soc_component *component = NULL; + + for_each_card_components(card, component) { + if (!strcmp(component->name, rt5682_component[0].name)) { + snd_soc_component_set_jack(component, NULL, NULL); + break; + } + } + + return 0; +} + static struct platform_driver sof_audio = { .probe = sof_audio_probe, + .remove = sof_rt5682_remove, .driver = { .name = "sof_rt5682", .pm = &snd_soc_pm_ops, From 136b7aaf8e3eb2c2b455963585bd815e06f6e13d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 1 Aug 2019 16:28:41 +0300 Subject: [PATCH 1617/1995] mfd: intel-lpss: Add Intel Tiger Lake PCI IDs Intel Tiger Lake has the same LPSS than Intel Broxton. Add the new IDs to the list of supported devices. Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones (cherry picked from commit ec65b56046d27a21a5ae02eb7fcb321e1942a541) Signed-off-by: Sathyanarayana Nujella Signed-off-by: Pierre-Louis Bossart --- drivers/mfd/intel-lpss-pci.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index ade6e1ce5a983d..f2c9cfe82f10c5 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -256,6 +256,29 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x9dea), (kernel_ulong_t)&cnl_i2c_info }, { PCI_VDEVICE(INTEL, 0x9deb), (kernel_ulong_t)&cnl_i2c_info }, { PCI_VDEVICE(INTEL, 0x9dfb), (kernel_ulong_t)&spt_info }, + /* TGL-LP */ + { PCI_VDEVICE(INTEL, 0xa0a8), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0xa0a9), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0xa0aa), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa0ab), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa0c5), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa0c6), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa0c7), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0xa0d8), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa0d9), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa0da), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0xa0db), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0xa0dc), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0xa0dd), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0xa0de), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa0df), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa0e8), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa0e9), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa0ea), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa0eb), (kernel_ulong_t)&spt_i2c_info }, + { PCI_VDEVICE(INTEL, 0xa0fb), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa0fd), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa0fe), (kernel_ulong_t)&spt_info }, /* SPT-H */ { PCI_VDEVICE(INTEL, 0xa127), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0xa128), (kernel_ulong_t)&spt_uart_info }, From a6f73b2a2824e128aadb9bfdff3b597c9582eb30 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Mon, 26 Aug 2019 17:13:54 +0800 Subject: [PATCH 1618/1995] ASoC: Intel: boards: add no hdmi support for bxt_pcm512x In machine drvier, there is ifdef for the HDMI codec support selection. Add the selection in its Kconfig. Signed-off-by: Pan Xiuli --- sound/soc/intel/boards/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index df986305f55b75..e1eadb88b13cf5 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -299,6 +299,7 @@ config SND_SOC_INTEL_BXT_PCM512x_MACH tristate "Broxton with TI PCM512x codec" depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_PCM512x_I2C + select SND_SOC_HDAC_HDMI if SND_SOC_SOF_HDA_LINK help This adds support for ASoC machine driver for Broxton platforms with TI PCM512x I2S audio codec. From 3b8a6c093d56526d6bc952cd8c2d228b6645c19c Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Mon, 26 Aug 2019 17:15:37 +0800 Subject: [PATCH 1619/1995] ASoC: Intel: boards: add no hdmi support for tgl_rt1308 In machine drvier, there is ifdef for the HDMI codec support selection. Fix the selection in its Kconfig. Signed-off-by: Pan Xiuli --- sound/soc/intel/boards/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index e1eadb88b13cf5..c153bc9621ed02 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -457,7 +457,7 @@ config SND_SOC_INTEL_TGL_RT1308_MACH depends on MFD_INTEL_LPSS || COMPILE_TEST select SND_SOC_RT1308 select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI if SND_SOC_SOF_HDA_COMMON + select SND_SOC_HDAC_HDMI if SND_SOC_SOF_HDA_LINK help This adds support for ASoC machine driver for Tigerlake platforms with RT1308 I2S audio codec. From f95e4ebfd5915b02e6e257345b47089ada35bc44 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Tue, 27 Aug 2019 18:55:15 +0800 Subject: [PATCH 1620/1995] ASoC: SOF: topology: fix parse fail issue for byte/bool tuple types We are using sof_parse_word_tokens() to parse tokens with bool/byte/short/word tuple types, here add the missing check, to fix the parsing failure at byte/bool tuple types. Signed-off-by: Keyon Jie --- sound/soc/sof/topology.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 28a7a6e06a5395..fe483382efdf22 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -920,7 +920,9 @@ static void sof_parse_word_tokens(struct snd_soc_component *scomp, for (j = 0; j < count; j++) { /* match token type */ if (!(tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_WORD || - tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_SHORT)) + tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_SHORT || + tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_BYTE || + tokens[j].type == SND_SOC_TPLG_TUPLE_TYPE_BOOL)) continue; /* match token id */ From f7f346d588fa0b0cd91db1f166f5fd598585f64f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 27 Aug 2019 15:01:31 -0500 Subject: [PATCH 1621/1995] ASoC: SOF: loader: fix kernel oops on firmware boot failure When we fail to boot the firmware, we encounter a kernel oops in hda_dsp_get_registers(), which is called conditionally in hda_dsp_dump() when the sdev_>boot_complete flag is set. Setting this flag _after_ dumping the data fixes the issue and does not change the programming flow. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/loader.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index d7f32745fefe42..9a9a381a908dee 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -546,10 +546,10 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) msecs_to_jiffies(sdev->boot_timeout)); if (ret == 0) { dev_err(sdev->dev, "error: firmware boot failure\n"); - /* after this point FW_READY msg should be ignored */ - sdev->boot_complete = true; snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX | SOF_DBG_TEXT | SOF_DBG_PCI); + /* after this point FW_READY msg should be ignored */ + sdev->boot_complete = true; return -EIO; } From fa20ceba7678d2eb8c23410df56f80ffca59cb82 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Tue, 27 Aug 2019 10:50:55 +0300 Subject: [PATCH 1622/1995] ASoC: intel: bytcr_rt5651: add null check to support_button_press When removing sof module the support_button_press function will oops because hp_jack pointer is not checked for NULL. So add a check to fix this. Signed-off-by: Jaska Uimonen --- sound/soc/codecs/rt5651.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 762595de956c15..c506c9305043e1 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -1770,6 +1770,9 @@ static int rt5651_detect_headset(struct snd_soc_component *component) static bool rt5651_support_button_press(struct rt5651_priv *rt5651) { + if (!rt5651->hp_jack) + return false; + /* Button press support only works with internal jack-detection */ return (rt5651->hp_jack->status & SND_JACK_MICROPHONE) && rt5651->gpiod_hp_det == NULL; From b437b46bfac6bb667c942487e3ab6bf406e23d26 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 24 Aug 2019 15:48:48 -0500 Subject: [PATCH 1623/1995] ASoC: soc-acpi: add link_mask field When interfaces can be pin-muxed, static information from ACPI might not be enough. Add information on which links needs to be enabled by hardware/firmware for a specific machine driver to be selected. When walking through the list of possible machines, links will be checked, which implies that configurations where multiple links are required need to be checked first. Additional criteria will be needed later, such as which SoundWire Slave devices are actually enabled, but for now this helps detect between basic configurations. Signed-off-by: Pierre-Louis Bossart --- include/sound/soc-acpi.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 35b38e41e5b296..c0fb71c7b3adc1 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -75,6 +75,7 @@ struct snd_soc_acpi_mach_params { * all firmware/topology related fields. * * @id: ACPI ID (usually the codec's) used to find a matching machine driver. + * @link_mask: describes required board layout, e.g. for SoundWire. * @drv_name: machine driver name * @fw_filename: firmware file name. Used when SOF is not enabled. * @board: board name @@ -90,6 +91,7 @@ struct snd_soc_acpi_mach_params { /* Descriptor for SST ASoC machine driver */ struct snd_soc_acpi_mach { const u8 id[ACPI_ID_LEN]; + const u32 link_mask; const char *drv_name; const char *fw_filename; const char *board; From 6cf9ef0552fd3e087e49023aefb3183efb9a4468 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 24 Aug 2019 16:04:17 -0500 Subject: [PATCH 1624/1995] ASoC: SOF: support alternate list of machines For cases where an interface can be pin-muxed, we need to assess at probe time which configuration should be used. In cases such as SoundWire, we need to maintain an alternate list of machines and walk through them when the primary detection based on ACPI _HID fails. Signed-off-by: Pierre-Louis Bossart --- include/sound/sof.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/sound/sof.h b/include/sound/sof.h index 4640566b54fe90..479101736ee063 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -61,6 +61,9 @@ struct sof_dev_desc { /* list of machines using this configuration */ struct snd_soc_acpi_mach *machines; + /* alternate list of machines using this configuration */ + struct snd_soc_acpi_mach *alt_machines; + /* Platform resource indexes in BAR / ACPI resources. */ /* Must set to -1 if not used - add new items to end */ int resindex_lpe_base; From 80d2619b4f207765b716263e81526d20592949e1 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 11 Sep 2019 13:53:24 +0300 Subject: [PATCH 1625/1995] ASoC: SOF: Intel: hda: fix warnings during FW load The "snd_pcm_substream" handle was not initialized properly in hda-loader.c for firmware load. When the HDA DMAs were used to load the firmware, the interrupts related to firmware load also triggered calls to snd_sof_pcm_period_elapsed() on a non-existent ALSA PCM stream. This caused runtime kernel warnings from pcm_lib.c:snd_pcm_period_elapsed(). Signed-off-by: Kai Vehmanen --- sound/soc/sof/intel/hda-loader.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 6427f0b3a2f113..65c2af3fcaab71 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -44,6 +44,7 @@ static int cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, return -ENODEV; } hstream = &dsp_stream->hstream; + hstream->substream = NULL; /* allocate DMA buffer */ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab); From d54248dda2cbd4d3fd85c1e366d7aa1aa79c9888 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 16 Sep 2019 14:42:34 +0100 Subject: [PATCH 1626/1995] ASoC: SOF: core: make debug module params and state global. Allow other non core.c users for debug module params and also make the prefix consistent. Signed-off-by: Liam Girdwood --- sound/soc/sof/core.c | 7 +++---- sound/soc/sof/sof-priv.h | 13 +++++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 15200841a12a12..15167b8220ed91 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -16,12 +16,11 @@ #include "sof-priv.h" #include "ops.h" -static int sof_core_debug; +/* see SOF_DBG_ flags */ +int sof_core_debug; module_param_named(sof_debug, sof_core_debug, int, 0444); MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)"); -#define SOF_CORE_ENABLE_TRACE BIT(0) - /* SOF defaults if not provided by the platform in ms */ #define TIMEOUT_DEFAULT_IPC_MS 500 #define TIMEOUT_DEFAULT_BOOT_MS 2000 @@ -357,7 +356,7 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) } if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_FIRMWARE_TRACE) || - (sof_core_debug & SOF_CORE_ENABLE_TRACE)) { + (sof_core_debug & SOF_DBG_ENABLE_TRACE)) { sdev->dtrace_is_supported = true; /* init DMA trace */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 6101c441c7c633..2705fe5c6150c1 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -28,10 +28,15 @@ #include /* debug flags */ -#define SOF_DBG_REGS BIT(1) -#define SOF_DBG_MBOX BIT(2) -#define SOF_DBG_TEXT BIT(3) -#define SOF_DBG_PCI BIT(4) +#define SOF_DBG_ENABLE_TRACE BIT(0) +#define SOF_DBG_REGS BIT(1) +#define SOF_DBG_MBOX BIT(2) +#define SOF_DBG_TEXT BIT(3) +#define SOF_DBG_PCI BIT(4) +#define SOF_DBG_RETAIN_CTX BIT(5) /* prevent DSP D3 on FW exception */ + +/* global debug state set by SOF_DBG_ flags */ +extern int sof_core_debug; /* max BARs mmaped devices can use */ #define SND_SOF_BARS 8 From 61c3ae2f476554cf1d1423a713cec2fc692c8d8d Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Sun, 8 Sep 2019 15:07:56 +0100 Subject: [PATCH 1627/1995] ASoC: SOF: Intel: initialise and verify FW crash dump data. FW mailbox offset was not set before use and HDR size was not validated. Fix this. Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/bdw.c | 7 +++++++ sound/soc/sof/intel/byt.c | 6 ++++++ sound/soc/sof/intel/hda.c | 7 +++++++ 3 files changed, 20 insertions(+) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index e282179263e834..80e2826fb447b2 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -37,6 +37,7 @@ #define MBOX_SIZE 0x1000 #define MBOX_DUMP_SIZE 0x30 #define EXCEPT_OFFSET 0x800 +#define EXCEPT_MAX_HDR_SIZE 0x400 /* DSP peripherals */ #define DMAC0_OFFSET 0xFE000 @@ -228,6 +229,11 @@ static void bdw_get_registers(struct snd_sof_dev *sdev, /* note: variable AR register array is not read */ /* then get panic info */ + if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) { + dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n", + xoops->arch_hdr.totalsize); + return; + } offset += xoops->arch_hdr.totalsize; sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info)); @@ -451,6 +457,7 @@ static int bdw_probe(struct snd_sof_dev *sdev) /* TODO: add offsets */ sdev->mmio_bar = BDW_DSP_BAR; sdev->mailbox_bar = BDW_DSP_BAR; + sdev->dsp_oops_offset = MBOX_OFFSET; /* PCI base */ mmio = platform_get_resource(pdev, IORESOURCE_MEM, diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 5e7a6aaa627a82..a1e514f7173952 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -28,6 +28,7 @@ #define MBOX_OFFSET 0x144000 #define MBOX_SIZE 0x1000 #define EXCEPT_OFFSET 0x800 +#define EXCEPT_MAX_HDR_SIZE 0x400 /* DSP peripherals */ #define DMAC0_OFFSET 0x098000 @@ -126,6 +127,11 @@ static void byt_get_registers(struct snd_sof_dev *sdev, /* note: variable AR register array is not read */ /* then get panic info */ + if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) { + dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n", + xoops->arch_hdr.totalsize); + return; + } offset += xoops->arch_hdr.totalsize; sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info)); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index c72e9a09eee16a..06e84679087bc6 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -35,6 +35,8 @@ #define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348) #define IS_CNL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9dc8) +#define EXCEPT_MAX_HDR_SIZE 0x400 + /* * Debug */ @@ -131,6 +133,11 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev, /* note: variable AR register array is not read */ /* then get panic info */ + if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) { + dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n", + xoops->arch_hdr.totalsize); + return; + } offset += xoops->arch_hdr.totalsize; sof_block_read(sdev, sdev->mmio_bar, offset, panic_info, sizeof(*panic_info)); From 795136d5eabdf75ffee66cc234b0f8be791a5b59 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 12 Sep 2019 17:26:00 +0100 Subject: [PATCH 1628/1995] ASoC: SOF: ipc: retain DSP context after FW exception. Add config option to prevent DSP entering D3 after any FW exception. This can then be used to dump FW context for debug. Signed-off-by: Liam Girdwood --- sound/soc/sof/Kconfig | 8 ++++++++ sound/soc/sof/debug.c | 16 ++++++++++++++++ sound/soc/sof/ipc.c | 4 +--- sound/soc/sof/sof-priv.h | 1 + 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index cc592bcadae710..56a3ab66b46b7b 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -158,6 +158,14 @@ config SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST Say Y if you want to enable IPC flood test. If unsure, select "N". +config SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT + bool "SOF retain DSP context on any FW exceptions" + help + This option keeps the DSP in D0 state so that firmware debug + information can be retained and dumped to userspace. + Say Y if you want to retain DSP context for FW exceptions. + If unsure, select "N". + endif ## SND_SOC_SOF_DEBUG endif ## SND_SOC_SOF_OPTIONS diff --git a/sound/soc/sof/debug.c b/sound/soc/sof/debug.c index 54cd431faab705..b8a4e899154c63 100644 --- a/sound/soc/sof/debug.c +++ b/sound/soc/sof/debug.c @@ -461,3 +461,19 @@ void snd_sof_free_debug(struct snd_sof_dev *sdev) debugfs_remove_recursive(sdev->debugfs_root); } EXPORT_SYMBOL_GPL(snd_sof_free_debug); + +void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev) +{ + if (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT) || + (sof_core_debug & SOF_DBG_RETAIN_CTX)) { + /* should we prevent DSP entering D3 ? */ + dev_info(sdev->dev, "info: preventing DSP entering D3 state to preserve context\n"); + pm_runtime_get_noresume(sdev->dev); + } + + /* dump vital information to the logs */ + snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX); + snd_sof_ipc_dump(sdev); + snd_sof_trace_notify_for_error(sdev); +} +EXPORT_SYMBOL(snd_sof_handle_fw_exception); diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index b2f359d2f7e530..b946c81197a1d5 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -210,9 +210,7 @@ static int tx_wait_done(struct snd_sof_ipc *ipc, struct snd_sof_ipc_msg *msg, if (ret == 0) { dev_err(sdev->dev, "error: ipc timed out for 0x%x size %d\n", hdr->cmd, hdr->size); - snd_sof_dsp_dbg_dump(ipc->sdev, SOF_DBG_REGS | SOF_DBG_MBOX); - snd_sof_ipc_dump(ipc->sdev); - snd_sof_trace_notify_for_error(ipc->sdev); + snd_sof_handle_fw_exception(ipc->sdev); ret = -ETIMEDOUT; } else { /* copy the data returned from DSP */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 2705fe5c6150c1..348759035dd035 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -581,6 +581,7 @@ void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, struct sof_ipc_panic_info *panic_info, void *stack, size_t stack_words); int snd_sof_init_trace_ipc(struct snd_sof_dev *sdev); +void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev); /* * Platform specific ops. From 630367b5c5789cfc823eb1d90f8f32e1f08589a0 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 12 Sep 2019 17:26:23 +0100 Subject: [PATCH 1629/1995] ASoC: SOF: intel: Add context data to any IPC timeout. Helps with FW debug as it provides DSP IPC processing context. Signed-off-by: Liam Girdwood --- sound/soc/sof/intel/bdw.c | 22 +++++++++++++++++++++- sound/soc/sof/intel/byt.c | 23 ++++++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 80e2826fb447b2..f395d063887656 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -247,7 +247,7 @@ static void bdw_dump(struct snd_sof_dev *sdev, u32 flags) struct sof_ipc_dsp_oops_xtensa xoops; struct sof_ipc_panic_info panic_info; u32 stack[BDW_STACK_DUMP_SIZE]; - u32 status, panic; + u32 status, panic, imrx, imrd; /* now try generic SOF status messages */ status = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IPCD); @@ -256,6 +256,26 @@ static void bdw_dump(struct snd_sof_dev *sdev, u32 flags) BDW_STACK_DUMP_SIZE); snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, BDW_STACK_DUMP_SIZE); + + /* provide some context for firmware debug */ + imrx = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IMRX); + imrd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IMRD); + dev_err(sdev->dev, + "error: ipc host -> DSP: pending %s complete %s raw 0x%8.8x\n", + panic & SHIM_IPCX_BUSY ? "yes" : "no", + panic & SHIM_IPCX_DONE ? "yes" : "no", panic); + dev_err(sdev->dev, + "error: mask host: pending %s complete %s raw 0x%8.8x\n", + imrx & SHIM_IMRX_BUSY ? "yes" : "no", + imrx & SHIM_IMRX_DONE ? "yes" : "no", imrx); + dev_err(sdev->dev, + "error: ipc DSP -> host: pending %s complete %s raw 0x%8.8x\n", + status & SHIM_IPCD_BUSY ? "yes" : "no", + status & SHIM_IPCD_DONE ? "yes" : "no", status); + dev_err(sdev->dev, + "error: mask DSP: pending %s complete %s raw 0x%8.8x\n", + imrd & SHIM_IMRD_BUSY ? "yes" : "no", + imrd & SHIM_IMRD_DONE ? "yes" : "no", imrd); } /* diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index a1e514f7173952..b2597ecfdc1caa 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -145,7 +145,7 @@ static void byt_dump(struct snd_sof_dev *sdev, u32 flags) struct sof_ipc_dsp_oops_xtensa xoops; struct sof_ipc_panic_info panic_info; u32 stack[BYT_STACK_DUMP_SIZE]; - u32 status, panic; + u32 status, panic, imrd, imrx; /* now try generic SOF status messages */ status = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IPCD); @@ -154,6 +154,27 @@ static void byt_dump(struct snd_sof_dev *sdev, u32 flags) BYT_STACK_DUMP_SIZE); snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, BYT_STACK_DUMP_SIZE); + + /* provide some context for firmware debug */ + imrx = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IMRX); + imrd = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IMRD); + dev_err(sdev->dev, + "error: ipc host -> DSP: pending %s complete %s raw 0x%8.8x\n", + panic & SHIM_IPCX_BUSY ? "yes" : "no", + panic & SHIM_IPCX_DONE ? "yes" : "no", panic); + dev_err(sdev->dev, + "error: mask host: pending %s complete %s raw 0x%8.8x\n", + imrx & SHIM_IMRX_BUSY ? "yes" : "no", + imrx & SHIM_IMRX_DONE ? "yes" : "no", imrx); + dev_err(sdev->dev, + "error: ipc DSP -> host: pending %s complete %s raw 0x%8.8x\n", + status & SHIM_IPCD_BUSY ? "yes" : "no", + status & SHIM_IPCD_DONE ? "yes" : "no", status); + dev_err(sdev->dev, + "error: mask DSP: pending %s complete %s raw 0x%8.8x\n", + imrd & SHIM_IMRD_BUSY ? "yes" : "no", + imrd & SHIM_IMRD_DONE ? "yes" : "no", imrd); + } /* From c5dec63aa270eee7e455b94f593fb9e3fcc2c855 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 11 Sep 2019 14:21:55 +0300 Subject: [PATCH 1630/1995] ASoC: SOF: pcm: fix resource leak in hw_free Fix a bug in sof_pcm_hw_free() where some cleanup actions were skipped if STREAM_PCM_FREE IPC was already successfully sent to DSP when the stream was stopped or suspended. This is incorrect as hw_free should clean up also other resources, including pcm lib page allocations, period elapsed work queue and call to platform hw_free. Fixes: c29d96c3b9b4 ("ASoC: SOF: reset DMA state in prepare") Signed-off-by: Kai Vehmanen --- sound/soc/sof/pcm.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index e3f6a6dc0f368a..fa7769dd825c42 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -244,7 +244,7 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; - int ret; + int ret, err = 0; /* nothing to do for BE */ if (rtd->dai_link->no_pcm) @@ -254,26 +254,26 @@ static int sof_pcm_hw_free(struct snd_pcm_substream *substream) if (!spcm) return -EINVAL; - if (!spcm->prepared[substream->stream]) - return 0; - dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); - ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); + if (spcm->prepared[substream->stream]) { + ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); + if (ret < 0) + err = ret; + } snd_pcm_lib_free_pages(substream); cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work); - if (ret < 0) - return ret; - ret = snd_sof_pcm_platform_hw_free(sdev, substream); - if (ret < 0) + if (ret < 0) { dev_err(sdev->dev, "error: platform hw free failed\n"); + err = ret; + } - return ret; + return err; } static int sof_pcm_prepare(struct snd_pcm_substream *substream) From 3f987314df703be35ccea8d891a638defc143454 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 23 Aug 2019 16:53:27 +0800 Subject: [PATCH 1631/1995] ASoC: SOF: add a field to store the current D0 substate of DSP Add field d0_substate to struct snd_sof_dev to store the current DSP D0 sub-state(only meaningful when DSP in D0), which could be D0I0 or D0I3. Signed-off-by: Keyon Jie --- sound/soc/sof/sof-priv.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 348759035dd035..125737356b352e 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -67,6 +67,12 @@ extern int sof_core_debug; #define DMA_CHAN_INVALID 0xFFFFFFFF +/* DSP D0ix sub-state */ +enum sof_d0_substate { + SOF_DSP_D0I0 = 0, /* DSP default D0 substate */ + SOF_DSP_D0I3, /* DSP D0i3(low power) substate*/ +}; + struct snd_sof_dev; struct snd_sof_ipc_msg; struct snd_sof_ipc; @@ -375,6 +381,9 @@ struct snd_sof_dev { */ struct snd_soc_component_driver plat_drv; + /* power states related */ + enum sof_d0_substate d0_substate; + /* DSP firmware boot */ wait_queue_head_t boot_wait; u32 boot_complete; From bcd30243e340ee645087b7fe63308ac6a673ff63 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 23 Aug 2019 16:59:37 +0800 Subject: [PATCH 1632/1995] ASoC: SOF: reset default d0_substate at probe() and resume() We initialize/reset d0_substate to default d0i0 value when doing transition D3-->D0, e.g. at success of probing and resuming. Signed-off-by: Keyon Jie --- sound/soc/sof/core.c | 3 +++ sound/soc/sof/pm.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 15167b8220ed91..e047912b22dbc2 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -458,6 +458,9 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) /* initialize sof device */ sdev->dev = dev; + /* initialize default D0 sub-state */ + sdev->d0_substate = SOF_DSP_D0I0; + sdev->pdata = plat_data; sdev->first_boot = true; dev_set_drvdata(dev, sdev); diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index e23beaeefe0054..81e623dfc7e52b 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -326,6 +326,9 @@ static int sof_resume(struct device *dev, bool runtime_resume) "error: ctx_restore ipc error during resume %d\n", ret); + /* initialize default D0 sub-state */ + sdev->d0_substate = SOF_DSP_D0I0; + return ret; } From 0a3cc629ce8400cad4266e18eb2a35868d3ff4ec Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 23 Aug 2019 18:05:12 +0800 Subject: [PATCH 1633/1995] ASoC: SOF: add set_power_state() to dsp_ops for power state update D0i3 is a platform-defined substate of D0, so we need a platform-specific callback in dsp_ops to handle the relevant configurations. Signed-off-by: Keyon Jie --- sound/soc/sof/ops.h | 9 +++++++++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 824d36fe59fd0d..d7c8fc06f961d6 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -193,6 +193,15 @@ static inline int snd_sof_dsp_set_clk(struct snd_sof_dev *sdev, u32 freq) return 0; } +static inline int snd_sof_dsp_set_power_state(struct snd_sof_dev *sdev, + enum sof_d0_substate substate) +{ + if (sof_ops(sdev)->set_power_state) + return sof_ops(sdev)->set_power_state(sdev, substate); + + return 0; +} + /* debug */ static inline void snd_sof_dsp_dbg_dump(struct snd_sof_dev *sdev, u32 flags) { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 125737356b352e..21000cb8b4b507 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -188,6 +188,8 @@ struct snd_sof_dsp_ops { int (*runtime_resume)(struct snd_sof_dev *sof_dev); /* optional */ int (*runtime_idle)(struct snd_sof_dev *sof_dev); /* optional */ int (*set_hw_params_upon_resume)(struct snd_sof_dev *sdev); /* optional */ + int (*set_power_state)(struct snd_sof_dev *sdev, + enum sof_d0_substate d0_substate); /* optional */ /* DSP clocking */ int (*set_clk)(struct snd_sof_dev *sof_dev, u32 freq); /* optional */ From d3ea13dfa52d00b80a9005a34b11b6c7df581fc2 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 31 Jul 2019 16:46:41 +0800 Subject: [PATCH 1634/1995] ASoC: SOF: Intel: hda-dsp: Add helper for setting DSP D0ix substate Adding helper to implement setting dsp to d0i3 or d0i0 status, this will be needed for driver D0ix support. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-dsp.c | 46 +++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 10 ++++++++ 2 files changed, 56 insertions(+) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index fb55a3c5afd0d5..f456ba962c8f1c 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -282,6 +282,52 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0); } +static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev, int retry) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + while (snd_hdac_chip_readb(bus, VS_D0I3C) & SOF_HDA_VS_D0I3C_CIP) { + if (!retry--) + return -ETIMEDOUT; + usleep_range(10, 15); + } + + return 0; +} + +int hda_dsp_set_power_state(struct snd_sof_dev *sdev, + enum sof_d0_substate d0_substate) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int retry = 50; + int ret; + u8 value; + + /* Write to D0I3C after Command-In-Progress bit is cleared */ + ret = hda_dsp_wait_d0i3c_done(sdev, retry); + if (ret < 0) { + dev_err(bus->dev, "CIP timeout before update D0I3C!\n"); + return ret; + } + + /* Update D0I3C register */ + value = d0_substate == SOF_DSP_D0I3 ? SOF_HDA_VS_D0I3C_I3 : 0; + snd_hdac_chip_updateb(bus, VS_D0I3C, SOF_HDA_VS_D0I3C_I3, value); + + /* Wait for cmd in progress to be cleared before exiting the function */ + retry = 50; + ret = hda_dsp_wait_d0i3c_done(sdev, retry); + if (ret < 0) { + dev_err(bus->dev, "CIP timeout after D0I3C updated!\n"); + return ret; + } + + dev_vdbg(bus->dev, "D0I3C updated, register = 0x%x\n", + snd_hdac_chip_readb(bus, VS_D0I3C)); + + return 0; +} + static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 5591841a1b6faf..7a2ff8b3d8a440 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -65,6 +65,13 @@ #define SOF_HDA_PPCTL_PIE BIT(31) #define SOF_HDA_PPCTL_GPROCEN BIT(30) +/*Vendor Specific Registers*/ +#define SOF_HDA_VS_D0I3C 0x104A + +/* D0I3C Register fields */ +#define SOF_HDA_VS_D0I3C_CIP BIT(0) /* Command-In-Progress */ +#define SOF_HDA_VS_D0I3C_I3 BIT(2) /* D0i3 enable bit */ + /* DPIB entry size: 8 Bytes = 2 DWords */ #define SOF_HDA_DPIB_ENTRY_SIZE 0x8 @@ -452,6 +459,9 @@ int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev); void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev); +int hda_dsp_set_power_state(struct snd_sof_dev *sdev, + enum sof_d0_substate d0_substate); + int hda_dsp_suspend(struct snd_sof_dev *sdev); int hda_dsp_resume(struct snd_sof_dev *sdev); int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev); From b5305a1f268951f18ba33d35d896ba946ac378e8 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 23 Aug 2019 18:27:22 +0800 Subject: [PATCH 1635/1995] ASoC: SOF: Intel: CNL: add set_power_state() ops Using hda_dsp_set_power_state() as set_power_state() ops for cnl to do d0ix platform configuration updates. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/cnl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 4ddd73762d813a..f5ed474474baa4 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -255,6 +255,7 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .runtime_resume = hda_dsp_runtime_resume, .runtime_idle = hda_dsp_runtime_idle, .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, + .set_power_state = hda_dsp_set_power_state, }; EXPORT_SYMBOL(sof_cnl_ops); From c4e77f25c647606da15fd0c48e48037148bb1d49 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 23 Aug 2019 18:30:00 +0800 Subject: [PATCH 1636/1995] ASoC: SOF: Intel: APL: add set_power_state() ops Using hda_dsp_set_power_state() as set_power_state() ops for apl to do d0ix platform configuration updates. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/apl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 8dc7a5558da4da..308bec97b53753 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -97,6 +97,7 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .runtime_resume = hda_dsp_runtime_resume, .runtime_idle = hda_dsp_runtime_idle, .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, + .set_power_state = hda_dsp_set_power_state, }; EXPORT_SYMBOL(sof_apl_ops); From 0b9151969bb327842861c58f3b9966b978c494ae Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Thu, 1 Aug 2019 17:30:25 +0800 Subject: [PATCH 1637/1995] ASoC: SOF: add flag to snd_sof_pcm_stream for D0i3 compatible stream Add flag d0i3_compatible to struct snd_sof_pcm_stream to denote if the stream can tolerate a transition to the D0i3 substate while opened (thus seen as 'active' by pm_runtime). Signed-off-by: Keyon Jie --- sound/soc/sof/sof-priv.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 21000cb8b4b507..9490e4c33c3b63 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -306,6 +306,7 @@ struct snd_sof_pcm_stream { struct sof_ipc_stream_posn posn; struct snd_pcm_substream *substream; struct work_struct period_elapsed_work; + bool d0i3_compatible; /* DSP can be in D0I3 when this pcm is opened */ }; /* ALSA SOF PCM device */ From 16e6318c1147bdbf5c9295592e8e52bd4d83c119 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Thu, 1 Aug 2019 17:29:00 +0800 Subject: [PATCH 1638/1995] ASoC: SOF: token: add tokens for PCM compatible with D0i3 substate Add stream token SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3 and SOF_TKN_STREAM_CAPTURE_COMPATIBLE_D0I3 to denote if the stream can be opened at low power d0i3 status or not. Signed-off-by: Keyon Jie --- include/uapi/sound/sof/tokens.h | 4 ++++ sound/soc/sof/topology.c | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 8f996857fb2427..1627e1f9fe1190 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -114,4 +114,8 @@ #define SOF_TKN_IMX_ESAI_FIRST_TOKEN 1100 /* TODO: Add ESAI tokens */ +/* Stream */ +#define SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3 1200 +#define SOF_TKN_STREAM_CAPTURE_COMPATIBLE_D0I3 1201 + #endif diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 0aabb3190ddc97..65d8e0022fbf62 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -724,6 +724,16 @@ static const struct sof_topology_token pcm_tokens[] = { offsetof(struct sof_ipc_comp_host, dmac_config), 0}, }; +/* PCM */ +static const struct sof_topology_token stream_tokens[] = { + {SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3, + SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, + offsetof(struct snd_sof_pcm, stream[0].d0i3_compatible), 0}, + {SOF_TKN_STREAM_CAPTURE_COMPATIBLE_D0I3, + SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, + offsetof(struct snd_sof_pcm, stream[1].d0i3_compatible), 0}, +}; + /* Generic components */ static const struct sof_topology_token comp_tokens[] = { {SOF_TKN_COMP_PERIOD_SINK_COUNT, From 6fc7eb30029afb1fad671a72c7171757f154dfd7 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Thu, 1 Aug 2019 17:35:55 +0800 Subject: [PATCH 1639/1995] ASoC: SOF: topology: parse and store d0i3_compatible flag Parses the token from tplg file and store it to snd_sof_pcm_stream d0i3_compatible flag, which can be used later for d0ix transition management. Signed-off-by: Keyon Jie --- sound/soc/sof/topology.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 65d8e0022fbf62..46aab02977530c 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2281,6 +2281,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_stream_caps *caps; + struct snd_soc_tplg_private *private = &pcm->priv; struct snd_sof_pcm *spcm; int stream = SNDRV_PCM_STREAM_PLAYBACK; int ret = 0; @@ -2304,10 +2305,22 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, dai_drv->dobj.private = spcm; list_add(&spcm->list, &sdev->pcm_list); + ret = sof_parse_tokens(scomp, spcm, stream_tokens, + ARRAY_SIZE(stream_tokens), private->array, + le32_to_cpu(private->size)); + if (ret) { + dev_err(sdev->dev, "error: parse stream tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + /* do we need to allocate playback PCM DMA pages */ if (!spcm->pcm.playback) goto capture; + dev_vdbg(sdev->dev, "tplg: pcm %s stream tokens: playback d0i3:%d\n", + spcm->pcm.pcm_name, spcm->stream[0].d0i3_compatible); + caps = &spcm->pcm.caps[stream]; /* allocate playback page table buffer */ @@ -2335,6 +2348,9 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, if (!spcm->pcm.capture) return ret; + dev_vdbg(sdev->dev, "tplg: pcm %s stream tokens: capture d0i3:%d\n", + spcm->pcm.pcm_name, spcm->stream[1].d0i3_compatible); + caps = &spcm->pcm.caps[stream]; /* allocate capture page table buffer */ From a45d08d36bfbff336c304bc164da7e78b981d46d Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Thu, 19 Sep 2019 15:35:34 +0800 Subject: [PATCH 1640/1995] ASoC: SOF: pcm: harden PCM STOP sequence The old STOP sequence is: 1. stop DMA 2. send STOP ipc If delay happen before the steps 1 and 2, the DMA buffer will be empty in short time and cause pipeline xrun then stop the pipeline. Then the step 2 ipc stop will return error as pipeline is already stopped. Suggested change to avoid the issue is to switch the order of steps 1 and 2 for the stop sequence. Signed-off-by: Pan Xiuli --- sound/soc/sof/pcm.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index fa7769dd825c42..2b876d4974476b 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -323,6 +323,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct sof_ipc_stream stream; struct sof_ipc_reply reply; bool reset_hw_params = false; + bool ipc_first = false; int ret; /* nothing to do for BE */ @@ -343,6 +344,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_PAUSE_PUSH: stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_PAUSE; + ipc_first = true; break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE; @@ -363,6 +365,7 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; + ipc_first = true; reset_hw_params = true; break; default: @@ -370,12 +373,22 @@ static int sof_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return -EINVAL; } - snd_sof_pcm_platform_trigger(sdev, substream, cmd); + /* + * DMA and IPC sequence is different for start and stop. Need to send + * STOP IPC before stop DMA + */ + if (!ipc_first) + snd_sof_pcm_platform_trigger(sdev, substream, cmd); /* send IPC to the DSP */ ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, sizeof(stream), &reply, sizeof(reply)); + /* need to STOP DMA even if STOP IPC failed */ + if (ipc_first) + snd_sof_pcm_platform_trigger(sdev, substream, cmd); + + /* free PCM if reset_hw_params is set and the STOP IPC is successful */ if (!ret && reset_hw_params) ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); From ec67965c906d79d72c489481ebbfc4bd3a70f528 Mon Sep 17 00:00:00 2001 From: Marcin Rajwa Date: Fri, 14 Jun 2019 02:41:10 +0200 Subject: [PATCH 1641/1995] ASoC: SOF: introduce no_stream_position in sof_ipc_stream_params struct The host period bytes value needs to be passed to firmware. However current implementation uses this field for different purpose - to indicate whether FW should send stream position to the host. Therefore this patch introduces another field "no_stream_position", a boolean value aimed to store information about position tracking. This way host_period_bytes preserves its original value. Signed-off-by: Marcin Rajwa --- include/sound/sof/stream.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/sound/sof/stream.h b/include/sound/sof/stream.h index 0b71b381b952e4..7facefb541b36a 100644 --- a/include/sound/sof/stream.h +++ b/include/sound/sof/stream.h @@ -83,10 +83,10 @@ struct sof_ipc_stream_params { uint16_t sample_valid_bytes; uint16_t sample_container_bytes; - /* for notifying host period has completed - 0 means no period IRQ */ uint32_t host_period_bytes; + uint16_t no_stream_position; /**< 1 means don't send stream position */ - uint32_t reserved[2]; + uint16_t reserved[3]; uint16_t chmap[SOF_IPC_MAX_CHANNELS]; /**< channel map - SOF_CHMAP_ */ } __packed; From 29561c621ca4edd6e0b1d12cd2ddad6e2c717329 Mon Sep 17 00:00:00 2001 From: Marcin Rajwa Date: Fri, 14 Jun 2019 02:44:13 +0200 Subject: [PATCH 1642/1995] ASoC: SOF: Intel: fix reset of host_period_bytes This patch prevents the reset of host period bytes and uses no_stream_position to record requests for stream position. Signed-off-by: Marcin Rajwa --- sound/soc/sof/intel/hda-pcm.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 9b730f18352918..79e0247f6487f7 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -89,6 +89,7 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream = stream_to_hdac_ext_stream(hstream); struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct snd_dma_buffer *dmab; + struct sof_ipc_fw_version *v = &sdev->fw_ready.version; int ret; u32 size, rate, bits; @@ -116,9 +117,17 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, /* disable SPIB, to enable buffer wrap for stream */ hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); - /* set host_period_bytes to 0 if no IPC position */ - if (hda && hda->no_ipc_position) - ipc_params->host_period_bytes = 0; + /* update no_stream_position flag for ipc params */ + if (hda && hda->no_ipc_position) { + /* For older ABIs set host_period_bytes to zero to inform + * FW we don't want position updates. Newer versions use + * no_stream_position for this purpose. + */ + if (v->abi_version < SOF_ABI_VER(3, 11, 0)) + ipc_params->host_period_bytes = 0; + else + ipc_params->no_stream_position = 1; + } ipc_params->stream_tag = hstream->stream_tag; From 208c9c65cf8843061d874f2c76a03f2c9b32f940 Mon Sep 17 00:00:00 2001 From: Naveen Manohar Date: Sun, 26 May 2019 10:45:06 +0530 Subject: [PATCH 1643/1995] ASoC: Intel: Add acpi match for rt1011 based m/c driver Add match for CML m/c with RT1011 and RT5682 Signed-off-by: Naveen Manohar Signed-off-by: Sathya Prakash M R --- sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index 985aa366c9e8a3..16d0bae8b316ae 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -47,6 +47,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .sof_fw_filename = "sof-cnl.ri", .sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg", }, + { + .id = "10EC1011", + .drv_name = "cml_rt1011_rt5682", + .quirk_data = &cml_codecs, + .sof_fw_filename = "sof-cnl.ri", + .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg", + }, { .id = "10EC5682", .drv_name = "sof_rt5682", From f05b2682f29f3cc9d16e0bf902081a24b4257bde Mon Sep 17 00:00:00 2001 From: Naveen Manohar Date: Sun, 26 May 2019 10:56:43 +0530 Subject: [PATCH 1644/1995] ASoC: Intel: boards: Add CML m/c using RT1011 and RT5682 Machine driver to enable RT5682 on SSP0, DMIC, HDMI and RT1011 AMP on SSP1 with 2 CH / 24 bit TDM Playback over 4 individual codecs and 4 CH / 24 bit Capture to provide feedback. Signed-off-by: Naveen Manohar Signed-off-by: Sathya Prakash M R --- sound/soc/intel/boards/Kconfig | 14 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/cml_rt1011_rt5682.c | 475 +++++++++++++++++++++ 3 files changed, 491 insertions(+) create mode 100644 sound/soc/intel/boards/cml_rt1011_rt5682.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index c153bc9621ed02..470b7ca1b8bb6f 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -447,6 +447,20 @@ config SND_SOC_INTEL_CML_LP_DA7219_MAX98357A_MACH depends on MFD_INTEL_LPSS || COMPILE_TEST select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC +config SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH + tristate "CML with RT1011 and RT5682 in I2S Mode" + depends on I2C && ACPI + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_RT1011 + select SND_SOC_RT5682 + select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI + help + This adds support for ASoC machine driver for SOF platform with + RT1011 + RT5682 I2S codec. + Say Y if you have such a device. + If unsure select "N". + endif ## SND_SOC_SOF_COMETLAKE_LP && SND_SOC_SOF_HDA_LINK if SND_SOC_SOF_TIGERLAKE diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 14b257d8413aaa..bfbea59f7bb530 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -20,6 +20,7 @@ snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o snd-soc-sof_rt5682-objs := sof_rt5682.o +snd-soc-cml_rt1011_rt5682-objs := cml_rt1011_rt5682.o snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o @@ -52,6 +53,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_CX2072X_MACH) += snd-soc-sst-byt-cht-cx2072x. obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH) += cml_rt1011_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o diff --git a/sound/soc/intel/boards/cml_rt1011_rt5682.c b/sound/soc/intel/boards/cml_rt1011_rt5682.c new file mode 100644 index 00000000000000..f2837a20834199 --- /dev/null +++ b/sound/soc/intel/boards/cml_rt1011_rt5682.c @@ -0,0 +1,475 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2019 Intel Corporation. + +/* + * Intel Cometlake I2S Machine driver for RT1011 + RT5682 codec + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/rt1011.h" +#include "../../codecs/rt5682.h" +#include "../../codecs/hdac_hdmi.h" + +/* The platform clock outputs 24Mhz clock to codec as I2S MCLK */ +#define CML_PLAT_CLK 24000000 +#define CML_RT1011_CODEC_DAI "rt1011-aif" +#define CML_RT5682_CODEC_DAI "rt5682-aif1" +#define NAME_SIZE 32 + +static struct snd_soc_jack hdmi_jack[3]; + +struct hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct card_private { + char codec_name[SND_ACPI_I2C_ID_LEN]; + struct snd_soc_jack headset; + struct list_head hdmi_pcm_list; +}; + +static const struct snd_kcontrol_new cml_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("TL Ext Spk"), + SOC_DAPM_PIN_SWITCH("TR Ext Spk"), + SOC_DAPM_PIN_SWITCH("WL Ext Spk"), + SOC_DAPM_PIN_SWITCH("WR Ext Spk"), +}; + +static const struct snd_soc_dapm_widget cml_rt1011_rt5682_widgets[] = { + SND_SOC_DAPM_SPK("TL Ext Spk", NULL), + SND_SOC_DAPM_SPK("TR Ext Spk", NULL), + SND_SOC_DAPM_SPK("WL Ext Spk", NULL), + SND_SOC_DAPM_SPK("WR Ext Spk", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("SoC DMIC", NULL), +}; + +static const struct snd_soc_dapm_route cml_rt1011_rt5682_map[] = { + /*speaker*/ + {"TL Ext Spk", NULL, "TL SPO"}, + {"TR Ext Spk", NULL, "TR SPO"}, + {"WL Ext Spk", NULL, "WL SPO"}, + {"WR Ext Spk", NULL, "WR SPO"}, + + /* HP jack connectors - unknown if we have jack detection */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + + /* other jacks */ + { "IN1P", NULL, "Headset Mic" }, + + /* DMIC */ + {"DMic", NULL, "SoC DMIC"}, +}; + +static int cml_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_component *component = rtd->codec_dai->component; + struct snd_soc_jack *jack; + int ret; + + /* need to enable ASRC function for 24MHz mclk rate */ + rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER | + RT5682_AD_STEREO1_FILTER, + RT5682_CLK_SEL_I2S1_ASRC); + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->headset, NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + jack = &ctx->headset; + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + ret = snd_soc_component_set_jack(component, jack, NULL); + if (ret) + dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); + + return ret; +}; + +static int cml_rt5682_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 clk_id, clk_freq, pll_out, ret; + + clk_id = RT5682_PLL1_S_MCLK; + clk_freq = CML_PLAT_CLK; + + pll_out = params_rate(params) * 512; + + ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); + if (ret < 0) + dev_warn(rtd->dev, "snd_soc_dai_set_pll err = %d\n", ret); + + /* Configure sysclk for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, + pll_out, SND_SOC_CLOCK_IN); + if (ret < 0) + dev_warn(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + + /* + * slot_width should be equal or large than data length, set them + * be the same + */ + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, + params_width(params)); + if (ret < 0) + dev_warn(rtd->dev, "set TDM slot err:%d\n", ret); + return ret; +} + +static int cml_rt1011_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; + struct snd_soc_card *card = rtd->card; + int srate, i, ret = 0; + + srate = params_rate(params); + + for (i = 0; i < rtd->num_codecs; i++) { + codec_dai = rtd->codec_dais[i]; + + /* 100 Fs to drive 24 bit data */ + ret = snd_soc_dai_set_pll(codec_dai, 0, RT1011_PLL1_S_BCLK, + 100 * srate, 256 * srate); + if (ret < 0) { + dev_err(card->dev, "codec_dai clock not set\n"); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, + RT1011_FS_SYS_PRE_S_PLL1, + 256 * srate, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "codec_dai clock not set\n"); + return ret; + } + + /* + * Codec TDM is configured as 24 bit capture/ playback. + * 2 CH PB is done over 4 codecs - 2 Woofers and 2 Tweeters. + * The Left woofer and tweeter plays the Left playback data + * and similar by the Right. + * Hence 2 codecs (1 T and 1 W pair) share same Rx slot. + * The feedback is captured for each codec individually. + * Hence all 4 codecs use 1 Tx slot each for feedback. + */ + if (!strcmp(codec_dai->component->name, "i2c-10EC1011:00")) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + 0x4, 0x1, 4, 24); + if (ret < 0) + break; + } + if (!strcmp(codec_dai->component->name, "i2c-10EC1011:02")) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + 0x1, 0x1, 4, 24); + if (ret < 0) + break; + } + /* TDM Rx slot 2 is used for Right Woofer & Tweeters pair */ + if (!strcmp(codec_dai->component->name, "i2c-10EC1011:01")) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + 0x8, 0x2, 4, 24); + if (ret < 0) + break; + } + if (!strcmp(codec_dai->component->name, "i2c-10EC1011:03")) { + ret = snd_soc_dai_set_tdm_slot(codec_dai, + 0x2, 0x2, 4, 24); + if (ret < 0) + break; + } + } + if (ret < 0) + dev_err(rtd->dev, + "set codec TDM slot for %s failed with error %d\n", + codec_dai->component->name, ret); + return ret; +} + +static struct snd_soc_ops cml_rt5682_ops = { + .hw_params = cml_rt5682_hw_params, +}; + +static const struct snd_soc_ops cml_rt1011_ops = { + .hw_params = cml_rt1011_hw_params, +}; + +static int sof_card_late_probe(struct snd_soc_card *card) +{ + struct card_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component = NULL; + char jack_name[NAME_SIZE]; + struct hdmi_pcm *pcm; + int ret, i = 0; + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + ret = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &hdmi_jack[i], + NULL, 0); + if (ret) + return ret; + + ret = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &hdmi_jack[i]); + if (ret < 0) + return ret; + + i++; + } + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); +} + +static int hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = dai->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +/* Cometlake digital audio interface glue - connects codec <--> CPU */ + +SND_SOC_DAILINK_DEF(ssp0_pin, + DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); +SND_SOC_DAILINK_DEF(ssp0_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", + CML_RT5682_CODEC_DAI))); + +SND_SOC_DAILINK_DEF(ssp1_pin, + DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); +SND_SOC_DAILINK_DEF(ssp1_codec, + DAILINK_COMP_ARRAY( + /* WL */ COMP_CODEC("i2c-10EC1011:00", CML_RT1011_CODEC_DAI), + /* WR */ COMP_CODEC("i2c-10EC1011:01", CML_RT1011_CODEC_DAI), + /* TL */ COMP_CODEC("i2c-10EC1011:02", CML_RT1011_CODEC_DAI), + /* TR */ COMP_CODEC("i2c-10EC1011:03", CML_RT1011_CODEC_DAI))); + +SND_SOC_DAILINK_DEF(dmic_pin, + DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); + +SND_SOC_DAILINK_DEF(dmic16k_pin, + DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); + +SND_SOC_DAILINK_DEF(dmic_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); + +SND_SOC_DAILINK_DEF(idisp1_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); +SND_SOC_DAILINK_DEF(idisp1_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); + +SND_SOC_DAILINK_DEF(idisp2_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); +SND_SOC_DAILINK_DEF(idisp2_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); + +SND_SOC_DAILINK_DEF(idisp3_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); +SND_SOC_DAILINK_DEF(idisp3_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); + +SND_SOC_DAILINK_DEF(platform, + DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); + +static struct snd_soc_dai_link cml_rt1011_rt5682_dailink[] = { + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .id = 0, + .init = cml_rt5682_codec_init, + .ignore_pmdown_time = 1, + .ops = &cml_rt5682_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), + }, + { + .name = "dmic01", + .id = 1, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), + }, + { + .name = "dmic16k", + .id = 2, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform), + }, + { + .name = "iDisp1", + .id = 3, + .init = hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), + }, + { + .name = "iDisp2", + .id = 4, + .init = hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), + }, + { + .name = "iDisp3", + .id = 5, + .init = hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), + }, + { + /* + * SSP1 - Codec : added to end of list ensuring + * reuse of common topologies for other end points + * and changing only SSP1's codec + */ + .name = "SSP1-Codec", + .id = 6, + .dpcm_playback = 1, + .dpcm_capture = 1, /* Capture stream provides Feedback */ + .no_pcm = 1, + .ops = &cml_rt1011_ops, + SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), + }, +}; + +static struct snd_soc_codec_conf rt1011_conf[] = { + { + .dev_name = "i2c-10EC1011:00", + .name_prefix = "WL", + }, + { + .dev_name = "i2c-10EC1011:01", + .name_prefix = "WR", + }, + { + .dev_name = "i2c-10EC1011:02", + .name_prefix = "TL", + }, + { + .dev_name = "i2c-10EC1011:03", + .name_prefix = "TR", + }, +}; + +/* Cometlake audio machine driver for RT1011 and RT5682 */ +static struct snd_soc_card snd_soc_card_cml = { + .name = "cml_rt1011_rt5682", + .dai_link = cml_rt1011_rt5682_dailink, + .num_links = ARRAY_SIZE(cml_rt1011_rt5682_dailink), + .codec_conf = rt1011_conf, + .num_configs = ARRAY_SIZE(rt1011_conf), + .dapm_widgets = cml_rt1011_rt5682_widgets, + .num_dapm_widgets = ARRAY_SIZE(cml_rt1011_rt5682_widgets), + .dapm_routes = cml_rt1011_rt5682_map, + .num_dapm_routes = ARRAY_SIZE(cml_rt1011_rt5682_map), + .controls = cml_controls, + .num_controls = ARRAY_SIZE(cml_controls), + .fully_routed = true, + .late_probe = sof_card_late_probe, +}; + +static int snd_cml_rt1011_probe(struct platform_device *pdev) +{ + struct card_private *ctx; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + int ret; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + mach = (&pdev->dev)->platform_data; + snd_soc_card_cml.dev = &pdev->dev; + platform_name = mach->mach_params.platform; + + /* set platform name for each dailink */ + ret = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cml, + platform_name); + if (ret) + return ret; + snd_soc_card_set_drvdata(&snd_soc_card_cml, ctx); + + return devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cml); +} + +static struct platform_driver snd_cml_rt1011_rt5682_driver = { + .probe = snd_cml_rt1011_probe, + .driver = { + .name = "cml_rt1011_rt5682", + .pm = &snd_soc_pm_ops, + }, +}; +module_platform_driver(snd_cml_rt1011_rt5682_driver); + +/* Module information */ +MODULE_DESCRIPTION("Cometlake Audio Machine driver - RT1011 and RT5682 in I2S mode"); +MODULE_AUTHOR("Naveen Manohar "); +MODULE_AUTHOR("Sathya Prakash M R "); +MODULE_AUTHOR("Shuming Fan "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cml_rt1011_rt5682"); From e03f8829f95c175f63c808f5747b977e7c443765 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 23 Sep 2019 15:45:46 -0500 Subject: [PATCH 1645/1995] ASoC: SOF: Intel: fix ABI level check for no_stream_position The firmware ABI was not updated, so testing against a future revision makes no sense. The current checks essentially force the IPC position to be reported, which is a change of behavior. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 79e0247f6487f7..575f5f5877d85a 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -123,7 +123,7 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev, * FW we don't want position updates. Newer versions use * no_stream_position for this purpose. */ - if (v->abi_version < SOF_ABI_VER(3, 11, 0)) + if (v->abi_version < SOF_ABI_VER(3, 10, 0)) ipc_params->host_period_bytes = 0; else ipc_params->no_stream_position = 1; From acd4ab2e89e9351d2a9634cb76da3a8a2a05601d Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 28 Jun 2019 17:36:15 +0300 Subject: [PATCH 1646/1995] drm/i915: Move the TypeC port handling code to a separate file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the TypeC port handling functions to a new file for clarity. While at it: - s/icl_tc_port_connected()/intel_tc_port_connected()/ icl_tc_phy_disconnect(), will be unexported later. - s/intel_dp_get_fia_supported_lane_count()/ intel_tc_port_fia_max_lane_count()/ It's used for HDMI legacy mode too. - Simplify function interfaces by passing only dig_port to them. No functional changes. v2: - Fix checkpatch issues: +1/-1 empty lines in intel_tc.c and add missing SPDX to intel_tc.h. (Jani) Cc: Animesh Manna Cc: Paulo Zanoni Cc: José Roberto de Souza Cc: Jani Nikula Signed-off-by: Imre Deak Acked-by: Jani Nikula Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20190628143635.22066-4-imre.deak@intel.com --- drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/display/intel_ddi.c | 6 +- drivers/gpu/drm/i915/display/intel_dp.c | 194 +------------------ drivers/gpu/drm/i915/display/intel_dp.h | 2 - drivers/gpu/drm/i915/display/intel_tc.c | 230 +++++++++++++++++++++++ drivers/gpu/drm/i915/display/intel_tc.h | 18 ++ 6 files changed, 256 insertions(+), 197 deletions(-) create mode 100644 drivers/gpu/drm/i915/display/intel_tc.c create mode 100644 drivers/gpu/drm/i915/display/intel_tc.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 8cace65f50ce2f..c212d9dff5d13b 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -173,7 +173,8 @@ i915-y += \ display/intel_overlay.o \ display/intel_psr.o \ display/intel_quirks.o \ - display/intel_sprite.o + display/intel_sprite.o \ + display/intel_tc.o i915-$(CONFIG_ACPI) += \ display/intel_acpi.o \ display/intel_opregion.o diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 1cb1fa74cfbc97..980f729e3d9234 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -45,6 +45,7 @@ #include "intel_lspcon.h" #include "intel_panel.h" #include "intel_psr.h" +#include "intel_tc.h" #include "intel_vdsc.h" struct ddi_buf_trans { @@ -3917,7 +3918,6 @@ static int intel_ddi_compute_config(struct intel_encoder *encoder, static void intel_ddi_encoder_suspend(struct intel_encoder *encoder) { struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base); - struct drm_i915_private *i915 = to_i915(encoder->base.dev); intel_dp_encoder_suspend(encoder); @@ -3927,7 +3927,7 @@ static void intel_ddi_encoder_suspend(struct intel_encoder *encoder) * even if the sink has disappeared while being suspended. */ if (dig_port->tc_legacy_port) - icl_tc_phy_disconnect(i915, dig_port); + icl_tc_phy_disconnect(dig_port); } static void intel_ddi_encoder_reset(struct drm_encoder *drm_encoder) @@ -3949,7 +3949,7 @@ static void intel_ddi_encoder_destroy(struct drm_encoder *encoder) intel_dp_encoder_flush_work(encoder); if (intel_port_is_tc(i915, dig_port->base.port)) - icl_tc_phy_disconnect(i915, dig_port); + icl_tc_phy_disconnect(dig_port); drm_encoder_cleanup(encoder); kfree(dig_port); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index d0fc3482677179..3d3e80ce7fcfd6 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -62,6 +62,7 @@ #include "intel_panel.h" #include "intel_psr.h" #include "intel_sideband.h" +#include "intel_tc.h" #include "intel_vdsc.h" #define DP_DPRX_ESI_LEN 14 @@ -251,7 +252,7 @@ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp) struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); int source_max = intel_dig_port->max_lanes; int sink_max = drm_dp_max_lane_count(intel_dp->dpcd); - int fia_max = intel_dp_get_fia_supported_lane_count(intel_dp); + int fia_max = intel_tc_port_fia_max_lane_count(intel_dig_port); return min3(source_max, sink_max, fia_max); } @@ -5233,195 +5234,6 @@ static bool icl_combo_port_connected(struct drm_i915_private *dev_priv, return I915_READ(SDEISR) & SDE_DDI_HOTPLUG_ICP(port); } -static const char *tc_type_name(enum tc_port_type type) -{ - static const char * const names[] = { - [TC_PORT_UNKNOWN] = "unknown", - [TC_PORT_LEGACY] = "legacy", - [TC_PORT_TYPEC] = "typec", - [TC_PORT_TBT] = "tbt", - }; - - if (WARN_ON(type >= ARRAY_SIZE(names))) - type = TC_PORT_UNKNOWN; - - return names[type]; -} - -static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, - struct intel_digital_port *intel_dig_port, - bool is_legacy, bool is_typec, bool is_tbt) -{ - enum port port = intel_dig_port->base.port; - enum tc_port_type old_type = intel_dig_port->tc_type; - - WARN_ON(is_legacy + is_typec + is_tbt != 1); - - if (is_legacy) - intel_dig_port->tc_type = TC_PORT_LEGACY; - else if (is_typec) - intel_dig_port->tc_type = TC_PORT_TYPEC; - else if (is_tbt) - intel_dig_port->tc_type = TC_PORT_TBT; - else - return; - - /* Types are not supposed to be changed at runtime. */ - WARN_ON(old_type != TC_PORT_UNKNOWN && - old_type != intel_dig_port->tc_type); - - if (old_type != intel_dig_port->tc_type) - DRM_DEBUG_KMS("Port %c has TC type %s\n", port_name(port), - tc_type_name(intel_dig_port->tc_type)); -} - -/* - * This function implements the first part of the Connect Flow described by our - * specification, Gen11 TypeC Programming chapter. The rest of the flow (reading - * lanes, EDID, etc) is done as needed in the typical places. - * - * Unlike the other ports, type-C ports are not available to use as soon as we - * get a hotplug. The type-C PHYs can be shared between multiple controllers: - * display, USB, etc. As a result, handshaking through FIA is required around - * connect and disconnect to cleanly transfer ownership with the controller and - * set the type-C power state. - * - * We could opt to only do the connect flow when we actually try to use the AUX - * channels or do a modeset, then immediately run the disconnect flow after - * usage, but there are some implications on this for a dynamic environment: - * things may go away or change behind our backs. So for now our driver is - * always trying to acquire ownership of the controller as soon as it gets an - * interrupt (or polls state and sees a port is connected) and only gives it - * back when it sees a disconnect. Implementation of a more fine-grained model - * will require a lot of coordination with user space and thorough testing for - * the extra possible cases. - */ -static bool icl_tc_phy_connect(struct drm_i915_private *dev_priv, - struct intel_digital_port *dig_port) -{ - enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); - u32 val; - - if (dig_port->tc_type != TC_PORT_LEGACY && - dig_port->tc_type != TC_PORT_TYPEC) - return true; - - val = I915_READ(PORT_TX_DFLEXDPPMS); - if (!(val & DP_PHY_MODE_STATUS_COMPLETED(tc_port))) { - DRM_DEBUG_KMS("DP PHY for TC port %d not ready\n", tc_port); - WARN_ON(dig_port->tc_legacy_port); - return false; - } - - /* - * This function may be called many times in a row without an HPD event - * in between, so try to avoid the write when we can. - */ - val = I915_READ(PORT_TX_DFLEXDPCSSS); - if (!(val & DP_PHY_MODE_STATUS_NOT_SAFE(tc_port))) { - val |= DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); - I915_WRITE(PORT_TX_DFLEXDPCSSS, val); - } - - /* - * Now we have to re-check the live state, in case the port recently - * became disconnected. Not necessary for legacy mode. - */ - if (dig_port->tc_type == TC_PORT_TYPEC && - !(I915_READ(PORT_TX_DFLEXDPSP) & TC_LIVE_STATE_TC(tc_port))) { - DRM_DEBUG_KMS("TC PHY %d sudden disconnect.\n", tc_port); - icl_tc_phy_disconnect(dev_priv, dig_port); - return false; - } - - return true; -} - -/* - * See the comment at the connect function. This implements the Disconnect - * Flow. - */ -void icl_tc_phy_disconnect(struct drm_i915_private *dev_priv, - struct intel_digital_port *dig_port) -{ - enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); - - if (dig_port->tc_type == TC_PORT_UNKNOWN) - return; - - /* - * TBT disconnection flow is read the live status, what was done in - * caller. - */ - if (dig_port->tc_type == TC_PORT_TYPEC || - dig_port->tc_type == TC_PORT_LEGACY) { - u32 val; - - val = I915_READ(PORT_TX_DFLEXDPCSSS); - val &= ~DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); - I915_WRITE(PORT_TX_DFLEXDPCSSS, val); - } - - DRM_DEBUG_KMS("Port %c TC type %s disconnected\n", - port_name(dig_port->base.port), - tc_type_name(dig_port->tc_type)); - - dig_port->tc_type = TC_PORT_UNKNOWN; -} - -/* - * The type-C ports are different because even when they are connected, they may - * not be available/usable by the graphics driver: see the comment on - * icl_tc_phy_connect(). So in our driver instead of adding the additional - * concept of "usable" and make everything check for "connected and usable" we - * define a port as "connected" when it is not only connected, but also when it - * is usable by the rest of the driver. That maintains the old assumption that - * connected ports are usable, and avoids exposing to the users objects they - * can't really use. - */ -static bool icl_tc_port_connected(struct drm_i915_private *dev_priv, - struct intel_digital_port *intel_dig_port) -{ - enum port port = intel_dig_port->base.port; - enum tc_port tc_port = intel_port_to_tc(dev_priv, port); - bool is_legacy, is_typec, is_tbt; - u32 dpsp; - - /* - * Complain if we got a legacy port HPD, but VBT didn't mark the port as - * legacy. Treat the port as legacy from now on. - */ - if (!intel_dig_port->tc_legacy_port && - I915_READ(SDEISR) & SDE_TC_HOTPLUG_ICP(tc_port)) { - DRM_ERROR("VBT incorrectly claims port %c is not TypeC legacy\n", - port_name(port)); - intel_dig_port->tc_legacy_port = true; - } - is_legacy = intel_dig_port->tc_legacy_port; - - /* - * The spec says we shouldn't be using the ISR bits for detecting - * between TC and TBT. We should use DFLEXDPSP. - */ - dpsp = I915_READ(PORT_TX_DFLEXDPSP); - is_typec = dpsp & TC_LIVE_STATE_TC(tc_port); - is_tbt = dpsp & TC_LIVE_STATE_TBT(tc_port); - - if (!is_legacy && !is_typec && !is_tbt) { - icl_tc_phy_disconnect(dev_priv, intel_dig_port); - - return false; - } - - icl_update_tc_port_type(dev_priv, intel_dig_port, is_legacy, is_typec, - is_tbt); - - if (!icl_tc_phy_connect(dev_priv, intel_dig_port)) - return false; - - return true; -} - static bool icl_digital_port_connected(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); @@ -5430,7 +5242,7 @@ static bool icl_digital_port_connected(struct intel_encoder *encoder) if (intel_port_is_combophy(dev_priv, encoder->port)) return icl_combo_port_connected(dev_priv, dig_port); else if (intel_port_is_tc(dev_priv, encoder->port)) - return icl_tc_port_connected(dev_priv, dig_port); + return intel_tc_port_connected(dig_port); else MISSING_CASE(encoder->hpd_pin); diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index da70b1a41c834c..657bbb1f5ed08f 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -112,8 +112,6 @@ bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp); int intel_dp_link_required(int pixel_clock, int bpp); int intel_dp_max_data_rate(int max_link_clock, int max_lanes); bool intel_digital_port_connected(struct intel_encoder *encoder); -void icl_tc_phy_disconnect(struct drm_i915_private *dev_priv, - struct intel_digital_port *dig_port); static inline unsigned int intel_dp_unused_lane_mask(int lane_count) { diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c new file mode 100644 index 00000000000000..4fa9ea695d510c --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2019 Intel Corporation + */ + +#include "intel_display.h" +#include "i915_drv.h" +#include "intel_tc.h" + +static const char *tc_type_name(enum tc_port_type type) +{ + static const char * const names[] = { + [TC_PORT_UNKNOWN] = "unknown", + [TC_PORT_LEGACY] = "legacy", + [TC_PORT_TYPEC] = "typec", + [TC_PORT_TBT] = "tbt", + }; + + if (WARN_ON(type >= ARRAY_SIZE(names))) + type = TC_PORT_UNKNOWN; + + return names[type]; +} + +int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + intel_wakeref_t wakeref; + u32 lane_info; + + if (tc_port == PORT_TC_NONE || dig_port->tc_type != TC_PORT_TYPEC) + return 4; + + lane_info = 0; + with_intel_display_power(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref) + lane_info = (I915_READ(PORT_TX_DFLEXDPSP) & + DP_LANE_ASSIGNMENT_MASK(tc_port)) >> + DP_LANE_ASSIGNMENT_SHIFT(tc_port); + + switch (lane_info) { + default: + MISSING_CASE(lane_info); + case 1: + case 2: + case 4: + case 8: + return 1; + case 3: + case 12: + return 2; + case 15: + return 4; + } +} + +/* + * This function implements the first part of the Connect Flow described by our + * specification, Gen11 TypeC Programming chapter. The rest of the flow (reading + * lanes, EDID, etc) is done as needed in the typical places. + * + * Unlike the other ports, type-C ports are not available to use as soon as we + * get a hotplug. The type-C PHYs can be shared between multiple controllers: + * display, USB, etc. As a result, handshaking through FIA is required around + * connect and disconnect to cleanly transfer ownership with the controller and + * set the type-C power state. + * + * We could opt to only do the connect flow when we actually try to use the AUX + * channels or do a modeset, then immediately run the disconnect flow after + * usage, but there are some implications on this for a dynamic environment: + * things may go away or change behind our backs. So for now our driver is + * always trying to acquire ownership of the controller as soon as it gets an + * interrupt (or polls state and sees a port is connected) and only gives it + * back when it sees a disconnect. Implementation of a more fine-grained model + * will require a lot of coordination with user space and thorough testing for + * the extra possible cases. + */ +static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + u32 val; + + if (dig_port->tc_type != TC_PORT_LEGACY && + dig_port->tc_type != TC_PORT_TYPEC) + return true; + + val = I915_READ(PORT_TX_DFLEXDPPMS); + if (!(val & DP_PHY_MODE_STATUS_COMPLETED(tc_port))) { + DRM_DEBUG_KMS("DP PHY for TC port %d not ready\n", tc_port); + WARN_ON(dig_port->tc_legacy_port); + return false; + } + + /* + * This function may be called many times in a row without an HPD event + * in between, so try to avoid the write when we can. + */ + val = I915_READ(PORT_TX_DFLEXDPCSSS); + if (!(val & DP_PHY_MODE_STATUS_NOT_SAFE(tc_port))) { + val |= DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); + I915_WRITE(PORT_TX_DFLEXDPCSSS, val); + } + + /* + * Now we have to re-check the live state, in case the port recently + * became disconnected. Not necessary for legacy mode. + */ + if (dig_port->tc_type == TC_PORT_TYPEC && + !(I915_READ(PORT_TX_DFLEXDPSP) & TC_LIVE_STATE_TC(tc_port))) { + DRM_DEBUG_KMS("TC PHY %d sudden disconnect.\n", tc_port); + icl_tc_phy_disconnect(dig_port); + return false; + } + + return true; +} + +/* + * See the comment at the connect function. This implements the Disconnect + * Flow. + */ +void icl_tc_phy_disconnect(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + + if (dig_port->tc_type == TC_PORT_UNKNOWN) + return; + + /* + * TBT disconnection flow is read the live status, what was done in + * caller. + */ + if (dig_port->tc_type == TC_PORT_TYPEC || + dig_port->tc_type == TC_PORT_LEGACY) { + u32 val; + + val = I915_READ(PORT_TX_DFLEXDPCSSS); + val &= ~DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); + I915_WRITE(PORT_TX_DFLEXDPCSSS, val); + } + + DRM_DEBUG_KMS("Port %c TC type %s disconnected\n", + port_name(dig_port->base.port), + tc_type_name(dig_port->tc_type)); + + dig_port->tc_type = TC_PORT_UNKNOWN; +} + +static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, + struct intel_digital_port *intel_dig_port, + bool is_legacy, bool is_typec, bool is_tbt) +{ + enum port port = intel_dig_port->base.port; + enum tc_port_type old_type = intel_dig_port->tc_type; + + WARN_ON(is_legacy + is_typec + is_tbt != 1); + + if (is_legacy) + intel_dig_port->tc_type = TC_PORT_LEGACY; + else if (is_typec) + intel_dig_port->tc_type = TC_PORT_TYPEC; + else if (is_tbt) + intel_dig_port->tc_type = TC_PORT_TBT; + else + return; + + /* Types are not supposed to be changed at runtime. */ + WARN_ON(old_type != TC_PORT_UNKNOWN && + old_type != intel_dig_port->tc_type); + + if (old_type != intel_dig_port->tc_type) + DRM_DEBUG_KMS("Port %c has TC type %s\n", port_name(port), + tc_type_name(intel_dig_port->tc_type)); +} + +/* + * The type-C ports are different because even when they are connected, they may + * not be available/usable by the graphics driver: see the comment on + * icl_tc_phy_connect(). So in our driver instead of adding the additional + * concept of "usable" and make everything check for "connected and usable" we + * define a port as "connected" when it is not only connected, but also when it + * is usable by the rest of the driver. That maintains the old assumption that + * connected ports are usable, and avoids exposing to the users objects they + * can't really use. + */ +bool intel_tc_port_connected(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + enum port port = dig_port->base.port; + enum tc_port tc_port = intel_port_to_tc(dev_priv, port); + bool is_legacy, is_typec, is_tbt; + u32 dpsp; + + /* + * Complain if we got a legacy port HPD, but VBT didn't mark the port as + * legacy. Treat the port as legacy from now on. + */ + if (!dig_port->tc_legacy_port && + I915_READ(SDEISR) & SDE_TC_HOTPLUG_ICP(tc_port)) { + DRM_ERROR("VBT incorrectly claims port %c is not TypeC legacy\n", + port_name(port)); + dig_port->tc_legacy_port = true; + } + is_legacy = dig_port->tc_legacy_port; + + /* + * The spec says we shouldn't be using the ISR bits for detecting + * between TC and TBT. We should use DFLEXDPSP. + */ + dpsp = I915_READ(PORT_TX_DFLEXDPSP); + is_typec = dpsp & TC_LIVE_STATE_TC(tc_port); + is_tbt = dpsp & TC_LIVE_STATE_TBT(tc_port); + + if (!is_legacy && !is_typec && !is_tbt) { + icl_tc_phy_disconnect(dig_port); + + return false; + } + + icl_update_tc_port_type(dev_priv, dig_port, is_legacy, is_typec, + is_tbt); + + if (!icl_tc_phy_connect(dig_port)) + return false; + + return true; +} + diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h new file mode 100644 index 00000000000000..0c65675394e54f --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_tc.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2019 Intel Corporation + */ + +#ifndef __INTEL_TC_H__ +#define __INTEL_TC_H__ + +#include + +struct intel_digital_port; + +void icl_tc_phy_disconnect(struct intel_digital_port *dig_port); + +bool intel_tc_port_connected(struct intel_digital_port *dig_port); +int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port); + +#endif /* __INTEL_TC_H__ */ From 1eef358cb6b8b8c49d11c2a33dd52ea3a0de5622 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 28 Jun 2019 17:36:16 +0300 Subject: [PATCH 1647/1995] drm/i915: Sanitize the terminology used for TypeC port modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TypeC port mode can switch dynamically, to reflect that better call the port's mode as 'mode' rather than 'type'. While at it: - s/TC_PORT_TBT/TC_PORT_TBT_ALT/ and s/TC_PORT_TYPEC/TC_PORT_DP_ALT/. 'TYPEC' is ambiguous, TBT_ALT and DP_ALT better match the reality. - Remove the 'unknown' TypeC port mode. The mode is always known, it's the TBT-alt/safe mode after HW reset and after disconnecting the PHY. Simplify the tc_port/tc_type checks accordingly. - Don't WARN if the port mode changes, that can happen normally. No functional changes. Cc: Animesh Manna Cc: Paulo Zanoni Cc: Anusha Srivatsa Cc: José Roberto de Souza Cc: Rodrigo Vivi Signed-off-by: Imre Deak Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20190628143635.22066-5-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 11 ++--- drivers/gpu/drm/i915/display/intel_display.h | 7 ++- drivers/gpu/drm/i915/display/intel_dp.c | 2 +- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 2 +- drivers/gpu/drm/i915/display/intel_tc.c | 48 ++++++++----------- drivers/gpu/drm/i915/intel_drv.h | 2 +- 6 files changed, 31 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 980f729e3d9234..c3ab57088c26a6 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2999,14 +2999,14 @@ static void icl_program_mg_dp_mode(struct intel_digital_port *intel_dig_port) enum tc_port tc_port = intel_port_to_tc(dev_priv, port); u32 ln0, ln1, lane_info; - if (tc_port == PORT_TC_NONE || intel_dig_port->tc_type == TC_PORT_TBT) + if (intel_dig_port->tc_mode == TC_PORT_TBT_ALT) return; ln0 = I915_READ(MG_DP_MODE(0, port)); ln1 = I915_READ(MG_DP_MODE(1, port)); - switch (intel_dig_port->tc_type) { - case TC_PORT_TYPEC: + switch (intel_dig_port->tc_mode) { + case TC_PORT_DP_ALT: ln0 &= ~(MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE); ln1 &= ~(MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE); @@ -3049,7 +3049,7 @@ static void icl_program_mg_dp_mode(struct intel_digital_port *intel_dig_port) break; default: - MISSING_CASE(intel_dig_port->tc_type); + MISSING_CASE(intel_dig_port->tc_mode); return; } @@ -3643,8 +3643,7 @@ intel_ddi_pre_pll_enable(struct intel_encoder *encoder, * Program the lane count for static/dynamic connections on Type-C ports. * Skip this step for TBT. */ - if (dig_port->tc_type == TC_PORT_UNKNOWN || - dig_port->tc_type == TC_PORT_TBT) + if (dig_port->tc_mode == TC_PORT_TBT_ALT) return; intel_ddi_set_fia_lane_count(encoder, crtc_state, port); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index ee6b8194a45910..d296556ed82ee9 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -189,10 +189,9 @@ enum tc_port { I915_MAX_TC_PORTS }; -enum tc_port_type { - TC_PORT_UNKNOWN = 0, - TC_PORT_TYPEC, - TC_PORT_TBT, +enum tc_port_mode { + TC_PORT_TBT_ALT, + TC_PORT_DP_ALT, TC_PORT_LEGACY, }; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 3d3e80ce7fcfd6..b0105d86a592ca 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1210,7 +1210,7 @@ static u32 skl_get_aux_send_ctl(struct intel_dp *intel_dp, DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(32) | DP_AUX_CH_CTL_SYNC_PULSE_SKL(32); - if (intel_dig_port->tc_type == TC_PORT_TBT) + if (intel_dig_port->tc_mode == TC_PORT_TBT_ALT) ret |= DP_AUX_CH_CTL_TBT_IO; return ret; diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 2d4e7b9a7b9df4..bf66261c8bf0a6 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -2817,7 +2817,7 @@ icl_get_dpll(struct intel_crtc_state *crtc_state, intel_dig_port = enc_to_dig_port(&encoder->base); } - if (intel_dig_port->tc_type == TC_PORT_TBT) { + if (intel_dig_port->tc_mode == TC_PORT_TBT_ALT) { min = DPLL_ID_ICL_TBTPLL; max = min; ret = icl_calc_dpll_state(crtc_state, encoder); diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 4fa9ea695d510c..59aad3e49f93aa 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -7,19 +7,18 @@ #include "i915_drv.h" #include "intel_tc.h" -static const char *tc_type_name(enum tc_port_type type) +static const char *tc_port_mode_name(enum tc_port_mode mode) { static const char * const names[] = { - [TC_PORT_UNKNOWN] = "unknown", + [TC_PORT_TBT_ALT] = "tbt-alt", + [TC_PORT_DP_ALT] = "dp-alt", [TC_PORT_LEGACY] = "legacy", - [TC_PORT_TYPEC] = "typec", - [TC_PORT_TBT] = "tbt", }; - if (WARN_ON(type >= ARRAY_SIZE(names))) - type = TC_PORT_UNKNOWN; + if (WARN_ON(mode >= ARRAY_SIZE(names))) + mode = TC_PORT_TBT_ALT; - return names[type]; + return names[mode]; } int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) @@ -29,7 +28,7 @@ int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) intel_wakeref_t wakeref; u32 lane_info; - if (tc_port == PORT_TC_NONE || dig_port->tc_type != TC_PORT_TYPEC) + if (dig_port->tc_mode != TC_PORT_DP_ALT) return 4; lane_info = 0; @@ -81,8 +80,8 @@ static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); u32 val; - if (dig_port->tc_type != TC_PORT_LEGACY && - dig_port->tc_type != TC_PORT_TYPEC) + if (dig_port->tc_mode != TC_PORT_LEGACY && + dig_port->tc_mode != TC_PORT_DP_ALT) return true; val = I915_READ(PORT_TX_DFLEXDPPMS); @@ -106,7 +105,7 @@ static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) * Now we have to re-check the live state, in case the port recently * became disconnected. Not necessary for legacy mode. */ - if (dig_port->tc_type == TC_PORT_TYPEC && + if (dig_port->tc_mode == TC_PORT_DP_ALT && !(I915_READ(PORT_TX_DFLEXDPSP) & TC_LIVE_STATE_TC(tc_port))) { DRM_DEBUG_KMS("TC PHY %d sudden disconnect.\n", tc_port); icl_tc_phy_disconnect(dig_port); @@ -125,15 +124,12 @@ void icl_tc_phy_disconnect(struct intel_digital_port *dig_port) struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); - if (dig_port->tc_type == TC_PORT_UNKNOWN) - return; - /* * TBT disconnection flow is read the live status, what was done in * caller. */ - if (dig_port->tc_type == TC_PORT_TYPEC || - dig_port->tc_type == TC_PORT_LEGACY) { + if (dig_port->tc_mode == TC_PORT_DP_ALT || + dig_port->tc_mode == TC_PORT_LEGACY) { u32 val; val = I915_READ(PORT_TX_DFLEXDPCSSS); @@ -143,9 +139,9 @@ void icl_tc_phy_disconnect(struct intel_digital_port *dig_port) DRM_DEBUG_KMS("Port %c TC type %s disconnected\n", port_name(dig_port->base.port), - tc_type_name(dig_port->tc_type)); + tc_port_mode_name(dig_port->tc_mode)); - dig_port->tc_type = TC_PORT_UNKNOWN; + dig_port->tc_mode = TC_PORT_TBT_ALT; } static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, @@ -153,26 +149,22 @@ static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, bool is_legacy, bool is_typec, bool is_tbt) { enum port port = intel_dig_port->base.port; - enum tc_port_type old_type = intel_dig_port->tc_type; + enum tc_port_mode old_mode = intel_dig_port->tc_mode; WARN_ON(is_legacy + is_typec + is_tbt != 1); if (is_legacy) - intel_dig_port->tc_type = TC_PORT_LEGACY; + intel_dig_port->tc_mode = TC_PORT_LEGACY; else if (is_typec) - intel_dig_port->tc_type = TC_PORT_TYPEC; + intel_dig_port->tc_mode = TC_PORT_DP_ALT; else if (is_tbt) - intel_dig_port->tc_type = TC_PORT_TBT; + intel_dig_port->tc_mode = TC_PORT_TBT_ALT; else return; - /* Types are not supposed to be changed at runtime. */ - WARN_ON(old_type != TC_PORT_UNKNOWN && - old_type != intel_dig_port->tc_type); - - if (old_type != intel_dig_port->tc_type) + if (old_mode != intel_dig_port->tc_mode) DRM_DEBUG_KMS("Port %c has TC type %s\n", port_name(port), - tc_type_name(intel_dig_port->tc_type)); + tc_port_mode_name(intel_dig_port->tc_mode)); } /* diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f11979879e7bc0..65540d7ba92190 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1225,7 +1225,7 @@ struct intel_digital_port { enum aux_ch aux_ch; enum intel_display_power_domain ddi_io_power_domain; bool tc_legacy_port:1; - enum tc_port_type tc_type; + enum tc_port_mode tc_mode; void (*write_infoframe)(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, From bf32094240f0a46ec6ee8d252d7016814071d43a Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 28 Jun 2019 17:36:20 +0300 Subject: [PATCH 1648/1995] drm/i915: Unify the TypeC port notation in debug/error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unify the TypeC port notation in log messages, so that it matches the spec. For instance the first ICL TypeC port will read as 'Port C/TC#1'. v2: - Format print the name only once. (José) Cc: José Roberto de Souza Cc: Rodrigo Vivi Cc: Paulo Zanoni Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20190628143635.22066-9-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 9 ++++--- drivers/gpu/drm/i915/display/intel_tc.c | 32 ++++++++++++++++++------ drivers/gpu/drm/i915/display/intel_tc.h | 2 ++ drivers/gpu/drm/i915/intel_drv.h | 1 + 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index c3ab57088c26a6..e5b511501703c8 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -4260,9 +4260,12 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) intel_dig_port->max_lanes = intel_ddi_max_lanes(intel_dig_port); intel_dig_port->aux_ch = intel_bios_port_aux_ch(dev_priv, port); - intel_dig_port->tc_legacy_port = intel_port_is_tc(dev_priv, port) && - !port_info->supports_typec_usb && - !port_info->supports_tbt; + if (intel_port_is_tc(dev_priv, port)) { + bool is_legacy = !port_info->supports_typec_usb && + !port_info->supports_tbt; + + intel_tc_port_init(intel_dig_port, is_legacy); + } switch (port) { case PORT_A: diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 59aad3e49f93aa..ca3b11e26474cc 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -86,7 +86,8 @@ static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) val = I915_READ(PORT_TX_DFLEXDPPMS); if (!(val & DP_PHY_MODE_STATUS_COMPLETED(tc_port))) { - DRM_DEBUG_KMS("DP PHY for TC port %d not ready\n", tc_port); + DRM_DEBUG_KMS("Port %s: PHY not ready\n", + dig_port->tc_port_name); WARN_ON(dig_port->tc_legacy_port); return false; } @@ -107,7 +108,8 @@ static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) */ if (dig_port->tc_mode == TC_PORT_DP_ALT && !(I915_READ(PORT_TX_DFLEXDPSP) & TC_LIVE_STATE_TC(tc_port))) { - DRM_DEBUG_KMS("TC PHY %d sudden disconnect.\n", tc_port); + DRM_DEBUG_KMS("Port %s: PHY sudden disconnect\n", + dig_port->tc_port_name); icl_tc_phy_disconnect(dig_port); return false; } @@ -137,8 +139,8 @@ void icl_tc_phy_disconnect(struct intel_digital_port *dig_port) I915_WRITE(PORT_TX_DFLEXDPCSSS, val); } - DRM_DEBUG_KMS("Port %c TC type %s disconnected\n", - port_name(dig_port->base.port), + DRM_DEBUG_KMS("Port %s: mode %s disconnected\n", + dig_port->tc_port_name, tc_port_mode_name(dig_port->tc_mode)); dig_port->tc_mode = TC_PORT_TBT_ALT; @@ -148,7 +150,6 @@ static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, struct intel_digital_port *intel_dig_port, bool is_legacy, bool is_typec, bool is_tbt) { - enum port port = intel_dig_port->base.port; enum tc_port_mode old_mode = intel_dig_port->tc_mode; WARN_ON(is_legacy + is_typec + is_tbt != 1); @@ -163,7 +164,8 @@ static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, return; if (old_mode != intel_dig_port->tc_mode) - DRM_DEBUG_KMS("Port %c has TC type %s\n", port_name(port), + DRM_DEBUG_KMS("Port %s: port has mode %s\n", + intel_dig_port->tc_port_name, tc_port_mode_name(intel_dig_port->tc_mode)); } @@ -191,8 +193,8 @@ bool intel_tc_port_connected(struct intel_digital_port *dig_port) */ if (!dig_port->tc_legacy_port && I915_READ(SDEISR) & SDE_TC_HOTPLUG_ICP(tc_port)) { - DRM_ERROR("VBT incorrectly claims port %c is not TypeC legacy\n", - port_name(port)); + DRM_ERROR("Port %s: VBT incorrectly claims port is not TypeC legacy\n", + dig_port->tc_port_name); dig_port->tc_legacy_port = true; } is_legacy = dig_port->tc_legacy_port; @@ -220,3 +222,17 @@ bool intel_tc_port_connected(struct intel_digital_port *dig_port) return true; } +void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy) +{ + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); + enum port port = dig_port->base.port; + enum tc_port tc_port = intel_port_to_tc(i915, port); + + if (WARN_ON(tc_port == PORT_TC_NONE)) + return; + + snprintf(dig_port->tc_port_name, sizeof(dig_port->tc_port_name), + "%c/TC#%d", port_name(port), tc_port + 1); + + dig_port->tc_legacy_port = is_legacy; +} diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h index 0c65675394e54f..ca173530325261 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.h +++ b/drivers/gpu/drm/i915/display/intel_tc.h @@ -15,4 +15,6 @@ void icl_tc_phy_disconnect(struct intel_digital_port *dig_port); bool intel_tc_port_connected(struct intel_digital_port *dig_port); int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port); +void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy); + #endif /* __INTEL_TC_H__ */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 65540d7ba92190..9fee1aec0504a7 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1225,6 +1225,7 @@ struct intel_digital_port { enum aux_ch aux_ch; enum intel_display_power_domain ddi_io_power_domain; bool tc_legacy_port:1; + char tc_port_name[8]; enum tc_port_mode tc_mode; void (*write_infoframe)(struct intel_encoder *encoder, From 91c984a2e7776db15eeec9c7026f416b0cabad50 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 28 Jun 2019 17:36:21 +0300 Subject: [PATCH 1649/1995] drm/i915: Factor out common parts from TypeC port handling functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Factor out helpers reading/parsing the TypeC specific registers, making current users of them clearer and letting us use them later. While at it also: - Simplify icl_tc_phy_connect() with an early return in legacy mode. - Simplify the live status check using one bitmask for all HPD bits. - Remove a micro-optimisation of the repeated safe-mode clearing. - Make sure we fix the legacy port flag in all cases. Except for the last two, no functional changes. v2: - Don't do reg reads at variable declarations. (Jani) - Prevent constant truncated compiler warning when assigning the valid_hpd_mask. (Nick) - s/intel_tc_port_get_lane_info/intel_tc_port_get_lane_mask/ (Ville) v3: - Make valid_hpd_mask init clear. (Ville) Cc: José Roberto de Souza Cc: Rodrigo Vivi Cc: Paulo Zanoni Cc: Jani Nikula Cc: Nick Desaulniers Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20190628143635.22066-10-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_ddi.c | 11 +- drivers/gpu/drm/i915/display/intel_dp.c | 34 ---- drivers/gpu/drm/i915/display/intel_tc.c | 188 ++++++++++++++--------- drivers/gpu/drm/i915/display/intel_tc.h | 1 + 4 files changed, 119 insertions(+), 115 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index e5b511501703c8..be6a2f93708623 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2996,8 +2996,7 @@ static void icl_program_mg_dp_mode(struct intel_digital_port *intel_dig_port) { struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev); enum port port = intel_dig_port->base.port; - enum tc_port tc_port = intel_port_to_tc(dev_priv, port); - u32 ln0, ln1, lane_info; + u32 ln0, ln1, lane_mask; if (intel_dig_port->tc_mode == TC_PORT_TBT_ALT) return; @@ -3010,11 +3009,9 @@ static void icl_program_mg_dp_mode(struct intel_digital_port *intel_dig_port) ln0 &= ~(MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE); ln1 &= ~(MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE); - lane_info = (I915_READ(PORT_TX_DFLEXDPSP) & - DP_LANE_ASSIGNMENT_MASK(tc_port)) >> - DP_LANE_ASSIGNMENT_SHIFT(tc_port); + lane_mask = intel_tc_port_get_lane_mask(intel_dig_port); - switch (lane_info) { + switch (lane_mask) { case 0x1: case 0x4: break; @@ -3039,7 +3036,7 @@ static void icl_program_mg_dp_mode(struct intel_digital_port *intel_dig_port) MG_DP_MODE_CFG_DP_X2_MODE; break; default: - MISSING_CASE(lane_info); + MISSING_CASE(lane_mask); } break; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index b0105d86a592ca..0c6afec78f93c7 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -212,40 +212,6 @@ static int intel_dp_max_common_rate(struct intel_dp *intel_dp) return intel_dp->common_rates[intel_dp->num_common_rates - 1]; } -static int intel_dp_get_fia_supported_lane_count(struct intel_dp *intel_dp) -{ - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); - intel_wakeref_t wakeref; - u32 lane_info; - - if (tc_port == PORT_TC_NONE || dig_port->tc_type != TC_PORT_TYPEC) - return 4; - - lane_info = 0; - with_intel_display_power(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref) - lane_info = (I915_READ(PORT_TX_DFLEXDPSP) & - DP_LANE_ASSIGNMENT_MASK(tc_port)) >> - DP_LANE_ASSIGNMENT_SHIFT(tc_port); - - switch (lane_info) { - default: - MISSING_CASE(lane_info); - /* fall through */ - case 1: - case 2: - case 4: - case 8: - return 1; - case 3: - case 12: - return 2; - case 15: - return 4; - } -} - /* Theoretical max between source and sink */ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp) { diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index ca3b11e26474cc..f0688c7450c7c8 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -21,25 +21,34 @@ static const char *tc_port_mode_name(enum tc_port_mode mode) return names[mode]; } -int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) +u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port) { struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + u32 lane_mask; + + lane_mask = I915_READ(PORT_TX_DFLEXDPSP); + + return (lane_mask & DP_LANE_ASSIGNMENT_MASK(tc_port)) >> + DP_LANE_ASSIGNMENT_SHIFT(tc_port); +} + +int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); intel_wakeref_t wakeref; - u32 lane_info; + u32 lane_mask; if (dig_port->tc_mode != TC_PORT_DP_ALT) return 4; - lane_info = 0; + lane_mask = 0; with_intel_display_power(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref) - lane_info = (I915_READ(PORT_TX_DFLEXDPSP) & - DP_LANE_ASSIGNMENT_MASK(tc_port)) >> - DP_LANE_ASSIGNMENT_SHIFT(tc_port); + lane_mask = intel_tc_port_get_lane_mask(dig_port); - switch (lane_info) { + switch (lane_mask) { default: - MISSING_CASE(lane_info); + MISSING_CASE(lane_mask); case 1: case 2: case 4: @@ -53,6 +62,76 @@ int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) } } +static void tc_port_fixup_legacy_flag(struct intel_digital_port *dig_port, + u32 live_status_mask) +{ + u32 valid_hpd_mask; + + if (dig_port->tc_legacy_port) + valid_hpd_mask = BIT(TC_PORT_LEGACY); + else + valid_hpd_mask = BIT(TC_PORT_DP_ALT) | + BIT(TC_PORT_TBT_ALT); + + if (!(live_status_mask & ~valid_hpd_mask)) + return; + + /* If live status mismatches the VBT flag, trust the live status. */ + DRM_ERROR("Port %s: live status %08x mismatches the legacy port flag, fix flag\n", + dig_port->tc_port_name, live_status_mask); + + dig_port->tc_legacy_port = !dig_port->tc_legacy_port; +} + +static u32 tc_port_live_status_mask(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + u32 mask = 0; + u32 val; + + val = I915_READ(PORT_TX_DFLEXDPSP); + + if (val & TC_LIVE_STATE_TBT(tc_port)) + mask |= BIT(TC_PORT_TBT_ALT); + if (val & TC_LIVE_STATE_TC(tc_port)) + mask |= BIT(TC_PORT_DP_ALT); + + if (I915_READ(SDEISR) & SDE_TC_HOTPLUG_ICP(tc_port)) + mask |= BIT(TC_PORT_LEGACY); + + /* The sink can be connected only in a single mode. */ + if (!WARN_ON(hweight32(mask) > 1)) + tc_port_fixup_legacy_flag(dig_port, mask); + + return mask; +} + +static bool icl_tc_phy_status_complete(struct intel_digital_port *dig_port) +{ + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + + return I915_READ(PORT_TX_DFLEXDPPMS) & + DP_PHY_MODE_STATUS_COMPLETED(tc_port); +} + +static void icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, + bool enable) +{ + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + u32 val; + + val = I915_READ(PORT_TX_DFLEXDPCSSS); + + val &= ~DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); + if (!enable) + val |= DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); + + I915_WRITE(PORT_TX_DFLEXDPCSSS, val); +} + /* * This function implements the first part of the Connect Flow described by our * specification, Gen11 TypeC Programming chapter. The rest of the flow (reading @@ -76,38 +155,31 @@ int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) */ static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) { - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); - u32 val; + u32 live_status_mask; if (dig_port->tc_mode != TC_PORT_LEGACY && dig_port->tc_mode != TC_PORT_DP_ALT) return true; - val = I915_READ(PORT_TX_DFLEXDPPMS); - if (!(val & DP_PHY_MODE_STATUS_COMPLETED(tc_port))) { + if (!icl_tc_phy_status_complete(dig_port)) { DRM_DEBUG_KMS("Port %s: PHY not ready\n", dig_port->tc_port_name); WARN_ON(dig_port->tc_legacy_port); return false; } - /* - * This function may be called many times in a row without an HPD event - * in between, so try to avoid the write when we can. - */ - val = I915_READ(PORT_TX_DFLEXDPCSSS); - if (!(val & DP_PHY_MODE_STATUS_NOT_SAFE(tc_port))) { - val |= DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); - I915_WRITE(PORT_TX_DFLEXDPCSSS, val); - } + icl_tc_phy_set_safe_mode(dig_port, false); + + if (dig_port->tc_mode == TC_PORT_LEGACY) + return true; + + live_status_mask = tc_port_live_status_mask(dig_port); /* * Now we have to re-check the live state, in case the port recently * became disconnected. Not necessary for legacy mode. */ - if (dig_port->tc_mode == TC_PORT_DP_ALT && - !(I915_READ(PORT_TX_DFLEXDPSP) & TC_LIVE_STATE_TC(tc_port))) { + if (!(live_status_mask & BIT(TC_PORT_DP_ALT))) { DRM_DEBUG_KMS("Port %s: PHY sudden disconnect\n", dig_port->tc_port_name); icl_tc_phy_disconnect(dig_port); @@ -123,46 +195,35 @@ static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) */ void icl_tc_phy_disconnect(struct intel_digital_port *dig_port) { - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); - - /* - * TBT disconnection flow is read the live status, what was done in - * caller. - */ - if (dig_port->tc_mode == TC_PORT_DP_ALT || - dig_port->tc_mode == TC_PORT_LEGACY) { - u32 val; - - val = I915_READ(PORT_TX_DFLEXDPCSSS); - val &= ~DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); - I915_WRITE(PORT_TX_DFLEXDPCSSS, val); + switch (dig_port->tc_mode) { + case TC_PORT_LEGACY: + case TC_PORT_DP_ALT: + icl_tc_phy_set_safe_mode(dig_port, true); + dig_port->tc_mode = TC_PORT_TBT_ALT; + break; + case TC_PORT_TBT_ALT: + /* Nothing to do, we stay in TBT-alt mode */ + break; + default: + MISSING_CASE(dig_port->tc_mode); } DRM_DEBUG_KMS("Port %s: mode %s disconnected\n", dig_port->tc_port_name, tc_port_mode_name(dig_port->tc_mode)); - - dig_port->tc_mode = TC_PORT_TBT_ALT; } static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, struct intel_digital_port *intel_dig_port, - bool is_legacy, bool is_typec, bool is_tbt) + u32 live_status_mask) { enum tc_port_mode old_mode = intel_dig_port->tc_mode; - WARN_ON(is_legacy + is_typec + is_tbt != 1); - - if (is_legacy) - intel_dig_port->tc_mode = TC_PORT_LEGACY; - else if (is_typec) - intel_dig_port->tc_mode = TC_PORT_DP_ALT; - else if (is_tbt) - intel_dig_port->tc_mode = TC_PORT_TBT_ALT; - else + if (!live_status_mask) return; + intel_dig_port->tc_mode = fls(live_status_mask) - 1; + if (old_mode != intel_dig_port->tc_mode) DRM_DEBUG_KMS("Port %s: port has mode %s\n", intel_dig_port->tc_port_name, @@ -182,40 +243,19 @@ static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, bool intel_tc_port_connected(struct intel_digital_port *dig_port) { struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - enum port port = dig_port->base.port; - enum tc_port tc_port = intel_port_to_tc(dev_priv, port); - bool is_legacy, is_typec, is_tbt; - u32 dpsp; - - /* - * Complain if we got a legacy port HPD, but VBT didn't mark the port as - * legacy. Treat the port as legacy from now on. - */ - if (!dig_port->tc_legacy_port && - I915_READ(SDEISR) & SDE_TC_HOTPLUG_ICP(tc_port)) { - DRM_ERROR("Port %s: VBT incorrectly claims port is not TypeC legacy\n", - dig_port->tc_port_name); - dig_port->tc_legacy_port = true; - } - is_legacy = dig_port->tc_legacy_port; + u32 live_status_mask = tc_port_live_status_mask(dig_port); /* * The spec says we shouldn't be using the ISR bits for detecting * between TC and TBT. We should use DFLEXDPSP. */ - dpsp = I915_READ(PORT_TX_DFLEXDPSP); - is_typec = dpsp & TC_LIVE_STATE_TC(tc_port); - is_tbt = dpsp & TC_LIVE_STATE_TBT(tc_port); - - if (!is_legacy && !is_typec && !is_tbt) { + if (!live_status_mask && !dig_port->tc_legacy_port) { icl_tc_phy_disconnect(dig_port); return false; } - icl_update_tc_port_type(dev_priv, dig_port, is_legacy, is_typec, - is_tbt); - + icl_update_tc_port_type(dev_priv, dig_port, live_status_mask); if (!icl_tc_phy_connect(dig_port)) return false; diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h index ca173530325261..8c338c45796dd4 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.h +++ b/drivers/gpu/drm/i915/display/intel_tc.h @@ -13,6 +13,7 @@ struct intel_digital_port; void icl_tc_phy_disconnect(struct intel_digital_port *dig_port); bool intel_tc_port_connected(struct intel_digital_port *dig_port); +u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port); int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port); void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy); From 58286c6c4c9d6634918d01427f24fb448a372611 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 28 Jun 2019 17:36:22 +0300 Subject: [PATCH 1650/1995] drm/i915: Wait for TypeC PHY complete flag to clear in safe mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PHY status complete flag normally clears when disconnecting the PHY in DP-alt mode (achieved by switching to safe mode), so wait for the flag to clear. v2: - Use DRM_DEBUG_KMS instead of DRM_DEBUG_DRIVER. (José) Cc: José Roberto de Souza Cc: Rodrigo Vivi Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20190628143635.22066-11-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_tc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index f0688c7450c7c8..4243db6d25a748 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -130,6 +130,10 @@ static void icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, val |= DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); I915_WRITE(PORT_TX_DFLEXDPCSSS, val); + + if (enable && wait_for(!icl_tc_phy_status_complete(dig_port), 10)) + DRM_DEBUG_KMS("Port %s: PHY complete clear timed out\n", + dig_port->tc_port_name); } /* From a227d32e34906868b04a42450bc40a02222441bf Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 28 Jun 2019 17:36:23 +0300 Subject: [PATCH 1651/1995] drm/i915: Handle the TCCOLD power-down event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on a recent BSpec update (Index/21750) we must handle the TCCOLD event associated with the DP-alt mode. We can detect this event by reading an invalid all-1s value from FIA registers. After detecting TCCOLD we will: - fall back to TBT-alt mode when attempting to switch to DP-alt mode - conclude that nothing is connected during live status detection - WARN when already in unsafe mode, since then TCCOLD is unexpected v2: - Use DRM_DEBUG_KMS instead of DRM_DEBUG_DRIVER. (José) v3: - Use 0xffffffff instead of -1 as invalid FIA reg value. (José, Ville) - Check for TCCOLD in icl_tc_phy_status_complete() too. (Ville) Cc: José Roberto de Souza Cc: Rodrigo Vivi Cc: Ville Syrjälä Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20190628143635.22066-12-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_tc.c | 33 ++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 4243db6d25a748..96855250a5be28 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -29,6 +29,8 @@ u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port) lane_mask = I915_READ(PORT_TX_DFLEXDPSP); + WARN_ON(lane_mask == 0xffffffff); + return (lane_mask & DP_LANE_ASSIGNMENT_MASK(tc_port)) >> DP_LANE_ASSIGNMENT_SHIFT(tc_port); } @@ -92,6 +94,12 @@ static u32 tc_port_live_status_mask(struct intel_digital_port *dig_port) val = I915_READ(PORT_TX_DFLEXDPSP); + if (val == 0xffffffff) { + DRM_DEBUG_KMS("Port %s: PHY in TCCOLD, nothing connected\n", + dig_port->tc_port_name); + return mask; + } + if (val & TC_LIVE_STATE_TBT(tc_port)) mask |= BIT(TC_PORT_TBT_ALT); if (val & TC_LIVE_STATE_TC(tc_port)) @@ -111,12 +119,19 @@ static bool icl_tc_phy_status_complete(struct intel_digital_port *dig_port) { struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + u32 val; - return I915_READ(PORT_TX_DFLEXDPPMS) & - DP_PHY_MODE_STATUS_COMPLETED(tc_port); + val = I915_READ(PORT_TX_DFLEXDPPMS); + if (val == 0xffffffff) { + DRM_DEBUG_KMS("Port %s: PHY in TCCOLD, assuming not complete\n", + dig_port->tc_port_name); + return false; + } + + return val & DP_PHY_MODE_STATUS_COMPLETED(tc_port); } -static void icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, +static bool icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, bool enable) { struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); @@ -124,6 +139,13 @@ static void icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, u32 val; val = I915_READ(PORT_TX_DFLEXDPCSSS); + if (val == 0xffffffff) { + DRM_DEBUG_KMS("Port %s: PHY in TCCOLD, can't set safe-mode to %s\n", + dig_port->tc_port_name, + enableddisabled(enable)); + + return false; + } val &= ~DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); if (!enable) @@ -134,6 +156,8 @@ static void icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, if (enable && wait_for(!icl_tc_phy_status_complete(dig_port), 10)) DRM_DEBUG_KMS("Port %s: PHY complete clear timed out\n", dig_port->tc_port_name); + + return true; } /* @@ -172,7 +196,8 @@ static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) return false; } - icl_tc_phy_set_safe_mode(dig_port, false); + if (!icl_tc_phy_set_safe_mode(dig_port, false)) + return false; if (dig_port->tc_mode == TC_PORT_LEGACY) return true; From 578ff8d784865eb312e16b2f6186c0d0869d1167 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 28 Jun 2019 17:36:24 +0300 Subject: [PATCH 1652/1995] drm/i915: Sanitize the TypeC connect/detect sequences MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the order during detection more consistent: first reset the TypeC port mode if needed (adding new helpers for this), then detect any connected sink. To check if a port mode reset is needed determine first the target port mode based on the live status if a sink is already connected or the PHY status complete flag otherwise. Add a WARN in legacy mode if unexpectedly we can't set the unsafe mode or if the FIA doesn't provide the 4 lanes required. Cc: José Roberto de Souza Cc: Rodrigo Vivi Cc: Paulo Zanoni Cc: Ville Syrjälä Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20190628143635.22066-13-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_tc.c | 96 ++++++++++++------------- 1 file changed, 47 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 96855250a5be28..f63ddf39b36987 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -181,41 +181,43 @@ static bool icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, * will require a lot of coordination with user space and thorough testing for * the extra possible cases. */ -static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) +static void icl_tc_phy_connect(struct intel_digital_port *dig_port) { - u32 live_status_mask; - - if (dig_port->tc_mode != TC_PORT_LEGACY && - dig_port->tc_mode != TC_PORT_DP_ALT) - return true; - if (!icl_tc_phy_status_complete(dig_port)) { DRM_DEBUG_KMS("Port %s: PHY not ready\n", dig_port->tc_port_name); - WARN_ON(dig_port->tc_legacy_port); - return false; + goto out_set_tbt_alt_mode; } - if (!icl_tc_phy_set_safe_mode(dig_port, false)) - return false; + if (!icl_tc_phy_set_safe_mode(dig_port, false) && + !WARN_ON(dig_port->tc_legacy_port)) + goto out_set_tbt_alt_mode; - if (dig_port->tc_mode == TC_PORT_LEGACY) - return true; + if (dig_port->tc_legacy_port) { + WARN_ON(intel_tc_port_fia_max_lane_count(dig_port) != 4); + dig_port->tc_mode = TC_PORT_LEGACY; - live_status_mask = tc_port_live_status_mask(dig_port); + return; + } /* * Now we have to re-check the live state, in case the port recently * became disconnected. Not necessary for legacy mode. */ - if (!(live_status_mask & BIT(TC_PORT_DP_ALT))) { + if (!(tc_port_live_status_mask(dig_port) & BIT(TC_PORT_DP_ALT))) { DRM_DEBUG_KMS("Port %s: PHY sudden disconnect\n", dig_port->tc_port_name); - icl_tc_phy_disconnect(dig_port); - return false; + goto out_set_safe_mode; } - return true; + dig_port->tc_mode = TC_PORT_DP_ALT; + + return; + +out_set_safe_mode: + icl_tc_phy_set_safe_mode(dig_port, true); +out_set_tbt_alt_mode: + dig_port->tc_mode = TC_PORT_TBT_ALT; } /* @@ -236,27 +238,37 @@ void icl_tc_phy_disconnect(struct intel_digital_port *dig_port) default: MISSING_CASE(dig_port->tc_mode); } +} - DRM_DEBUG_KMS("Port %s: mode %s disconnected\n", - dig_port->tc_port_name, - tc_port_mode_name(dig_port->tc_mode)); +static enum tc_port_mode +intel_tc_port_get_target_mode(struct intel_digital_port *dig_port) +{ + u32 live_status_mask = tc_port_live_status_mask(dig_port); + + if (live_status_mask) + return fls(live_status_mask) - 1; + + return icl_tc_phy_status_complete(dig_port) && + dig_port->tc_legacy_port ? TC_PORT_LEGACY : + TC_PORT_TBT_ALT; } -static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, - struct intel_digital_port *intel_dig_port, - u32 live_status_mask) +static void intel_tc_port_reset_mode(struct intel_digital_port *dig_port) { - enum tc_port_mode old_mode = intel_dig_port->tc_mode; + enum tc_port_mode old_tc_mode = dig_port->tc_mode; - if (!live_status_mask) - return; + icl_tc_phy_disconnect(dig_port); + icl_tc_phy_connect(dig_port); - intel_dig_port->tc_mode = fls(live_status_mask) - 1; + DRM_DEBUG_KMS("Port %s: TC port mode reset (%s -> %s)\n", + dig_port->tc_port_name, + tc_port_mode_name(old_tc_mode), + tc_port_mode_name(dig_port->tc_mode)); +} - if (old_mode != intel_dig_port->tc_mode) - DRM_DEBUG_KMS("Port %s: port has mode %s\n", - intel_dig_port->tc_port_name, - tc_port_mode_name(intel_dig_port->tc_mode)); +static bool intel_tc_port_needs_reset(struct intel_digital_port *dig_port) +{ + return intel_tc_port_get_target_mode(dig_port) != dig_port->tc_mode; } /* @@ -271,24 +283,10 @@ static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, */ bool intel_tc_port_connected(struct intel_digital_port *dig_port) { - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - u32 live_status_mask = tc_port_live_status_mask(dig_port); - - /* - * The spec says we shouldn't be using the ISR bits for detecting - * between TC and TBT. We should use DFLEXDPSP. - */ - if (!live_status_mask && !dig_port->tc_legacy_port) { - icl_tc_phy_disconnect(dig_port); - - return false; - } - - icl_update_tc_port_type(dev_priv, dig_port, live_status_mask); - if (!icl_tc_phy_connect(dig_port)) - return false; + if (intel_tc_port_needs_reset(dig_port)) + intel_tc_port_reset_mode(dig_port); - return true; + return tc_port_live_status_mask(dig_port) & BIT(dig_port->tc_mode); } void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy) From aed3684fb2b1ca3b0549021473baadc52b92acb8 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 24 Sep 2019 16:09:42 +0800 Subject: [PATCH 1653/1995] ALSA: hda: clear link output stream mapping Fix potential DMA hang upon starting playback on devices in HDA mode on intel platform :Gemini Lake/Whiskey Lake/Comet Lake/Ice Lake. It doesn't affect platforms before Gemini Lake or any intel device in non-HDA mode. The reset value for the LOSDIV register is all output streams valid. Clear this register to invalidate non-existent streams when the bus is powered up. Signed-off-by: Rander Wang --- include/sound/hda_register.h | 3 +++ sound/hda/ext/hdac_ext_controller.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h index 0fd39295b426b0..057d2a2d0bd05f 100644 --- a/include/sound/hda_register.h +++ b/include/sound/hda_register.h @@ -264,6 +264,9 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_REG_ML_LOUTPAY 0x20 #define AZX_REG_ML_LINPAY 0x30 +/* bit0 is reserved, with BIT(1) mapping to stream1 */ +#define ML_LOSIDV_STREAM_MASK 0xFFFE + #define ML_LCTL_SCF_MASK 0xF #define AZX_MLCTL_SPA (0x1 << 16) #define AZX_MLCTL_CPA (0x1 << 23) diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index 211ca85acd8c4d..cfab60d88c921c 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c @@ -270,6 +270,11 @@ int snd_hdac_ext_bus_link_get(struct hdac_bus *bus, ret = snd_hdac_ext_bus_link_power_up(link); + /* + * clear the register to invalidate all the output streams + */ + snd_hdac_updatew(link->ml_addr, AZX_REG_ML_LOSIDV, + ML_LOSIDV_STREAM_MASK, 0); /* * wait for 521usec for codec to report status * HDA spec section 4.3 - Codec Discovery From 6ac5067c989225af57b7d014f9ca3f08a1164707 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 19 Sep 2019 18:01:14 -0700 Subject: [PATCH 1654/1995] ASoC: SOF: core: check for mandatory fw_ready op during SOF probe fw_ready should be a mandatory op. Make sure fw_ready ops is set during probe. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 3 ++- sound/soc/sof/ipc.c | 6 ------ sound/soc/sof/sof-priv.h | 2 +- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index e047912b22dbc2..8661c2cca76b9a 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -469,7 +469,8 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) if (!sof_ops(sdev) || !sof_ops(sdev)->probe || !sof_ops(sdev)->run || !sof_ops(sdev)->block_read || !sof_ops(sdev)->block_write || !sof_ops(sdev)->send_msg || !sof_ops(sdev)->load_firmware || - !sof_ops(sdev)->ipc_msg_data || !sof_ops(sdev)->ipc_pcm_params) + !sof_ops(sdev)->ipc_msg_data || !sof_ops(sdev)->ipc_pcm_params || + !sof_ops(sdev)->fw_ready) return -EINVAL; INIT_LIST_HEAD(&sdev->pcm_list); diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index b946c81197a1d5..26675dfe024049 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -792,12 +792,6 @@ struct snd_sof_ipc *snd_sof_ipc_init(struct snd_sof_dev *sdev) struct snd_sof_ipc *ipc; struct snd_sof_ipc_msg *msg; - /* check if mandatory ops required for ipc are defined */ - if (!sof_ops(sdev)->fw_ready) { - dev_err(sdev->dev, "error: ipc mandatory ops not defined\n"); - return NULL; - } - ipc = devm_kzalloc(sdev->dev, sizeof(*ipc), GFP_KERNEL); if (!ipc) return NULL; diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 9490e4c33c3b63..9d5151f7cc2fc8 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -139,7 +139,7 @@ struct snd_sof_dsp_ops { * FW ready checks for ABI compatibility and creates * memory windows at first boot */ - int (*fw_ready)(struct snd_sof_dev *sdev, u32 msg_id); /* optional */ + int (*fw_ready)(struct snd_sof_dev *sdev, u32 msg_id); /* mandatory */ /* connect pcm substream to a host stream */ int (*pcm_open)(struct snd_sof_dev *sdev, From c5a665d53040d5d0a35d919bc83d00fdd6090cf1 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 3 Jul 2019 16:36:04 -0700 Subject: [PATCH 1655/1995] ASoC: SOF: Intel: hda: Disable DMI L1 entry during capture There is a known issue on some Intel platforms which causes pause/release to run into xrun's during capture usecases. The suggested workaround to address the issue is to disable the entry of lower power L1 state in the physical DMI link when there is a capture stream open. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/Kconfig | 10 +++++++ sound/soc/sof/intel/hda-ctrl.c | 12 +++------ sound/soc/sof/intel/hda-stream.c | 45 +++++++++++++++++++++++++++----- sound/soc/sof/intel/hda.h | 5 +++- 4 files changed, 56 insertions(+), 16 deletions(-) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 479ba249e219af..d62f51d33be148 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -273,6 +273,16 @@ config SND_SOC_SOF_HDA_AUDIO_CODEC Say Y if you want to enable HDAudio codecs with SOF. If unsure select "N". +config SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1 + bool "SOF enable DMI Link L1" + help + This option enables DMI L1 for both playback and capture + and disables known workarounds for specific HDaudio platforms. + Only use to look into power optimizations on platforms not + affected by DMI L1 issues. This option is not recommended. + Say Y if you want to enable DMI Link L1 + If unsure, select "N". + endif ## SND_SOC_SOF_HDA_COMMON config SND_SOC_SOF_HDA_LINK_BASELINE diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index bc41028a7a01de..df1909e1d95060 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -139,20 +139,16 @@ void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable) */ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable) { -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - struct hdac_bus *bus = sof_to_bus(sdev); -#endif u32 val; /* enable/disable audio dsp clock gating */ val = enable ? PCI_CGCTL_ADSPDCGE : 0; snd_sof_pci_update_bits(sdev, PCI_CGCTL, PCI_CGCTL_ADSPDCGE, val); -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) - /* enable/disable L1 support */ - val = enable ? SOF_HDA_VS_EM2_L1SEN : 0; - snd_hdac_chip_updatel(bus, VS_EM2, SOF_HDA_VS_EM2_L1SEN, val); -#endif + /* enable/disable DMI Link L1 support */ + val = enable ? HDA_VS_INTEL_EM2_L1SEN : 0; + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_EM2, + HDA_VS_INTEL_EM2_L1SEN, val); /* enable/disable audio dsp power gating */ val = enable ? 0 : PCI_PGCTL_ADSPPGD; diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index ad8d41f22e92dd..2c744718840254 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -185,6 +185,17 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction) direction == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture"); + /* + * Disable DMI Link L1 entry when capture stream is opened. + * Workaround to address a known issue with host DMA that results + * in xruns during pause/release in capture scenarios. + */ + if (!IS_ENABLED(SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1)) + if (stream && direction == SNDRV_PCM_STREAM_CAPTURE) + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + HDA_VS_INTEL_EM2, + HDA_VS_INTEL_EM2_L1SEN, 0); + return stream; } @@ -193,23 +204,43 @@ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag) { struct hdac_bus *bus = sof_to_bus(sdev); struct hdac_stream *s; + bool active_capture_stream = false; + bool found = false; spin_lock_irq(&bus->reg_lock); - /* find used stream */ + /* + * close stream matching the stream tag + * and check if there are any open capture streams. + */ list_for_each_entry(s, &bus->stream_list, list) { - if (s->direction == direction && - s->opened && s->stream_tag == stream_tag) { + if (!s->opened) + continue; + + if (s->direction == direction && s->stream_tag == stream_tag) { s->opened = false; - spin_unlock_irq(&bus->reg_lock); - return 0; + found = true; + } else if (s->direction == SNDRV_PCM_STREAM_CAPTURE) { + active_capture_stream = true; } } spin_unlock_irq(&bus->reg_lock); - dev_dbg(sdev->dev, "stream_tag %d not opened!\n", stream_tag); - return -ENODEV; + /* Enable DMI L1 entry if there are no capture streams open */ + if (!IS_ENABLED(SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1)) + if (!active_capture_stream) + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + HDA_VS_INTEL_EM2, + HDA_VS_INTEL_EM2_L1SEN, + HDA_VS_INTEL_EM2_L1SEN); + + if (!found) { + dev_dbg(sdev->dev, "stream_tag %d not opened!\n", stream_tag); + return -ENODEV; + } + + return 0; } int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 7a2ff8b3d8a440..ad5e2df8800ac5 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -39,7 +39,6 @@ #define SOF_HDA_WAKESTS 0x0E #define SOF_HDA_WAKESTS_INT_MASK ((1 << 8) - 1) #define SOF_HDA_RIRBSTS 0x5d -#define SOF_HDA_VS_EM2_L1SEN BIT(13) /* SOF_HDA_GCTL register bist */ #define SOF_HDA_GCTL_RESET BIT(0) @@ -235,6 +234,10 @@ #define HDA_DSP_REG_HIPCIE (HDA_DSP_IPC_BASE + 0x0C) #define HDA_DSP_REG_HIPCCTL (HDA_DSP_IPC_BASE + 0x10) +/* Intel Vendor Specific Registers */ +#define HDA_VS_INTEL_EM2 0x1030 +#define HDA_VS_INTEL_EM2_L1SEN BIT(13) + /* HIPCI */ #define HDA_DSP_REG_HIPCI_BUSY BIT(31) #define HDA_DSP_REG_HIPCI_MSG_MASK 0x7FFFFFFF From ba875d656ef1b10e31fb94d9cc9767d1ddc7f9e1 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 15 Sep 2019 12:32:03 -0700 Subject: [PATCH 1656/1995] Revert "ext4: make __ext4_get_inode_loc plug" This reverts commit b03755ad6f33b7b8cd7312a3596a2dbf496de6e7. This is sad, and done for all the wrong reasons. Because that commit is good, and does exactly what it says: avoids a lot of small disk requests for the inode table read-ahead. However, it turns out that it causes an entirely unrelated problem: the getrandom() system call was introduced back in 2014 by commit c6e9d6f38894 ("random: introduce getrandom(2) system call"), and people use it as a convenient source of good random numbers. But part of the current semantics for getrandom() is that it waits for the entropy pool to fill at least partially (unlike /dev/urandom). And at least ArchLinux apparently has a systemd that uses getrandom() at boot time, and the improvements in IO patterns means that existing installations suddenly start hanging, waiting for entropy that will never happen. It seems to be an unlucky combination of not _quite_ enough entropy, together with a particular systemd version and configuration. Lennart says that the systemd-random-seed process (which is what does this early access) is supposed to not block any other boot activity, but sadly that doesn't actually seem to be the case (possibly due bogus dependencies on cryptsetup for encrypted swapspace). The correct fix is to fix getrandom() to not block when it's not appropriate, but that fix is going to take a lot more discussion. Do we just make it act like /dev/urandom by default, and add a new flag for "wait for entropy"? Do we add a boot-time option? Or do we just limit the amount of time it will wait for entropy? So in the meantime, we do the revert to give us time to discuss the eventual fix for the fundamental problem, at which point we can re-apply the ext4 inode table access optimization. Reported-by: Ahmed S. Darwish Cc: Ted Ts'o Cc: Willy Tarreau Cc: Alexander E. Patrakov Cc: Lennart Poettering Signed-off-by: Linus Torvalds (cherry picked from commit 72dbcf72156641fde4d8ea401e977341bfd35a05) --- fs/ext4/inode.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 420fe3deed3970..006b7a2070bf68 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4586,7 +4586,6 @@ static int __ext4_get_inode_loc(struct inode *inode, struct buffer_head *bh; struct super_block *sb = inode->i_sb; ext4_fsblk_t block; - struct blk_plug plug; int inodes_per_block, inode_offset; iloc->bh = NULL; @@ -4675,7 +4674,6 @@ static int __ext4_get_inode_loc(struct inode *inode, * If we need to do any I/O, try to pre-readahead extra * blocks from the inode table. */ - blk_start_plug(&plug); if (EXT4_SB(sb)->s_inode_readahead_blks) { ext4_fsblk_t b, end, table; unsigned num; @@ -4706,7 +4704,6 @@ static int __ext4_get_inode_loc(struct inode *inode, get_bh(bh); bh->b_end_io = end_buffer_read_sync; submit_bh(REQ_OP_READ, REQ_META | REQ_PRIO, bh); - blk_finish_plug(&plug); wait_on_buffer(bh); if (!buffer_uptodate(bh)) { EXT4_ERROR_INODE_BLOCK(inode, block, From 2cb73a9e8fe67c881281590e5344fb218dcfeaee Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 28 Jun 2019 17:36:27 +0300 Subject: [PATCH 1657/1995] drm/i915: Sanitize the TypeC FIA lane configuration decoding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use hex numbers, since that makes more sense when decoding a bit pattern. No functional change. Suggested-by: Ville Syrjälä Cc: Animesh Manna Cc: Ville Syrjälä Signed-off-by: Imre Deak Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20190628143635.22066-16-imre.deak@intel.com --- drivers/gpu/drm/i915/display/intel_tc.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index f63ddf39b36987..98735ab44f7e73 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -51,15 +51,16 @@ int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) switch (lane_mask) { default: MISSING_CASE(lane_mask); - case 1: - case 2: - case 4: - case 8: + /* fall-through */ + case 0x1: + case 0x2: + case 0x4: + case 0x8: return 1; - case 3: - case 12: + case 0x3: + case 0xc: return 2; - case 15: + case 0xf: return 4; } } From 125914ba5a503703bca1c5f29dca23cbac555fc3 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 2 Oct 2019 00:54:10 +0300 Subject: [PATCH 1658/1995] ASoC: SOF: imx: Describe ESAI parameters to be sent to DSP Introduce sof_ipc_dai_esai_params to keep information that we get from topology and we send to DSP FW. Also bump the ABI minor to reflect the changes on DSP FW. Signed-off-by: Daniel Baluta --- include/sound/sof/dai-imx.h | 35 +++++++++++++++++++++++++++++++++ include/sound/sof/dai.h | 2 ++ include/uapi/sound/sof/abi.h | 2 +- include/uapi/sound/sof/tokens.h | 3 +-- 4 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 include/sound/sof/dai-imx.h diff --git a/include/sound/sof/dai-imx.h b/include/sound/sof/dai-imx.h new file mode 100644 index 00000000000000..206620cc315071 --- /dev/null +++ b/include/sound/sof/dai-imx.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * Copyright 2019 NXP + * + * Author: Daniel Baluta + */ + +#ifndef __INCLUDE_SOUND_SOF_DAI_IMX_H__ +#define __INCLUDE_SOUND_SOF_DAI_IMX_H__ + +#include + +/* ESAI Configuration Request - SOF_IPC_DAI_ESAI_CONFIG */ +struct sof_ipc_dai_esai_params { + struct sof_ipc_hdr hdr; + + /* MCLK */ + uint16_t reserved1; + uint16_t mclk_id; + uint32_t mclk_direction; + + uint32_t mclk_rate; /* MCLK frequency in Hz */ + uint32_t fsync_rate; /* FSYNC frequency in Hz */ + uint32_t bclk_rate; /* BCLK frequency in Hz */ + + /* TDM */ + uint32_t tdm_slots; + uint32_t rx_slots; + uint32_t tx_slots; + uint16_t tdm_slot_width; + uint16_t reserved2; /* alignment */ +} __packed; + +#endif + diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 0f123502214647..c229565767e53a 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -11,6 +11,7 @@ #include #include +#include /* * DAI Configuration. @@ -73,6 +74,7 @@ struct sof_ipc_dai_config { struct sof_ipc_dai_dmic_params dmic; struct sof_ipc_dai_hda_params hda; struct sof_ipc_dai_alh_params alh; + struct sof_ipc_dai_esai_params esai; }; } __packed; diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index a0fe0d4c4b6657..ebfdc20ca08185 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 10 +#define SOF_ABI_MINOR 11 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 1627e1f9fe1190..6139ec50784066 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -111,8 +111,7 @@ /* TODO: Add SAI tokens */ /* ESAI */ -#define SOF_TKN_IMX_ESAI_FIRST_TOKEN 1100 -/* TODO: Add ESAI tokens */ +#define SOF_TKN_IMX_ESAI_MCLK_ID 1100 /* Stream */ #define SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3 1200 From 7b7f94cc67989222a296083eb4c73a838797ae69 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Wed, 2 Oct 2019 00:53:29 +0300 Subject: [PATCH 1659/1995] ASoC: SOF: imx: Read ESAI parameters and send them to DSP ESAI parameters are read for topology file, packed into sof_ipc_dai_esai_parms struct and then sent to DSP. Signed-off-by: Daniel Baluta --- sound/soc/sof/pcm.c | 8 +++++ sound/soc/sof/topology.c | 69 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 2b876d4974476b..b0f4217433e5f4 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -691,6 +691,14 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, case SOF_DAI_INTEL_ALH: /* do nothing for ALH dai_link */ break; + case SOF_DAI_IMX_ESAI: + channels->min = dai->dai_config->esai.tdm_slots; + channels->max = dai->dai_config->esai.tdm_slots; + + dev_dbg(sdev->dev, + "channels_min: %d channels_max: %d\n", + channels->min, channels->max); + break; default: dev_err(sdev->dev, "error: invalid DAI type %d\n", dai->dai_config->type); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 46aab02977530c..b254042581e64b 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -808,6 +808,13 @@ static const struct sof_topology_token dmic_tokens[] = { }; +/* ESAI */ +static const struct sof_topology_token esai_tokens[] = { + {SOF_TKN_IMX_ESAI_MCLK_ID, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_esai_params, mclk_id), 0}, +}; + /* * DMIC PDM Tokens * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token @@ -2561,8 +2568,66 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_hw_config *hw_config, struct sof_ipc_dai_config *config) { - /*TODO: Add implementation */ - return 0; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &cfg->priv; + struct sof_ipc_reply reply; + u32 size = sizeof(*config); + int ret; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->esai, 0, sizeof(struct sof_ipc_dai_esai_params)); + config->hdr.size = size; + + ret = sof_parse_tokens(scomp, &config->esai, esai_tokens, + ARRAY_SIZE(esai_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(sdev->dev, "error: parse esai tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + + config->esai.mclk_rate = le32_to_cpu(hw_config->mclk_rate); + config->esai.bclk_rate = le32_to_cpu(hw_config->bclk_rate); + config->esai.fsync_rate = le32_to_cpu(hw_config->fsync_rate); + config->esai.mclk_direction = hw_config->mclk_direction; + config->esai.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + config->esai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width); + config->esai.rx_slots = le32_to_cpu(hw_config->rx_slots); + config->esai.tx_slots = le32_to_cpu(hw_config->tx_slots); + + dev_info(sdev->dev, + "tplg: config ESAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n", + config->dai_index, config->format, + config->esai.mclk_rate, config->esai.tdm_slot_width, + config->esai.tdm_slots, config->esai.mclk_id); + + if (config->esai.tdm_slots < 1 || config->esai.tdm_slots > 8) { + dev_err(sdev->dev, "error: invalid channel count for ESAI%d\n", + config->dai_index); + return -EINVAL; + } + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + config->hdr.cmd, config, size, &reply, + sizeof(reply)); + if (ret < 0) { + dev_err(sdev->dev, "error: failed to set DAI config for ESAI%d\n", + config->dai_index); + return ret; + } + + /* set config for all DAI's with name matching the link name */ + ret = sof_set_dai_config(sdev, size, link, config); + if (ret < 0) + dev_err(sdev->dev, "error: failed to save DAI config for ESAI%d\n", + config->dai_index); + + return ret; } static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, From b07aa789c551cd719b597b5133dbacb0d3983272 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Oct 2019 19:01:33 -0500 Subject: [PATCH 1660/1995] Revert "drm/i915: Sanitize the TypeC FIA lane configuration decoding" This reverts commit 2cb73a9e8fe67c881281590e5344fb218dcfeaee. --- drivers/gpu/drm/i915/display/intel_tc.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 98735ab44f7e73..f63ddf39b36987 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -51,16 +51,15 @@ int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) switch (lane_mask) { default: MISSING_CASE(lane_mask); - /* fall-through */ - case 0x1: - case 0x2: - case 0x4: - case 0x8: + case 1: + case 2: + case 4: + case 8: return 1; - case 0x3: - case 0xc: + case 3: + case 12: return 2; - case 0xf: + case 15: return 4; } } From 5f20f6eb774dc12f48038471b52f745d085d4e18 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Oct 2019 19:01:50 -0500 Subject: [PATCH 1661/1995] Revert "drm/i915: Sanitize the TypeC connect/detect sequences" This reverts commit 578ff8d784865eb312e16b2f6186c0d0869d1167. --- drivers/gpu/drm/i915/display/intel_tc.c | 96 +++++++++++++------------ 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index f63ddf39b36987..96855250a5be28 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -181,43 +181,41 @@ static bool icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, * will require a lot of coordination with user space and thorough testing for * the extra possible cases. */ -static void icl_tc_phy_connect(struct intel_digital_port *dig_port) +static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) { + u32 live_status_mask; + + if (dig_port->tc_mode != TC_PORT_LEGACY && + dig_port->tc_mode != TC_PORT_DP_ALT) + return true; + if (!icl_tc_phy_status_complete(dig_port)) { DRM_DEBUG_KMS("Port %s: PHY not ready\n", dig_port->tc_port_name); - goto out_set_tbt_alt_mode; + WARN_ON(dig_port->tc_legacy_port); + return false; } - if (!icl_tc_phy_set_safe_mode(dig_port, false) && - !WARN_ON(dig_port->tc_legacy_port)) - goto out_set_tbt_alt_mode; + if (!icl_tc_phy_set_safe_mode(dig_port, false)) + return false; - if (dig_port->tc_legacy_port) { - WARN_ON(intel_tc_port_fia_max_lane_count(dig_port) != 4); - dig_port->tc_mode = TC_PORT_LEGACY; + if (dig_port->tc_mode == TC_PORT_LEGACY) + return true; - return; - } + live_status_mask = tc_port_live_status_mask(dig_port); /* * Now we have to re-check the live state, in case the port recently * became disconnected. Not necessary for legacy mode. */ - if (!(tc_port_live_status_mask(dig_port) & BIT(TC_PORT_DP_ALT))) { + if (!(live_status_mask & BIT(TC_PORT_DP_ALT))) { DRM_DEBUG_KMS("Port %s: PHY sudden disconnect\n", dig_port->tc_port_name); - goto out_set_safe_mode; + icl_tc_phy_disconnect(dig_port); + return false; } - dig_port->tc_mode = TC_PORT_DP_ALT; - - return; - -out_set_safe_mode: - icl_tc_phy_set_safe_mode(dig_port, true); -out_set_tbt_alt_mode: - dig_port->tc_mode = TC_PORT_TBT_ALT; + return true; } /* @@ -238,37 +236,27 @@ void icl_tc_phy_disconnect(struct intel_digital_port *dig_port) default: MISSING_CASE(dig_port->tc_mode); } -} - -static enum tc_port_mode -intel_tc_port_get_target_mode(struct intel_digital_port *dig_port) -{ - u32 live_status_mask = tc_port_live_status_mask(dig_port); - - if (live_status_mask) - return fls(live_status_mask) - 1; - return icl_tc_phy_status_complete(dig_port) && - dig_port->tc_legacy_port ? TC_PORT_LEGACY : - TC_PORT_TBT_ALT; + DRM_DEBUG_KMS("Port %s: mode %s disconnected\n", + dig_port->tc_port_name, + tc_port_mode_name(dig_port->tc_mode)); } -static void intel_tc_port_reset_mode(struct intel_digital_port *dig_port) +static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, + struct intel_digital_port *intel_dig_port, + u32 live_status_mask) { - enum tc_port_mode old_tc_mode = dig_port->tc_mode; + enum tc_port_mode old_mode = intel_dig_port->tc_mode; - icl_tc_phy_disconnect(dig_port); - icl_tc_phy_connect(dig_port); + if (!live_status_mask) + return; - DRM_DEBUG_KMS("Port %s: TC port mode reset (%s -> %s)\n", - dig_port->tc_port_name, - tc_port_mode_name(old_tc_mode), - tc_port_mode_name(dig_port->tc_mode)); -} + intel_dig_port->tc_mode = fls(live_status_mask) - 1; -static bool intel_tc_port_needs_reset(struct intel_digital_port *dig_port) -{ - return intel_tc_port_get_target_mode(dig_port) != dig_port->tc_mode; + if (old_mode != intel_dig_port->tc_mode) + DRM_DEBUG_KMS("Port %s: port has mode %s\n", + intel_dig_port->tc_port_name, + tc_port_mode_name(intel_dig_port->tc_mode)); } /* @@ -283,10 +271,24 @@ static bool intel_tc_port_needs_reset(struct intel_digital_port *dig_port) */ bool intel_tc_port_connected(struct intel_digital_port *dig_port) { - if (intel_tc_port_needs_reset(dig_port)) - intel_tc_port_reset_mode(dig_port); + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + u32 live_status_mask = tc_port_live_status_mask(dig_port); + + /* + * The spec says we shouldn't be using the ISR bits for detecting + * between TC and TBT. We should use DFLEXDPSP. + */ + if (!live_status_mask && !dig_port->tc_legacy_port) { + icl_tc_phy_disconnect(dig_port); + + return false; + } + + icl_update_tc_port_type(dev_priv, dig_port, live_status_mask); + if (!icl_tc_phy_connect(dig_port)) + return false; - return tc_port_live_status_mask(dig_port) & BIT(dig_port->tc_mode); + return true; } void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy) From b7663006adeaa4670cba6a0ea5148c2aa20be7f1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Oct 2019 19:02:02 -0500 Subject: [PATCH 1662/1995] Revert "drm/i915: Handle the TCCOLD power-down event" This reverts commit a227d32e34906868b04a42450bc40a02222441bf. --- drivers/gpu/drm/i915/display/intel_tc.c | 33 +++---------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 96855250a5be28..4243db6d25a748 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -29,8 +29,6 @@ u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port) lane_mask = I915_READ(PORT_TX_DFLEXDPSP); - WARN_ON(lane_mask == 0xffffffff); - return (lane_mask & DP_LANE_ASSIGNMENT_MASK(tc_port)) >> DP_LANE_ASSIGNMENT_SHIFT(tc_port); } @@ -94,12 +92,6 @@ static u32 tc_port_live_status_mask(struct intel_digital_port *dig_port) val = I915_READ(PORT_TX_DFLEXDPSP); - if (val == 0xffffffff) { - DRM_DEBUG_KMS("Port %s: PHY in TCCOLD, nothing connected\n", - dig_port->tc_port_name); - return mask; - } - if (val & TC_LIVE_STATE_TBT(tc_port)) mask |= BIT(TC_PORT_TBT_ALT); if (val & TC_LIVE_STATE_TC(tc_port)) @@ -119,19 +111,12 @@ static bool icl_tc_phy_status_complete(struct intel_digital_port *dig_port) { struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); - u32 val; - val = I915_READ(PORT_TX_DFLEXDPPMS); - if (val == 0xffffffff) { - DRM_DEBUG_KMS("Port %s: PHY in TCCOLD, assuming not complete\n", - dig_port->tc_port_name); - return false; - } - - return val & DP_PHY_MODE_STATUS_COMPLETED(tc_port); + return I915_READ(PORT_TX_DFLEXDPPMS) & + DP_PHY_MODE_STATUS_COMPLETED(tc_port); } -static bool icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, +static void icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, bool enable) { struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); @@ -139,13 +124,6 @@ static bool icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, u32 val; val = I915_READ(PORT_TX_DFLEXDPCSSS); - if (val == 0xffffffff) { - DRM_DEBUG_KMS("Port %s: PHY in TCCOLD, can't set safe-mode to %s\n", - dig_port->tc_port_name, - enableddisabled(enable)); - - return false; - } val &= ~DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); if (!enable) @@ -156,8 +134,6 @@ static bool icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, if (enable && wait_for(!icl_tc_phy_status_complete(dig_port), 10)) DRM_DEBUG_KMS("Port %s: PHY complete clear timed out\n", dig_port->tc_port_name); - - return true; } /* @@ -196,8 +172,7 @@ static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) return false; } - if (!icl_tc_phy_set_safe_mode(dig_port, false)) - return false; + icl_tc_phy_set_safe_mode(dig_port, false); if (dig_port->tc_mode == TC_PORT_LEGACY) return true; From 7f395b4b9810c7c917f99ddbd21459a8c665a467 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Oct 2019 19:02:15 -0500 Subject: [PATCH 1663/1995] Revert "drm/i915: Wait for TypeC PHY complete flag to clear in safe mode" This reverts commit 58286c6c4c9d6634918d01427f24fb448a372611. --- drivers/gpu/drm/i915/display/intel_tc.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 4243db6d25a748..f0688c7450c7c8 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -130,10 +130,6 @@ static void icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, val |= DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); I915_WRITE(PORT_TX_DFLEXDPCSSS, val); - - if (enable && wait_for(!icl_tc_phy_status_complete(dig_port), 10)) - DRM_DEBUG_KMS("Port %s: PHY complete clear timed out\n", - dig_port->tc_port_name); } /* From 6a16ab9f2938d4186da09627c2cb0e5731d5822e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Oct 2019 19:02:24 -0500 Subject: [PATCH 1664/1995] Revert "drm/i915: Factor out common parts from TypeC port handling functions" This reverts commit 91c984a2e7776db15eeec9c7026f416b0cabad50. --- drivers/gpu/drm/i915/display/intel_ddi.c | 11 +- drivers/gpu/drm/i915/display/intel_dp.c | 34 ++++ drivers/gpu/drm/i915/display/intel_tc.c | 188 +++++++++-------------- drivers/gpu/drm/i915/display/intel_tc.h | 1 - 4 files changed, 115 insertions(+), 119 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index be6a2f93708623..e5b511501703c8 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2996,7 +2996,8 @@ static void icl_program_mg_dp_mode(struct intel_digital_port *intel_dig_port) { struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev); enum port port = intel_dig_port->base.port; - u32 ln0, ln1, lane_mask; + enum tc_port tc_port = intel_port_to_tc(dev_priv, port); + u32 ln0, ln1, lane_info; if (intel_dig_port->tc_mode == TC_PORT_TBT_ALT) return; @@ -3009,9 +3010,11 @@ static void icl_program_mg_dp_mode(struct intel_digital_port *intel_dig_port) ln0 &= ~(MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE); ln1 &= ~(MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE); - lane_mask = intel_tc_port_get_lane_mask(intel_dig_port); + lane_info = (I915_READ(PORT_TX_DFLEXDPSP) & + DP_LANE_ASSIGNMENT_MASK(tc_port)) >> + DP_LANE_ASSIGNMENT_SHIFT(tc_port); - switch (lane_mask) { + switch (lane_info) { case 0x1: case 0x4: break; @@ -3036,7 +3039,7 @@ static void icl_program_mg_dp_mode(struct intel_digital_port *intel_dig_port) MG_DP_MODE_CFG_DP_X2_MODE; break; default: - MISSING_CASE(lane_mask); + MISSING_CASE(lane_info); } break; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 0c6afec78f93c7..b0105d86a592ca 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -212,6 +212,40 @@ static int intel_dp_max_common_rate(struct intel_dp *intel_dp) return intel_dp->common_rates[intel_dp->num_common_rates - 1]; } +static int intel_dp_get_fia_supported_lane_count(struct intel_dp *intel_dp) +{ + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + intel_wakeref_t wakeref; + u32 lane_info; + + if (tc_port == PORT_TC_NONE || dig_port->tc_type != TC_PORT_TYPEC) + return 4; + + lane_info = 0; + with_intel_display_power(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref) + lane_info = (I915_READ(PORT_TX_DFLEXDPSP) & + DP_LANE_ASSIGNMENT_MASK(tc_port)) >> + DP_LANE_ASSIGNMENT_SHIFT(tc_port); + + switch (lane_info) { + default: + MISSING_CASE(lane_info); + /* fall through */ + case 1: + case 2: + case 4: + case 8: + return 1; + case 3: + case 12: + return 2; + case 15: + return 4; + } +} + /* Theoretical max between source and sink */ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp) { diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index f0688c7450c7c8..ca3b11e26474cc 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -21,34 +21,25 @@ static const char *tc_port_mode_name(enum tc_port_mode mode) return names[mode]; } -u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port) -{ - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); - u32 lane_mask; - - lane_mask = I915_READ(PORT_TX_DFLEXDPSP); - - return (lane_mask & DP_LANE_ASSIGNMENT_MASK(tc_port)) >> - DP_LANE_ASSIGNMENT_SHIFT(tc_port); -} - int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) { struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); intel_wakeref_t wakeref; - u32 lane_mask; + u32 lane_info; if (dig_port->tc_mode != TC_PORT_DP_ALT) return 4; - lane_mask = 0; + lane_info = 0; with_intel_display_power(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref) - lane_mask = intel_tc_port_get_lane_mask(dig_port); + lane_info = (I915_READ(PORT_TX_DFLEXDPSP) & + DP_LANE_ASSIGNMENT_MASK(tc_port)) >> + DP_LANE_ASSIGNMENT_SHIFT(tc_port); - switch (lane_mask) { + switch (lane_info) { default: - MISSING_CASE(lane_mask); + MISSING_CASE(lane_info); case 1: case 2: case 4: @@ -62,76 +53,6 @@ int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) } } -static void tc_port_fixup_legacy_flag(struct intel_digital_port *dig_port, - u32 live_status_mask) -{ - u32 valid_hpd_mask; - - if (dig_port->tc_legacy_port) - valid_hpd_mask = BIT(TC_PORT_LEGACY); - else - valid_hpd_mask = BIT(TC_PORT_DP_ALT) | - BIT(TC_PORT_TBT_ALT); - - if (!(live_status_mask & ~valid_hpd_mask)) - return; - - /* If live status mismatches the VBT flag, trust the live status. */ - DRM_ERROR("Port %s: live status %08x mismatches the legacy port flag, fix flag\n", - dig_port->tc_port_name, live_status_mask); - - dig_port->tc_legacy_port = !dig_port->tc_legacy_port; -} - -static u32 tc_port_live_status_mask(struct intel_digital_port *dig_port) -{ - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); - u32 mask = 0; - u32 val; - - val = I915_READ(PORT_TX_DFLEXDPSP); - - if (val & TC_LIVE_STATE_TBT(tc_port)) - mask |= BIT(TC_PORT_TBT_ALT); - if (val & TC_LIVE_STATE_TC(tc_port)) - mask |= BIT(TC_PORT_DP_ALT); - - if (I915_READ(SDEISR) & SDE_TC_HOTPLUG_ICP(tc_port)) - mask |= BIT(TC_PORT_LEGACY); - - /* The sink can be connected only in a single mode. */ - if (!WARN_ON(hweight32(mask) > 1)) - tc_port_fixup_legacy_flag(dig_port, mask); - - return mask; -} - -static bool icl_tc_phy_status_complete(struct intel_digital_port *dig_port) -{ - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); - - return I915_READ(PORT_TX_DFLEXDPPMS) & - DP_PHY_MODE_STATUS_COMPLETED(tc_port); -} - -static void icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, - bool enable) -{ - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); - u32 val; - - val = I915_READ(PORT_TX_DFLEXDPCSSS); - - val &= ~DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); - if (!enable) - val |= DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); - - I915_WRITE(PORT_TX_DFLEXDPCSSS, val); -} - /* * This function implements the first part of the Connect Flow described by our * specification, Gen11 TypeC Programming chapter. The rest of the flow (reading @@ -155,31 +76,38 @@ static void icl_tc_phy_set_safe_mode(struct intel_digital_port *dig_port, */ static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) { - u32 live_status_mask; + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + u32 val; if (dig_port->tc_mode != TC_PORT_LEGACY && dig_port->tc_mode != TC_PORT_DP_ALT) return true; - if (!icl_tc_phy_status_complete(dig_port)) { + val = I915_READ(PORT_TX_DFLEXDPPMS); + if (!(val & DP_PHY_MODE_STATUS_COMPLETED(tc_port))) { DRM_DEBUG_KMS("Port %s: PHY not ready\n", dig_port->tc_port_name); WARN_ON(dig_port->tc_legacy_port); return false; } - icl_tc_phy_set_safe_mode(dig_port, false); - - if (dig_port->tc_mode == TC_PORT_LEGACY) - return true; - - live_status_mask = tc_port_live_status_mask(dig_port); + /* + * This function may be called many times in a row without an HPD event + * in between, so try to avoid the write when we can. + */ + val = I915_READ(PORT_TX_DFLEXDPCSSS); + if (!(val & DP_PHY_MODE_STATUS_NOT_SAFE(tc_port))) { + val |= DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); + I915_WRITE(PORT_TX_DFLEXDPCSSS, val); + } /* * Now we have to re-check the live state, in case the port recently * became disconnected. Not necessary for legacy mode. */ - if (!(live_status_mask & BIT(TC_PORT_DP_ALT))) { + if (dig_port->tc_mode == TC_PORT_DP_ALT && + !(I915_READ(PORT_TX_DFLEXDPSP) & TC_LIVE_STATE_TC(tc_port))) { DRM_DEBUG_KMS("Port %s: PHY sudden disconnect\n", dig_port->tc_port_name); icl_tc_phy_disconnect(dig_port); @@ -195,34 +123,45 @@ static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) */ void icl_tc_phy_disconnect(struct intel_digital_port *dig_port) { - switch (dig_port->tc_mode) { - case TC_PORT_LEGACY: - case TC_PORT_DP_ALT: - icl_tc_phy_set_safe_mode(dig_port, true); - dig_port->tc_mode = TC_PORT_TBT_ALT; - break; - case TC_PORT_TBT_ALT: - /* Nothing to do, we stay in TBT-alt mode */ - break; - default: - MISSING_CASE(dig_port->tc_mode); + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + + /* + * TBT disconnection flow is read the live status, what was done in + * caller. + */ + if (dig_port->tc_mode == TC_PORT_DP_ALT || + dig_port->tc_mode == TC_PORT_LEGACY) { + u32 val; + + val = I915_READ(PORT_TX_DFLEXDPCSSS); + val &= ~DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); + I915_WRITE(PORT_TX_DFLEXDPCSSS, val); } DRM_DEBUG_KMS("Port %s: mode %s disconnected\n", dig_port->tc_port_name, tc_port_mode_name(dig_port->tc_mode)); + + dig_port->tc_mode = TC_PORT_TBT_ALT; } static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, struct intel_digital_port *intel_dig_port, - u32 live_status_mask) + bool is_legacy, bool is_typec, bool is_tbt) { enum tc_port_mode old_mode = intel_dig_port->tc_mode; - if (!live_status_mask) - return; + WARN_ON(is_legacy + is_typec + is_tbt != 1); - intel_dig_port->tc_mode = fls(live_status_mask) - 1; + if (is_legacy) + intel_dig_port->tc_mode = TC_PORT_LEGACY; + else if (is_typec) + intel_dig_port->tc_mode = TC_PORT_DP_ALT; + else if (is_tbt) + intel_dig_port->tc_mode = TC_PORT_TBT_ALT; + else + return; if (old_mode != intel_dig_port->tc_mode) DRM_DEBUG_KMS("Port %s: port has mode %s\n", @@ -243,19 +182,40 @@ static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, bool intel_tc_port_connected(struct intel_digital_port *dig_port) { struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - u32 live_status_mask = tc_port_live_status_mask(dig_port); + enum port port = dig_port->base.port; + enum tc_port tc_port = intel_port_to_tc(dev_priv, port); + bool is_legacy, is_typec, is_tbt; + u32 dpsp; + + /* + * Complain if we got a legacy port HPD, but VBT didn't mark the port as + * legacy. Treat the port as legacy from now on. + */ + if (!dig_port->tc_legacy_port && + I915_READ(SDEISR) & SDE_TC_HOTPLUG_ICP(tc_port)) { + DRM_ERROR("Port %s: VBT incorrectly claims port is not TypeC legacy\n", + dig_port->tc_port_name); + dig_port->tc_legacy_port = true; + } + is_legacy = dig_port->tc_legacy_port; /* * The spec says we shouldn't be using the ISR bits for detecting * between TC and TBT. We should use DFLEXDPSP. */ - if (!live_status_mask && !dig_port->tc_legacy_port) { + dpsp = I915_READ(PORT_TX_DFLEXDPSP); + is_typec = dpsp & TC_LIVE_STATE_TC(tc_port); + is_tbt = dpsp & TC_LIVE_STATE_TBT(tc_port); + + if (!is_legacy && !is_typec && !is_tbt) { icl_tc_phy_disconnect(dig_port); return false; } - icl_update_tc_port_type(dev_priv, dig_port, live_status_mask); + icl_update_tc_port_type(dev_priv, dig_port, is_legacy, is_typec, + is_tbt); + if (!icl_tc_phy_connect(dig_port)) return false; diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h index 8c338c45796dd4..ca173530325261 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.h +++ b/drivers/gpu/drm/i915/display/intel_tc.h @@ -13,7 +13,6 @@ struct intel_digital_port; void icl_tc_phy_disconnect(struct intel_digital_port *dig_port); bool intel_tc_port_connected(struct intel_digital_port *dig_port); -u32 intel_tc_port_get_lane_mask(struct intel_digital_port *dig_port); int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port); void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy); From 4f13a12104fc5da1490ba2fdac08e3d0792f453c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Oct 2019 19:02:34 -0500 Subject: [PATCH 1665/1995] Revert "drm/i915: Unify the TypeC port notation in debug/error messages" This reverts commit bf32094240f0a46ec6ee8d252d7016814071d43a. --- drivers/gpu/drm/i915/display/intel_ddi.c | 9 +++---- drivers/gpu/drm/i915/display/intel_tc.c | 32 ++++++------------------ drivers/gpu/drm/i915/display/intel_tc.h | 2 -- drivers/gpu/drm/i915/intel_drv.h | 1 - 4 files changed, 11 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index e5b511501703c8..c3ab57088c26a6 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -4260,12 +4260,9 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) intel_dig_port->max_lanes = intel_ddi_max_lanes(intel_dig_port); intel_dig_port->aux_ch = intel_bios_port_aux_ch(dev_priv, port); - if (intel_port_is_tc(dev_priv, port)) { - bool is_legacy = !port_info->supports_typec_usb && - !port_info->supports_tbt; - - intel_tc_port_init(intel_dig_port, is_legacy); - } + intel_dig_port->tc_legacy_port = intel_port_is_tc(dev_priv, port) && + !port_info->supports_typec_usb && + !port_info->supports_tbt; switch (port) { case PORT_A: diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index ca3b11e26474cc..59aad3e49f93aa 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -86,8 +86,7 @@ static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) val = I915_READ(PORT_TX_DFLEXDPPMS); if (!(val & DP_PHY_MODE_STATUS_COMPLETED(tc_port))) { - DRM_DEBUG_KMS("Port %s: PHY not ready\n", - dig_port->tc_port_name); + DRM_DEBUG_KMS("DP PHY for TC port %d not ready\n", tc_port); WARN_ON(dig_port->tc_legacy_port); return false; } @@ -108,8 +107,7 @@ static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) */ if (dig_port->tc_mode == TC_PORT_DP_ALT && !(I915_READ(PORT_TX_DFLEXDPSP) & TC_LIVE_STATE_TC(tc_port))) { - DRM_DEBUG_KMS("Port %s: PHY sudden disconnect\n", - dig_port->tc_port_name); + DRM_DEBUG_KMS("TC PHY %d sudden disconnect.\n", tc_port); icl_tc_phy_disconnect(dig_port); return false; } @@ -139,8 +137,8 @@ void icl_tc_phy_disconnect(struct intel_digital_port *dig_port) I915_WRITE(PORT_TX_DFLEXDPCSSS, val); } - DRM_DEBUG_KMS("Port %s: mode %s disconnected\n", - dig_port->tc_port_name, + DRM_DEBUG_KMS("Port %c TC type %s disconnected\n", + port_name(dig_port->base.port), tc_port_mode_name(dig_port->tc_mode)); dig_port->tc_mode = TC_PORT_TBT_ALT; @@ -150,6 +148,7 @@ static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, struct intel_digital_port *intel_dig_port, bool is_legacy, bool is_typec, bool is_tbt) { + enum port port = intel_dig_port->base.port; enum tc_port_mode old_mode = intel_dig_port->tc_mode; WARN_ON(is_legacy + is_typec + is_tbt != 1); @@ -164,8 +163,7 @@ static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, return; if (old_mode != intel_dig_port->tc_mode) - DRM_DEBUG_KMS("Port %s: port has mode %s\n", - intel_dig_port->tc_port_name, + DRM_DEBUG_KMS("Port %c has TC type %s\n", port_name(port), tc_port_mode_name(intel_dig_port->tc_mode)); } @@ -193,8 +191,8 @@ bool intel_tc_port_connected(struct intel_digital_port *dig_port) */ if (!dig_port->tc_legacy_port && I915_READ(SDEISR) & SDE_TC_HOTPLUG_ICP(tc_port)) { - DRM_ERROR("Port %s: VBT incorrectly claims port is not TypeC legacy\n", - dig_port->tc_port_name); + DRM_ERROR("VBT incorrectly claims port %c is not TypeC legacy\n", + port_name(port)); dig_port->tc_legacy_port = true; } is_legacy = dig_port->tc_legacy_port; @@ -222,17 +220,3 @@ bool intel_tc_port_connected(struct intel_digital_port *dig_port) return true; } -void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy) -{ - struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); - enum port port = dig_port->base.port; - enum tc_port tc_port = intel_port_to_tc(i915, port); - - if (WARN_ON(tc_port == PORT_TC_NONE)) - return; - - snprintf(dig_port->tc_port_name, sizeof(dig_port->tc_port_name), - "%c/TC#%d", port_name(port), tc_port + 1); - - dig_port->tc_legacy_port = is_legacy; -} diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h index ca173530325261..0c65675394e54f 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.h +++ b/drivers/gpu/drm/i915/display/intel_tc.h @@ -15,6 +15,4 @@ void icl_tc_phy_disconnect(struct intel_digital_port *dig_port); bool intel_tc_port_connected(struct intel_digital_port *dig_port); int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port); -void intel_tc_port_init(struct intel_digital_port *dig_port, bool is_legacy); - #endif /* __INTEL_TC_H__ */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9fee1aec0504a7..65540d7ba92190 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1225,7 +1225,6 @@ struct intel_digital_port { enum aux_ch aux_ch; enum intel_display_power_domain ddi_io_power_domain; bool tc_legacy_port:1; - char tc_port_name[8]; enum tc_port_mode tc_mode; void (*write_infoframe)(struct intel_encoder *encoder, From bf5009bfbec8816311850ce8b439408ec3c7b2e8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Oct 2019 19:02:47 -0500 Subject: [PATCH 1666/1995] Revert "drm/i915: Sanitize the terminology used for TypeC port modes" This reverts commit 1eef358cb6b8b8c49d11c2a33dd52ea3a0de5622. --- drivers/gpu/drm/i915/display/intel_ddi.c | 11 +++-- drivers/gpu/drm/i915/display/intel_display.h | 7 +-- drivers/gpu/drm/i915/display/intel_dp.c | 2 +- drivers/gpu/drm/i915/display/intel_dpll_mgr.c | 2 +- drivers/gpu/drm/i915/display/intel_tc.c | 48 +++++++++++-------- drivers/gpu/drm/i915/intel_drv.h | 2 +- 6 files changed, 41 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index c3ab57088c26a6..980f729e3d9234 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2999,14 +2999,14 @@ static void icl_program_mg_dp_mode(struct intel_digital_port *intel_dig_port) enum tc_port tc_port = intel_port_to_tc(dev_priv, port); u32 ln0, ln1, lane_info; - if (intel_dig_port->tc_mode == TC_PORT_TBT_ALT) + if (tc_port == PORT_TC_NONE || intel_dig_port->tc_type == TC_PORT_TBT) return; ln0 = I915_READ(MG_DP_MODE(0, port)); ln1 = I915_READ(MG_DP_MODE(1, port)); - switch (intel_dig_port->tc_mode) { - case TC_PORT_DP_ALT: + switch (intel_dig_port->tc_type) { + case TC_PORT_TYPEC: ln0 &= ~(MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE); ln1 &= ~(MG_DP_MODE_CFG_DP_X1_MODE | MG_DP_MODE_CFG_DP_X2_MODE); @@ -3049,7 +3049,7 @@ static void icl_program_mg_dp_mode(struct intel_digital_port *intel_dig_port) break; default: - MISSING_CASE(intel_dig_port->tc_mode); + MISSING_CASE(intel_dig_port->tc_type); return; } @@ -3643,7 +3643,8 @@ intel_ddi_pre_pll_enable(struct intel_encoder *encoder, * Program the lane count for static/dynamic connections on Type-C ports. * Skip this step for TBT. */ - if (dig_port->tc_mode == TC_PORT_TBT_ALT) + if (dig_port->tc_type == TC_PORT_UNKNOWN || + dig_port->tc_type == TC_PORT_TBT) return; intel_ddi_set_fia_lane_count(encoder, crtc_state, port); diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index d296556ed82ee9..ee6b8194a45910 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -189,9 +189,10 @@ enum tc_port { I915_MAX_TC_PORTS }; -enum tc_port_mode { - TC_PORT_TBT_ALT, - TC_PORT_DP_ALT, +enum tc_port_type { + TC_PORT_UNKNOWN = 0, + TC_PORT_TYPEC, + TC_PORT_TBT, TC_PORT_LEGACY, }; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index b0105d86a592ca..3d3e80ce7fcfd6 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -1210,7 +1210,7 @@ static u32 skl_get_aux_send_ctl(struct intel_dp *intel_dp, DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(32) | DP_AUX_CH_CTL_SYNC_PULSE_SKL(32); - if (intel_dig_port->tc_mode == TC_PORT_TBT_ALT) + if (intel_dig_port->tc_type == TC_PORT_TBT) ret |= DP_AUX_CH_CTL_TBT_IO; return ret; diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index bf66261c8bf0a6..2d4e7b9a7b9df4 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -2817,7 +2817,7 @@ icl_get_dpll(struct intel_crtc_state *crtc_state, intel_dig_port = enc_to_dig_port(&encoder->base); } - if (intel_dig_port->tc_mode == TC_PORT_TBT_ALT) { + if (intel_dig_port->tc_type == TC_PORT_TBT) { min = DPLL_ID_ICL_TBTPLL; max = min; ret = icl_calc_dpll_state(crtc_state, encoder); diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index 59aad3e49f93aa..4fa9ea695d510c 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -7,18 +7,19 @@ #include "i915_drv.h" #include "intel_tc.h" -static const char *tc_port_mode_name(enum tc_port_mode mode) +static const char *tc_type_name(enum tc_port_type type) { static const char * const names[] = { - [TC_PORT_TBT_ALT] = "tbt-alt", - [TC_PORT_DP_ALT] = "dp-alt", + [TC_PORT_UNKNOWN] = "unknown", [TC_PORT_LEGACY] = "legacy", + [TC_PORT_TYPEC] = "typec", + [TC_PORT_TBT] = "tbt", }; - if (WARN_ON(mode >= ARRAY_SIZE(names))) - mode = TC_PORT_TBT_ALT; + if (WARN_ON(type >= ARRAY_SIZE(names))) + type = TC_PORT_UNKNOWN; - return names[mode]; + return names[type]; } int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) @@ -28,7 +29,7 @@ int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) intel_wakeref_t wakeref; u32 lane_info; - if (dig_port->tc_mode != TC_PORT_DP_ALT) + if (tc_port == PORT_TC_NONE || dig_port->tc_type != TC_PORT_TYPEC) return 4; lane_info = 0; @@ -80,8 +81,8 @@ static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); u32 val; - if (dig_port->tc_mode != TC_PORT_LEGACY && - dig_port->tc_mode != TC_PORT_DP_ALT) + if (dig_port->tc_type != TC_PORT_LEGACY && + dig_port->tc_type != TC_PORT_TYPEC) return true; val = I915_READ(PORT_TX_DFLEXDPPMS); @@ -105,7 +106,7 @@ static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) * Now we have to re-check the live state, in case the port recently * became disconnected. Not necessary for legacy mode. */ - if (dig_port->tc_mode == TC_PORT_DP_ALT && + if (dig_port->tc_type == TC_PORT_TYPEC && !(I915_READ(PORT_TX_DFLEXDPSP) & TC_LIVE_STATE_TC(tc_port))) { DRM_DEBUG_KMS("TC PHY %d sudden disconnect.\n", tc_port); icl_tc_phy_disconnect(dig_port); @@ -124,12 +125,15 @@ void icl_tc_phy_disconnect(struct intel_digital_port *dig_port) struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + if (dig_port->tc_type == TC_PORT_UNKNOWN) + return; + /* * TBT disconnection flow is read the live status, what was done in * caller. */ - if (dig_port->tc_mode == TC_PORT_DP_ALT || - dig_port->tc_mode == TC_PORT_LEGACY) { + if (dig_port->tc_type == TC_PORT_TYPEC || + dig_port->tc_type == TC_PORT_LEGACY) { u32 val; val = I915_READ(PORT_TX_DFLEXDPCSSS); @@ -139,9 +143,9 @@ void icl_tc_phy_disconnect(struct intel_digital_port *dig_port) DRM_DEBUG_KMS("Port %c TC type %s disconnected\n", port_name(dig_port->base.port), - tc_port_mode_name(dig_port->tc_mode)); + tc_type_name(dig_port->tc_type)); - dig_port->tc_mode = TC_PORT_TBT_ALT; + dig_port->tc_type = TC_PORT_UNKNOWN; } static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, @@ -149,22 +153,26 @@ static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, bool is_legacy, bool is_typec, bool is_tbt) { enum port port = intel_dig_port->base.port; - enum tc_port_mode old_mode = intel_dig_port->tc_mode; + enum tc_port_type old_type = intel_dig_port->tc_type; WARN_ON(is_legacy + is_typec + is_tbt != 1); if (is_legacy) - intel_dig_port->tc_mode = TC_PORT_LEGACY; + intel_dig_port->tc_type = TC_PORT_LEGACY; else if (is_typec) - intel_dig_port->tc_mode = TC_PORT_DP_ALT; + intel_dig_port->tc_type = TC_PORT_TYPEC; else if (is_tbt) - intel_dig_port->tc_mode = TC_PORT_TBT_ALT; + intel_dig_port->tc_type = TC_PORT_TBT; else return; - if (old_mode != intel_dig_port->tc_mode) + /* Types are not supposed to be changed at runtime. */ + WARN_ON(old_type != TC_PORT_UNKNOWN && + old_type != intel_dig_port->tc_type); + + if (old_type != intel_dig_port->tc_type) DRM_DEBUG_KMS("Port %c has TC type %s\n", port_name(port), - tc_port_mode_name(intel_dig_port->tc_mode)); + tc_type_name(intel_dig_port->tc_type)); } /* diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 65540d7ba92190..f11979879e7bc0 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1225,7 +1225,7 @@ struct intel_digital_port { enum aux_ch aux_ch; enum intel_display_power_domain ddi_io_power_domain; bool tc_legacy_port:1; - enum tc_port_mode tc_mode; + enum tc_port_type tc_type; void (*write_infoframe)(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, From b4a43a6388faebc20d657545b53a1ef39b43e73f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 4 Oct 2019 19:02:56 -0500 Subject: [PATCH 1667/1995] Revert "drm/i915: Move the TypeC port handling code to a separate file" This reverts commit acd4ab2e89e9351d2a9634cb76da3a8a2a05601d. --- drivers/gpu/drm/i915/Makefile | 3 +- drivers/gpu/drm/i915/display/intel_ddi.c | 6 +- drivers/gpu/drm/i915/display/intel_dp.c | 194 ++++++++++++++++++- drivers/gpu/drm/i915/display/intel_dp.h | 2 + drivers/gpu/drm/i915/display/intel_tc.c | 230 ----------------------- drivers/gpu/drm/i915/display/intel_tc.h | 18 -- 6 files changed, 197 insertions(+), 256 deletions(-) delete mode 100644 drivers/gpu/drm/i915/display/intel_tc.c delete mode 100644 drivers/gpu/drm/i915/display/intel_tc.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index c212d9dff5d13b..8cace65f50ce2f 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -173,8 +173,7 @@ i915-y += \ display/intel_overlay.o \ display/intel_psr.o \ display/intel_quirks.o \ - display/intel_sprite.o \ - display/intel_tc.o + display/intel_sprite.o i915-$(CONFIG_ACPI) += \ display/intel_acpi.o \ display/intel_opregion.o diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 980f729e3d9234..1cb1fa74cfbc97 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -45,7 +45,6 @@ #include "intel_lspcon.h" #include "intel_panel.h" #include "intel_psr.h" -#include "intel_tc.h" #include "intel_vdsc.h" struct ddi_buf_trans { @@ -3918,6 +3917,7 @@ static int intel_ddi_compute_config(struct intel_encoder *encoder, static void intel_ddi_encoder_suspend(struct intel_encoder *encoder) { struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base); + struct drm_i915_private *i915 = to_i915(encoder->base.dev); intel_dp_encoder_suspend(encoder); @@ -3927,7 +3927,7 @@ static void intel_ddi_encoder_suspend(struct intel_encoder *encoder) * even if the sink has disappeared while being suspended. */ if (dig_port->tc_legacy_port) - icl_tc_phy_disconnect(dig_port); + icl_tc_phy_disconnect(i915, dig_port); } static void intel_ddi_encoder_reset(struct drm_encoder *drm_encoder) @@ -3949,7 +3949,7 @@ static void intel_ddi_encoder_destroy(struct drm_encoder *encoder) intel_dp_encoder_flush_work(encoder); if (intel_port_is_tc(i915, dig_port->base.port)) - icl_tc_phy_disconnect(dig_port); + icl_tc_phy_disconnect(i915, dig_port); drm_encoder_cleanup(encoder); kfree(dig_port); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 3d3e80ce7fcfd6..d0fc3482677179 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -62,7 +62,6 @@ #include "intel_panel.h" #include "intel_psr.h" #include "intel_sideband.h" -#include "intel_tc.h" #include "intel_vdsc.h" #define DP_DPRX_ESI_LEN 14 @@ -252,7 +251,7 @@ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp) struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); int source_max = intel_dig_port->max_lanes; int sink_max = drm_dp_max_lane_count(intel_dp->dpcd); - int fia_max = intel_tc_port_fia_max_lane_count(intel_dig_port); + int fia_max = intel_dp_get_fia_supported_lane_count(intel_dp); return min3(source_max, sink_max, fia_max); } @@ -5234,6 +5233,195 @@ static bool icl_combo_port_connected(struct drm_i915_private *dev_priv, return I915_READ(SDEISR) & SDE_DDI_HOTPLUG_ICP(port); } +static const char *tc_type_name(enum tc_port_type type) +{ + static const char * const names[] = { + [TC_PORT_UNKNOWN] = "unknown", + [TC_PORT_LEGACY] = "legacy", + [TC_PORT_TYPEC] = "typec", + [TC_PORT_TBT] = "tbt", + }; + + if (WARN_ON(type >= ARRAY_SIZE(names))) + type = TC_PORT_UNKNOWN; + + return names[type]; +} + +static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, + struct intel_digital_port *intel_dig_port, + bool is_legacy, bool is_typec, bool is_tbt) +{ + enum port port = intel_dig_port->base.port; + enum tc_port_type old_type = intel_dig_port->tc_type; + + WARN_ON(is_legacy + is_typec + is_tbt != 1); + + if (is_legacy) + intel_dig_port->tc_type = TC_PORT_LEGACY; + else if (is_typec) + intel_dig_port->tc_type = TC_PORT_TYPEC; + else if (is_tbt) + intel_dig_port->tc_type = TC_PORT_TBT; + else + return; + + /* Types are not supposed to be changed at runtime. */ + WARN_ON(old_type != TC_PORT_UNKNOWN && + old_type != intel_dig_port->tc_type); + + if (old_type != intel_dig_port->tc_type) + DRM_DEBUG_KMS("Port %c has TC type %s\n", port_name(port), + tc_type_name(intel_dig_port->tc_type)); +} + +/* + * This function implements the first part of the Connect Flow described by our + * specification, Gen11 TypeC Programming chapter. The rest of the flow (reading + * lanes, EDID, etc) is done as needed in the typical places. + * + * Unlike the other ports, type-C ports are not available to use as soon as we + * get a hotplug. The type-C PHYs can be shared between multiple controllers: + * display, USB, etc. As a result, handshaking through FIA is required around + * connect and disconnect to cleanly transfer ownership with the controller and + * set the type-C power state. + * + * We could opt to only do the connect flow when we actually try to use the AUX + * channels or do a modeset, then immediately run the disconnect flow after + * usage, but there are some implications on this for a dynamic environment: + * things may go away or change behind our backs. So for now our driver is + * always trying to acquire ownership of the controller as soon as it gets an + * interrupt (or polls state and sees a port is connected) and only gives it + * back when it sees a disconnect. Implementation of a more fine-grained model + * will require a lot of coordination with user space and thorough testing for + * the extra possible cases. + */ +static bool icl_tc_phy_connect(struct drm_i915_private *dev_priv, + struct intel_digital_port *dig_port) +{ + enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + u32 val; + + if (dig_port->tc_type != TC_PORT_LEGACY && + dig_port->tc_type != TC_PORT_TYPEC) + return true; + + val = I915_READ(PORT_TX_DFLEXDPPMS); + if (!(val & DP_PHY_MODE_STATUS_COMPLETED(tc_port))) { + DRM_DEBUG_KMS("DP PHY for TC port %d not ready\n", tc_port); + WARN_ON(dig_port->tc_legacy_port); + return false; + } + + /* + * This function may be called many times in a row without an HPD event + * in between, so try to avoid the write when we can. + */ + val = I915_READ(PORT_TX_DFLEXDPCSSS); + if (!(val & DP_PHY_MODE_STATUS_NOT_SAFE(tc_port))) { + val |= DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); + I915_WRITE(PORT_TX_DFLEXDPCSSS, val); + } + + /* + * Now we have to re-check the live state, in case the port recently + * became disconnected. Not necessary for legacy mode. + */ + if (dig_port->tc_type == TC_PORT_TYPEC && + !(I915_READ(PORT_TX_DFLEXDPSP) & TC_LIVE_STATE_TC(tc_port))) { + DRM_DEBUG_KMS("TC PHY %d sudden disconnect.\n", tc_port); + icl_tc_phy_disconnect(dev_priv, dig_port); + return false; + } + + return true; +} + +/* + * See the comment at the connect function. This implements the Disconnect + * Flow. + */ +void icl_tc_phy_disconnect(struct drm_i915_private *dev_priv, + struct intel_digital_port *dig_port) +{ + enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); + + if (dig_port->tc_type == TC_PORT_UNKNOWN) + return; + + /* + * TBT disconnection flow is read the live status, what was done in + * caller. + */ + if (dig_port->tc_type == TC_PORT_TYPEC || + dig_port->tc_type == TC_PORT_LEGACY) { + u32 val; + + val = I915_READ(PORT_TX_DFLEXDPCSSS); + val &= ~DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); + I915_WRITE(PORT_TX_DFLEXDPCSSS, val); + } + + DRM_DEBUG_KMS("Port %c TC type %s disconnected\n", + port_name(dig_port->base.port), + tc_type_name(dig_port->tc_type)); + + dig_port->tc_type = TC_PORT_UNKNOWN; +} + +/* + * The type-C ports are different because even when they are connected, they may + * not be available/usable by the graphics driver: see the comment on + * icl_tc_phy_connect(). So in our driver instead of adding the additional + * concept of "usable" and make everything check for "connected and usable" we + * define a port as "connected" when it is not only connected, but also when it + * is usable by the rest of the driver. That maintains the old assumption that + * connected ports are usable, and avoids exposing to the users objects they + * can't really use. + */ +static bool icl_tc_port_connected(struct drm_i915_private *dev_priv, + struct intel_digital_port *intel_dig_port) +{ + enum port port = intel_dig_port->base.port; + enum tc_port tc_port = intel_port_to_tc(dev_priv, port); + bool is_legacy, is_typec, is_tbt; + u32 dpsp; + + /* + * Complain if we got a legacy port HPD, but VBT didn't mark the port as + * legacy. Treat the port as legacy from now on. + */ + if (!intel_dig_port->tc_legacy_port && + I915_READ(SDEISR) & SDE_TC_HOTPLUG_ICP(tc_port)) { + DRM_ERROR("VBT incorrectly claims port %c is not TypeC legacy\n", + port_name(port)); + intel_dig_port->tc_legacy_port = true; + } + is_legacy = intel_dig_port->tc_legacy_port; + + /* + * The spec says we shouldn't be using the ISR bits for detecting + * between TC and TBT. We should use DFLEXDPSP. + */ + dpsp = I915_READ(PORT_TX_DFLEXDPSP); + is_typec = dpsp & TC_LIVE_STATE_TC(tc_port); + is_tbt = dpsp & TC_LIVE_STATE_TBT(tc_port); + + if (!is_legacy && !is_typec && !is_tbt) { + icl_tc_phy_disconnect(dev_priv, intel_dig_port); + + return false; + } + + icl_update_tc_port_type(dev_priv, intel_dig_port, is_legacy, is_typec, + is_tbt); + + if (!icl_tc_phy_connect(dev_priv, intel_dig_port)) + return false; + + return true; +} + static bool icl_digital_port_connected(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); @@ -5242,7 +5430,7 @@ static bool icl_digital_port_connected(struct intel_encoder *encoder) if (intel_port_is_combophy(dev_priv, encoder->port)) return icl_combo_port_connected(dev_priv, dig_port); else if (intel_port_is_tc(dev_priv, encoder->port)) - return intel_tc_port_connected(dig_port); + return icl_tc_port_connected(dev_priv, dig_port); else MISSING_CASE(encoder->hpd_pin); diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 657bbb1f5ed08f..da70b1a41c834c 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -112,6 +112,8 @@ bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp); int intel_dp_link_required(int pixel_clock, int bpp); int intel_dp_max_data_rate(int max_link_clock, int max_lanes); bool intel_digital_port_connected(struct intel_encoder *encoder); +void icl_tc_phy_disconnect(struct drm_i915_private *dev_priv, + struct intel_digital_port *dig_port); static inline unsigned int intel_dp_unused_lane_mask(int lane_count) { diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c deleted file mode 100644 index 4fa9ea695d510c..00000000000000 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ /dev/null @@ -1,230 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright © 2019 Intel Corporation - */ - -#include "intel_display.h" -#include "i915_drv.h" -#include "intel_tc.h" - -static const char *tc_type_name(enum tc_port_type type) -{ - static const char * const names[] = { - [TC_PORT_UNKNOWN] = "unknown", - [TC_PORT_LEGACY] = "legacy", - [TC_PORT_TYPEC] = "typec", - [TC_PORT_TBT] = "tbt", - }; - - if (WARN_ON(type >= ARRAY_SIZE(names))) - type = TC_PORT_UNKNOWN; - - return names[type]; -} - -int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port) -{ - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); - intel_wakeref_t wakeref; - u32 lane_info; - - if (tc_port == PORT_TC_NONE || dig_port->tc_type != TC_PORT_TYPEC) - return 4; - - lane_info = 0; - with_intel_display_power(dev_priv, POWER_DOMAIN_DISPLAY_CORE, wakeref) - lane_info = (I915_READ(PORT_TX_DFLEXDPSP) & - DP_LANE_ASSIGNMENT_MASK(tc_port)) >> - DP_LANE_ASSIGNMENT_SHIFT(tc_port); - - switch (lane_info) { - default: - MISSING_CASE(lane_info); - case 1: - case 2: - case 4: - case 8: - return 1; - case 3: - case 12: - return 2; - case 15: - return 4; - } -} - -/* - * This function implements the first part of the Connect Flow described by our - * specification, Gen11 TypeC Programming chapter. The rest of the flow (reading - * lanes, EDID, etc) is done as needed in the typical places. - * - * Unlike the other ports, type-C ports are not available to use as soon as we - * get a hotplug. The type-C PHYs can be shared between multiple controllers: - * display, USB, etc. As a result, handshaking through FIA is required around - * connect and disconnect to cleanly transfer ownership with the controller and - * set the type-C power state. - * - * We could opt to only do the connect flow when we actually try to use the AUX - * channels or do a modeset, then immediately run the disconnect flow after - * usage, but there are some implications on this for a dynamic environment: - * things may go away or change behind our backs. So for now our driver is - * always trying to acquire ownership of the controller as soon as it gets an - * interrupt (or polls state and sees a port is connected) and only gives it - * back when it sees a disconnect. Implementation of a more fine-grained model - * will require a lot of coordination with user space and thorough testing for - * the extra possible cases. - */ -static bool icl_tc_phy_connect(struct intel_digital_port *dig_port) -{ - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); - u32 val; - - if (dig_port->tc_type != TC_PORT_LEGACY && - dig_port->tc_type != TC_PORT_TYPEC) - return true; - - val = I915_READ(PORT_TX_DFLEXDPPMS); - if (!(val & DP_PHY_MODE_STATUS_COMPLETED(tc_port))) { - DRM_DEBUG_KMS("DP PHY for TC port %d not ready\n", tc_port); - WARN_ON(dig_port->tc_legacy_port); - return false; - } - - /* - * This function may be called many times in a row without an HPD event - * in between, so try to avoid the write when we can. - */ - val = I915_READ(PORT_TX_DFLEXDPCSSS); - if (!(val & DP_PHY_MODE_STATUS_NOT_SAFE(tc_port))) { - val |= DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); - I915_WRITE(PORT_TX_DFLEXDPCSSS, val); - } - - /* - * Now we have to re-check the live state, in case the port recently - * became disconnected. Not necessary for legacy mode. - */ - if (dig_port->tc_type == TC_PORT_TYPEC && - !(I915_READ(PORT_TX_DFLEXDPSP) & TC_LIVE_STATE_TC(tc_port))) { - DRM_DEBUG_KMS("TC PHY %d sudden disconnect.\n", tc_port); - icl_tc_phy_disconnect(dig_port); - return false; - } - - return true; -} - -/* - * See the comment at the connect function. This implements the Disconnect - * Flow. - */ -void icl_tc_phy_disconnect(struct intel_digital_port *dig_port) -{ - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - enum tc_port tc_port = intel_port_to_tc(dev_priv, dig_port->base.port); - - if (dig_port->tc_type == TC_PORT_UNKNOWN) - return; - - /* - * TBT disconnection flow is read the live status, what was done in - * caller. - */ - if (dig_port->tc_type == TC_PORT_TYPEC || - dig_port->tc_type == TC_PORT_LEGACY) { - u32 val; - - val = I915_READ(PORT_TX_DFLEXDPCSSS); - val &= ~DP_PHY_MODE_STATUS_NOT_SAFE(tc_port); - I915_WRITE(PORT_TX_DFLEXDPCSSS, val); - } - - DRM_DEBUG_KMS("Port %c TC type %s disconnected\n", - port_name(dig_port->base.port), - tc_type_name(dig_port->tc_type)); - - dig_port->tc_type = TC_PORT_UNKNOWN; -} - -static void icl_update_tc_port_type(struct drm_i915_private *dev_priv, - struct intel_digital_port *intel_dig_port, - bool is_legacy, bool is_typec, bool is_tbt) -{ - enum port port = intel_dig_port->base.port; - enum tc_port_type old_type = intel_dig_port->tc_type; - - WARN_ON(is_legacy + is_typec + is_tbt != 1); - - if (is_legacy) - intel_dig_port->tc_type = TC_PORT_LEGACY; - else if (is_typec) - intel_dig_port->tc_type = TC_PORT_TYPEC; - else if (is_tbt) - intel_dig_port->tc_type = TC_PORT_TBT; - else - return; - - /* Types are not supposed to be changed at runtime. */ - WARN_ON(old_type != TC_PORT_UNKNOWN && - old_type != intel_dig_port->tc_type); - - if (old_type != intel_dig_port->tc_type) - DRM_DEBUG_KMS("Port %c has TC type %s\n", port_name(port), - tc_type_name(intel_dig_port->tc_type)); -} - -/* - * The type-C ports are different because even when they are connected, they may - * not be available/usable by the graphics driver: see the comment on - * icl_tc_phy_connect(). So in our driver instead of adding the additional - * concept of "usable" and make everything check for "connected and usable" we - * define a port as "connected" when it is not only connected, but also when it - * is usable by the rest of the driver. That maintains the old assumption that - * connected ports are usable, and avoids exposing to the users objects they - * can't really use. - */ -bool intel_tc_port_connected(struct intel_digital_port *dig_port) -{ - struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); - enum port port = dig_port->base.port; - enum tc_port tc_port = intel_port_to_tc(dev_priv, port); - bool is_legacy, is_typec, is_tbt; - u32 dpsp; - - /* - * Complain if we got a legacy port HPD, but VBT didn't mark the port as - * legacy. Treat the port as legacy from now on. - */ - if (!dig_port->tc_legacy_port && - I915_READ(SDEISR) & SDE_TC_HOTPLUG_ICP(tc_port)) { - DRM_ERROR("VBT incorrectly claims port %c is not TypeC legacy\n", - port_name(port)); - dig_port->tc_legacy_port = true; - } - is_legacy = dig_port->tc_legacy_port; - - /* - * The spec says we shouldn't be using the ISR bits for detecting - * between TC and TBT. We should use DFLEXDPSP. - */ - dpsp = I915_READ(PORT_TX_DFLEXDPSP); - is_typec = dpsp & TC_LIVE_STATE_TC(tc_port); - is_tbt = dpsp & TC_LIVE_STATE_TBT(tc_port); - - if (!is_legacy && !is_typec && !is_tbt) { - icl_tc_phy_disconnect(dig_port); - - return false; - } - - icl_update_tc_port_type(dev_priv, dig_port, is_legacy, is_typec, - is_tbt); - - if (!icl_tc_phy_connect(dig_port)) - return false; - - return true; -} - diff --git a/drivers/gpu/drm/i915/display/intel_tc.h b/drivers/gpu/drm/i915/display/intel_tc.h deleted file mode 100644 index 0c65675394e54f..00000000000000 --- a/drivers/gpu/drm/i915/display/intel_tc.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Copyright © 2019 Intel Corporation - */ - -#ifndef __INTEL_TC_H__ -#define __INTEL_TC_H__ - -#include - -struct intel_digital_port; - -void icl_tc_phy_disconnect(struct intel_digital_port *dig_port); - -bool intel_tc_port_connected(struct intel_digital_port *dig_port); -int intel_tc_port_fia_max_lane_count(struct intel_digital_port *dig_port); - -#endif /* __INTEL_TC_H__ */ From 0a8ed115d84adf120a3dc6ef003a24edd1acf453 Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Tue, 24 Sep 2019 15:56:57 +0300 Subject: [PATCH 1668/1995] ASoC: SOF: enable dual control for pga Currently sof pga element supports only 1 kcontrol and you can't create for example a mixer element with combined volume slider and mute switch. So enable sof pga to have more than 1 kcontrol associated with it. Also check for possible NULL tlv pointer as switch element might not have it. Signed-off-by: Jaska Uimonen --- sound/soc/sof/topology.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index b254042581e64b..678929fbfc17a8 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1597,7 +1597,7 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, if (!volume) return -ENOMEM; - if (le32_to_cpu(tw->num_kcontrols) != 1) { + if (!le32_to_cpu(tw->num_kcontrols)) { dev_err(sdev->dev, "error: invalid kcontrol count %d for volume\n", tw->num_kcontrols); ret = -EINVAL; @@ -1634,7 +1634,8 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, swidget->private = volume; list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { - if (scontrol->comp_id == swidget->comp_id) { + if (scontrol->comp_id == swidget->comp_id && + scontrol->volume_table) { min_step = scontrol->min_volume_step; max_step = scontrol->max_volume_step; volume->min_value = scontrol->volume_table[min_step]; From a3e7c99b6e4249aa851685bf5d4dc95e5d45979d Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Mon, 30 Sep 2019 17:30:03 +0300 Subject: [PATCH 1669/1995] AsoC: SOF: refactor control load code Move code around to enable token parsing in control load. Signed-off-by: Jaska Uimonen --- sound/soc/sof/topology.c | 314 +++++++++++++++++++-------------------- 1 file changed, 157 insertions(+), 157 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 678929fbfc17a8..2dea270d2bae93 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -432,163 +432,6 @@ static enum sof_comp_type find_process_comp_type(enum sof_ipc_process_type type) return SOF_COMP_NONE; } -/* - * Standard Kcontrols. - */ - -static int sof_control_load_volume(struct snd_soc_component *scomp, - struct snd_sof_control *scontrol, - struct snd_kcontrol_new *kc, - struct snd_soc_tplg_ctl_hdr *hdr) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_tplg_mixer_control *mc = - container_of(hdr, struct snd_soc_tplg_mixer_control, hdr); - struct sof_ipc_ctrl_data *cdata; - int tlv[TLV_ITEMS]; - unsigned int i; - int ret; - - /* validate topology data */ - if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN) - return -EINVAL; - - /* init the volume get/put data */ - scontrol->size = struct_size(scontrol->control_data, chanv, - le32_to_cpu(mc->num_channels)); - scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); - if (!scontrol->control_data) - return -ENOMEM; - - scontrol->comp_id = sdev->next_comp_id; - scontrol->min_volume_step = le32_to_cpu(mc->min); - scontrol->max_volume_step = le32_to_cpu(mc->max); - scontrol->num_channels = le32_to_cpu(mc->num_channels); - - /* set cmd for mixer control */ - if (le32_to_cpu(mc->max) == 1) { - scontrol->cmd = SOF_CTRL_CMD_SWITCH; - goto out; - } - - scontrol->cmd = SOF_CTRL_CMD_VOLUME; - - /* extract tlv data */ - if (get_tlv_data(kc->tlv.p, tlv) < 0) { - dev_err(sdev->dev, "error: invalid TLV data\n"); - return -EINVAL; - } - - /* set up volume table */ - ret = set_up_volume_table(scontrol, tlv, le32_to_cpu(mc->max) + 1); - if (ret < 0) { - dev_err(sdev->dev, "error: setting up volume table\n"); - return ret; - } - - /* set default volume values to 0dB in control */ - cdata = scontrol->control_data; - for (i = 0; i < scontrol->num_channels; i++) { - cdata->chanv[i].channel = i; - cdata->chanv[i].value = VOL_ZERO_DB; - } - -out: - dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", - scontrol->comp_id, scontrol->num_channels); - - return 0; -} - -static int sof_control_load_enum(struct snd_soc_component *scomp, - struct snd_sof_control *scontrol, - struct snd_kcontrol_new *kc, - struct snd_soc_tplg_ctl_hdr *hdr) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_soc_tplg_enum_control *ec = - container_of(hdr, struct snd_soc_tplg_enum_control, hdr); - - /* validate topology data */ - if (le32_to_cpu(ec->num_channels) > SND_SOC_TPLG_MAX_CHAN) - return -EINVAL; - - /* init the enum get/put data */ - scontrol->size = struct_size(scontrol->control_data, chanv, - le32_to_cpu(ec->num_channels)); - scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); - if (!scontrol->control_data) - return -ENOMEM; - - scontrol->comp_id = sdev->next_comp_id; - scontrol->num_channels = le32_to_cpu(ec->num_channels); - - scontrol->cmd = SOF_CTRL_CMD_ENUM; - - dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d comp_id %d\n", - scontrol->comp_id, scontrol->num_channels, scontrol->comp_id); - - return 0; -} - -static int sof_control_load_bytes(struct snd_soc_component *scomp, - struct snd_sof_control *scontrol, - struct snd_kcontrol_new *kc, - struct snd_soc_tplg_ctl_hdr *hdr) -{ - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct sof_ipc_ctrl_data *cdata; - struct snd_soc_tplg_bytes_control *control = - container_of(hdr, struct snd_soc_tplg_bytes_control, hdr); - struct soc_bytes_ext *sbe = (struct soc_bytes_ext *)kc->private_value; - int max_size = sbe->max; - - if (le32_to_cpu(control->priv.size) > max_size) { - dev_err(sdev->dev, "err: bytes data size %d exceeds max %d.\n", - control->priv.size, max_size); - return -EINVAL; - } - - /* init the get/put bytes data */ - scontrol->size = sizeof(struct sof_ipc_ctrl_data) + - le32_to_cpu(control->priv.size); - scontrol->control_data = kzalloc(max_size, GFP_KERNEL); - cdata = scontrol->control_data; - if (!scontrol->control_data) - return -ENOMEM; - - scontrol->comp_id = sdev->next_comp_id; - scontrol->cmd = SOF_CTRL_CMD_BINARY; - - dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", - scontrol->comp_id, scontrol->num_channels); - - if (le32_to_cpu(control->priv.size) > 0) { - memcpy(cdata->data, control->priv.data, - le32_to_cpu(control->priv.size)); - - if (cdata->data->magic != SOF_ABI_MAGIC) { - dev_err(sdev->dev, "error: Wrong ABI magic 0x%08x.\n", - cdata->data->magic); - return -EINVAL; - } - if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, - cdata->data->abi)) { - dev_err(sdev->dev, - "error: Incompatible ABI version 0x%08x.\n", - cdata->data->abi); - return -EINVAL; - } - if (cdata->data->size + sizeof(const struct sof_abi_hdr) != - le32_to_cpu(control->priv.size)) { - dev_err(sdev->dev, - "error: Conflict in bytes vs. priv size.\n"); - return -EINVAL; - } - } - return 0; -} - /* * Topology Token Parsing. * New tokens should be added to headers and parsing tables below. @@ -1056,6 +899,163 @@ static void sof_dbg_comp_config(struct snd_soc_component *scomp, config->frame_fmt); } +/* + * Standard Kcontrols. + */ + +static int sof_control_load_volume(struct snd_soc_component *scomp, + struct snd_sof_control *scontrol, + struct snd_kcontrol_new *kc, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_mixer_control *mc = + container_of(hdr, struct snd_soc_tplg_mixer_control, hdr); + struct sof_ipc_ctrl_data *cdata; + int tlv[TLV_ITEMS]; + unsigned int i; + int ret; + + /* validate topology data */ + if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN) + return -EINVAL; + + /* init the volume get/put data */ + scontrol->size = struct_size(scontrol->control_data, chanv, + le32_to_cpu(mc->num_channels)); + scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); + if (!scontrol->control_data) + return -ENOMEM; + + scontrol->comp_id = sdev->next_comp_id; + scontrol->min_volume_step = le32_to_cpu(mc->min); + scontrol->max_volume_step = le32_to_cpu(mc->max); + scontrol->num_channels = le32_to_cpu(mc->num_channels); + + /* set cmd for mixer control */ + if (le32_to_cpu(mc->max) == 1) { + scontrol->cmd = SOF_CTRL_CMD_SWITCH; + goto out; + } + + scontrol->cmd = SOF_CTRL_CMD_VOLUME; + + /* extract tlv data */ + if (get_tlv_data(kc->tlv.p, tlv) < 0) { + dev_err(sdev->dev, "error: invalid TLV data\n"); + return -EINVAL; + } + + /* set up volume table */ + ret = set_up_volume_table(scontrol, tlv, le32_to_cpu(mc->max) + 1); + if (ret < 0) { + dev_err(sdev->dev, "error: setting up volume table\n"); + return ret; + } + + /* set default volume values to 0dB in control */ + cdata = scontrol->control_data; + for (i = 0; i < scontrol->num_channels; i++) { + cdata->chanv[i].channel = i; + cdata->chanv[i].value = VOL_ZERO_DB; + } + +out: + dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", + scontrol->comp_id, scontrol->num_channels); + + return 0; +} + +static int sof_control_load_enum(struct snd_soc_component *scomp, + struct snd_sof_control *scontrol, + struct snd_kcontrol_new *kc, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_enum_control *ec = + container_of(hdr, struct snd_soc_tplg_enum_control, hdr); + + /* validate topology data */ + if (le32_to_cpu(ec->num_channels) > SND_SOC_TPLG_MAX_CHAN) + return -EINVAL; + + /* init the enum get/put data */ + scontrol->size = struct_size(scontrol->control_data, chanv, + le32_to_cpu(ec->num_channels)); + scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); + if (!scontrol->control_data) + return -ENOMEM; + + scontrol->comp_id = sdev->next_comp_id; + scontrol->num_channels = le32_to_cpu(ec->num_channels); + + scontrol->cmd = SOF_CTRL_CMD_ENUM; + + dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d comp_id %d\n", + scontrol->comp_id, scontrol->num_channels, scontrol->comp_id); + + return 0; +} + +static int sof_control_load_bytes(struct snd_soc_component *scomp, + struct snd_sof_control *scontrol, + struct snd_kcontrol_new *kc, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc_ctrl_data *cdata; + struct snd_soc_tplg_bytes_control *control = + container_of(hdr, struct snd_soc_tplg_bytes_control, hdr); + struct soc_bytes_ext *sbe = (struct soc_bytes_ext *)kc->private_value; + int max_size = sbe->max; + + if (le32_to_cpu(control->priv.size) > max_size) { + dev_err(sdev->dev, "err: bytes data size %d exceeds max %d.\n", + control->priv.size, max_size); + return -EINVAL; + } + + /* init the get/put bytes data */ + scontrol->size = sizeof(struct sof_ipc_ctrl_data) + + le32_to_cpu(control->priv.size); + scontrol->control_data = kzalloc(max_size, GFP_KERNEL); + cdata = scontrol->control_data; + if (!scontrol->control_data) + return -ENOMEM; + + scontrol->comp_id = sdev->next_comp_id; + scontrol->cmd = SOF_CTRL_CMD_BINARY; + + dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", + scontrol->comp_id, scontrol->num_channels); + + if (le32_to_cpu(control->priv.size) > 0) { + memcpy(cdata->data, control->priv.data, + le32_to_cpu(control->priv.size)); + + if (cdata->data->magic != SOF_ABI_MAGIC) { + dev_err(sdev->dev, "error: Wrong ABI magic 0x%08x.\n", + cdata->data->magic); + return -EINVAL; + } + if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, + cdata->data->abi)) { + dev_err(sdev->dev, + "error: Incompatible ABI version 0x%08x.\n", + cdata->data->abi); + return -EINVAL; + } + if (cdata->data->size + sizeof(const struct sof_abi_hdr) != + le32_to_cpu(control->priv.size)) { + dev_err(sdev->dev, + "error: Conflict in bytes vs. priv size.\n"); + return -EINVAL; + } + } + return 0; +} + /* external kcontrol init - used for any driver specific init */ static int sof_control_load(struct snd_soc_component *scomp, int index, struct snd_kcontrol_new *kc, From febc9f2215711de0603813b25e00dc3ef549c87a Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Tue, 24 Sep 2019 15:58:45 +0300 Subject: [PATCH 1670/1995] ASoC: SOF: acpi led support for switch controls Currently sof doesn't support acpi leds with mute switches. So implement acpi leds following quite shamelessly existing HDA implementation by Takashi Iwai. Mute leds can be enabled in topology by adding led and direction token in switch control private data. Signed-off-by: Jaska Uimonen --- include/uapi/sound/sof/tokens.h | 4 ++++ sound/soc/sof/control.c | 32 ++++++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 9 +++++++++ sound/soc/sof/topology.c | 13 +++++++++++++ 4 files changed, 58 insertions(+) diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 6139ec50784066..76883e6fb75081 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -117,4 +117,8 @@ #define SOF_TKN_STREAM_PLAYBACK_COMPATIBLE_D0I3 1200 #define SOF_TKN_STREAM_CAPTURE_COMPATIBLE_D0I3 1201 +/* Led control for mute switches */ +#define SOF_TKN_MUTE_LED_USE 1300 +#define SOF_TKN_MUTE_LED_DIRECTION 1301 + #endif diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index a4983f90ff5b31..41551e8f6ac36b 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -11,8 +11,37 @@ /* Mixer Controls */ #include +#include #include "sof-priv.h" +static void update_mute_led(struct snd_sof_control *scontrol, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + unsigned int temp = 0; + unsigned int mask; + int i; + + mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + + for (i = 0; i < scontrol->num_channels; i++) { + if (ucontrol->value.integer.value[i]) { + temp |= mask; + break; + } + } + + if (temp == scontrol->led_ctl.led_value) + return; + + scontrol->led_ctl.led_value = temp; + + if (!scontrol->led_ctl.direction) + ledtrig_audio_set(LED_AUDIO_MUTE, temp ? LED_OFF : LED_ON); + else + ledtrig_audio_set(LED_AUDIO_MICMUTE, temp ? LED_OFF : LED_ON); +} + static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size) { if (value >= size) @@ -112,6 +141,9 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, cdata->chanv[i].channel = i; } + if (scontrol->led_ctl.use_led) + update_mute_led(scontrol, kcontrol, ucontrol); + /* notify DSP of mixer updates */ if (pm_runtime_active(sdev->dev)) snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 9d5151f7cc2fc8..2121d9d0ffdab4 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -15,6 +15,7 @@ #include #include +#include #include #include /* needs to be included before control.h */ @@ -319,6 +320,12 @@ struct snd_sof_pcm { bool prepared[2]; /* PCM_PARAMS set successfully */ }; +struct snd_sof_led_control { + unsigned int use_led; + unsigned int direction; + unsigned int led_value; +}; + /* ALSA SOF Kcontrol device */ struct snd_sof_control { struct snd_sof_dev *sdev; @@ -333,6 +340,8 @@ struct snd_sof_control { u32 *volume_table; /* volume table computed from tlv data*/ struct list_head list; /* list in sdev control list */ + + struct snd_sof_led_control led_ctl; }; /* ASoC SOF DAPM widget */ diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 2dea270d2bae93..ab70f37082e896 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -699,6 +699,14 @@ static const struct sof_topology_token dmic_pdm_tokens[] = { static const struct sof_topology_token hda_tokens[] = { }; +/* Leds */ +static const struct sof_topology_token led_tokens[] = { + {SOF_TKN_MUTE_LED_USE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct snd_sof_led_control, use_led), 0}, + {SOF_TKN_MUTE_LED_DIRECTION, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, offsetof(struct snd_sof_led_control, direction), 0}, +}; + static void sof_parse_uuid_tokens(struct snd_soc_component *scomp, void *object, const struct sof_topology_token *tokens, @@ -961,6 +969,11 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, } out: + /* set up possible led control from mixer private data */ + ret = sof_parse_tokens(scomp, &scontrol->led_ctl, led_tokens, + ARRAY_SIZE(led_tokens), mc->priv.array, + le32_to_cpu(mc->priv.size)); + dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", scontrol->comp_id, scontrol->num_channels); From e5c16604b6a673f51ff314d2ebc43fd44f097e5b Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 8 Oct 2019 12:32:49 +0300 Subject: [PATCH 1671/1995] ASoC: SOF: rename sof_debug module params for PCI/ACPI The SOF core module already has a "sof_debug" module parameter, so it is confusing for the PCI and ACPI modules to have parameter with the same name, but different semantics. Rename the module parameters to "sof_pci_debug" and "sof_acpi_debug". Signed-off-by: Kai Vehmanen --- sound/soc/sof/sof-acpi-dev.c | 4 ++-- sound/soc/sof/sof-pci-dev.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index be727c8f132ae7..df318f50dd0ba4 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -30,8 +30,8 @@ module_param(tplg_path, charp, 0444); MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); static int sof_acpi_debug; -module_param_named(sof_debug, sof_acpi_debug, int, 0444); -MODULE_PARM_DESC(sof_debug, "SOF ACPI debug options (0x0 all off)"); +module_param_named(sof_acpi_debug, sof_acpi_debug, int, 0444); +MODULE_PARM_DESC(sof_acpi_debug, "SOF ACPI debug options (0x0 all off)"); #define SOF_ACPI_DISABLE_PM_RUNTIME BIT(0) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 25537e23ec4bf3..030f2cb0692144 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -30,8 +30,8 @@ module_param(tplg_path, charp, 0444); MODULE_PARM_DESC(tplg_path, "alternate path for SOF topology."); static int sof_pci_debug; -module_param_named(sof_debug, sof_pci_debug, int, 0444); -MODULE_PARM_DESC(sof_debug, "SOF PCI debug options (0x0 all off)"); +module_param_named(sof_pci_debug, sof_pci_debug, int, 0444); +MODULE_PARM_DESC(sof_pci_debug, "SOF PCI debug options (0x0 all off)"); #define SOF_PCI_DISABLE_PM_RUNTIME BIT(0) From a97c8daa07af5d87b71808b5fb34cd5189511978 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 7 Oct 2019 16:10:49 +0300 Subject: [PATCH 1672/1995] ASoC: SOF: enable sync_write in hdac_bus Align SOF HDA implementation with legacy driver and enable sync_write flag for all supported platforms. Matches the change done in commit 2756d9143aa5 ("ALSA: hda - Fix intermittent CORB/RIRB stall on Intel chips"). Signed-off-by: Kai Vehmanen --- sound/soc/sof/intel/hda.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 06e84679087bc6..5a5163eef2ef41 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -268,6 +268,7 @@ static int hda_init(struct snd_sof_dev *sdev) bus->use_posbuf = 1; bus->bdl_pos_adj = 0; + bus->sync_write = 1; mutex_init(&hbus->prepare_mutex); hbus->pci = pci; From fd6618c35cecbe449627843227d03d04450a7299 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 7 Oct 2019 16:18:54 +0300 Subject: [PATCH 1673/1995] Revert "ASoC: SOF: Force polling mode on CFL and CNL" This reverts commit 64ca9d9fcb3e3c86b1417e3d17a90b43dd660f81. The workaround is no longer needed after configuring HDAC bus with sync_write=1. Signed-off-by: Kai Vehmanen --- sound/soc/sof/intel/hda.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 5a5163eef2ef41..103f4273c4d34f 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -32,9 +32,6 @@ /* platform specific devices */ #include "shim.h" -#define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348) -#define IS_CNL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9dc8) - #define EXCEPT_MAX_HDR_SIZE 0x400 /* @@ -262,10 +259,6 @@ static int hda_init(struct snd_sof_dev *sdev) /* HDA bus init */ sof_hda_bus_init(bus, &pci->dev); - /* Workaround for a communication error on CFL (bko#199007) and CNL */ - if (IS_CFL(pci) || IS_CNL(pci)) - bus->polling_mode = 1; - bus->use_posbuf = 1; bus->bdl_pos_adj = 0; bus->sync_write = 1; From 0cb09ee9864db3d2fecd7414e9ca6939bc515247 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 8 Oct 2019 10:58:31 -0500 Subject: [PATCH 1674/1995] ext4: fix bad merge Align with upstream, looks like the revert of the revert didn't quite work. Signed-off-by: Pierre-Louis Bossart --- fs/ext4/inode.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 123e3dee7733b6..516faa280ceda8 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4551,6 +4551,7 @@ static int __ext4_get_inode_loc(struct inode *inode, struct buffer_head *bh; struct super_block *sb = inode->i_sb; ext4_fsblk_t block; + struct blk_plug plug; int inodes_per_block, inode_offset; iloc->bh = NULL; @@ -4639,6 +4640,7 @@ static int __ext4_get_inode_loc(struct inode *inode, * If we need to do any I/O, try to pre-readahead extra * blocks from the inode table. */ + blk_start_plug(&plug); if (EXT4_SB(sb)->s_inode_readahead_blks) { ext4_fsblk_t b, end, table; unsigned num; @@ -4669,6 +4671,7 @@ static int __ext4_get_inode_loc(struct inode *inode, get_bh(bh); bh->b_end_io = end_buffer_read_sync; submit_bh(REQ_OP_READ, REQ_META | REQ_PRIO, bh); + blk_finish_plug(&plug); wait_on_buffer(bh); if (!buffer_uptodate(bh)) { EXT4_ERROR_INODE_BLOCK(inode, block, From 0f665a4f8bf1616c68d95e93d36aed8d6f91b4d0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 8 Oct 2019 11:49:01 -0500 Subject: [PATCH 1675/1995] ASoC: SOF: dai-imx: remove spurious newline at EOF Align with code sent upstream (git am complained about newlines) Signed-off-by: Pierre-Louis Bossart --- include/sound/sof/dai-imx.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/sound/sof/dai-imx.h b/include/sound/sof/dai-imx.h index 206620cc315071..e02fb0b0fae165 100644 --- a/include/sound/sof/dai-imx.h +++ b/include/sound/sof/dai-imx.h @@ -32,4 +32,3 @@ struct sof_ipc_dai_esai_params { } __packed; #endif - From 3129cc5d6a411123bf43318cac23ec3ca132e21e Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 1 Oct 2019 11:45:43 +0300 Subject: [PATCH 1676/1995] drm/i915: Fix audio power up sequence for gen10+ display On platfroms with gen10+ display, driver must set the enable bit of AUDIO_PIN_BUF_CTL register before transactions with the HDA controller can proceed. Add setting this bit to the audio power up sequence. Failing to do this resulted in errors during display audio codec probe, and failures during resume from suspend. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=111214 Signed-off-by: Kai Vehmanen --- drivers/gpu/drm/i915/display/intel_audio.c | 8 +++++++- drivers/gpu/drm/i915/i915_reg.h | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index ddcccf4408c37d..2ae8354646aac4 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -851,10 +851,16 @@ static unsigned long i915_audio_component_get_power(struct device *kdev) ret = intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO); /* Force CDCLK to 2*BCLK as long as we need audio to be powered. */ - if (dev_priv->audio_power_refcount++ == 0) + if (dev_priv->audio_power_refcount++ == 0) { if (IS_CANNONLAKE(dev_priv) || IS_GEMINILAKE(dev_priv)) glk_force_audio_cdclk(dev_priv, true); + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) + I915_WRITE(AUD_PIN_BUF_CTL, + (I915_READ(AUD_PIN_BUF_CTL) | + AUD_PIN_BUF_ENABLE)); + } + return ret; } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2abd199093c5bf..6f08b6543c0294 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -9094,6 +9094,9 @@ enum { #define HSW_AUD_CHICKENBIT _MMIO(0x65f10) #define SKL_AUD_CODEC_WAKE_SIGNAL (1 << 15) +#define AUD_PIN_BUF_CTL _MMIO(0x48414) +#define AUD_PIN_BUF_ENABLE REG_BIT(31) + /* * HSW - ICL power wells * From 5c56119031734d156fd064a2677c7aaa38f54138 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 1 Oct 2019 15:10:42 +0300 Subject: [PATCH 1677/1995] drm/i915: extend audio CDCLK>=2*BCLK constraint to more platforms The CDCLK>=2*BCLK constraint applies to all generations since gen10. Extend the constraint logic in audio get/put_power(). Signed-off-by: Kai Vehmanen --- drivers/gpu/drm/i915/display/intel_audio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 2ae8354646aac4..191561f0834b4b 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -852,7 +852,7 @@ static unsigned long i915_audio_component_get_power(struct device *kdev) /* Force CDCLK to 2*BCLK as long as we need audio to be powered. */ if (dev_priv->audio_power_refcount++ == 0) { - if (IS_CANNONLAKE(dev_priv) || IS_GEMINILAKE(dev_priv)) + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) glk_force_audio_cdclk(dev_priv, true); if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) @@ -871,7 +871,7 @@ static void i915_audio_component_put_power(struct device *kdev, /* Stop forcing CDCLK to 2*BCLK if no need for audio to be powered. */ if (--dev_priv->audio_power_refcount == 0) - if (IS_CANNONLAKE(dev_priv) || IS_GEMINILAKE(dev_priv)) + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) glk_force_audio_cdclk(dev_priv, false); intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO, cookie); From 5edcfdf3907354de7a260a451ba611f22c5e6a07 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 20 Sep 2019 11:39:18 +0300 Subject: [PATCH 1678/1995] drm/i915: save AUD_FREQ_CNTRL state at audio domain suspend When audio power domain is suspended, the display driver must save state of AUD_FREQ_CNTRL on Tiger Lake and Ice Lake systems. The initial value of the register is set by BIOS and is read by driver during the audio component init sequence. Cc: Jani Nikula Cc: Imre Deak Signed-off-by: Kai Vehmanen Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/20190920083918.27057-1-kai.vehmanen@linux.intel.com --- drivers/gpu/drm/i915/display/intel_audio.c | 12 ++++++++++++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_reg.h | 2 ++ 3 files changed, 15 insertions(+) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 191561f0834b4b..ae64cfa1e5de08 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -852,6 +852,12 @@ static unsigned long i915_audio_component_get_power(struct device *kdev) /* Force CDCLK to 2*BCLK as long as we need audio to be powered. */ if (dev_priv->audio_power_refcount++ == 0) { + if (IS_TIGERLAKE(dev_priv) || IS_ICELAKE(dev_priv)) { + I915_WRITE(AUD_FREQ_CNTRL, dev_priv->audio_freq_cntrl); + DRM_DEBUG_KMS("restored AUD_FREQ_CNTRL to 0x%x\n", + dev_priv->audio_freq_cntrl); + } + if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) glk_force_audio_cdclk(dev_priv, true); @@ -1120,6 +1126,12 @@ static void i915_audio_component_init(struct drm_i915_private *dev_priv) return; } + if (IS_TIGERLAKE(dev_priv) || IS_ICELAKE(dev_priv)) { + dev_priv->audio_freq_cntrl = I915_READ(AUD_FREQ_CNTRL); + DRM_DEBUG_KMS("init value of AUD_FREQ_CNTRL of 0x%x\n", + dev_priv->audio_freq_cntrl); + } + dev_priv->audio_component_registered = true; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 772154e4073e26..2dd0a59549d444 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1528,6 +1528,7 @@ struct drm_i915_private { */ struct mutex av_mutex; int audio_power_refcount; + u32 audio_freq_cntrl; struct { struct mutex mutex; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6f08b6543c0294..ca080a29460903 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -9097,6 +9097,8 @@ enum { #define AUD_PIN_BUF_CTL _MMIO(0x48414) #define AUD_PIN_BUF_ENABLE REG_BIT(31) +#define AUD_FREQ_CNTRL _MMIO(0x65900) + /* * HSW - ICL power wells * From f02b9308dcef01b765e3c396096d7f67df81fd44 Mon Sep 17 00:00:00 2001 From: Dragos Tarcatu Date: Wed, 16 Oct 2019 09:14:06 +0300 Subject: [PATCH 1679/1995] ASoC: SOF: control: return true when kcontrol values change All the kcontrol put() functions are currently returning 0 when successful. This does not go well with alsamixer as it does not seem to get notified on SND_CTL_EVENT_MASK_VALUE callbacks when values change for (some of) the sof kcontrols. This patch fixes that by returning true for volume, switch and enum type kcontrols when values do change in put(). Signed-off-by: Dragos Tarcatu --- sound/soc/sof/control.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 41551e8f6ac36b..b73d4587c5da2a 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -89,13 +89,16 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; + bool change = false; + u32 value; /* update each channel */ for (i = 0; i < channels; i++) { - cdata->chanv[i].value = - mixer_to_ipc(ucontrol->value.integer.value[i], + value = mixer_to_ipc(ucontrol->value.integer.value[i], scontrol->volume_table, sm->max + 1); + change = change || (value != cdata->chanv[i].value); cdata->chanv[i].channel = i; + cdata->chanv[i].value = value; } /* notify DSP of mixer updates */ @@ -105,8 +108,7 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, SOF_CTRL_TYPE_VALUE_CHAN_GET, SOF_CTRL_CMD_VOLUME, true); - - return 0; + return change; } int snd_sof_switch_get(struct snd_kcontrol *kcontrol, @@ -134,11 +136,15 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; + bool change = false; + u32 value; /* update each channel */ for (i = 0; i < channels; i++) { - cdata->chanv[i].value = ucontrol->value.integer.value[i]; + value = ucontrol->value.integer.value[i]; + change = change || (value != cdata->chanv[i].value); cdata->chanv[i].channel = i; + cdata->chanv[i].value = value; } if (scontrol->led_ctl.use_led) @@ -152,7 +158,7 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, SOF_CTRL_CMD_SWITCH, true); - return 0; + return change; } int snd_sof_enum_get(struct snd_kcontrol *kcontrol, @@ -180,11 +186,15 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, struct snd_sof_dev *sdev = scontrol->sdev; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; + bool change = false; + u32 value; /* update each channel */ for (i = 0; i < channels; i++) { - cdata->chanv[i].value = ucontrol->value.enumerated.item[i]; + value = ucontrol->value.enumerated.item[i]; + change = change || (value != cdata->chanv[i].value); cdata->chanv[i].channel = i; + cdata->chanv[i].value = value; } /* notify DSP of enum updates */ @@ -195,7 +205,7 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, SOF_CTRL_CMD_ENUM, true); - return 0; + return change; } int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, From dfabe4253fe987fc474856438586ead74c8dc2e5 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Wed, 24 Jul 2019 22:42:41 +0800 Subject: [PATCH 1680/1995] ASoC: Intel: common: add ACPI matching tables for JSL There are no upstream machine drivers just yet so just add dummy table for compilation in nocodec-mode. Signed-off-by: Pan Xiuli --- include/sound/soc-acpi-intel-match.h | 1 + sound/soc/intel/common/Makefile | 1 + .../intel/common/soc-acpi-intel-jsl-match.c | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 sound/soc/intel/common/soc-acpi-intel-jsl-match.c diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index 6c9929abd90b84..4e44782862df39 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -27,6 +27,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[]; /* * generic table used for HDA codec-based platforms, possibly with diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 18d9630ae9a232..eafe95ead49b67 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -9,6 +9,7 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \ soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \ + soc-acpi-intel-jsl-match.o \ soc-acpi-intel-hda-match.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c new file mode 100644 index 00000000000000..1c68a04f0c6e6c --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-apci-intel-jsl-match.c - tables and support for JSL ACPI enumeration. + * + * Copyright (c) 2019, Intel Corporation. + * + */ + +#include +#include + +struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = { + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_jsl_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); From e10ebc8e21b8a4692f714a5407d7935485bd33ee Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Sun, 16 Jun 2019 13:49:33 +0800 Subject: [PATCH 1681/1995] ASoC: SOF: Intel: initial support to JasperLake. Add Kconfig, PCI ID and chip info for JSL platform. The DSP only has 2 cores for this platform. Signed-off-by: Pan Xiuli --- sound/soc/sof/intel/Kconfig | 16 ++++++++++++++++ sound/soc/sof/intel/cnl.c | 17 +++++++++++++++++ sound/soc/sof/intel/hda.h | 1 + sound/soc/sof/sof-pci-dev.c | 22 ++++++++++++++++++++++ 4 files changed, 56 insertions(+) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index d62f51d33be148..342f22a7c64f93 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -29,6 +29,7 @@ config SND_SOC_SOF_INTEL_PCI select SND_SOC_SOF_COMETLAKE_H if SND_SOC_SOF_COMETLAKE_H_SUPPORT select SND_SOC_SOF_TIGERLAKE if SND_SOC_SOF_TIGERLAKE_SUPPORT select SND_SOC_SOF_ELKHARTLAKE if SND_SOC_SOF_ELKHARTLAKE_SUPPORT + select SND_SOC_SOF_JASPERLAKE if SND_SOC_SOF_JASPERLAKE_SUPPORT help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -244,6 +245,21 @@ config SND_SOC_SOF_ELKHARTLAKE This option is not user-selectable but automagically handled by 'select' statements at a higher level +config SND_SOC_SOF_JASPERLAKE_SUPPORT + bool "SOF support for JasperLake" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the JasperLake processors. + Say Y if you have such a device. + If unsure select "N". + +config SND_SOC_SOF_JASPERLAKE + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + config SND_SOC_SOF_HDA_COMMON tristate select SND_SOC_SOF_INTEL_COMMON diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index f5ed474474baa4..0563706f1e0349 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -328,3 +328,20 @@ const struct sof_intel_dsp_desc ehl_chip_info = { .ssp_base_offset = CNL_SSP_BASE_OFFSET, }; EXPORT_SYMBOL(ehl_chip_info); + +const struct sof_intel_dsp_desc jsl_chip_info = { + /* Jasperlake */ + .cores_num = 2, + .init_core_mask = 1, + .cores_mask = HDA_DSP_CORE_MASK(0) | + HDA_DSP_CORE_MASK(1), + .ipc_req = CNL_DSP_REG_HIPCIDR, + .ipc_req_mask = CNL_DSP_REG_HIPCIDR_BUSY, + .ipc_ack = CNL_DSP_REG_HIPCIDA, + .ipc_ack_mask = CNL_DSP_REG_HIPCIDA_DONE, + .ipc_ctl = CNL_DSP_REG_HIPCCTL, + .rom_init_timeout = 300, + .ssp_count = ICL_SSP_COUNT, + .ssp_base_offset = CNL_SSP_BASE_OFFSET, +}; +EXPORT_SYMBOL(jsl_chip_info); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index ad5e2df8800ac5..0e7c366b8f71e7 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -614,5 +614,6 @@ extern const struct sof_intel_dsp_desc skl_chip_info; extern const struct sof_intel_dsp_desc icl_chip_info; extern const struct sof_intel_dsp_desc tgl_chip_info; extern const struct sof_intel_dsp_desc ehl_chip_info; +extern const struct sof_intel_dsp_desc jsl_chip_info; #endif diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 030f2cb0692144..4adbb27c76c5d1 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -245,6 +245,24 @@ static const struct sof_dev_desc ehl_desc = { }; #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE) +static const struct sof_dev_desc jsl_desc = { + .machines = snd_soc_acpi_intel_jsl_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &jsl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .nocodec_fw_filename = "sof-jsl.ri", + .nocodec_tplg_filename = "sof-jsl-nocodec.tplg", + .ops = &sof_cnl_ops, + .arch_ops = &sof_xtensa_arch_ops +}; +#endif + static const struct dev_pm_ops sof_pci_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, @@ -423,6 +441,10 @@ static const struct pci_device_id sof_pci_ids[] = { { PCI_DEVICE(0x8086, 0x34C8), .driver_data = (unsigned long)&icl_desc}, #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE) + { PCI_DEVICE(0x8086, 0x38c8), + .driver_data = (unsigned long)&jsl_desc}, +#endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_LP) { PCI_DEVICE(0x8086, 0x02c8), .driver_data = (unsigned long)&cml_desc}, From 65ebfda9bccc4f482f8bdcf5289b029c81cff3ed Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Wed, 25 Sep 2019 13:06:55 +0800 Subject: [PATCH 1682/1995] ALSA: hda: Add Tigerlake/Jasperlake PCI ID Add HD Audio Device PCI ID for the Intel Tigerlake and Jasperlake platform. Signed-off-by: Pan Xiuli --- sound/pci/hda/hda_intel.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 240f4ca76391fb..a815bc8117994d 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2399,6 +2399,12 @@ static const struct pci_device_id azx_ids[] = { /* Icelake */ { PCI_DEVICE(0x8086, 0x34c8), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + /* Jasperlake */ + { PCI_DEVICE(0x8086, 0x38c8), + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, + /* Tigerlake */ + { PCI_DEVICE(0x8086, 0xa0c8), + .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, /* Elkhart Lake */ { PCI_DEVICE(0x8086, 0x4b55), .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE}, From fcb9d2363e6309627ea1addcd25519a8b1fdc1f1 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 3 Oct 2019 12:41:41 -0700 Subject: [PATCH 1683/1995] ASoC: pcm: update FE/BE trigger order based on the command Currently, the trigger orders SND_SOC_DPCM_TRIGGER_PRE/POST determine the order in which FE DAI and BE DAI are triggered. In the case of SND_SOC_DPCM_TRIGGER_PRE, the FE DAI is triggered before the BE DAI and in the case of SND_SOC_DPCM_TRIGGER_POST, the BE DAI is triggered before the FE DAI. And this order remains the same irrespective of the trigger command. In the case of the SOF driver, during playback, the FW expects the BE DAI to be triggered before the FE DAI during the START trigger. The BE DAI trigger handles the starting of Link DMA and so it must be started before the FE DAI is started to prevent xruns during pause/release. This can be addressed by setting the trigger order for the FE dai link to SND_SOC_DPCM_TRIGGER_POST. But during the STOP trigger, the FW expects the FE DAI to be triggered before the BE DAI. Retaining the same order during the START and STOP commands, results in FW error as the DAI component in the FW is still active. The issue can be fixed by mirroring the trigger order of FE and BE DAI's during the START and STOP trigger. So, with the trigger order set to SND_SOC_DPCM_TRIGGER_PRE, the FE DAI will be trigger first during SNDRV_PCM_TRIGGER_START/STOP/RESUME and the BE DAI will be triggered first during the STOP/SUSPEND/PAUSE commands. Conversely, with the trigger order set to SND_SOC_DPCM_TRIGGER_POST, the BE DAI will be triggered first during the SNDRV_PCM_TRIGGER_START/STOP/RESUME commands and the FE DAI will be triggered first during the SNDRV_PCM_TRIGGER_STOP/SUSPEND/PAUSE commands. Github Issue: https://github.com/thesofproject/linux/issues/1160 Signed-off-by: Ranjani Sridharan --- sound/soc/soc-pcm.c | 95 ++++++++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 27 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 6706b917e851f5..9d176a99a2023b 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2347,42 +2347,81 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, } EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger); +static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream, + int cmd, bool fe_first) +{ + struct snd_soc_pcm_runtime *fe = substream->private_data; + int ret; + + /* call trigger on the frontend before the backend. */ + if (fe_first) { + dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n", + fe->dai_link->name, cmd); + + ret = soc_pcm_trigger(substream, cmd); + if (ret < 0) + return ret; + + ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); + return ret; + } + + /* call trigger on the frontend after the backend. */ + ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); + if (ret < 0) + return ret; + + dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n", + fe->dai_link->name, cmd); + + ret = soc_pcm_trigger(substream, cmd); + + return ret; +} + static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *fe = substream->private_data; - int stream = substream->stream, ret; + int stream = substream->stream; + int ret = 0; enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; switch (trigger) { case SND_SOC_DPCM_TRIGGER_PRE: - /* call trigger on the frontend before the backend. */ - - dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n", - fe->dai_link->name, cmd); - - ret = soc_pcm_trigger(substream, cmd); - if (ret < 0) { - dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); - goto out; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = dpcm_dai_trigger_fe_be(substream, cmd, true); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = dpcm_dai_trigger_fe_be(substream, cmd, false); + break; + default: + ret = -EINVAL; + break; } - - ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); break; case SND_SOC_DPCM_TRIGGER_POST: - /* call trigger on the frontend after the backend. */ - - ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); - if (ret < 0) { - dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); - goto out; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = dpcm_dai_trigger_fe_be(substream, cmd, false); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = dpcm_dai_trigger_fe_be(substream, cmd, true); + break; + default: + ret = -EINVAL; + break; } - - dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n", - fe->dai_link->name, cmd); - - ret = soc_pcm_trigger(substream, cmd); break; case SND_SOC_DPCM_TRIGGER_BESPOKE: /* bespoke trigger() - handles both FE and BEs */ @@ -2391,10 +2430,6 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) fe->dai_link->name, cmd); ret = soc_pcm_bespoke_trigger(substream, cmd); - if (ret < 0) { - dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); - goto out; - } break; default: dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd, @@ -2403,6 +2438,12 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) goto out; } + if (ret < 0) { + dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n", + cmd, ret); + goto out; + } + switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: From fd274c2b7267bc5cff1777a462837572908b545c Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 3 Oct 2019 12:53:08 -0700 Subject: [PATCH 1684/1995] ASoC: SOF: topology: set trigger order for FE DAI link Set trigger order for FE DAI links to SND_SOC_DPCM_TRIGGER_POST to trigger the BE DAI's before the FE DAI's. This prevents the xruns seen on playback pipelines using the link DMA. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/topology.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index cc138ac6a8eb94..c3827266c690b9 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -2936,6 +2936,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, if (!link->no_pcm) { link->nonatomic = true; + /* set trigger order */ + link->trigger[0] = SND_SOC_DPCM_TRIGGER_POST; + link->trigger[1] = SND_SOC_DPCM_TRIGGER_POST; + /* nothing more to do for FE dai links */ return 0; } From 533fbd90056f0d6f78e7127f9f99f252930b4a4a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 17 Oct 2019 13:35:19 -0500 Subject: [PATCH 1685/1995] ASoC: SOF: define INFO_ flags in dsp_ops Currently the INFO_ flags such as PAUSE/NO_PERIOD_WAKEUP are defined in the SOF PCM core, which doesn't scale. To account for platform variations, these flags need to be set in DSP ops. This patch only moves the definitions and does not change any functionality. Reviewed-by: Jaska Uimonen Reviewed-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/imx/imx8.c | 7 +++++++ sound/soc/sof/intel/apl.c | 7 +++++++ sound/soc/sof/intel/bdw.c | 9 ++++++++- sound/soc/sof/intel/byt.c | 21 +++++++++++++++++++++ sound/soc/sof/intel/cnl.c | 7 +++++++ sound/soc/sof/pcm.c | 8 +++----- sound/soc/sof/sof-priv.h | 3 +++ 7 files changed, 56 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index 2a22b18e5ec076..cfefcfd927986d 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -388,6 +388,13 @@ struct snd_sof_dsp_ops sof_imx8_ops = { /* DAI drivers */ .drv = imx8_dai, .num_drv = 1, /* we have only 1 ESAI interface on i.MX8 */ + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP }; EXPORT_SYMBOL(sof_imx8_ops); diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 308bec97b53753..7daa8eb456c8d1 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -98,6 +98,13 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .runtime_idle = hda_dsp_runtime_idle, .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, .set_power_state = hda_dsp_set_power_state, + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; EXPORT_SYMBOL(sof_apl_ops); diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index bf961a8798a704..7b4cd1f456bf11 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -591,7 +591,14 @@ const struct snd_sof_dsp_ops sof_bdw_ops = { /* DAI drivers */ .drv = bdw_dai, - .num_drv = ARRAY_SIZE(bdw_dai) + .num_drv = ARRAY_SIZE(bdw_dai), + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; EXPORT_SYMBOL(sof_bdw_ops); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 07e5efe4945c99..62edb959f1fcb7 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -532,6 +532,13 @@ const struct snd_sof_dsp_ops sof_tng_ops = { /* DAI drivers */ .drv = byt_dai, .num_drv = 3, /* we have only 3 SSPs on byt*/ + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; EXPORT_SYMBOL(sof_tng_ops); @@ -693,6 +700,13 @@ const struct snd_sof_dsp_ops sof_byt_ops = { /* DAI drivers */ .drv = byt_dai, .num_drv = 3, /* we have only 3 SSPs on byt*/ + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; EXPORT_SYMBOL(sof_byt_ops); @@ -753,6 +767,13 @@ const struct snd_sof_dsp_ops sof_cht_ops = { .drv = byt_dai, /* all 6 SSPs may be available for cherrytrail */ .num_drv = ARRAY_SIZE(byt_dai), + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; EXPORT_SYMBOL(sof_cht_ops); diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 0563706f1e0349..982b81a0b13a1f 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -256,6 +256,13 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .runtime_idle = hda_dsp_runtime_idle, .set_hw_params_upon_resume = hda_dsp_set_hw_params_upon_resume, .set_power_state = hda_dsp_set_power_state, + + /* ALSA HW info flags */ + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, }; EXPORT_SYMBOL(sof_cnl_ops); diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index d72798d2b3026f..9ba505cf596657 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -440,6 +440,7 @@ static int sof_pcm_open(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + const struct snd_sof_dsp_ops *ops = sof_ops(sdev); struct snd_sof_pcm *spcm; struct snd_soc_tplg_stream_caps *caps; int ret; @@ -469,11 +470,8 @@ static int sof_pcm_open(struct snd_soc_component *component, le32_to_cpu(caps->period_size_min)); /* set runtime config */ - runtime->hw.info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP; + runtime->hw.info = ops->hw_info; /* platform-specific */ + runtime->hw.formats = le64_to_cpu(caps->formats); runtime->hw.period_bytes_min = le32_to_cpu(caps->period_size_min); runtime->hw.period_bytes_max = le32_to_cpu(caps->period_size_max); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 2121d9d0ffdab4..7a21a45d36354f 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -219,6 +219,9 @@ struct snd_sof_dsp_ops { /* DAI ops */ struct snd_soc_dai_driver *drv; int num_drv; + + /* ALSA HW info flags, will be stored in snd_pcm_runtime.hw.info */ + u32 hw_info; }; /* DSP architecture specific callbacks for oops and stack dumps */ From c105b6ffb7f4f9d41ddc2acd17cba2bafaf58748 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 17 Oct 2019 13:39:52 -0500 Subject: [PATCH 1686/1995] ASoC: SOF: Intel: only support INFO_BATCH for legacy platforms The current position update is not precise enough for PulseAudio to work reliably with the timer-based scheduling on Baytrail, Cherrytrail, Broadwell. Disable the NO_PERIOD_WAKEUP capability and use BATCH to signal that the position is only reliable and updated during period_elapsed events. This will be reverted when the firmware provides a more accurate position for those platforms. Reviewed-by: Jaska Uimonen Reviewed-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/bdw.c | 2 +- sound/soc/sof/intel/byt.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 7b4cd1f456bf11..141dad55476447 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -598,7 +598,7 @@ const struct snd_sof_dsp_ops sof_bdw_ops = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + SNDRV_PCM_INFO_BATCH, }; EXPORT_SYMBOL(sof_bdw_ops); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 62edb959f1fcb7..2abf80b3eb52fe 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -538,7 +538,7 @@ const struct snd_sof_dsp_ops sof_tng_ops = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + SNDRV_PCM_INFO_BATCH, }; EXPORT_SYMBOL(sof_tng_ops); @@ -706,7 +706,7 @@ const struct snd_sof_dsp_ops sof_byt_ops = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + SNDRV_PCM_INFO_BATCH, }; EXPORT_SYMBOL(sof_byt_ops); @@ -773,7 +773,7 @@ const struct snd_sof_dsp_ops sof_cht_ops = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + SNDRV_PCM_INFO_BATCH, }; EXPORT_SYMBOL(sof_cht_ops); From dfdd340b19b5fca754a27a24aae18bdeec250abc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sun, 13 Oct 2019 12:17:43 -0500 Subject: [PATCH 1687/1995] ASoC: SOF: Intel: hda-loader: improve error handling If a ROM timeout is detected, we still stop the DMA but will return the initial error should the DMA stop also fail. Likewise the cleanup is handled regardless of the status, but we return the initial error. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-loader.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 65c2af3fcaab71..7956dbf5be8882 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -253,10 +253,16 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_BASEFW_TIMEOUT_US); + /* + * even in case of errors we still need to stop the DMAs, + * but we return the initial error should the DMA stop also fail + */ + ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_STOP); if (ret < 0) { dev_err(sdev->dev, "error: DMA trigger stop failed\n"); - return ret; + if (!status) + status = ret; } return status; @@ -341,13 +347,15 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) /* * Perform codeloader stream cleanup. * This should be done even if firmware loading fails. + * If the cleanup also fails, we return the initial error */ ret1 = cl_cleanup(sdev, &sdev->dmab, stream); if (ret1 < 0) { dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); /* set return value to indicate cleanup failure */ - ret = ret1; + if (!ret) + ret = ret1; } /* From fee9b43e98bb080d1c505468f6a9fcdbf505dcee Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 9 Oct 2019 18:32:15 -0500 Subject: [PATCH 1688/1995] ASoC: SOF: Intel: hda: add dev_err() traces for snd_sof_dsp_read_poll_timeout() Such traces should be extremely rare but extremely useful for debug. Report errors for all calls to sdn_sof_dsp_read_poll_timeout(), but only on negative values for consistency. Add traces that enable each timeout to be uniquely identified. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-dsp.c | 30 +++++++++++++++++++++++++++--- sound/soc/sof/intel/hda-loader.c | 13 ++++++++++++- sound/soc/sof/intel/hda-stream.c | 24 ++++++++++++++++++++---- 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index f456ba962c8f1c..fa2f1f66c72cd4 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -42,6 +42,12 @@ int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask) ((adspcs & reset) == reset), HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: timeout on HDA_DSP_REG_ADSPCS read\n", + __func__); + return ret; + } /* has core entered reset ? */ adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -77,6 +83,13 @@ int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask) HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: timeout on HDA_DSP_REG_ADSPCS read\n", + __func__); + return ret; + } + /* has core left reset ? */ adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS); @@ -151,8 +164,12 @@ int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) (adspcs & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); - if (ret < 0) - dev_err(sdev->dev, "error: timeout on core powerup\n"); + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: timeout on HDA_DSP_REG_ADSPCS read\n", + __func__); + return ret; + } /* did core power up ? */ adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR, @@ -171,17 +188,24 @@ int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask) int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask) { u32 adspcs; + int ret; /* update bits */ snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, HDA_DSP_ADSPCS_SPA_MASK(core_mask), 0); - return snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS, adspcs, !(adspcs & HDA_DSP_ADSPCS_SPA_MASK(core_mask)), HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_PD_TIMEOUT * USEC_PER_MSEC); + if (ret < 0) + dev_err(sdev->dev, + "error: %s: timeout on HDA_DSP_REG_ADSPCS read\n", + __func__); + + return ret; } bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 7956dbf5be8882..b1783360fe106b 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -126,7 +126,8 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, HDA_DSP_INIT_TIMEOUT_US); if (ret < 0) { - dev_err(sdev->dev, "error: waiting for HIPCIE done\n"); + dev_err(sdev->dev, "error: %s: timeout for HIPCIE done\n", + __func__); goto err; } @@ -152,6 +153,10 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, if (!ret) return 0; + dev_err(sdev->dev, + "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n", + __func__); + err: hda_dsp_dump(sdev, SOF_DBG_REGS | SOF_DBG_PCI | SOF_DBG_MBOX); hda_dsp_core_reset_power_down(sdev, chip->cores_mask); @@ -258,6 +263,12 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream) * but we return the initial error should the DMA stop also fail */ + if (status < 0) { + dev_err(sdev->dev, + "error: %s: timeout HDA_DSP_SRAM_REG_ROM_STATUS read\n", + __func__); + } + ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_STOP); if (ret < 0) { dev_err(sdev->dev, "error: DMA trigger stop failed\n"); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 2c744718840254..450f9c55785fa4 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -275,8 +275,12 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_STREAM_RUN_TIMEOUT); - if (ret) + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: cmd %d: timeout on STREAM_SD_OFFSET read\n", + __func__, cmd); return ret; + } hstream->running = true; break; @@ -294,8 +298,12 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_STREAM_RUN_TIMEOUT); - if (ret) + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: cmd %d: timeout on STREAM_SD_OFFSET read\n", + __func__, cmd); return ret; + } snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, @@ -356,8 +364,12 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_STREAM_RUN_TIMEOUT); - if (ret) + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: timeout on STREAM_SD_OFFSET read1\n", + __func__); return ret; + } snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, @@ -418,8 +430,12 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_STREAM_RUN_TIMEOUT); - if (ret) + if (ret < 0) { + dev_err(sdev->dev, + "error: %s: timeout on STREAM_SD_OFFSET read2\n", + __func__); return ret; + } snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, From c9b2e8f911c111e15ceb7351986f352c2344f8b2 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 23 Oct 2019 08:38:31 +0800 Subject: [PATCH 1689/1995] ASoC: SOF: Intel: hda-stream: fix the CONFIG_ prefix missing We are missing the 'CONFIG_' prefix when using the kernel configure item SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1, here correct them. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-stream.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 450f9c55785fa4..29ab4328167016 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -190,7 +190,7 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction) * Workaround to address a known issue with host DMA that results * in xruns during pause/release in capture scenarios. */ - if (!IS_ENABLED(SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1)) + if (!IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1)) if (stream && direction == SNDRV_PCM_STREAM_CAPTURE) snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_EM2, @@ -228,7 +228,7 @@ int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag) spin_unlock_irq(&bus->reg_lock); /* Enable DMI L1 entry if there are no capture streams open */ - if (!IS_ENABLED(SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1)) + if (!IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1)) if (!active_capture_stream) snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_EM2, From 398ffcdb439c68fe9f922d24b86b8d139d516aca Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Sat, 19 Oct 2019 06:46:04 +0800 Subject: [PATCH 1690/1995] ASoC: SOF: Intel: hda-dsp: align the comments for D0I3C update Align the logs for CIP timeout at D0I3C.I3 updating. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-dsp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index fa2f1f66c72cd4..74805a06618344 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -330,7 +330,7 @@ int hda_dsp_set_power_state(struct snd_sof_dev *sdev, /* Write to D0I3C after Command-In-Progress bit is cleared */ ret = hda_dsp_wait_d0i3c_done(sdev, retry); if (ret < 0) { - dev_err(bus->dev, "CIP timeout before update D0I3C!\n"); + dev_err(bus->dev, "CIP timeout before D0I3C update!\n"); return ret; } @@ -342,7 +342,7 @@ int hda_dsp_set_power_state(struct snd_sof_dev *sdev, retry = 50; ret = hda_dsp_wait_d0i3c_done(sdev, retry); if (ret < 0) { - dev_err(bus->dev, "CIP timeout after D0I3C updated!\n"); + dev_err(bus->dev, "CIP timeout after D0I3C update!\n"); return ret; } From fcd9ba4dae14f3404ac87122e001496525749461 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Sat, 19 Oct 2019 06:54:59 +0800 Subject: [PATCH 1691/1995] ASoC: SOF: Intel: HDA: use macro for register polling retry count Define macro and use it for the register polling retry count. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-dsp.c | 6 ++---- sound/soc/sof/intel/hda.h | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 74805a06618344..936361bd25e935 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -323,12 +323,11 @@ int hda_dsp_set_power_state(struct snd_sof_dev *sdev, enum sof_d0_substate d0_substate) { struct hdac_bus *bus = sof_to_bus(sdev); - int retry = 50; int ret; u8 value; /* Write to D0I3C after Command-In-Progress bit is cleared */ - ret = hda_dsp_wait_d0i3c_done(sdev, retry); + ret = hda_dsp_wait_d0i3c_done(sdev, HDA_DSP_REG_POLL_RETRY_COUNT); if (ret < 0) { dev_err(bus->dev, "CIP timeout before D0I3C update!\n"); return ret; @@ -339,8 +338,7 @@ int hda_dsp_set_power_state(struct snd_sof_dev *sdev, snd_hdac_chip_updateb(bus, VS_D0I3C, SOF_HDA_VS_D0I3C_I3, value); /* Wait for cmd in progress to be cleared before exiting the function */ - retry = 50; - ret = hda_dsp_wait_d0i3c_done(sdev, retry); + ret = hda_dsp_wait_d0i3c_done(sdev, HDA_DSP_REG_POLL_RETRY_COUNT); if (ret < 0) { dev_err(bus->dev, "CIP timeout after D0I3C update!\n"); return ret; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 0e7c366b8f71e7..99ec60218c1668 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -214,6 +214,7 @@ #define HDA_DSP_CTRL_RESET_TIMEOUT 100 #define HDA_DSP_WAIT_TIMEOUT 500 /* 500 msec */ #define HDA_DSP_REG_POLL_INTERVAL_US 500 /* 0.5 msec */ +#define HDA_DSP_REG_POLL_RETRY_COUNT 50 #define HDA_DSP_ADSPIC_IPC 1 #define HDA_DSP_ADSPIS_IPC 1 From fbdf90b2618383352e42f15a183f8efb022a0a8f Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Sat, 21 Sep 2019 07:04:47 +0800 Subject: [PATCH 1692/1995] ASoC: SOF: PM: rename sof_send_pm_ipc to sof_send_pm_ctx_ipc The helper sof_send_pm_ipc() is only suitable for context save/restore IPCs' sending, so rename it to sof_send_pm_ctx_ipc here. Signed-off-by: Keyon Jie --- sound/soc/sof/pm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 81e623dfc7e52b..ac900fb3379ea9 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -197,7 +197,7 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev) return ret; } -static int sof_send_pm_ipc(struct snd_sof_dev *sdev, int cmd) +static int sof_send_pm_ctx_ipc(struct snd_sof_dev *sdev, int cmd) { struct sof_ipc_pm_ctx pm_ctx; struct sof_ipc_reply reply; @@ -320,7 +320,7 @@ static int sof_resume(struct device *dev, bool runtime_resume) } /* notify DSP of system resume */ - ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_RESTORE); + ret = sof_send_pm_ctx_ipc(sdev, SOF_IPC_PM_CTX_RESTORE); if (ret < 0) dev_err(sdev->dev, "error: ctx_restore ipc error during resume %d\n", @@ -361,7 +361,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) sof_cache_debugfs(sdev); #endif /* notify DSP of upcoming power down */ - ret = sof_send_pm_ipc(sdev, SOF_IPC_PM_CTX_SAVE); + ret = sof_send_pm_ctx_ipc(sdev, SOF_IPC_PM_CTX_SAVE); if (ret == -EBUSY || ret == -EAGAIN) { /* * runtime PM has logic to handle -EBUSY/-EAGAIN so From 2bdda862582ae0b357fe76c92b0b9d7758d5b6f3 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 30 Aug 2019 15:04:22 +0800 Subject: [PATCH 1693/1995] ASoC: SOF: ipc: introduce message for DSP power gating Add new ipc messages which will be sent from driver to FW, to ask FW to enter specific power saving state. Signed-off-by: Keyon Jie --- include/sound/sof/header.h | 1 + include/sound/sof/pm.h | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h index 332143ff727855..bf3edd9c08b46d 100644 --- a/include/sound/sof/header.h +++ b/include/sound/sof/header.h @@ -75,6 +75,7 @@ #define SOF_IPC_PM_CLK_GET SOF_CMD_TYPE(0x005) #define SOF_IPC_PM_CLK_REQ SOF_CMD_TYPE(0x006) #define SOF_IPC_PM_CORE_ENABLE SOF_CMD_TYPE(0x007) +#define SOF_IPC_PM_GATE SOF_CMD_TYPE(0x008) /* component runtime config - multiple different types */ #define SOF_IPC_COMP_SET_VALUE SOF_CMD_TYPE(0x001) diff --git a/include/sound/sof/pm.h b/include/sound/sof/pm.h index 003879401d6336..3cf2e0f39d94a7 100644 --- a/include/sound/sof/pm.h +++ b/include/sound/sof/pm.h @@ -45,4 +45,12 @@ struct sof_ipc_pm_core_config { uint32_t enable_mask; } __packed; +struct sof_ipc_pm_gate { + struct sof_ipc_cmd_hdr hdr; + uint32_t flags; /* platform specific */ + + /* reserved for future use */ + uint32_t reserved[5]; +} __packed; + #endif From e1491045f1542a21c083ef87a87021e9a91fcc89 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Tue, 15 Oct 2019 14:36:11 +0800 Subject: [PATCH 1694/1995] ASoC: SOF: Intel: hda-ipc: Don't read mailbox for PM_GATE reply Memory windows could be powered off before receiving PM_GATE IPC reply from FW, we can't read the mailbox to get reply. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-ipc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 6aae6f18b3dcaa..0fd2153c176953 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -83,10 +83,12 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev) } hdr = msg->msg_data; - if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE)) { + if (hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE) || + hdr->cmd == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE)) { /* * memory windows are powered off before sending IPC reply, - * so we can't read the mailbox for CTX_SAVE reply. + * so we can't read the mailbox for CTX_SAVE and PM_GATE + * replies. */ reply.error = 0; reply.hdr.cmd = SOF_IPC_GLB_REPLY; From a8cebf3a5419386dec058088bdcd59494dc1efb2 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Tue, 1 Oct 2019 05:18:26 +0800 Subject: [PATCH 1695/1995] ASoC: SOF: Intel: HDA: add cAVS specific compact IPC header file On cAVS platforms, some IPCs are required to be sent via IPC registers only(e.g. when in D0i3, mailbox is unaccessible), add hda-ipc.h to hold definition of those compact IPCs. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-ipc.h | 51 +++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 sound/soc/sof/intel/hda-ipc.h diff --git a/sound/soc/sof/intel/hda-ipc.h b/sound/soc/sof/intel/hda-ipc.h new file mode 100644 index 00000000000000..aef0ceac9803d1 --- /dev/null +++ b/sound/soc/sof/intel/hda-ipc.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2019 Intel Corporation. All rights reserved. + * + * Author: Keyon Jie + */ + +#ifndef __SOF_INTEL_HDA_IPC_H +#define __SOF_INTEL_HDA_IPC_H + +/* + * Primary register, mapped to + * - DIPCTDR (HIPCIDR) in sideband IPC (cAVS 1.8+) + * - DIPCT in cAVS 1.5 IPC + * + * Secondary register, mapped to: + * - DIPCTDD (HIPCIDD) in sideband IPC (cAVS 1.8+) + * - DIPCTE in cAVS 1.5 IPC + */ + +/* Common bits in primary register */ + +/* Reserved for doorbell */ +#define HDA_IPC_RSVD_31 BIT(31) +/* Target, 0 - normal message, 1 - compact message(cAVS compatible) */ +#define HDA_IPC_MSG_COMPACT BIT(30) +/* Direction, 0 - request, 1 - response */ +#define HDA_IPC_RSP BIT(29) + +#define HDA_IPC_TYPE_SHIFT 24 +#define HDA_IPC_TYPE_MASK GENMASK(28, 24) +#define HDA_IPC_TYPE(x) ((x) << HDA_IPC_TYPE_SHIFT) + +#define HDA_IPC_PM_GATE HDA_IPC_TYPE(0x8U) + +/* Command specific payload bits in secondary register */ + +/* Disable DMA tracing (0 - keep tracing, 1 - to disable DMA trace) */ +#define HDA_PM_NO_DMA_TRACE BIT(4) +/* Prevent clock gating (0 - cg allowed, 1 - DSP clock always on) */ +#define HDA_PM_PCG BIT(3) +/* Prevent power gating (0 - deep power state transitions allowed) */ +#define HDA_PM_PPG BIT(2) +/* Indicates whether streaming is active */ +#define HDA_PM_PG_STREAMING BIT(1) +#define HDA_PM_PG_RSVD BIT(0) + +#endif From da1859546b95fa1a0ae24d61fb22de77912b2ecd Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Thu, 26 Sep 2019 06:31:21 +0800 Subject: [PATCH 1696/1995] ASoC: SOF: configure D0ix IPC flags in set_power_state The configuration for D0ix in FW is platform specific, let's do this and send IPC in the platform set_power_state() ops. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-dsp.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 936361bd25e935..b5070409a5e37e 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -19,6 +19,7 @@ #include #include "../ops.h" #include "hda.h" +#include "hda-ipc.h" /* * DSP Core control. @@ -319,10 +320,28 @@ static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev, int retry) return 0; } +static int hda_dsp_send_pm_gate_ipc(struct snd_sof_dev *sdev, u32 flags) +{ + struct sof_ipc_pm_gate pm_gate; + struct sof_ipc_reply reply; + + memset(&pm_gate, 0, sizeof(pm_gate)); + + /* configure pm_gate ipc message */ + pm_gate.hdr.size = sizeof(pm_gate); + pm_gate.hdr.cmd = SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE; + pm_gate.flags = flags; + + /* send pm_gate ipc to dsp */ + return sof_ipc_tx_message(sdev->ipc, pm_gate.hdr.cmd, &pm_gate, + sizeof(pm_gate), &reply, sizeof(reply)); +} + int hda_dsp_set_power_state(struct snd_sof_dev *sdev, enum sof_d0_substate d0_substate) { struct hdac_bus *bus = sof_to_bus(sdev); + u32 flags; int ret; u8 value; @@ -347,7 +366,18 @@ int hda_dsp_set_power_state(struct snd_sof_dev *sdev, dev_vdbg(bus->dev, "D0I3C updated, register = 0x%x\n", snd_hdac_chip_readb(bus, VS_D0I3C)); - return 0; + if (d0_substate == SOF_DSP_D0I0) + flags = HDA_PM_PPG;/* prevent power gating in D0 */ + else + flags = HDA_PM_NO_DMA_TRACE;/* disable DMA trace in D0I3*/ + + /* sending pm_gate IPC */ + ret = hda_dsp_send_pm_gate_ipc(sdev, flags); + if (ret < 0) + dev_err(sdev->dev, + "error: PM_GATE ipc error %d\n", ret); + + return ret; } static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) From acbec3579391292a8dec721825a7ac5ccf6f2f2f Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 23 Aug 2019 18:50:53 +0800 Subject: [PATCH 1697/1995] ASoC: SOF: PM: add helpers for setting D0 substate for ADSP Add snd_sof_set_d0_substate() helper for setting ADSP to a specific D0 substate, it will call into the platform specific implementation, and update the d0_substate at success. Signed-off-by: Keyon Jie --- sound/soc/sof/pm.c | 17 +++++++++++++++++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index ac900fb3379ea9..584241e9734a54 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -411,6 +411,23 @@ int snd_sof_runtime_resume(struct device *dev) } EXPORT_SYMBOL(snd_sof_runtime_resume); +int snd_sof_set_d0_substate(struct snd_sof_dev *sdev, + enum sof_d0_substate d0_substate) +{ + int ret; + + /* do platform specific set_state */ + ret = snd_sof_dsp_set_power_state(sdev, d0_substate); + if (ret < 0) + return ret; + + /* update dsp D0 sub-state */ + sdev->d0_substate = d0_substate; + + return 0; +} +EXPORT_SYMBOL(snd_sof_set_d0_substate); + int snd_sof_resume(struct device *dev) { return sof_resume(dev, false); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 7a21a45d36354f..2231c673c67880 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -485,6 +485,8 @@ int snd_sof_runtime_resume(struct device *dev); int snd_sof_runtime_idle(struct device *dev); int snd_sof_resume(struct device *dev); int snd_sof_suspend(struct device *dev); +int snd_sof_set_d0_substate(struct snd_sof_dev *sdev, + enum sof_d0_substate d0_substate); void snd_sof_new_platform_drv(struct snd_sof_dev *sdev); From 05f6258ef722d54d0a0e725d86afa380bfafd0e3 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 20 Sep 2019 04:44:33 +0800 Subject: [PATCH 1698/1995] ASoC: SOF: Intel: CNL: add support for sending compact IPC For compact IPCs, we will send the IPC header/command via the HIPCIDR register and the first 32bit payload via the HIPCIDD register, no mailbox will be used. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/cnl.c | 42 ++++++++++++++++++++++++++++++++++----- sound/soc/sof/intel/hda.h | 1 + 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 982b81a0b13a1f..0e1e265f3f3b3b 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -17,6 +17,7 @@ #include "../ops.h" #include "hda.h" +#include "hda-ipc.h" static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = { {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, @@ -150,14 +151,45 @@ static void cnl_ipc_dsp_done(struct snd_sof_dev *sdev) CNL_DSP_REG_HIPCCTL_DONE); } +static bool cnl_compact_ipc_compress(struct snd_sof_ipc_msg *msg, + u32 *dr, u32 *dd) +{ + struct sof_ipc_pm_gate *pm_gate; + + if (msg->header == (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_GATE)) { + pm_gate = msg->msg_data; + + /* send the compact message via the primary register */ + *dr = HDA_IPC_MSG_COMPACT | HDA_IPC_PM_GATE; + + /* send payload via the extended data register */ + *dd = pm_gate->flags; + + return true; + } + + return false; +} + static int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { - /* send the message */ - sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, - msg->msg_size); - snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, - CNL_DSP_REG_HIPCIDR_BUSY); + u32 dr = 0; + u32 dd = 0; + + if (cnl_compact_ipc_compress(msg, &dr, &dd)) { + /* send the message via IPC registers */ + snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDD, + dd); + snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, + CNL_DSP_REG_HIPCIDR_BUSY | dr); + } else { + /* send the message via mailbox */ + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + snd_sof_dsp_write(sdev, HDA_DSP_BAR, CNL_DSP_REG_HIPCIDR, + CNL_DSP_REG_HIPCIDR_BUSY); + } return 0; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 99ec60218c1668..52a87a47029dc9 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -312,6 +312,7 @@ #define CNL_DSP_REG_HIPCTDD (CNL_DSP_IPC_BASE + 0x08) #define CNL_DSP_REG_HIPCIDR (CNL_DSP_IPC_BASE + 0x10) #define CNL_DSP_REG_HIPCIDA (CNL_DSP_IPC_BASE + 0x14) +#define CNL_DSP_REG_HIPCIDD (CNL_DSP_IPC_BASE + 0x18) #define CNL_DSP_REG_HIPCCTL (CNL_DSP_IPC_BASE + 0x28) /* HIPCI */ From f2fd9903fbac4facceb8a25231fcccfa05ca527c Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 2 Oct 2019 00:52:20 +0800 Subject: [PATCH 1699/1995] ASoC: SOF: add a flag to indicate the system suspend target Add flag 's0_suspend' to indicate if the system is entering S0ix or not. Signed-off-by: Keyon Jie --- sound/soc/sof/sof-priv.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 2231c673c67880..e715673f20e584 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -398,6 +398,8 @@ struct snd_sof_dev { /* power states related */ enum sof_d0_substate d0_substate; + /* flag to track if the intended power target of suspend is S0ix */ + bool s0_suspend; /* DSP firmware boot */ wait_queue_head_t boot_wait; From 0cfafd69c247b04a5270bbb8417b1a66cea3b4b6 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 9 Oct 2019 10:08:45 +0800 Subject: [PATCH 1700/1995] ASoC: SOF: add a flag suspend_ignored for sof stream Add a suspend_ignored flag to snd_sof_pcm_stream that will be used to decide if the corresponding FW pipeline should be kept active to perform always on tasks when the system is entering the S0ix state. Signed-off-by: Keyon Jie --- sound/soc/sof/sof-priv.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index e715673f20e584..c2541d020bde5f 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -311,6 +311,11 @@ struct snd_sof_pcm_stream { struct snd_pcm_substream *substream; struct work_struct period_elapsed_work; bool d0i3_compatible; /* DSP can be in D0I3 when this pcm is opened */ + /* + * flag to indicate that the DSP pipelines should be kept + * active or not while suspending the stream + */ + bool suspend_ignored; }; /* ALSA SOF PCM device */ From 2b0d1684e55d560ef885a2d0b664d634885c48ff Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 2 Oct 2019 00:59:04 +0800 Subject: [PATCH 1701/1995] ASoC: SOF: PM: implement prepare/complete callbacks Implement the prepare() and complete() callbacks for power management, initialize s0_suspend flag at prepare(), and reset it at complete(). Signed-off-by: Keyon Jie --- sound/soc/sof/pm.c | 23 +++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 584241e9734a54..99e4e6ffff74f3 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -439,3 +439,26 @@ int snd_sof_suspend(struct device *dev) return sof_suspend(dev, false); } EXPORT_SYMBOL(snd_sof_suspend); + +int snd_sof_prepare(struct device *dev) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + +#if defined(CONFIG_ACPI) + sdev->s0_suspend = acpi_target_system_state() == ACPI_STATE_S0; +#else + /* will suspend to S3 by default */ + sdev->s0_suspend = false; +#endif + + return 0; +} +EXPORT_SYMBOL(snd_sof_prepare); + +void snd_sof_complete(struct device *dev) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + + sdev->s0_suspend = false; +} +EXPORT_SYMBOL(snd_sof_complete); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index c2541d020bde5f..6408ac88a3e582 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -492,6 +492,8 @@ int snd_sof_runtime_resume(struct device *dev); int snd_sof_runtime_idle(struct device *dev); int snd_sof_resume(struct device *dev); int snd_sof_suspend(struct device *dev); +int snd_sof_prepare(struct device *dev); +void snd_sof_complete(struct device *dev); int snd_sof_set_d0_substate(struct snd_sof_dev *sdev, enum sof_d0_substate d0_substate); From 4e889849321f7b422469282dc88a2a1ae75eb223 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Tue, 24 Sep 2019 08:04:25 +0800 Subject: [PATCH 1702/1995] ASoC: SOF: ignore suspend/resume for D0ix compatible streams During system suspend, the PM framework will freeze all applications and the ALSA/ASoC core will suspend all RUNNING PCM streams. However, D0ix-compatible PCM streams should keep the related pipelines active in the DSP when the system is entering S0ix. The TRIGGER_SUSPEND event is trapped in such cases to prevent the pipelines from being stopped. Likewise, the TRIGGER_RESUME/START events should not affect the pipeline state. The SOF driver also triggers some DSP Firmware pipelines based on the DAPM widgets power events. In such cases, we also ignore PRE_PMU and POST_PMD events to keep the pipelines active. Signed-off-by: Keyon Jie --- sound/soc/sof/pcm.c | 31 +++++++++++++++++++++++++++++++ sound/soc/sof/topology.c | 17 ++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 9ba505cf596657..3d5cd1b445ba0a 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -346,6 +346,16 @@ static int sof_pcm_trigger(struct snd_soc_component *component, stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE; break; case SNDRV_PCM_TRIGGER_RESUME: + if (spcm->stream[substream->stream].suspend_ignored) { + /* + * this case will be triggered when INFO_RESUME is + * supported, no need to resume streams that remained + * enabled in D0ix. + */ + spcm->stream[substream->stream].suspend_ignored = false; + return 0; + } + /* set up hw_params */ ret = sof_pcm_prepare(component, substream); if (ret < 0) { @@ -356,9 +366,30 @@ static int sof_pcm_trigger(struct snd_soc_component *component, /* fallthrough */ case SNDRV_PCM_TRIGGER_START: + if (spcm->stream[substream->stream].suspend_ignored) { + /* + * This case will be triggered when INFO_RESUME is + * not supported, no need to re-start streams that + * remained enabled in D0ix. + */ + spcm->stream[substream->stream].suspend_ignored = false; + return 0; + } stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_START; break; case SNDRV_PCM_TRIGGER_SUSPEND: + if (sdev->s0_suspend && + spcm->stream[substream->stream].d0i3_compatible) { + /* + * trap the event, not sending trigger stop to + * prevent the FW pipelines from being stopped, + * and mark the flag to ignore the upcoming DAPM + * PM events. + */ + spcm->stream[substream->stream].suspend_ignored = true; + return 0; + } + /* fallthrough */ case SNDRV_PCM_TRIGGER_STOP: stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; ipc_first = true; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index c3827266c690b9..e7076692119be9 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -135,7 +135,9 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { struct snd_sof_widget *swidget = w->dobj.private; + int stream = SNDRV_PCM_STREAM_CAPTURE; struct snd_sof_dev *sdev; + struct snd_sof_pcm *spcm; int ret = 0; if (!swidget) @@ -146,11 +148,19 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, dev_dbg(sdev->dev, "received event %d for widget %s\n", event, w->name); + /* get runtime PCM params using widget's stream name */ + spcm = snd_sof_find_spcm_name(sdev, swidget->widget->sname); + /* process events */ switch (event) { case SND_SOC_DAPM_PRE_PMU: + if (spcm->stream[stream].suspend_ignored) { + dev_dbg(sdev->dev, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n"); + return 0; + } + /* set pcm params */ - ret = ipc_pcm_params(swidget, SOF_IPC_STREAM_CAPTURE); + ret = ipc_pcm_params(swidget, stream); if (ret < 0) { dev_err(sdev->dev, "error: failed to set pcm params for widget %s\n", @@ -166,6 +176,11 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, swidget->widget->name); break; case SND_SOC_DAPM_POST_PMD: + if (spcm->stream[stream].suspend_ignored) { + dev_dbg(sdev->dev, "POST_PMD even ignored, KWD pipeline will remain RUNNING\n"); + return 0; + } + /* stop trigger */ ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP); if (ret < 0) From dfdafb3f8e54701792bbbdc5c259ec574fa7b682 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Sat, 19 Oct 2019 03:31:57 +0800 Subject: [PATCH 1703/1995] ASoC: SOF: Intel: hda-dsp: implement suspend/resume for S0ix<->S0 transition Enable system wake up via IPC interrupt from DSP when the system is suspending to the S0ix state, and disable it in the corresponding resuming. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-dsp.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index b5070409a5e37e..d23573d9e9c40c 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -477,6 +477,15 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) int hda_dsp_resume(struct snd_sof_dev *sdev) { + struct pci_dev *pci = to_pci_dev(sdev->dev); + + if (sdev->s0_suspend) { + /* restore and disable the system wakeup */ + pci_restore_state(pci); + disable_irq_wake(pci->irq); + return 0; + } + /* init hda controller. DSP cores will be powered up during fw boot */ return hda_resume(sdev, false); } @@ -509,8 +518,16 @@ int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev) int hda_dsp_suspend(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); + struct pci_dev *pci = to_pci_dev(sdev->dev); int ret; + if (sdev->s0_suspend) { + /* enable the system waking up via IPC IRQ */ + enable_irq_wake(pci->irq); + pci_save_state(pci); + return 0; + } + /* stop hda controller and power dsp off */ ret = hda_suspend(sdev, false); if (ret < 0) { From e3e98fa88fda37eb7b9d730210ddf5391cab62c6 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Sat, 26 Oct 2019 01:50:59 +0800 Subject: [PATCH 1704/1995] ASoC: SOF: return -ENOTSUPP if D0I3 is not supported No set_power_state ops means that the platform doesn't support D0i3, return -ENOTSUPP for the case. Signed-off-by: Keyon Jie --- sound/soc/sof/ops.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index d7c8fc06f961d6..93512dcbaacdd0 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -199,7 +199,8 @@ static inline int snd_sof_dsp_set_power_state(struct snd_sof_dev *sdev, if (sof_ops(sdev)->set_power_state) return sof_ops(sdev)->set_power_state(sdev, substate); - return 0; + /* D0 substate is not supported */ + return -ENOTSUPP; } /* debug */ From 51155e854999058887a60846480b9b39355f74f1 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Sat, 21 Sep 2019 09:21:42 +0800 Subject: [PATCH 1705/1995] ASoC: SOF: PM: Add support for DSP D0i3 state when entering S0ix When system is entering into S0ix, the PCI device may transition to the D0i3 substate instead of D3. In D0i3, some always-on functionality can be enabled, such as acoustic event detection, voice activity detection or hotwording. When an event is detected, the DSP firmware can wake-up the device for a transition to D0 with an interrupt. Signed-off-by: Keyon Jie --- sound/soc/sof/pm.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 99e4e6ffff74f3..560a937e048420 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -430,12 +430,58 @@ EXPORT_SYMBOL(snd_sof_set_d0_substate); int snd_sof_resume(struct device *dev) { + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + int ret; + + if (sdev->s0_suspend) { + /* resume from D0I3 */ + dev_dbg(sdev->dev, "DSP will exit from D0i3...\n"); + ret = snd_sof_set_d0_substate(sdev, SOF_DSP_D0I0); + if (ret == -ENOTSUPP) { + /* fallback to resume from D3 */ + dev_dbg(sdev->dev, "D0i3 not supported, fall back to resume from D3...\n"); + goto d3_resume; + } else if (ret < 0) { + dev_err(sdev->dev, "error: failed to exit from D0I3 %d\n", + ret); + return ret; + } + + /* platform-specific resume from D0i3 */ + return snd_sof_dsp_resume(sdev); + } + +d3_resume: + /* resume from D3 */ return sof_resume(dev, false); } EXPORT_SYMBOL(snd_sof_resume); int snd_sof_suspend(struct device *dev) { + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + int ret; + + if (sdev->s0_suspend) { + /* suspend to D0i3 */ + dev_dbg(sdev->dev, "DSP is trying to enter D0i3...\n"); + ret = snd_sof_set_d0_substate(sdev, SOF_DSP_D0I3); + if (ret == -ENOTSUPP) { + /* fallback to D3 suspend */ + dev_dbg(sdev->dev, "D0i3 not supported, fall back to D3...\n"); + goto d3_suspend; + } else if (ret < 0) { + dev_err(sdev->dev, "error: failed to enter D0I3, %d\n", + ret); + return ret; + } + + /* platform-specific suspend to D0i3 */ + return snd_sof_dsp_suspend(sdev); + } + +d3_suspend: + /* suspend to D3 */ return sof_suspend(dev, false); } EXPORT_SYMBOL(snd_sof_suspend); From 5d67c4bf9ad710bdaaa94e40fb58c326f18ee18e Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Wed, 2 Oct 2019 01:16:13 +0800 Subject: [PATCH 1706/1995] ASoC: SOF: pci: Add prepare/complete PM callbacks Use the new implemented snd_sof_prepare() and snd_sof_complete() as the power management callbacks for pci probing platforms. Signed-off-by: Keyon Jie --- sound/soc/sof/sof-pci-dev.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 4adbb27c76c5d1..487b1f29f84d45 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -264,6 +264,8 @@ static const struct sof_dev_desc jsl_desc = { #endif static const struct dev_pm_ops sof_pci_pm = { + .prepare = snd_sof_prepare, + .complete = snd_sof_complete, SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, snd_sof_runtime_idle) From 195c1736f070af3744b7143662c335b1a9533f74 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Sat, 26 Oct 2019 12:53:22 +0800 Subject: [PATCH 1707/1995] ASoC: SOF: topology: fix a missing of NULL pointer check Add check to avoid possible NULL pointer dereference issue. Reported-by: Keqiao Zhang Signed-off-by: Keyon Jie --- sound/soc/sof/topology.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index e7076692119be9..17fe6a1d5f3e77 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -150,6 +150,11 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, /* get runtime PCM params using widget's stream name */ spcm = snd_sof_find_spcm_name(sdev, swidget->widget->sname); + if (!spcm) { + dev_err(sdev->dev, "error: cannot find PCM for %s\n", + swidget->widget->name); + return -EINVAL; + } /* process events */ switch (event) { From f5e70ced2179810ce0de1e0c70b6dd6cbe8f0fed Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Thu, 10 Oct 2019 12:18:31 +0300 Subject: [PATCH 1708/1995] ASoC: hdac_hda: fix race in device removal When ASoC card instance is removed containing a HDA codec, hdac_hda_codec_remove() may run in parallel with codec resume. This will cause problems if the HDA link is freed with snd_hdac_ext_bus_link_put() while the codec is still in middle of its resume process. To fix this, change the order such that pm_runtime_disable() is called before the link is freed. This will ensure any pending runtime PM action is completed before proceeding to free the link. This issue can be easily hit with e.g. SOF driver by loading and unloading the drivers. Signed-off-by: Kai Vehmanen --- sound/soc/codecs/hdac_hda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 91242b6f8ea7ad..4570f662fb48b4 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -410,8 +410,8 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component) return; } - snd_hdac_ext_bus_link_put(hdev->bus, hlink); pm_runtime_disable(&hdev->dev); + snd_hdac_ext_bus_link_put(hdev->bus, hlink); } static const struct snd_soc_dapm_route hdac_hda_dapm_routes[] = { From 6e1f1be6a2ca3bfc3b079fd7478b04be6c40bd6d Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 13:46:02 +0800 Subject: [PATCH 1709/1995] ASoC: SOF: Intel: hda: set L1SEN on S0ix suspend Set L1SEN to make sure the system can enter S0ix, and restore it on resume. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-dsp.c | 15 +++++++++++++++ sound/soc/sof/intel/hda.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index d23573d9e9c40c..3a54edd017fe6f 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -477,9 +477,16 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume) int hda_dsp_resume(struct snd_sof_dev *sdev) { + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct pci_dev *pci = to_pci_dev(sdev->dev); if (sdev->s0_suspend) { + /* restore L1SEN bit */ + if (hda->l1_support_changed) + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + HDA_VS_INTEL_EM2, + HDA_VS_INTEL_EM2_L1SEN, 0); + /* restore and disable the system wakeup */ pci_restore_state(pci); disable_irq_wake(pci->irq); @@ -517,11 +524,19 @@ int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev) int hda_dsp_suspend(struct snd_sof_dev *sdev) { + struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct hdac_bus *bus = sof_to_bus(sdev); struct pci_dev *pci = to_pci_dev(sdev->dev); int ret; if (sdev->s0_suspend) { + /* enable L1SEN to make sure the system can enter S0Ix */ + hda->l1_support_changed = + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + HDA_VS_INTEL_EM2, + HDA_VS_INTEL_EM2_L1SEN, + HDA_VS_INTEL_EM2_L1SEN); + /* enable the system waking up via IPC IRQ */ enable_irq_wake(pci->irq); pci_save_state(pci); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 5ad73a34b09c60..18d7e72bf9b722 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -408,6 +408,9 @@ struct sof_intel_hda_dev { int irq; + /* PM related */ + bool l1_support_changed;/* during suspend, is L1SEN changed or not */ + /* DMIC device */ struct platform_device *dmic_dev; }; From b1785faf1881cca51ed03073dfdb11e40e2d5dbb Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 16 Aug 2019 13:23:11 +0300 Subject: [PATCH 1710/1995] ASoC: Intel: bxt_pcm512x: use snd-hda-codec-hdmi Add support for using snd-hda-codec-hdmi driver for HDMI/DP instead of ASoC hdac-hdmi. This is aligned with how other HDA codecs are already handled. Signed-off-by: Kai Vehmanen --- sound/soc/intel/boards/Makefile | 2 +- sound/soc/intel/boards/bxt_pcm512x.c | 49 +++++++++++++++++++++++----- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index c8e02f7494cb37..fb4e1b34992368 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -6,7 +6,7 @@ snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o snd-soc-sst-broadwell-objs := broadwell.o snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o hda_dsp_common.o snd-soc-sst-bxt-rt298-objs := bxt_rt298.o hda_dsp_common.o -snd-soc-sst-bxt-pcm512x-objs := bxt_pcm512x.o +snd-soc-sst-bxt-pcm512x-objs := bxt_pcm512x.o hda_dsp_common.o snd-soc-sst-bxt-wm8804-objs := bxt_wm8804.o snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o hda_dsp_common.o snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o diff --git a/sound/soc/intel/boards/bxt_pcm512x.c b/sound/soc/intel/boards/bxt_pcm512x.c index 2e3e8bee751ce4..dd30698ec462a2 100644 --- a/sound/soc/intel/boards/bxt_pcm512x.c +++ b/sound/soc/intel/boards/bxt_pcm512x.c @@ -20,15 +20,20 @@ #include #include #include -#include "../../codecs/hdac_hdmi.h" #include "../../codecs/pcm512x.h" -#include "../atom/sst-atom-controls.h" struct bxt_card_private { struct list_head hdmi_pcm_list; + bool common_hdmi_codec_drv; }; -#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) +#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) || \ + IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) + +#include "../../codecs/hdac_hdmi.h" +#include "../atom/sst-atom-controls.h" +#include "hda_dsp_common.h" + static struct snd_soc_jack broxton_hdmi[3]; struct bxt_hdmi_pcm { @@ -57,12 +62,12 @@ static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) } #define NAME_SIZE 32 -static int bxt_card_late_probe(struct snd_soc_card *card) +static int hdmi_jack_create_controls(struct snd_soc_card *card) { struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card); struct bxt_hdmi_pcm *pcm; struct snd_soc_component *component = NULL; - int err, i = 0; + int err = 0, i = 0; char jack_name[NAME_SIZE]; list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { @@ -72,7 +77,6 @@ static int bxt_card_late_probe(struct snd_soc_card *card) err = snd_soc_card_jack_new(card, jack_name, SND_JACK_AVOUT, &broxton_hdmi[i], NULL, 0); - if (err) return err; @@ -84,9 +88,29 @@ static int bxt_card_late_probe(struct snd_soc_card *card) i++; } + return err; +} + +static int bxt_card_late_probe(struct snd_soc_card *card) +{ + struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_component *component; + struct bxt_hdmi_pcm *pcm; + int err; + + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct bxt_hdmi_pcm, + head); + component = pcm->codec_dai->component; if (!component) return -EINVAL; + if (ctx->common_hdmi_codec_drv) + return hda_dsp_hdmi_build_controls(card, component); + + err = hdmi_jack_create_controls(card); + if (err < 0) + return err; + return hdac_hdmi_jack_port_init(component, &card->dapm); } #else @@ -175,6 +199,9 @@ SND_SOC_DAILINK_DEF(ssp5_codec, SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:0e.0"))); +#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) || \ + IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) + SND_SOC_DAILINK_DEF(idisp1_pin, DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); SND_SOC_DAILINK_DEF(idisp1_codec, @@ -190,6 +217,8 @@ SND_SOC_DAILINK_DEF(idisp3_pin, SND_SOC_DAILINK_DEF(idisp3_codec, DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); +#endif + static struct snd_soc_dai_link dailink[] = { /* CODEC<->CODEC link */ /* back ends */ @@ -206,7 +235,8 @@ static struct snd_soc_dai_link dailink[] = { .dpcm_capture = 1, SND_SOC_DAILINK_REG(ssp5_pin, ssp5_codec, platform), }, -#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) || \ + IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_COMMON_HDMI_CODEC) { .name = "iDisp1", .id = 1, @@ -264,7 +294,8 @@ static int bxt_pcm512x_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + if (IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) || + IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) INIT_LIST_HEAD(&ctx->hdmi_pcm_list); mach = (&pdev->dev)->platform_data; @@ -277,6 +308,8 @@ static int bxt_pcm512x_probe(struct platform_device *pdev) if (ret_val) return ret_val; + ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; + /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(dailink); i++) { if (!strcmp(dailink[i].codecs->name, "i2c-104C5122:00")) { From 08c972e70330871344338e43ba77a30c89c6a2f6 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 1 Nov 2019 15:59:24 +0200 Subject: [PATCH 1711/1995] ASoC: Intel: cml_rt1011_rt5682: fix bug in Makefile Fix incorrect use of the intermediate variable snd-soc-cml_rt1011_rt5682-objs in Makefile. Signed-off-by: Kai Vehmanen --- sound/soc/intel/boards/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index fb4e1b34992368..5ffa9b2bfb928f 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -53,7 +53,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_CX2072X_MACH) += snd-soc-sst-byt-cht-cx2072x. obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o -obj-$(CONFIG_SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH) += cml_rt1011_rt5682.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH) += snd-soc-cml_rt1011_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o From 636efb99fda8a43a87f2aff4707731f2b247e55a Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 1 Nov 2019 12:40:38 +0200 Subject: [PATCH 1712/1995] ASoC: Intel: cml_rt1011_rt5682: common hdmi codec support Add support for using snd-hda-codec-hdmi driver for HDMI/DP instead of ASoC hdac-hdmi. This is aligned with how other HDA codecs are already handled. Signed-off-by: Kai Vehmanen --- sound/soc/intel/boards/Makefile | 2 +- sound/soc/intel/boards/cml_rt1011_rt5682.c | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 5ffa9b2bfb928f..28acd6ed292a0d 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -20,7 +20,7 @@ snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o snd-soc-sof_rt5682-objs := sof_rt5682.o hda_dsp_common.o -snd-soc-cml_rt1011_rt5682-objs := cml_rt1011_rt5682.o +snd-soc-cml_rt1011_rt5682-objs := cml_rt1011_rt5682.o hda_dsp_common.o snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o diff --git a/sound/soc/intel/boards/cml_rt1011_rt5682.c b/sound/soc/intel/boards/cml_rt1011_rt5682.c index f2837a20834199..a22f9723420117 100644 --- a/sound/soc/intel/boards/cml_rt1011_rt5682.c +++ b/sound/soc/intel/boards/cml_rt1011_rt5682.c @@ -23,6 +23,7 @@ #include "../../codecs/rt1011.h" #include "../../codecs/rt5682.h" #include "../../codecs/hdac_hdmi.h" +#include "hda_dsp_common.h" /* The platform clock outputs 24Mhz clock to codec as I2S MCLK */ #define CML_PLAT_CLK 24000000 @@ -42,6 +43,7 @@ struct card_private { char codec_name[SND_ACPI_I2C_ID_LEN]; struct snd_soc_jack headset; struct list_head hdmi_pcm_list; + bool common_hdmi_codec_drv; }; static const struct snd_kcontrol_new cml_controls[] = { @@ -240,6 +242,13 @@ static int sof_card_late_probe(struct snd_soc_card *card) struct hdmi_pcm *pcm; int ret, i = 0; + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm, + head); + component = pcm->codec_dai->component; + + if (ctx->common_hdmi_codec_drv) + return hda_dsp_hdmi_build_controls(card, component); + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { component = pcm->codec_dai->component; snprintf(jack_name, sizeof(jack_name), @@ -452,6 +461,9 @@ static int snd_cml_rt1011_probe(struct platform_device *pdev) platform_name); if (ret) return ret; + + ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; + snd_soc_card_set_drvdata(&snd_soc_card_cml, ctx); return devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cml); From 3e8221b117149425c7faa1f2544ea716236aced6 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 1 Nov 2019 12:44:38 +0200 Subject: [PATCH 1713/1995] ASoC: Intel: tgl_rt1308: common hdmi codec support Add support for using snd-hda-codec-hdmi driver for HDMI/DP instead of ASoC hdac-hdmi. This is aligned with how other HDA codecs are already handled. Signed-off-by: Kai Vehmanen --- sound/soc/intel/boards/Makefile | 2 +- sound/soc/intel/boards/tgl_rt1308.c | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 28acd6ed292a0d..9bab36acf2d232 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -30,7 +30,7 @@ snd-soc-skl_rt286-objs := skl_rt286.o snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o hda_dsp_common.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o -snd-soc-tgl-rt1308-objs := tgl_rt1308.o +snd-soc-tgl-rt1308-objs := tgl_rt1308.o hda_dsp_common.o obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o diff --git a/sound/soc/intel/boards/tgl_rt1308.c b/sound/soc/intel/boards/tgl_rt1308.c index c6b6e4a5215a82..c9e3c479b27cd6 100644 --- a/sound/soc/intel/boards/tgl_rt1308.c +++ b/sound/soc/intel/boards/tgl_rt1308.c @@ -21,9 +21,11 @@ #include "../../codecs/rt1308.h" #include "../../codecs/hdac_hdmi.h" +#include "hda_dsp_common.h" struct tgl_card_private { struct list_head hdmi_pcm_list; + bool common_hdmi_codec_drv; }; #if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) @@ -63,6 +65,13 @@ static int tgl_card_late_probe(struct snd_soc_card *card) int err, i = 0; char jack_name[NAME_SIZE]; + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct tgl_hdmi_pcm, + head); + component = pcm->codec_dai->component; + + if (ctx->common_hdmi_codec_drv) + return hda_dsp_hdmi_build_controls(card, component); + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { component = pcm->codec_dai->component; snprintf(jack_name, sizeof(jack_name), @@ -284,6 +293,8 @@ static int tgl_rt1308_probe(struct platform_device *pdev) if (ret) return ret; + ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; + snd_soc_card_set_drvdata(card, ctx); return devm_snd_soc_register_card(&pdev->dev, card); From b1fd93ee931d46795924fe4c310c8daed624ba32 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Oct 2019 21:00:17 -0500 Subject: [PATCH 1714/1995] ASoC: Intel: Kconfig: REVERT: "disable SST and legacy drivers when SOF is selected" This reverts commit e1e6e54bef6257680e8e61c22d5ff57a69f77e6f. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index d34e400a266cb5..3f9e65c10d5b57 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -62,7 +62,7 @@ config SND_SOC_INTEL_HASWELL config SND_SOC_INTEL_BAYTRAIL tristate "Baytrail (legacy) Platforms" - depends on DMADEVICES && ACPI && SND_SST_ATOM_HIFI2_PLATFORM=n && SND_SOC_SOF_BAYTRAIL=n + depends on DMADEVICES && ACPI && SND_SST_ATOM_HIFI2_PLATFORM=n select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST_ACPI select SND_SOC_INTEL_SST_FIRMWARE @@ -92,7 +92,7 @@ config SND_SST_ATOM_HIFI2_PLATFORM_PCI config SND_SST_ATOM_HIFI2_PLATFORM_ACPI tristate "ACPI HiFi2 (Baytrail, Cherrytrail) Platforms" default ACPI - depends on X86 && ACPI && PCI && SND_SOC_SOF_BAYTRAIL=n + depends on X86 && ACPI && PCI select SND_SST_IPC_ACPI select SND_SST_ATOM_HIFI2_PLATFORM select SND_SOC_ACPI_INTEL_MATCH From 2a4d5940f9821dd2a8e364078259d93f7bfe4c9f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Oct 2019 21:07:07 -0500 Subject: [PATCH 1715/1995] ASoC: SOF: Intel: Baytrail: clarify mutual exclusion with Atom/SST driver Some distros select all options blindly, which leads to confusion and bug reports. Since SOF does not support Baytrail-CR for now, and UCM/topology files are still being propagated to downstream distros, make SOF on Baytrail an opt-in option that first require distros to opt-out of existing defaults. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/Kconfig | 3 +++ sound/soc/sof/intel/Kconfig | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 3f9e65c10d5b57..9376d72663ea16 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -101,6 +101,9 @@ config SND_SST_ATOM_HIFI2_PLATFORM_ACPI If you have a Intel Baytrail or Cherrytrail platform with an I2S codec, then enable this option by saying Y or m. This is a recommended option + This option is mutually exclusive with the SOF support on + Baytrail/Cherrytrail. If you want to enable SOF on + Baytrail/Cherrytrail, you need to deselect this option first. config SND_SOC_INTEL_SKYLAKE tristate "All Skylake/SST Platforms" diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 36180af5c0aa58..8f44b1e9c6bd7d 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -62,10 +62,18 @@ if SND_SOC_SOF_INTEL_ACPI config SND_SOC_SOF_BAYTRAIL_SUPPORT bool "SOF support for Baytrail, Braswell and Cherrytrail" + depends on SND_SST_ATOM_HIFI2_PLATFORM_ACPI=n help This adds support for Sound Open Firmware for Intel(R) platforms using the Baytrail, Braswell or Cherrytrail processors. - Say Y if you have such a device. + This option is mutually exclusive with the Atom/SST and Baytrail + legacy drivers. If you want to enable SOF on Baytrail/Cherrytrail, + you need to deselect those options first. + SOF does not support Baytrail-CR for now, so this option is not + recommended for distros. At some point all legacy drivers will be + deprecated but not before all userspace firmware/topology/UCM files + are made available to downstream distros. + Say Y if you want to enable SOF on Baytrail/Cherrytrail If unsure select "N". config SND_SOC_SOF_BAYTRAIL From 4ae17e2512f73591976989499f278803a32c895b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Oct 2019 21:13:15 -0500 Subject: [PATCH 1716/1995] ASoC: SOF: Intel: Broadwell: clarify mutual exclusion with legacy driver Some distros select all options blindly, which leads to confusion and bug reports. SOF does not fully support Broadwell due to firmware dependencies, the machine drivers can only support one option, and UCM/topology files are still being propagated to downstream distros, so make SOF on Broadwell an opt-in option that first require distros to opt-out of existing defaults. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=204237 Fixes: f35bf70f61d3 ('ASoC: Intel: Make sure BDW based machine drivers build for SOF') Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/Kconfig | 3 +++ sound/soc/sof/intel/Kconfig | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 9376d72663ea16..7e9feca333b789 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -59,6 +59,9 @@ config SND_SOC_INTEL_HASWELL If you have a Intel Haswell or Broadwell platform connected to an I2S codec, then enable this option by saying Y or m. This is typically used for Chromebooks. This is a recommended option. + This option is mutually exclusive with the SOF support on + Broadwell. If you want to enable SOF on Broadwell, you need to + deselect this option first. config SND_SOC_INTEL_BAYTRAIL tristate "Baytrail (legacy) Platforms" diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 8f44b1e9c6bd7d..0cc82325d9fe96 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -85,10 +85,18 @@ config SND_SOC_SOF_BAYTRAIL config SND_SOC_SOF_BROADWELL_SUPPORT bool "SOF support for Broadwell" + depends on SND_SOC_INTEL_HASWELL=n help This adds support for Sound Open Firmware for Intel(R) platforms using the Broadwell processors. - Say Y if you have such a device. + This option is mutually exclusive with the Haswell/Broadwell legacy + driver. If you want to enable SOF on Broadwell you need to deselect + the legacy driver first. + SOF does fully support Broadwell yet, so this option is not + recommended for distros. At some point all legacy drivers will be + deprecated but not before all userspace firmware/topology/UCM files + are made available to downstream distros. + Say Y if you want to enable SOF on Broadwell If unsure select "N". config SND_SOC_SOF_BROADWELL From 9e4b3d0ffd4002ecd496e50383efabc449cd6f17 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Oct 2019 22:42:26 -0500 Subject: [PATCH 1717/1995] ASoC: Intel: add mutual exclusion between SOF and legacy Baytrail driver This legacy driver is already deprecated, let's make sure there is no conflict with SOF. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 7e9feca333b789..d6c5c68b749997 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -65,7 +65,7 @@ config SND_SOC_INTEL_HASWELL config SND_SOC_INTEL_BAYTRAIL tristate "Baytrail (legacy) Platforms" - depends on DMADEVICES && ACPI && SND_SST_ATOM_HIFI2_PLATFORM=n + depends on DMADEVICES && ACPI && SND_SST_ATOM_HIFI2_PLATFORM=n && SND_SOC_SOF_BAYTRAIL=n select SND_SOC_INTEL_SST select SND_SOC_INTEL_SST_ACPI select SND_SOC_INTEL_SST_FIRMWARE From f85394df179a5d362c72c7bd7cb96757b5cf65dd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Oct 2019 21:34:29 -0500 Subject: [PATCH 1718/1995] ASoC: SOF: Kconfig: add EXPERT dependency for developer options, clarify help Some distros select all possible options, despite existing warnings to be careful. This leads to e.g. user reports that the HDaudio codec and DMIC are not handled by SOF. Add an explicit menu item to unlock developer options, and make them dependent on CONFIG_EXPERT. Hopefully with this double-lock these options will only be selected by developers. GitHub issue: https://github.com/thesofproject/sof/issues/1885 Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/Kconfig | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 56a3ab66b46b7b..6435eb531668da 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -14,7 +14,6 @@ config SND_SOC_SOF_PCI depends on PCI select SND_SOC_SOF select SND_SOC_ACPI if ACPI - select SND_SOC_SOF_OPTIONS select SND_SOC_SOF_INTEL_PCI if SND_SOC_SOF_INTEL_TOPLEVEL help This adds support for PCI enumeration. This option is @@ -27,7 +26,6 @@ config SND_SOC_SOF_ACPI depends on ACPI || COMPILE_TEST select SND_SOC_SOF select SND_SOC_ACPI if ACPI - select SND_SOC_SOF_OPTIONS select SND_SOC_SOF_INTEL_ACPI if SND_SOC_SOF_INTEL_TOPLEVEL select IOSF_MBI if X86 && PCI help @@ -40,19 +38,23 @@ config SND_SOC_SOF_OF tristate "SOF OF enumeration support" depends on OF || COMPILE_TEST select SND_SOC_SOF - select SND_SOC_SOF_OPTIONS help This adds support for Device Tree enumeration. This option is required to enable i.MX8 devices. Say Y if you need this option. If unsure select "N". -config SND_SOC_SOF_OPTIONS - tristate +config SND_SOC_SOF_DEVELOPER_SUPPORT + bool "SOF developer options support" + depends on EXPERT help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level + This option unlock SOF developer options for debug/performance/ + code hardening. + Distributions should not select this option, only SOF development + teams should select it. + Say Y if you are involved in SOF development and need this option + If not, select N -if SND_SOC_SOF_OPTIONS +if SND_SOC_SOF_DEVELOPER_SUPPORT config SND_SOC_SOF_NOCODEC tristate @@ -64,6 +66,11 @@ config SND_SOC_SOF_NOCODEC_SUPPORT option if no known codec is detected. This is typically only enabled for developers or devices where the sound card is controlled externally + This option is mutually exclusive with the Intel HDaudio support, + selecting it may have negative impacts and prevent e.g. microphone + functionality from being enabled on Intel CoffeeLake and later + platforms. + Distributions should not select this option! Say Y if you need this nocodec fallback option If unsure select "N". @@ -168,7 +175,7 @@ config SND_SOC_SOF_DEBUG_RETAIN_DSP_CONTEXT endif ## SND_SOC_SOF_DEBUG -endif ## SND_SOC_SOF_OPTIONS +endif ## SND_SOC_SOF_DEVELOPER_SUPPORT config SND_SOC_SOF tristate From 672d39360c8f3d90782012f1d4fc02277930a440 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Oct 2019 21:57:22 -0500 Subject: [PATCH 1719/1995] ASoC: SOF: imx: fix reverse CONFIG_SND_SOC_SOF_OF dependency updated solution to the problem reported with randconfig: CONFIG_SND_SOC_SOF_IMX depends on CONFIG_SND_SOC_SOF, but is in turn referenced by the sof-of-dev driver. This creates a reverse dependency that manifests in a link error when CONFIG_SND_SOC_SOF_OF is built-in but CONFIG_SND_SOC_SOF_IMX=m: sound/soc/sof/sof-of-dev.o:(.data+0x118): undefined reference to `sof_imx8_ops' use def_trisate to propagate the right settings without select. Fixes: f4df4e4042b0 ("ASoC: SOF: imx8: Fix COMPILE_TEST error") Fixes: 202acc565a1f ("ASoC: SOF: imx: Add i.MX8 HW support") Suggested-by: Arnd Bergmann Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/imx/Kconfig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig index 6315fba8ce719c..bae4f7bf5f75cc 100644 --- a/sound/soc/sof/imx/Kconfig +++ b/sound/soc/sof/imx/Kconfig @@ -11,8 +11,8 @@ config SND_SOC_SOF_IMX_TOPLEVEL if SND_SOC_SOF_IMX_TOPLEVEL -config SND_SOC_SOF_IMX8 - tristate "SOF support for i.MX8" +config SND_SOC_SOF_IMX8_SUPPORT + bool "SOF support for i.MX8" depends on IMX_SCU depends on IMX_DSP help @@ -20,4 +20,8 @@ config SND_SOC_SOF_IMX8 Say Y if you have such a device. If unsure select "N". +config SND_SOC_SOF_IMX8 + def_tristate SND_SOC_SOF_OF + depends on SND_SOC_SOF_IMX8_SUPPORT + endif ## SND_SOC_SOF_IMX_IMX_TOPLEVEL From 15333103b2ca84f88a24d489ce1495dc9fc6dc69 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Oct 2019 22:04:19 -0500 Subject: [PATCH 1720/1995] ASoC: SOF: Intel: use def_tristate, avoid using select So far we used select to use the relevant built-in/module options, but this led to blurring layers between core and Intel Kconfigs. Use def_tristate works just as well and removes Intel stuff from the code. Suggested-by: Arnd Bergmann Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/Kconfig | 2 -- sound/soc/sof/intel/Kconfig | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 6435eb531668da..71a0fc075a63d8 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -14,7 +14,6 @@ config SND_SOC_SOF_PCI depends on PCI select SND_SOC_SOF select SND_SOC_ACPI if ACPI - select SND_SOC_SOF_INTEL_PCI if SND_SOC_SOF_INTEL_TOPLEVEL help This adds support for PCI enumeration. This option is required to enable Intel Skylake+ devices @@ -26,7 +25,6 @@ config SND_SOC_SOF_ACPI depends on ACPI || COMPILE_TEST select SND_SOC_SOF select SND_SOC_ACPI if ACPI - select SND_SOC_SOF_INTEL_ACPI if SND_SOC_SOF_INTEL_TOPLEVEL select IOSF_MBI if X86 && PCI help This adds support for ACPI enumeration. This option is required diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 0cc82325d9fe96..b27fd3fdf335d7 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -10,7 +10,7 @@ config SND_SOC_SOF_INTEL_TOPLEVEL if SND_SOC_SOF_INTEL_TOPLEVEL config SND_SOC_SOF_INTEL_ACPI - tristate + def_tristate SND_SOC_SOF_ACPI select SND_SOC_SOF_BAYTRAIL if SND_SOC_SOF_BAYTRAIL_SUPPORT select SND_SOC_SOF_BROADWELL if SND_SOC_SOF_BROADWELL_SUPPORT help @@ -18,7 +18,7 @@ config SND_SOC_SOF_INTEL_ACPI 'select' statements at a higher level config SND_SOC_SOF_INTEL_PCI - tristate + def_tristate SND_SOC_SOF_PCI select SND_SOC_SOF_MERRIFIELD if SND_SOC_SOF_MERRIFIELD_SUPPORT select SND_SOC_SOF_APOLLOLAKE if SND_SOC_SOF_APOLLOLAKE_SUPPORT select SND_SOC_SOF_GEMINILAKE if SND_SOC_SOF_GEMINILAKE_SUPPORT From ce4a78b6bc61c060b65f2e9feddc2d8dfb757b1f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 25 Oct 2019 21:51:30 -0500 Subject: [PATCH 1721/1995] ASoC: Intel: Skylake: mark HDAudio codec support as deprecated. This option famously broke audio on Linus' laptop and the problem have not been fixed. Mark as DEPRECATED to avoid any ambiguity with distros. Use SOF if you need HDaudio support w/ the DSP enabled, e.g. for DMIC capture. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/Kconfig | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index d6c5c68b749997..c8de0bb5bed9e5 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -209,9 +209,12 @@ config SND_SOC_INTEL_SKYLAKE_SSP_CLK config SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC bool "HDAudio codec support" help - If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/ - GeminiLake or CannonLake platform with an HDaudio codec - then enable this option by saying Y + This option broke audio on Linus' Skylake laptop in December 2018 + and the race conditions during the probe were not fixed since. + This option is DEPRECATED, all HDaudio codec support needs + to be handled by the SOF driver. + Distributions should not enable this option and there are no known + users of this capability. config SND_SOC_INTEL_SKYLAKE_COMMON tristate From 0f28f72d0778c76bc59fda5bc47e08df577ddc7a Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 30 Oct 2019 15:28:59 -0500 Subject: [PATCH 1722/1995] ASoC: Intel: boards: remove select SND_HDA_DSP_LOADER This option is only required with the Skylake platform driver, there is no reason to have this option in machine drivers. This is e.g. useless for SOF-based solutions. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index b69aa655618d39..f49fb80b25276a 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -270,7 +270,6 @@ config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH depends on I2C && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC - select SND_HDA_DSP_LOADER help This adds support for ASoC machine driver for Broxton-P platforms with DA7219 + MAX98357A I2S audio codec. @@ -284,7 +283,6 @@ config SND_SOC_INTEL_BXT_RT298_MACH select SND_SOC_RT298 select SND_SOC_DMIC select SND_SOC_HDAC_HDMI - select SND_HDA_DSP_LOADER help This adds support for ASoC machine driver for Broxton platforms with RT286 I2S audio codec. @@ -400,7 +398,6 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH select SND_SOC_MAX98357A select SND_SOC_DMIC select SND_SOC_HDAC_HDMI - select SND_HDA_DSP_LOADER help This adds support for ASoC machine driver for Geminilake platforms with RT5682 + MAX98357A I2S audio codec. From 17423c2d7a4d6752f97d9f1236cc79b07521922e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 30 Oct 2019 15:32:47 -0500 Subject: [PATCH 1723/1995] ASoC: Intel: boards: remove support for SOF for APL devices This isn't upstream anyways Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index f49fb80b25276a..5cb34317ed78c0 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -263,7 +263,7 @@ config SND_SOC_INTEL_DA7219_MAX98357A_GENERIC select SND_SOC_DMIC select SND_SOC_HDAC_HDMI -if SND_SOC_INTEL_APL || (SND_SOC_SOF_APOLLOLAKE && SND_SOC_SOF_HDA_LINK) +if SND_SOC_INTEL_APL config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH tristate "Broxton with DA7219 and MAX98357A in I2S Mode" @@ -289,7 +289,7 @@ config SND_SOC_INTEL_BXT_RT298_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". -endif ## SND_SOC_INTEL_APL || (SND_SOC_SOF_APOLLOLAKE && SND_SOC_SOF_HDA_LINK) +endif ## SND_SOC_INTEL_APL if SND_SOC_SOF_APOLLOLAKE From 67a8046506b19885cda6deaae0cd8e4ddf618e22 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 30 Oct 2019 15:49:04 -0500 Subject: [PATCH 1724/1995] ASoC: Intel: boards: fix configs for bxt-da7219-max98057a The same driver is reused for 3 different configurations, but the driver will only be build if ApolloLake is selected. Fix and make sure each device can work without dependencies on others (useful for minimal configurations). Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 24 ++++++++++++++++++++++-- sound/soc/intel/boards/Makefile | 2 +- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 5cb34317ed78c0..5b3588fc63a3dd 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -263,13 +263,17 @@ config SND_SOC_INTEL_DA7219_MAX98357A_GENERIC select SND_SOC_DMIC select SND_SOC_HDAC_HDMI +config SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON + tristate + select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC + if SND_SOC_INTEL_APL config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH tristate "Broxton with DA7219 and MAX98357A in I2S Mode" depends on I2C && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC + select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON help This adds support for ASoC machine driver for Broxton-P platforms with DA7219 + MAX98357A I2S audio codec. @@ -390,6 +394,17 @@ endif ## SND_SOC_INTEL_KBL if SND_SOC_INTEL_GLK || (SND_SOC_SOF_GEMINILAKE && SND_SOC_SOF_HDA_LINK) +config SND_SOC_INTEL_GLK_DA7219_MAX98357A_MACH + tristate "GLK with DA7219 and MAX98357A in I2S Mode" + depends on I2C && ACPI + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON + help + This adds support for ASoC machine driver for Geminilake platforms + with DA7219 + MAX98357A I2S audio codec. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH tristate "GLK with RT5682 and MAX98357A in I2S Mode" depends on I2C && ACPI @@ -443,7 +458,12 @@ config SND_SOC_INTEL_CML_LP_DA7219_MAX98357A_MACH tristate "CML_LP with DA7219 and MAX98357A in I2S Mode" depends on I2C && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC + select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON + help + This adds support for ASoC machine driver for Cometlake platforms + with DA7219 + MAX98357A I2S audio codec. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". config SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH tristate "CML with RT1011 and RT5682 in I2S Mode" diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 9bab36acf2d232..2c2eaaf7e83e4d 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -36,7 +36,7 @@ obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o -obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_max98357a.o +obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON) += snd-soc-sst-bxt-da7219_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o obj-$(CONFIG_SND_SOC_INTEL_BXT_PCM512x_MACH) += snd-soc-sst-bxt-pcm512x.o obj-$(CONFIG_SND_SOC_INTEL_BXT_WM8804_MACH) += snd-soc-sst-bxt-wm8804.o From 2909abf0050fa2597abe2f542134c23d223d2c9f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 30 Oct 2019 15:57:53 -0500 Subject: [PATCH 1725/1995] ASoC: Intel: boards: Geminilake is only supported by SOF Geminilake machine drivers are only tested and recommended with SOF. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 5b3588fc63a3dd..580bb7c51d8c2b 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -392,7 +392,7 @@ config SND_SOC_INTEL_KBL_RT5660_MACH endif ## SND_SOC_INTEL_KBL -if SND_SOC_INTEL_GLK || (SND_SOC_SOF_GEMINILAKE && SND_SOC_SOF_HDA_LINK) +if SND_SOC_SOF_GEMINILAKE && SND_SOC_SOF_HDA_LINK config SND_SOC_INTEL_GLK_DA7219_MAX98357A_MACH tristate "GLK with DA7219 and MAX98357A in I2S Mode" @@ -419,7 +419,7 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH Say Y if you have such a device. If unsure select "N". -endif ## SND_SOC_INTEL_GLK || (SND_SOC_SOF_GEMINILAKE && SND_SOC_SOF_HDA_LINK) +endif ## SND_SOC_SOF_GEMINILAKE && SND_SOC_SOF_HDA_LINK if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC From 2286f8fad76df7916806b3a08b0fff1f6a6b44c4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 30 Oct 2019 16:01:10 -0500 Subject: [PATCH 1726/1995] ASoC: Intel: boards: sof_rt5682: use dependency on SOF_HDA_LINK The wrong dependency is used and the build can be broken Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 580bb7c51d8c2b..7815080e5e7eb1 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -436,11 +436,11 @@ config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC -if SND_SOC_SOF_HDA_COMMON || SND_SOC_SOF_BAYTRAIL +if SND_SOC_SOF_HDA_LINK || SND_SOC_SOF_BAYTRAIL config SND_SOC_INTEL_SOF_RT5682_MACH tristate "SOF with rt5682 codec in I2S Mode" depends on I2C && ACPI - depends on (SND_SOC_SOF_HDA_COMMON && (MFD_INTEL_LPSS || COMPILE_TEST)) ||\ + depends on (SND_SOC_SOF_HDA_LINK && (MFD_INTEL_LPSS || COMPILE_TEST)) ||\ (SND_SOC_SOF_BAYTRAIL && (X86_INTEL_LPSS || COMPILE_TEST)) select SND_SOC_RT5682 select SND_SOC_DMIC @@ -450,7 +450,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH with rt5682 codec. Say Y if you have such a device. If unsure select "N". -endif ## SND_SOC_SOF_HDA_COMMON || SND_SOC_SOF_BAYTRAIL +endif ## SND_SOC_SOF_HDA_LINK || SND_SOC_SOF_BAYTRAIL if (SND_SOC_SOF_COMETLAKE_LP && SND_SOC_SOF_HDA_LINK) From 0f9c0f9307d86ff11a4ce16d8fb4a1edfdf197ec Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 30 Oct 2019 15:09:24 -0500 Subject: [PATCH 1727/1995] ASoC: Intel: acpi-match: split CNL tables in three Due to firmware manifest/signature differences, we have to use different firmware names, so split CNL machine table in three (CNL, CFL, CML). The CFL table is currently empty since all known platforms use HDaudio, but let's plan ahead. Reviewed-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart --- include/sound/soc-acpi-intel-match.h | 2 + sound/soc/intel/common/Makefile | 3 +- .../intel/common/soc-acpi-intel-cfl-match.c | 18 ++++++ .../intel/common/soc-acpi-intel-cml-match.c | 56 +++++++++++++++++++ .../intel/common/soc-acpi-intel-cnl-match.c | 38 ------------- 5 files changed, 78 insertions(+), 39 deletions(-) create mode 100644 sound/soc/intel/common/soc-acpi-intel-cfl-match.c create mode 100644 sound/soc/intel/common/soc-acpi-intel-cml-match.c diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index 4e44782862df39..20c0bee3b959db 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -24,6 +24,8 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[]; diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index eafe95ead49b67..bd352878f89a56 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -7,7 +7,8 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-hsw-bdw-match.o \ soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ - soc-acpi-intel-cnl-match.o soc-acpi-intel-icl-match.o \ + soc-acpi-intel-cnl-match.o soc-acpi-intel-cfl-match.o \ + soc-acpi-intel-cml-match.o soc-acpi-intel-icl-match.o \ soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \ soc-acpi-intel-jsl-match.o \ soc-acpi-intel-hda-match.o diff --git a/sound/soc/intel/common/soc-acpi-intel-cfl-match.c b/sound/soc/intel/common/soc-acpi-intel-cfl-match.c new file mode 100644 index 00000000000000..d6fd2026d0b863 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-cfl-match.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-apci-intel-cfl-match.c - tables and support for CFL ACPI enumeration. + * + * Copyright (c) 2019, Intel Corporation. + * + */ + +#include +#include + +struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_machines[] = { + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cfl_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c new file mode 100644 index 00000000000000..5d08ae0667380b --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * soc-acpi-intel-cml-match.c - tables and support for CML ACPI enumeration. + * + * Copyright (c) 2019, Intel Corporation. + * + */ + +#include +#include + +static struct snd_soc_acpi_codecs cml_codecs = { + .num_codecs = 1, + .codecs = {"10EC5682"} +}; + +static struct snd_soc_acpi_codecs cml_spk_codecs = { + .num_codecs = 1, + .codecs = {"MX98357A"} +}; + +struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = { + { + .id = "DLGS7219", + .drv_name = "cml_da7219_max98357a", + .quirk_data = &cml_spk_codecs, + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-da7219-max98357a.tplg", + }, + { + .id = "MX98357A", + .drv_name = "sof_rt5682", + .quirk_data = &cml_codecs, + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg", + }, + { + .id = "10EC1011", + .drv_name = "cml_rt1011_rt5682", + .quirk_data = &cml_codecs, + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg", + }, + { + .id = "10EC5682", + .drv_name = "sof_rt5682", + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-rt5682.tplg", + }, + + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cml_machines); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Common ACPI Match module"); diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index 16d0bae8b316ae..27588841c8b005 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -14,16 +14,6 @@ static struct skl_machine_pdata cnl_pdata = { .use_tplg_pcm = true, }; -static struct snd_soc_acpi_codecs cml_codecs = { - .num_codecs = 1, - .codecs = {"10EC5682"} -}; - -static struct snd_soc_acpi_codecs cml_spk_codecs = { - .num_codecs = 1, - .codecs = {"MX98357A"} -}; - struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { { .id = "INT34C2", @@ -33,34 +23,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { .sof_fw_filename = "sof-cnl.ri", .sof_tplg_filename = "sof-cnl-rt274.tplg", }, - { - .id = "DLGS7219", - .drv_name = "cml_da7219_max98357a", - .quirk_data = &cml_spk_codecs, - .sof_fw_filename = "sof-cnl.ri", - .sof_tplg_filename = "sof-cml-da7219-max98357a.tplg", - }, - { - .id = "MX98357A", - .drv_name = "sof_rt5682", - .quirk_data = &cml_codecs, - .sof_fw_filename = "sof-cnl.ri", - .sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg", - }, - { - .id = "10EC1011", - .drv_name = "cml_rt1011_rt5682", - .quirk_data = &cml_codecs, - .sof_fw_filename = "sof-cnl.ri", - .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg", - }, - { - .id = "10EC5682", - .drv_name = "sof_rt5682", - .sof_fw_filename = "sof-cnl.ri", - .sof_tplg_filename = "sof-cml-rt5682.tplg", - }, - {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_machines); From fd5f04d471f2d9ee107991553fdcab55ca1d68ed Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 4 Oct 2019 11:05:00 +0100 Subject: [PATCH 1728/1995] ASoC: SOF: Intel: Fix CFL and CML FW nocodec binary names. The manifest information is different between CNL, CML and CFL platforms hence we need to load different files. Signed-off-by: Liam Girdwood Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-pci-dev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 3b58b91e7b9e57..bbeffd932de7fd 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -120,7 +120,7 @@ static const struct sof_dev_desc cnl_desc = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) static const struct sof_dev_desc cfl_desc = { - .machines = snd_soc_acpi_intel_cnl_machines, + .machines = snd_soc_acpi_intel_cfl_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, @@ -129,7 +129,7 @@ static const struct sof_dev_desc cfl_desc = { .chip_info = &cnl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", - .nocodec_fw_filename = "sof-cnl.ri", + .nocodec_fw_filename = "sof-cfl.ri", .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops @@ -140,7 +140,7 @@ static const struct sof_dev_desc cfl_desc = { IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) static const struct sof_dev_desc cml_desc = { - .machines = snd_soc_acpi_intel_cnl_machines, + .machines = snd_soc_acpi_intel_cml_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, @@ -149,7 +149,7 @@ static const struct sof_dev_desc cml_desc = { .chip_info = &cnl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", - .nocodec_fw_filename = "sof-cnl.ri", + .nocodec_fw_filename = "sof-cml.ri", .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops From 1cae79902b68ed733bbcfe5ea7007f70fad59e3c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 30 Oct 2019 14:55:14 -0500 Subject: [PATCH 1729/1995] ASoC: SOF: Intel: hda: use fallback for firmware name We have platforms such as CFL with no known I2S codec being used, and the ACPI tables are currently empty, so fall-back to using the firmware filename used in nocodec mode Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 7dc0018dc4c3a4..91bd88fddac7aa 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -415,9 +415,16 @@ static int hda_init_caps(struct snd_sof_dev *sdev) pdata->tplg_filename = hda_mach->sof_tplg_filename; - /* firmware: pick the first in machine list */ + /* + * firmware: pick the first in machine list, + * or use nocodec firmware name if list is empty + */ mach = pdata->desc->machines; - pdata->fw_filename = mach->sof_fw_filename; + if (mach->id[0]) + pdata->fw_filename = mach->sof_fw_filename; + else + pdata->fw_filename = + pdata->desc->nocodec_fw_filename; dev_info(bus->dev, "using HDA machine driver %s now\n", hda_mach->drv_name); From 4e76b4a1623eb90f42b45147420d03ebbe48f9a4 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 30 Oct 2019 08:33:56 -0700 Subject: [PATCH 1730/1995] ASoC: SOF: Intel: hda: Simplify the hda_dsp_wait_d0i3c_done() function Remove the retry argument for the hda_dsp_wait_d0i3c_done() function and use the HDA_DSP_REG_POLL_RETRY_COUNT macro directly. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-dsp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 3a54edd017fe6f..4a4d318f97ffa5 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -307,9 +307,10 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0); } -static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev, int retry) +static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); + int retry = HDA_DSP_REG_POLL_RETRY_COUNT; while (snd_hdac_chip_readb(bus, VS_D0I3C) & SOF_HDA_VS_D0I3C_CIP) { if (!retry--) @@ -346,7 +347,7 @@ int hda_dsp_set_power_state(struct snd_sof_dev *sdev, u8 value; /* Write to D0I3C after Command-In-Progress bit is cleared */ - ret = hda_dsp_wait_d0i3c_done(sdev, HDA_DSP_REG_POLL_RETRY_COUNT); + ret = hda_dsp_wait_d0i3c_done(sdev); if (ret < 0) { dev_err(bus->dev, "CIP timeout before D0I3C update!\n"); return ret; @@ -357,7 +358,7 @@ int hda_dsp_set_power_state(struct snd_sof_dev *sdev, snd_hdac_chip_updateb(bus, VS_D0I3C, SOF_HDA_VS_D0I3C_I3, value); /* Wait for cmd in progress to be cleared before exiting the function */ - ret = hda_dsp_wait_d0i3c_done(sdev, HDA_DSP_REG_POLL_RETRY_COUNT); + ret = hda_dsp_wait_d0i3c_done(sdev); if (ret < 0) { dev_err(bus->dev, "CIP timeout after D0I3C update!\n"); return ret; From c437b23c6682b55901486d3f25ead1d00eaaa67a Mon Sep 17 00:00:00 2001 From: Dragos Tarcatu Date: Tue, 5 Nov 2019 16:04:14 +0200 Subject: [PATCH 1731/1995] ASoC: SOF: topology: Fix bytes control size checks When using the example SOF amp widget topology, KASAN dumps this when the AMP bytes kcontrol gets loaded: [ 9.579548] BUG: KASAN: slab-out-of-bounds in sof_control_load+0x8cc/0xac0 [snd_sof] [ 9.588194] Write of size 40 at addr ffff8882314559dc by task systemd-udevd/2411 [ 9.596447] [ 9.598110] CPU: 0 PID: 2411 Comm: systemd-udevd Not tainted 5.4.0-rc4-quilt+ #44 [ 9.606466] Call Trace: [ 9.609201] dump_stack+0x86/0xc5 [ 9.612916] ? sof_control_load+0x8cc/0xac0 [snd_sof] [ 9.618559] print_address_description.constprop.4+0x26/0x360 [ 9.624987] ? sof_control_load+0x8cc/0xac0 [snd_sof] [ 9.630617] __kasan_report+0x158/0x1d0 [ 9.634899] ? _dev_crit+0xf1/0xf1 [ 9.638696] ? __kasan_kmalloc.constprop.5+0x21/0xd0 [ 9.644247] ? sof_control_load+0x8cc/0xac0 [snd_sof] [ 9.649884] kasan_report+0x12/0x20 [ 9.653775] check_memory_region+0x152/0x1b0 [ 9.658540] memcpy+0x37/0x50 [ 9.661873] sof_control_load+0x8cc/0xac0 [snd_sof] [ 9.661887] ? __asan_loadN+0xf/0x20 [ 9.671324] ? soc_tplg_kcontrol_bind_io+0x55c/0x640 [ 9.676879] ? sof_link_load+0x1880/0x1880 [snd_sof] [ 9.682429] soc_tplg_dapm_widget_create+0xa06/0x1bd0 [ 9.688077] ? soc_tplg_denum_create_texts+0x290/0x290 [ 9.693827] soc_tplg_process_headers+0xb87/0x4470 [ 9.699188] ? _raw_spin_unlock_irqrestore+0x1c/0x40 [ 9.704739] ? devres_add+0x3f/0x50 [ 9.708641] ? trace_hardirqs_on+0x3a/0x130 [ 9.713320] ? soc_tplg_dapm_widget_create+0x1bd0/0x1bd0 [ 9.719257] ? mutex_unlock+0x22/0x40 [ 9.723348] ? assign_fw+0x91/0x1f0 [ 9.727236] ? _request_firmware+0xe4/0xb50 [ 9.731910] snd_soc_tplg_component_load+0x122/0x1b0 [ 9.737455] ? soc_tplg_process_headers+0x4470/0x4470 [ 9.743112] snd_sof_load_topology+0xcd/0x180 [snd_sof] [ 9.748975] ? sof_dbg_comp_config+0xa0/0xa0 [snd_sof] [ 9.748994] sof_pcm_probe+0xaa/0x180 [snd_sof] [ 9.749003] snd_soc_component_probe+0x38/0x50 [ 9.749009] soc_probe_component+0x2d1/0x670 [ 9.749015] snd_soc_instantiate_card+0x95d/0x1750 [ 9.749021] ? soc_cleanup_card_resources+0x5b0/0x5b0 [ 9.749027] ? kernfs_put+0x2c/0x2a0 [ 9.749034] ? debug_mutex_init+0x11/0x20 [ 9.749039] snd_soc_register_card+0x26a/0x290 ... Fix that by rejecting the topology if the bytes data size > max_size Signed-off-by: Dragos Tarcatu --- sound/soc/sof/topology.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 17fe6a1d5f3e77..6096731e89ce14 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1048,15 +1048,16 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, struct soc_bytes_ext *sbe = (struct soc_bytes_ext *)kc->private_value; int max_size = sbe->max; - if (le32_to_cpu(control->priv.size) > max_size) { + /* init the get/put bytes data */ + scontrol->size = sizeof(struct sof_ipc_ctrl_data) + + le32_to_cpu(control->priv.size); + + if (scontrol->size > max_size) { dev_err(sdev->dev, "err: bytes data size %d exceeds max %d.\n", - control->priv.size, max_size); + scontrol->size, max_size); return -EINVAL; } - /* init the get/put bytes data */ - scontrol->size = sizeof(struct sof_ipc_ctrl_data) + - le32_to_cpu(control->priv.size); scontrol->control_data = kzalloc(max_size, GFP_KERNEL); cdata = scontrol->control_data; if (!scontrol->control_data) From 872e5e80c67a8805694529918621260bc506e0f5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 1 Nov 2019 16:45:38 -0500 Subject: [PATCH 1732/1995] ASoC: soc-core: fix RIP warning on card removal SOF module load/unload tests show nasty recurring warnings: WARNING: CPU: 5 PID: 1339 at sound/core/control.c:466 snd_ctl_remove+0xf0/0x100 [snd] RIP: 0010:snd_ctl_remove+0xf0/0x100 [snd] This regression was introduced by the removal of the call to soc_remove_link_components() before soc_card_free() is invoked. Go back to the initial order but only call soc_remove_link_components() once. Reviewed-by: Ranjani Sridharan Acked-by: Kuninori Morimoto Fixes: 5a4c9f054ceea ("ASoC: soc-core: snd_soc_unbind_card() cleanup") GitHub issue: https://github.com/thesofproject/linux/issues/1424 Signed-off-by: Pierre-Louis Bossart --- sound/soc/soc-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b07ecfac39d752..1e08fb5da1704a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1951,6 +1951,9 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card) { struct snd_soc_dai_link *link, *_link; + /* This should be called before snd_card_free() */ + soc_remove_link_components(card); + /* free the ALSA card at first; this syncs with pending operations */ if (card->snd_card) { snd_card_free(card->snd_card); @@ -1959,7 +1962,6 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card) /* remove and free each DAI */ soc_remove_link_dais(card); - soc_remove_link_components(card); for_each_card_links_safe(card, link, _link) snd_soc_remove_dai_link(card, link); From 4425a3e5a97912349fd3c9bc097fd05f1b71cf2f Mon Sep 17 00:00:00 2001 From: Bard liao Date: Fri, 8 Nov 2019 02:01:02 +0800 Subject: [PATCH 1733/1995] ASoC: rt5682: cancel jack_detect_work if hs_jack is set to null jack_detect_work will be triggered by rt5682_irq. We should cancel it if hs_jack is set to null. Signed-off-by: Bard liao --- sound/soc/codecs/rt5682.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index c50b75ce82e0b7..62b8ed412bd140 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -1002,6 +1002,7 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component, RT5682_JD1_EN_MASK, RT5682_JD1_DIS); regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL, RT5682_POW_JDH | RT5682_POW_JDL, 0); + cancel_delayed_work_sync(&rt5682->jack_detect_work); return 0; } From 2a37cf0b8bad026dd87ed273c8dcb4bc5a309d13 Mon Sep 17 00:00:00 2001 From: Dragos Tarcatu Date: Fri, 8 Nov 2019 13:15:04 +0200 Subject: [PATCH 1734/1995] ASoC: SOF: topology: free kcontrol memory on error The volume and bytes kcontrols are currently not freeing their memory on initialization failures. When an error occurs, all the widgets loaded so far are unloaded via sof_widget_unload(). But this only happens for the widgets that got successfully loaded. Fix that by kfree()-ing the allocated memory on load error. Signed-off-by: Dragos Tarcatu --- sound/soc/sof/topology.c | 67 +++++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 6096731e89ce14..d82ab981e8408a 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -942,18 +942,22 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, struct sof_ipc_ctrl_data *cdata; int tlv[TLV_ITEMS]; unsigned int i; - int ret; + int ret = 0; /* validate topology data */ - if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN) - return -EINVAL; + if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN) { + ret = -EINVAL; + goto out; + } /* init the volume get/put data */ scontrol->size = struct_size(scontrol->control_data, chanv, le32_to_cpu(mc->num_channels)); scontrol->control_data = kzalloc(scontrol->size, GFP_KERNEL); - if (!scontrol->control_data) - return -ENOMEM; + if (!scontrol->control_data) { + ret = -ENOMEM; + goto out; + } scontrol->comp_id = sdev->next_comp_id; scontrol->min_volume_step = le32_to_cpu(mc->min); @@ -963,7 +967,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, /* set cmd for mixer control */ if (le32_to_cpu(mc->max) == 1) { scontrol->cmd = SOF_CTRL_CMD_SWITCH; - goto out; + goto skip; } scontrol->cmd = SOF_CTRL_CMD_VOLUME; @@ -971,14 +975,15 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, /* extract tlv data */ if (get_tlv_data(kc->tlv.p, tlv) < 0) { dev_err(sdev->dev, "error: invalid TLV data\n"); - return -EINVAL; + ret = -EINVAL; + goto out_free; } /* set up volume table */ ret = set_up_volume_table(scontrol, tlv, le32_to_cpu(mc->max) + 1); if (ret < 0) { dev_err(sdev->dev, "error: setting up volume table\n"); - return ret; + goto out_free; } /* set default volume values to 0dB in control */ @@ -988,7 +993,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, cdata->chanv[i].value = VOL_ZERO_DB; } -out: +skip: /* set up possible led control from mixer private data */ ret = sof_parse_tokens(scomp, &scontrol->led_ctl, led_tokens, ARRAY_SIZE(led_tokens), mc->priv.array, @@ -996,13 +1001,21 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, if (ret != 0) { dev_err(sdev->dev, "error: parse led tokens failed %d\n", le32_to_cpu(mc->priv.size)); - return ret; + goto out_free_table; } dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", scontrol->comp_id, scontrol->num_channels); - return 0; + return ret; + +out_free_table: + if (le32_to_cpu(mc->max) > 1) + kfree(scontrol->volume_table); +out_free: + kfree(scontrol->control_data); +out: + return ret; } static int sof_control_load_enum(struct snd_soc_component *scomp, @@ -1047,6 +1060,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, container_of(hdr, struct snd_soc_tplg_bytes_control, hdr); struct soc_bytes_ext *sbe = (struct soc_bytes_ext *)kc->private_value; int max_size = sbe->max; + int ret = 0; /* init the get/put bytes data */ scontrol->size = sizeof(struct sof_ipc_ctrl_data) + @@ -1055,13 +1069,16 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, if (scontrol->size > max_size) { dev_err(sdev->dev, "err: bytes data size %d exceeds max %d.\n", scontrol->size, max_size); - return -EINVAL; + ret = -EINVAL; + goto out; } scontrol->control_data = kzalloc(max_size, GFP_KERNEL); cdata = scontrol->control_data; - if (!scontrol->control_data) - return -ENOMEM; + if (!scontrol->control_data) { + ret = -ENOMEM; + goto out; + } scontrol->comp_id = sdev->next_comp_id; scontrol->cmd = SOF_CTRL_CMD_BINARY; @@ -1076,23 +1093,32 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, if (cdata->data->magic != SOF_ABI_MAGIC) { dev_err(sdev->dev, "error: Wrong ABI magic 0x%08x.\n", cdata->data->magic); - return -EINVAL; + ret = -EINVAL; + goto out_free; } if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { dev_err(sdev->dev, "error: Incompatible ABI version 0x%08x.\n", cdata->data->abi); - return -EINVAL; + ret = -EINVAL; + goto out_free; } if (cdata->data->size + sizeof(const struct sof_abi_hdr) != le32_to_cpu(control->priv.size)) { dev_err(sdev->dev, "error: Conflict in bytes vs. priv size.\n"); - return -EINVAL; + ret = -EINVAL; + goto out_free; } } - return 0; + + return ret; + +out_free: + kfree(scontrol->control_data); +out: + return ret; } /* external kcontrol init - used for any driver specific init */ @@ -1150,6 +1176,11 @@ static int sof_control_load(struct snd_soc_component *scomp, int index, return 0; } + if (ret < 0) { + kfree(scontrol); + return ret; + } + dobj->private = scontrol; list_add(&scontrol->list, &sdev->kcontrol_list); return ret; From 0e1a9616fac66b934635a63951ceebd18d158ee9 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Sat, 9 Nov 2019 05:21:00 +0800 Subject: [PATCH 1735/1995] ASoC: SOF: Intel: hda-loader: clear the IPC ack bit after FW_PURGE done Set DONE bit after the FW_PURGE IPC is polled successfully, to clear the interrupt and avoid the arrival of the confusing unexpected ipc. Signed-off-by: Keyon Jie --- sound/soc/sof/intel/hda-loader.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index b1783360fe106b..784229d23160b7 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -131,6 +131,12 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, goto err; } + /* set DONE bit to clear the reply IPC message */ + snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, + chip->ipc_ack, + chip->ipc_ack_mask, + chip->ipc_ack_mask); + /* step 5: power down corex */ ret = hda_dsp_core_power_down(sdev, chip->cores_mask & ~(HDA_DSP_CORE_MASK(0))); From 031bea594f6570c6df6f8d169a035b25584c666a Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Sat, 2 Nov 2019 01:13:59 +0800 Subject: [PATCH 1736/1995] ASoC: SOF: PM: add check before setting d0_substate Add check before seeting d0_substate and return success if Audio DSP is already in the target substate. Signed-off-by: Keyon Jie --- sound/soc/sof/pm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 560a937e048420..717251432ee93b 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -416,6 +416,9 @@ int snd_sof_set_d0_substate(struct snd_sof_dev *sdev, { int ret; + if (sdev->d0_substate == d0_substate) + return 0; + /* do platform specific set_state */ ret = snd_sof_dsp_set_power_state(sdev, d0_substate); if (ret < 0) From df365f514dd2b46e40b94839ca8133d1cd349554 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 8 Nov 2019 08:26:28 +0800 Subject: [PATCH 1737/1995] ASoC: SOF: add helper to check if we should enter d0i3 suspend Add helper to check if the DSP should be put in D0i3. This function returns true if a stream has ignored the SUSPEND trigger to keep the pipelines running in the DSP. Signed-off-by: Keyon Jie --- sound/soc/sof/core.c | 13 +++++++++++++ sound/soc/sof/sof-priv.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 8661c2cca76b9a..805918d3bcc09d 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -132,6 +132,19 @@ struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev, return NULL; } +bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev) +{ + struct snd_sof_pcm *spcm; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored || + spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored) + return true; + } + + return false; +} + /* * FW Panic/fault handling. */ diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 6408ac88a3e582..c7c2c70ee4d04d 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -553,6 +553,8 @@ struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_sof_dev *sdev, return NULL; } +bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev); + struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev, const char *name); struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev, From 669d398e7975fafb151cce491cc02109dbc1aef5 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 1 Nov 2019 05:43:46 +0800 Subject: [PATCH 1738/1995] ASoC: SOF: PM: only suspend to D0I3 when needed We should suspend audio to D3 by default, for the sake of power saving, change the condition of D0I3 suspending here to that when there is stream with suspend_ignored specified. Signed-off-by: Keyon Jie --- sound/soc/sof/pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 717251432ee93b..1436cb201fa07b 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -436,7 +436,7 @@ int snd_sof_resume(struct device *dev) struct snd_sof_dev *sdev = dev_get_drvdata(dev); int ret; - if (sdev->s0_suspend) { + if (snd_sof_dsp_d0i3_on_suspend(sdev)) { /* resume from D0I3 */ dev_dbg(sdev->dev, "DSP will exit from D0i3...\n"); ret = snd_sof_set_d0_substate(sdev, SOF_DSP_D0I0); @@ -465,7 +465,7 @@ int snd_sof_suspend(struct device *dev) struct snd_sof_dev *sdev = dev_get_drvdata(dev); int ret; - if (sdev->s0_suspend) { + if (snd_sof_dsp_d0i3_on_suspend(sdev)) { /* suspend to D0i3 */ dev_dbg(sdev->dev, "DSP is trying to enter D0i3...\n"); ret = snd_sof_set_d0_substate(sdev, SOF_DSP_D0I3); From f55db62ec6a17a50cc3f82729c7aaee82dc56033 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Tue, 5 Nov 2019 06:44:30 +0800 Subject: [PATCH 1739/1995] ASoC: SOF: PM: add state machine to comments Add Audio DSP state machine with comments, be noticed that the 'D0<-->runtime D0I3' part is not implemented yet. Signed-off-by: Keyon Jie --- sound/soc/sof/pm.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 1436cb201fa07b..0fd5567237a8d5 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -431,6 +431,38 @@ int snd_sof_set_d0_substate(struct snd_sof_dev *sdev, } EXPORT_SYMBOL(snd_sof_set_d0_substate); +/* + * Audio DSP states may transform as below:- + * + * D0I3 compatible stream + * Runtime +---------------------+ opened only, timeout + * suspend | +--------------------+ + * +------------+ D0(active) | | + * | | <---------------+ | + * | +--------> | | | + * | |Runtime +--^--+---------^--+--+ The last | | + * | |resume | | | | opened D0I3 | | + * | | | | | | compatible | | + * | | resume| | | | stream closed | | + * | | from | | D3 | | | | + * | | D3 | |suspend | | d0i3 | | + * | | | | | |suspend | | + * | | | | | | | | + * | | | | | | | | + * +-v---+-----------+--v-------+ | | +------+----v----+ + * | | | +-----------> | + * | D3 (suspended) | | | D0I3 +-----+ + * | | +--------------+ | | + * | | resume from | | | + * +-------------------^--------+ d0i3 suspend +----------------+ | + * | | + * | D3 suspend | + * +------------------------------------------------+ + * + * d0i3_suspend = s0_suspend && D0I3 stream opened, + * D3 suspend = !d0i3_suspend, + */ + int snd_sof_resume(struct device *dev) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); From fd30230359e5b9106d69eb3cf30ef987921d2cee Mon Sep 17 00:00:00 2001 From: Pierre Bossart Date: Wed, 13 Nov 2019 09:07:31 -0600 Subject: [PATCH 1740/1995] Revert "ASoC: SOF: Intel: hda-loader: clear the IPC ack bit after FW_PURGE done" This reverts commit 0e1a9616fac66b934635a63951ceebd18d158ee9. --- sound/soc/sof/intel/hda-loader.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 784229d23160b7..b1783360fe106b 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -131,12 +131,6 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata, goto err; } - /* set DONE bit to clear the reply IPC message */ - snd_sof_dsp_update_bits_forced(sdev, HDA_DSP_BAR, - chip->ipc_ack, - chip->ipc_ack_mask, - chip->ipc_ack_mask); - /* step 5: power down corex */ ret = hda_dsp_core_power_down(sdev, chip->cores_mask & ~(HDA_DSP_CORE_MASK(0))); From f6ff3e958e0ec5949434b7db3c42c3604c85c8a0 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 15 Nov 2019 15:57:03 +0530 Subject: [PATCH 1741/1995] ALSA: compress: add flac decoder params The current design of sending codec parameters assumes that decoders will have parsers so they can parse the encoded stream for parameters and configure the decoder. But this assumption may not be universally true and we know some DSPs which do not contain the parsers so additional parameters are required to be passed. So add these parameters starting with FLAC decoder. The size of snd_codec_options is still 120 bytes after this change (due to this being a union) Co-developed-by: Srinivas Kandagatla Signed-off-by: Srinivas Kandagatla Signed-off-by: Vinod Koul Link: https://lore.kernel.org/r/20191115102705.649976-2-vkoul@kernel.org Signed-off-by: Mark Brown --- include/uapi/sound/compress_params.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index 3d4d6de66a17ea..9c96fb0e4d903d 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -317,12 +317,22 @@ struct snd_enc_generic { __s32 reserved[15]; /* Can be used for SND_AUDIOCODEC_BESPOKE */ } __attribute__((packed, aligned(4))); +struct snd_dec_flac { + __u16 sample_size; + __u16 min_blk_size; + __u16 max_blk_size; + __u16 min_frame_size; + __u16 max_frame_size; + __u16 reserved; +} __attribute__((packed, aligned(4))); + union snd_codec_options { struct snd_enc_wma wma; struct snd_enc_vorbis vorbis; struct snd_enc_real real; struct snd_enc_flac flac; struct snd_enc_generic generic; + struct snd_dec_flac flac_d; } __attribute__((packed, aligned(4))); /** struct snd_codec_desc - description of codec capabilities From badfe2c0666b1b65ad443aca74540bf6d976ec83 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 15 Nov 2019 15:57:04 +0530 Subject: [PATCH 1742/1995] ASoC: qcom: q6asm: add support to flac config Qualcomm DSPs expect flac config to be set for flac decoders, so add the API to program the flac config to the DSP Signed-off-by: Srinivas Kandagatla Signed-off-by: Vinod Koul Link: https://lore.kernel.org/r/20191115102705.649976-3-vkoul@kernel.org Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6asm.c | 55 ++++++++++++++++++++++++++++++++++++ sound/soc/qcom/qdsp6/q6asm.h | 15 ++++++++++ 2 files changed, 70 insertions(+) diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c index e8141a33a55e58..36e0eab13a9831 100644 --- a/sound/soc/qcom/qdsp6/q6asm.c +++ b/sound/soc/qcom/qdsp6/q6asm.c @@ -38,6 +38,7 @@ #define ASM_SESSION_CMD_RUN_V2 0x00010DAA #define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 0x00010DA5 #define ASM_MEDIA_FMT_MP3 0x00010BE9 +#define ASM_MEDIA_FMT_FLAC 0x00010C16 #define ASM_DATA_CMD_WRITE_V2 0x00010DAB #define ASM_DATA_CMD_READ_V2 0x00010DAC #define ASM_SESSION_CMD_SUSPEND 0x00010DEC @@ -89,6 +90,20 @@ struct asm_multi_channel_pcm_fmt_blk_v2 { u8 channel_mapping[PCM_MAX_NUM_CHANNEL]; } __packed; +struct asm_flac_fmt_blk_v2 { + struct asm_data_cmd_media_fmt_update_v2 fmt_blk; + u16 is_stream_info_present; + u16 num_channels; + u16 min_blk_size; + u16 max_blk_size; + u16 md5_sum[8]; + u32 sample_rate; + u32 min_frame_size; + u32 max_frame_size; + u16 sample_size; + u16 reserved; +} __packed; + struct asm_stream_cmd_set_encdec_param { u32 param_id; u32 param_size; @@ -876,6 +891,9 @@ int q6asm_open_write(struct audio_client *ac, uint32_t format, case FORMAT_LINEAR_PCM: open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; break; + case SND_AUDIOCODEC_FLAC: + open->dec_fmt_id = ASM_MEDIA_FMT_FLAC; + break; default: dev_err(ac->dev, "Invalid format 0x%x\n", format); rc = -EINVAL; @@ -1021,6 +1039,42 @@ int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, } EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm); + +int q6asm_stream_media_format_block_flac(struct audio_client *ac, + struct q6asm_flac_cfg *cfg) +{ + struct asm_flac_fmt_blk_v2 *fmt; + struct apr_pkt *pkt; + void *p; + int rc, pkt_size; + + pkt_size = APR_HDR_SIZE + sizeof(*fmt); + p = kzalloc(pkt_size, GFP_KERNEL); + if (!p) + return -ENOMEM; + + pkt = p; + fmt = p + APR_HDR_SIZE; + + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + + pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; + fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); + fmt->is_stream_info_present = cfg->stream_info_present; + fmt->num_channels = cfg->ch_cfg; + fmt->min_blk_size = cfg->min_blk_size; + fmt->max_blk_size = cfg->max_blk_size; + fmt->sample_rate = cfg->sample_rate; + fmt->min_frame_size = cfg->min_frame_size; + fmt->max_frame_size = cfg->max_frame_size; + fmt->sample_size = cfg->sample_size; + + rc = q6asm_ac_send_cmd_sync(ac, pkt); + kfree(pkt); + + return rc; +} +EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_flac); /** * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture * @@ -1075,6 +1129,7 @@ int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac, } EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support); + /** * q6asm_read() - read data of period size from audio client * diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h index 9f5fb573e4a028..6764f55f7078a8 100644 --- a/sound/soc/qcom/qdsp6/q6asm.h +++ b/sound/soc/qcom/qdsp6/q6asm.h @@ -32,6 +32,19 @@ enum { #define NO_TIMESTAMP 0xFF00 #define FORMAT_LINEAR_PCM 0x0000 +struct q6asm_flac_cfg { + u32 sample_rate; + u32 ext_sample_rate; + u32 min_frame_size; + u32 max_frame_size; + u16 stream_info_present; + u16 min_blk_size; + u16 max_blk_size; + u16 ch_cfg; + u16 sample_size; + u16 md5_sum; +}; + typedef void (*q6asm_cb) (uint32_t opcode, uint32_t token, void *payload, void *priv); struct audio_client; @@ -54,6 +67,8 @@ int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, uint32_t rate, uint32_t channels, u8 channel_map[PCM_MAX_NUM_CHANNEL], uint16_t bits_per_sample); +int q6asm_stream_media_format_block_flac(struct audio_client *ac, + struct q6asm_flac_cfg *cfg); int q6asm_run(struct audio_client *ac, uint32_t flags, uint32_t msw_ts, uint32_t lsw_ts); int q6asm_run_nowait(struct audio_client *ac, uint32_t flags, uint32_t msw_ts, From 69efab0fc638704e100c3dfb29eac971a4c1cc29 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 15 Nov 2019 15:57:05 +0530 Subject: [PATCH 1743/1995] ASoC: qcom: q6asm-dai: add support to flac decoder Qualcomm DSPs also support the flac decoder, so add support for FLAC decoder and convert the snd_dec_flac params to qdsp format. Co-developed-by: Srinivas Kandagatla Signed-off-by: Srinivas Kandagatla Signed-off-by: Vinod Koul Link: https://lore.kernel.org/r/20191115102705.649976-4-vkoul@kernel.org Signed-off-by: Mark Brown --- sound/soc/qcom/qdsp6/q6asm-dai.c | 35 +++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c index f59353f510b8a2..8150c10f081ef2 100644 --- a/sound/soc/qcom/qdsp6/q6asm-dai.c +++ b/sound/soc/qcom/qdsp6/q6asm-dai.c @@ -626,8 +626,14 @@ static int q6asm_dai_compr_set_params(struct snd_compr_stream *stream, struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME); int dir = stream->direction; struct q6asm_dai_data *pdata; + struct q6asm_flac_cfg flac_cfg; struct device *dev = c->dev; int ret; + union snd_codec_options *codec_options; + struct snd_dec_flac *flac; + + codec_options = &(prtd->codec_param.codec.options); + memcpy(&prtd->codec_param, params, sizeof(*params)); @@ -664,6 +670,32 @@ static int q6asm_dai_compr_set_params(struct snd_compr_stream *stream, return ret; } + switch (params->codec.id) { + case SND_AUDIOCODEC_FLAC: + + memset(&flac_cfg, 0x0, sizeof(struct q6asm_flac_cfg)); + flac = &codec_options->flac_d; + + flac_cfg.ch_cfg = params->codec.ch_in; + flac_cfg.sample_rate = params->codec.sample_rate; + flac_cfg.stream_info_present = 1; + flac_cfg.sample_size = flac->sample_size; + flac_cfg.min_blk_size = flac->min_blk_size; + flac_cfg.max_blk_size = flac->max_blk_size; + flac_cfg.max_frame_size = flac->max_frame_size; + flac_cfg.min_frame_size = flac->min_frame_size; + + ret = q6asm_stream_media_format_block_flac(prtd->audio_client, + &flac_cfg); + if (ret < 0) { + dev_err(dev, "FLAC CMD Format block failed:%d\n", ret); + return -EIO; + } + break; + default: + break; + } + ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys, (prtd->pcm_size / prtd->periods), prtd->periods); @@ -759,8 +791,9 @@ static int q6asm_dai_compr_get_caps(struct snd_compr_stream *stream, caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE; caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS; caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS; - caps->num_codecs = 1; + caps->num_codecs = 2; caps->codecs[0] = SND_AUDIOCODEC_MP3; + caps->codecs[1] = SND_AUDIOCODEC_FLAC; return 0; } From 51af759a930c18d2ee450772e01c614564772b2a Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Mon, 18 Nov 2019 15:36:33 +0800 Subject: [PATCH 1744/1995] ASoC: wm2200: add missed operations in remove and probe failure This driver misses calls to pm_runtime_disable and regulator_bulk_disable in remove and a call to free_irq in probe failure. Add the calls to fix it. Signed-off-by: Chuhong Yuan Link: https://lore.kernel.org/r/20191118073633.28237-1-hslester96@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm2200.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index cf64e109c65878..7b087d94141bd1 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2410,6 +2410,8 @@ static int wm2200_i2c_probe(struct i2c_client *i2c, err_pm_runtime: pm_runtime_disable(&i2c->dev); + if (i2c->irq) + free_irq(i2c->irq, wm2200); err_reset: if (wm2200->pdata.reset) gpio_set_value_cansleep(wm2200->pdata.reset, 0); @@ -2426,12 +2428,15 @@ static int wm2200_i2c_remove(struct i2c_client *i2c) { struct wm2200_priv *wm2200 = i2c_get_clientdata(i2c); + pm_runtime_disable(&i2c->dev); if (i2c->irq) free_irq(i2c->irq, wm2200); if (wm2200->pdata.reset) gpio_set_value_cansleep(wm2200->pdata.reset, 0); if (wm2200->pdata.ldo_ena) gpio_set_value_cansleep(wm2200->pdata.ldo_ena, 0); + regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies), + wm2200->core_supplies); return 0; } From c194a3615baddc4f32133c163036d9bc284d94cc Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Mon, 18 Nov 2019 15:37:07 +0800 Subject: [PATCH 1745/1995] ASoC: wm5100: add missed pm_runtime_disable The driver forgets to call pm_runtime_disable in remove and probe failure. Add the calls to fix it. Signed-off-by: Chuhong Yuan Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20191118073707.28298-1-hslester96@gmail.com Signed-off-by: Mark Brown --- sound/soc/codecs/wm5100.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 4af0e519e6235f..91cc63c5a51fad 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2617,6 +2617,7 @@ static int wm5100_i2c_probe(struct i2c_client *i2c, return ret; err_reset: + pm_runtime_disable(&i2c->dev); if (i2c->irq) free_irq(i2c->irq, wm5100); wm5100_free_gpio(i2c); @@ -2640,6 +2641,7 @@ static int wm5100_i2c_remove(struct i2c_client *i2c) { struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c); + pm_runtime_disable(&i2c->dev); if (i2c->irq) free_irq(i2c->irq, wm5100); wm5100_free_gpio(i2c); From ecc776aef3085e3f45a6b8d4e22c7a5cd5fd85cc Mon Sep 17 00:00:00 2001 From: Slawomir Blauciak Date: Mon, 7 Oct 2019 11:49:06 +0200 Subject: [PATCH 1746/1995] ASoC: SOF: channel map structures This change adds stream map and channel map structures used for channel re-routing and stream aggregation. Signed-off-by: Slawomir Blauciak --- include/sound/sof/channel_map.h | 61 +++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 include/sound/sof/channel_map.h diff --git a/include/sound/sof/channel_map.h b/include/sound/sof/channel_map.h new file mode 100644 index 00000000000000..75e77b0b664bbc --- /dev/null +++ b/include/sound/sof/channel_map.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2019 Intel Corporation. All rights reserved. + */ + +#ifndef __IPC_CHANNEL_MAP_H__ +#define __IPC_CHANNEL_MAP_H__ + +#include +#include + +/** + * \brief Channel map, specifies transformation of one-to-many or many-to-one. + * + * In case of one-to-many specifies how the output channels are computed out of + * a single source channel, + * in case of many-to-one specifies how a single target channel is computed + * from a multichannel input stream. + * + * Channel index specifies position of the channel in the stream on the 'one' + * side. + * + * Ext ID is the identifier of external part of the transformation. Depending + * on the context, it may be pipeline ID, dai ID, ... + * + * Channel mask describes which channels are taken into account on the "many" + * side. Bit[i] set to 1 means that i-th channel is used for computation + * (either as source or as a target). + * + * Channel mask is followed by array of coefficients in Q2.30 format, + * one per each channel set in the mask (left to right, LS bit set in the + * mask corresponds to ch_coeffs[0]). + */ +struct sof_ipc_channel_map { + uint32_t ch_index; + uint32_t ext_id; + uint32_t ch_mask; + uint32_t reserved; + int32_t ch_coeffs[0]; +} __packed; + +/** + * \brief Complete map for each channel of a multichannel stream. + * + * num_ch_map Specifies number of items in the ch_map. + * More than one transformation per a single channel is allowed (in case + * multiple external entities are transformed). + * A channel may be skipped in the transformation list, then it is filled + * with 0's by the transformation function. + */ +struct sof_ipc_stream_map { + struct sof_ipc_cmd_hdr hdr; + uint32_t num_ch_map; + uint32_t reserved[3]; + struct sof_ipc_channel_map ch_map[0]; +} __packed; + +#endif /* __IPC_CHANNEL_MAP_H__ */ From 6a2162249965e91eed480f68153fea25701b1136 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 15 Nov 2019 14:19:05 +0200 Subject: [PATCH 1747/1995] [DEBUG][CI]travis: Add build for arm64 For the moment the only arm64 platforms supporting SOF are NXP's i.MX8/i.MX8X. .config file used to create the final Image is obtained like this; * first create arm64 defconfig (this will enable *huge* amounts of config options) * merge it with imx-no-bloat (this will remove all arm64 platform configs except IMX) * finally merge it with sof-defconfig Signed-off-by: Daniel Baluta --- .travis.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d226c5e6e38d14..f7a05d36d2c3d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ git: before_install: - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test - sudo apt-get update -qq - - sudo apt-get install -y python-ply python-git libelf-dev codespell sparse fakeroot gcc-7 g++-7 + - sudo apt-get install -y python-ply python-git libelf-dev codespell sparse fakeroot gcc-7 g++-7 gcc-aarch64-linux-gnu - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 70 --slave /usr/bin/g++ g++ /usr/bin/g++-7 - git clone https://github.com/thesofproject/kconfig.git @@ -47,3 +47,9 @@ jobs: - make defconfig - scripts/kconfig/merge_config.sh .config kconfig/base-defconfig kconfig/sst-defconfig - KCFLAGS="-Wall -Werror" make -j`getconf _NPROCESSORS_ONLN` + - name: "BUILD SOF Kernel arm64" + script: + - export ARCH=arm64 CROSS_COMPILE=/usr/bin/aarch64-linux-gnu- + - make defconfig + - scripts/kconfig/merge_config.sh .config kconfig/nobloat-imx-defconfig kconfig/sof-defconfig + - KCFLAGS="-Wall -Werror" make -j`getconf _NPROCESSORS_ONLN` From 575cb13eead8c75a63077443b079434fec8f76bf Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 5 Nov 2019 20:05:11 -0800 Subject: [PATCH 1748/1995] ASoC: SOF: topology: remove snd_sof_init_topology() Remove snd_sof_init_topology() as it is never used. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/sof-priv.h | 2 -- sound/soc/sof/topology.c | 9 --------- 2 files changed, 11 deletions(-) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index c7c2c70ee4d04d..31f0eb31598a46 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -585,8 +585,6 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc, * There is no snd_sof_free_topology since topology components will * be freed by snd_soc_unregister_component, */ -int snd_sof_init_topology(struct snd_sof_dev *sdev, - struct snd_soc_tplg_ops *ops); int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file); int snd_sof_complete_pipeline(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index d82ab981e8408a..b8701d3407ad1e 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -3463,15 +3463,6 @@ static struct snd_soc_tplg_ops sof_tplg_ops = { .bytes_ext_ops_count = ARRAY_SIZE(sof_bytes_ext_ops), }; -int snd_sof_init_topology(struct snd_sof_dev *sdev, - struct snd_soc_tplg_ops *ops) -{ - /* TODO: support linked list of topologies */ - sdev->tplg_ops = ops; - return 0; -} -EXPORT_SYMBOL(snd_sof_init_topology); - int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file) { const struct firmware *fw; From 9753e6e8860b076546f29fc302fe007d859553d1 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 23 Oct 2019 09:14:54 -0700 Subject: [PATCH 1749/1995] ASoC: SOF: core: modify the signature for snd_sof_create_page_table Modify the signature for snd_sof_create_page_table to take struct device pointer as an argument instead of struct snd_sof_dev as this will be used by both the SOF core device and its clients. Also, move the definition out of core.c to utils.c. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 59 --------------------------------------- sound/soc/sof/pcm.c | 2 +- sound/soc/sof/sof-priv.h | 2 +- sound/soc/sof/trace.c | 4 +-- sound/soc/sof/utils.c | 60 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 64 insertions(+), 63 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 805918d3bcc09d..6a7f342203e93b 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include "sof-priv.h" @@ -213,64 +212,6 @@ void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, } EXPORT_SYMBOL(snd_sof_get_status); -/* - * Generic buffer page table creation. - * Take the each physical page address and drop the least significant unused - * bits from each (based on PAGE_SIZE). Then pack valid page address bits - * into compressed page table. - */ - -int snd_sof_create_page_table(struct snd_sof_dev *sdev, - struct snd_dma_buffer *dmab, - unsigned char *page_table, size_t size) -{ - int i, pages; - - pages = snd_sgbuf_aligned_pages(size); - - dev_dbg(sdev->dev, "generating page table for %p size 0x%zx pages %d\n", - dmab->area, size, pages); - - for (i = 0; i < pages; i++) { - /* - * The number of valid address bits for each page is 20. - * idx determines the byte position within page_table - * where the current page's address is stored - * in the compressed page_table. - * This can be calculated by multiplying the page number by 2.5. - */ - u32 idx = (5 * i) >> 1; - u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT; - u8 *pg_table; - - dev_vdbg(sdev->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); - - pg_table = (u8 *)(page_table + idx); - - /* - * pagetable compression: - * byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 - * ___________pfn 0__________ __________pfn 1___________ _pfn 2... - * .... .... .... .... .... .... .... .... .... .... .... - * It is created by: - * 1. set current location to 0, PFN index i to 0 - * 2. put pfn[i] at current location in Little Endian byte order - * 3. calculate an intermediate value as - * x = (pfn[i+1] << 4) | (pfn[i] & 0xf) - * 4. put x at offset (current location + 2) in LE byte order - * 5. increment current location by 5 bytes, increment i by 2 - * 6. continue to (2) - */ - if (i & 1) - put_unaligned_le32((pg_table[0] & 0xf) | pfn << 4, - pg_table); - else - put_unaligned_le32(pfn, pg_table); - } - - return pages; -} - /* * SOF Driver enumeration. */ diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 549238a98b2ab5..9fd73ef08904c3 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -33,7 +33,7 @@ static int create_page_table(struct snd_soc_component *component, if (!spcm) return -EINVAL; - return snd_sof_create_page_table(sdev, dmab, + return snd_sof_create_page_table(sdev->dev, dmab, spcm->stream[stream].page_table.area, size); } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 31f0eb31598a46..18dd832f2053a8 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -499,7 +499,7 @@ int snd_sof_set_d0_substate(struct snd_sof_dev *sdev, void snd_sof_new_platform_drv(struct snd_sof_dev *sdev); -int snd_sof_create_page_table(struct snd_sof_dev *sdev, +int snd_sof_create_page_table(struct device *dev, struct snd_dma_buffer *dmab, unsigned char *page_table, size_t size); diff --git a/sound/soc/sof/trace.c b/sound/soc/sof/trace.c index b0e4556c8536a3..4bb65030819d31 100644 --- a/sound/soc/sof/trace.c +++ b/sound/soc/sof/trace.c @@ -250,8 +250,8 @@ int snd_sof_init_trace(struct snd_sof_dev *sdev) } /* create compressed page table for audio firmware */ - ret = snd_sof_create_page_table(sdev, &sdev->dmatb, sdev->dmatp.area, - sdev->dmatb.bytes); + ret = snd_sof_create_page_table(sdev->dev, &sdev->dmatb, + sdev->dmatp.area, sdev->dmatb.bytes); if (ret < 0) goto table_err; diff --git a/sound/soc/sof/utils.c b/sound/soc/sof/utils.c index 2ac4c3da03206d..9831eb57df6ce0 100644 --- a/sound/soc/sof/utils.c +++ b/sound/soc/sof/utils.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include "sof-priv.h" @@ -110,3 +111,62 @@ void sof_block_read(struct snd_sof_dev *sdev, u32 bar, u32 offset, void *dest, memcpy_fromio(dest, src, size); } EXPORT_SYMBOL(sof_block_read); + +/* + * Generic buffer page table creation. + * Take the each physical page address and drop the least significant unused + * bits from each (based on PAGE_SIZE). Then pack valid page address bits + * into compressed page table. + */ + +int snd_sof_create_page_table(struct device *dev, + struct snd_dma_buffer *dmab, + unsigned char *page_table, size_t size) +{ + int i, pages; + + pages = snd_sgbuf_aligned_pages(size); + + dev_dbg(dev, "generating page table for %p size 0x%zx pages %d\n", + dmab->area, size, pages); + + for (i = 0; i < pages; i++) { + /* + * The number of valid address bits for each page is 20. + * idx determines the byte position within page_table + * where the current page's address is stored + * in the compressed page_table. + * This can be calculated by multiplying the page number by 2.5. + */ + u32 idx = (5 * i) >> 1; + u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT; + u8 *pg_table; + + dev_vdbg(dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); + + pg_table = (u8 *)(page_table + idx); + + /* + * pagetable compression: + * byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 + * ___________pfn 0__________ __________pfn 1___________ _pfn 2... + * .... .... .... .... .... .... .... .... .... .... .... + * It is created by: + * 1. set current location to 0, PFN index i to 0 + * 2. put pfn[i] at current location in Little Endian byte order + * 3. calculate an intermediate value as + * x = (pfn[i+1] << 4) | (pfn[i] & 0xf) + * 4. put x at offset (current location + 2) in LE byte order + * 5. increment current location by 5 bytes, increment i by 2 + * 6. continue to (2) + */ + if (i & 1) + put_unaligned_le32((pg_table[0] & 0xf) | pfn << 4, + pg_table); + else + put_unaligned_le32(pfn, pg_table); + } + + return pages; +} +EXPORT_SYMBOL(snd_sof_create_page_table); From ec3f7f6ca890a2f0fc56e3690445db820294f77a Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 5 Nov 2019 21:28:35 -0800 Subject: [PATCH 1750/1995] ASoC: SOF: core: move check for runtime callbacks to core For some platforms, the refcount is explicitly incremented to prevent it from entering runtime suspend. This should be be done during probe in the core instead of being done in the PCM driver. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 8 ++++++++ sound/soc/sof/pcm.c | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 6a7f342203e93b..d8446fb9fdded8 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -355,6 +355,14 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) dev_dbg(sdev->dev, "created machine %s\n", dev_name(&plat_data->pdev_mach->dev)); + /* + * Some platforms in SOF, ex: BYT, may not have their platform PM + * callbacks set. Increment the usage count so as to + * prevent the device from entering runtime suspend. + */ + if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume) + pm_runtime_get_noresume(sdev->dev); + if (plat_data->sof_probe_complete) plat_data->sof_probe_complete(sdev->dev); diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 9fd73ef08904c3..a9c47f6bf657f8 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -741,14 +741,6 @@ static int sof_pcm_probe(struct snd_soc_component *component) return ret; } - /* - * Some platforms in SOF, ex: BYT, may not have their platform PM - * callbacks set. Increment the usage count so as to - * prevent the device from entering runtime suspend. - */ - if (!sof_ops(sdev)->runtime_suspend || !sof_ops(sdev)->runtime_resume) - pm_runtime_get_noresume(sdev->dev); - return ret; } From da7ecf7cff4f79f2717dfdceb90935cb0e639519 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 16 Oct 2019 20:54:17 -0700 Subject: [PATCH 1751/1995] ASoC: SOF: Introduce default_fw_filename member in sof_dev_desc Currently the FW filename is obtained from the ACPI matching table when determining which machine driver to use. In preparation for making the machine driver ACPI match optional for Device Tree platforms and moving the machine driver selection out of the SOF core, this patch introduces the default_fw_filename member in struct sof_dev_desc. Once the machine driver selection is moved out of SOF core, the nocodec_fw_filename will become obsolete and will be removed. Signed-off-by: Ranjani Sridharan Signed-off-by: Daniel Baluta --- include/sound/sof.h | 3 +++ sound/soc/sof/sof-acpi-dev.c | 5 +++++ sound/soc/sof/sof-of-dev.c | 1 + sound/soc/sof/sof-pci-dev.c | 9 +++++++++ 4 files changed, 18 insertions(+) diff --git a/include/sound/sof.h b/include/sound/sof.h index 479101736ee063..1723478db4a21c 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -91,6 +91,9 @@ struct sof_dev_desc { const char *default_fw_path; const char *default_tplg_path; + /* default firmware name */ + const char *default_fw_filename; + const struct snd_sof_dsp_ops *ops; const struct sof_arch_ops *arch_ops; }; diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index df318f50dd0ba4..22e13ef098119a 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -45,6 +45,7 @@ static const struct sof_dev_desc sof_acpi_haswell_desc = { .chip_info = &hsw_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-hsw.ri", .nocodec_fw_filename = "sof-hsw.ri", .nocodec_tplg_filename = "sof-hsw-nocodec.tplg", .ops = &sof_hsw_ops, @@ -62,6 +63,7 @@ static const struct sof_dev_desc sof_acpi_broadwell_desc = { .chip_info = &bdw_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-bdw.ri", .nocodec_fw_filename = "sof-bdw.ri", .nocodec_tplg_filename = "sof-bdw-nocodec.tplg", .ops = &sof_bdw_ops, @@ -81,6 +83,7 @@ static const struct sof_dev_desc sof_acpi_baytrailcr_desc = { .chip_info = &byt_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-byt.ri", .nocodec_fw_filename = "sof-byt.ri", .nocodec_tplg_filename = "sof-byt-nocodec.tplg", .ops = &sof_byt_ops, @@ -96,6 +99,7 @@ static const struct sof_dev_desc sof_acpi_baytrail_desc = { .chip_info = &byt_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-byt.ri", .nocodec_fw_filename = "sof-byt.ri", .nocodec_tplg_filename = "sof-byt-nocodec.tplg", .ops = &sof_byt_ops, @@ -111,6 +115,7 @@ static const struct sof_dev_desc sof_acpi_cherrytrail_desc = { .chip_info = &cht_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-cht.ri", .nocodec_fw_filename = "sof-cht.ri", .nocodec_tplg_filename = "sof-cht-nocodec.tplg", .ops = &sof_cht_ops, diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c index 28a9692974e51d..81deb5582d7725 100644 --- a/sound/soc/sof/sof-of-dev.c +++ b/sound/soc/sof/sof-of-dev.c @@ -19,6 +19,7 @@ extern struct snd_sof_dsp_ops sof_imx8_ops; static struct sof_dev_desc sof_of_imx8qxp_desc = { .default_fw_path = "imx/sof", .default_tplg_path = "imx/sof-tplg", + .default_fw_filename = "sof-imx8.ri", .nocodec_fw_filename = "sof-imx8.ri", .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", .ops = &sof_imx8_ops, diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index bbeffd932de7fd..046bd57657ca3a 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -47,6 +47,7 @@ static const struct sof_dev_desc bxt_desc = { .chip_info = &apl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-apl.ri", .nocodec_fw_filename = "sof-apl.ri", .nocodec_tplg_filename = "sof-apl-nocodec.tplg", .ops = &sof_apl_ops, @@ -65,6 +66,7 @@ static const struct sof_dev_desc glk_desc = { .chip_info = &apl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-glk.ri", .nocodec_fw_filename = "sof-glk.ri", .nocodec_tplg_filename = "sof-glk-nocodec.tplg", .ops = &sof_apl_ops, @@ -93,6 +95,7 @@ static const struct sof_dev_desc tng_desc = { .chip_info = &tng_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-byt.ri", .nocodec_fw_filename = "sof-byt.ri", .nocodec_tplg_filename = "sof-byt.tplg", .ops = &sof_tng_ops, @@ -111,6 +114,7 @@ static const struct sof_dev_desc cnl_desc = { .chip_info = &cnl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-cnl.ri", .nocodec_fw_filename = "sof-cnl.ri", .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, @@ -129,6 +133,7 @@ static const struct sof_dev_desc cfl_desc = { .chip_info = &cnl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-cfl.ri", .nocodec_fw_filename = "sof-cfl.ri", .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, @@ -149,6 +154,7 @@ static const struct sof_dev_desc cml_desc = { .chip_info = &cnl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-cml.ri", .nocodec_fw_filename = "sof-cml.ri", .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, @@ -167,6 +173,7 @@ static const struct sof_dev_desc icl_desc = { .chip_info = &icl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-icl.ri", .nocodec_fw_filename = "sof-icl.ri", .nocodec_tplg_filename = "sof-icl-nocodec.tplg", .ops = &sof_cnl_ops, @@ -185,6 +192,7 @@ static const struct sof_dev_desc tgl_desc = { .chip_info = &tgl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-tgl.ri", .nocodec_fw_filename = "sof-tgl.ri", .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", .ops = &sof_cnl_ops, @@ -203,6 +211,7 @@ static const struct sof_dev_desc ehl_desc = { .chip_info = &ehl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-ehl.ri", .nocodec_fw_filename = "sof-ehl.ri", .nocodec_tplg_filename = "sof-ehl-nocodec.tplg", .ops = &sof_cnl_ops, From 172dfd1a1534736094e659d355cc1f40fee1d295 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 12 Nov 2019 22:42:21 -0800 Subject: [PATCH 1752/1995] ASoC: SOF: partition audio-related parts from SOF core Move all the audio-specific code in the core, audio-specific logic in the top-level PM callbacks and the core header files into a separate file (sof-audio.*) in preparation for adding an audio client device. In the process of moving all structure definitions for widget, routes, pcm's etc, the snd_sof_dev member in all these structs is replaced with the snd_soc_component member. Also, use the component device instead of the snd_sof_dev device wherever possible in the PCM component driver, control IO functions and the topology parser as the component device will be moved over to the client device later on. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/Makefile | 2 +- sound/soc/sof/control.c | 55 ++--- sound/soc/sof/core.c | 120 ---------- sound/soc/sof/intel/hda-dai.c | 1 + sound/soc/sof/intel/hda-pcm.c | 4 +- sound/soc/sof/intel/hda-stream.c | 1 + sound/soc/sof/ipc.c | 16 +- sound/soc/sof/pcm.c | 123 ++++++----- sound/soc/sof/pm.c | 219 +------------------ sound/soc/sof/sof-audio.c | 362 ++++++++++++++++++++++++++++++ sound/soc/sof/sof-audio.h | 207 ++++++++++++++++++ sound/soc/sof/sof-priv.h | 187 ---------------- sound/soc/sof/topology.c | 365 +++++++++++++++---------------- 13 files changed, 860 insertions(+), 802 deletions(-) create mode 100644 sound/soc/sof/sof-audio.c create mode 100644 sound/soc/sof/sof-audio.h diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 3639f7c006600b..ac83589e3a9c1c 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -3,7 +3,7 @@ ccflags-y += -DDEBUG snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ - control.o trace.o utils.o + control.o trace.o utils.o sof-audio.o snd-sof-pci-objs := sof-pci-dev.o snd-sof-acpi-objs := sof-acpi-dev.o diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 7baf7f1507c3a3..dfc412e2d95651 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -13,6 +13,7 @@ #include #include #include "sof-priv.h" +#include "sof-audio.h" static void update_mute_led(struct snd_sof_control *scontrol, struct snd_kcontrol *kcontrol, @@ -88,7 +89,7 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; + struct snd_soc_component *scomp = scontrol->scomp; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; bool change = false; @@ -104,8 +105,8 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol, } /* notify DSP of mixer updates */ - if (pm_runtime_active(sdev->dev)) - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + if (pm_runtime_active(scomp->dev)) + snd_sof_ipc_set_get_comp_data(scontrol, SOF_IPC_COMP_SET_VALUE, SOF_CTRL_TYPE_VALUE_CHAN_GET, SOF_CTRL_CMD_VOLUME, @@ -135,7 +136,7 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; + struct snd_soc_component *scomp = scontrol->scomp; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; bool change = false; @@ -153,8 +154,8 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol, update_mute_led(scontrol, kcontrol, ucontrol); /* notify DSP of mixer updates */ - if (pm_runtime_active(sdev->dev)) - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + if (pm_runtime_active(scomp->dev)) + snd_sof_ipc_set_get_comp_data(scontrol, SOF_IPC_COMP_SET_VALUE, SOF_CTRL_TYPE_VALUE_CHAN_GET, SOF_CTRL_CMD_SWITCH, @@ -185,7 +186,7 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, struct soc_enum *se = (struct soc_enum *)kcontrol->private_value; struct snd_sof_control *scontrol = se->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; + struct snd_soc_component *scomp = scontrol->scomp; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; unsigned int i, channels = scontrol->num_channels; bool change = false; @@ -200,8 +201,8 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol, } /* notify DSP of enum updates */ - if (pm_runtime_active(sdev->dev)) - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + if (pm_runtime_active(scomp->dev)) + snd_sof_ipc_set_get_comp_data(scontrol, SOF_IPC_COMP_SET_VALUE, SOF_CTRL_TYPE_VALUE_CHAN_GET, SOF_CTRL_CMD_ENUM, @@ -216,14 +217,14 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; + struct snd_soc_component *scomp = scontrol->scomp; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_abi_hdr *data = cdata->data; size_t size; int ret = 0; if (be->max > sizeof(ucontrol->value.bytes.data)) { - dev_err_ratelimited(sdev->dev, + dev_err_ratelimited(scomp->dev, "error: data max %d exceeds ucontrol data array size\n", be->max); return -EINVAL; @@ -231,7 +232,7 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, size = data->size + sizeof(*data); if (size > be->max) { - dev_err_ratelimited(sdev->dev, + dev_err_ratelimited(scomp->dev, "error: DSP sent %zu bytes max is %d\n", size, be->max); ret = -EINVAL; @@ -251,20 +252,20 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; + struct snd_soc_component *scomp = scontrol->scomp; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct sof_abi_hdr *data = cdata->data; size_t size = data->size + sizeof(*data); if (be->max > sizeof(ucontrol->value.bytes.data)) { - dev_err_ratelimited(sdev->dev, + dev_err_ratelimited(scomp->dev, "error: data max %d exceeds ucontrol data array size\n", be->max); return -EINVAL; } if (size > be->max) { - dev_err_ratelimited(sdev->dev, + dev_err_ratelimited(scomp->dev, "error: size too big %zu bytes max is %d\n", size, be->max); return -EINVAL; @@ -274,8 +275,8 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, memcpy(data, ucontrol->value.bytes.data, size); /* notify DSP of byte control updates */ - if (pm_runtime_active(sdev->dev)) - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + if (pm_runtime_active(scomp->dev)) + snd_sof_ipc_set_get_comp_data(scontrol, SOF_IPC_COMP_SET_DATA, SOF_CTRL_TYPE_DATA_SET, scontrol->cmd, @@ -291,7 +292,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; + struct snd_soc_component *scomp = scontrol->scomp; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct snd_ctl_tlv header; const struct snd_ctl_tlv __user *tlvd = @@ -307,14 +308,14 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, /* be->max is coming from topology */ if (header.length > be->max) { - dev_err_ratelimited(sdev->dev, "error: Bytes data size %d exceeds max %d.\n", + dev_err_ratelimited(scomp->dev, "error: Bytes data size %d exceeds max %d.\n", header.length, be->max); return -EINVAL; } /* Check that header id matches the command */ if (header.numid != scontrol->cmd) { - dev_err_ratelimited(sdev->dev, + dev_err_ratelimited(scomp->dev, "error: incorrect numid %d\n", header.numid); return -EINVAL; @@ -324,26 +325,26 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, return -EFAULT; if (cdata->data->magic != SOF_ABI_MAGIC) { - dev_err_ratelimited(sdev->dev, + dev_err_ratelimited(scomp->dev, "error: Wrong ABI magic 0x%08x.\n", cdata->data->magic); return -EINVAL; } if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { - dev_err_ratelimited(sdev->dev, "error: Incompatible ABI version 0x%08x.\n", + dev_err_ratelimited(scomp->dev, "error: Incompatible ABI version 0x%08x.\n", cdata->data->abi); return -EINVAL; } if (cdata->data->size + sizeof(const struct sof_abi_hdr) > be->max) { - dev_err_ratelimited(sdev->dev, "error: Mismatch in ABI data size (truncated?).\n"); + dev_err_ratelimited(scomp->dev, "error: Mismatch in ABI data size (truncated?).\n"); return -EINVAL; } /* notify DSP of byte control updates */ - if (pm_runtime_active(sdev->dev)) - snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + if (pm_runtime_active(scomp->dev)) + snd_sof_ipc_set_get_comp_data(scontrol, SOF_IPC_COMP_SET_DATA, SOF_CTRL_TYPE_DATA_SET, scontrol->cmd, @@ -359,7 +360,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; - struct snd_sof_dev *sdev = scontrol->sdev; + struct snd_soc_component *scomp = scontrol->scomp; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; struct snd_ctl_tlv header; struct snd_ctl_tlv __user *tlvd = @@ -382,7 +383,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, /* check data size doesn't exceed max coming from topology */ if (data_size > be->max) { - dev_err_ratelimited(sdev->dev, "error: user data size %d exceeds max size %d.\n", + dev_err_ratelimited(scomp->dev, "error: user data size %d exceeds max size %d.\n", data_size, be->max); ret = -EINVAL; goto out; diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index d8446fb9fdded8..9832322adbec0e 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -24,126 +24,6 @@ MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)"); #define TIMEOUT_DEFAULT_IPC_MS 500 #define TIMEOUT_DEFAULT_BOOT_MS 2000 -/* - * Generic object lookup APIs. - */ - -struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev, - const char *name) -{ - struct snd_sof_pcm *spcm; - - list_for_each_entry(spcm, &sdev->pcm_list, list) { - /* match with PCM dai name */ - if (strcmp(spcm->pcm.dai_name, name) == 0) - return spcm; - - /* match with playback caps name if set */ - if (*spcm->pcm.caps[0].name && - !strcmp(spcm->pcm.caps[0].name, name)) - return spcm; - - /* match with capture caps name if set */ - if (*spcm->pcm.caps[1].name && - !strcmp(spcm->pcm.caps[1].name, name)) - return spcm; - } - - return NULL; -} - -struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev, - unsigned int comp_id, - int *direction) -{ - struct snd_sof_pcm *spcm; - - list_for_each_entry(spcm, &sdev->pcm_list, list) { - if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id == comp_id) { - *direction = SNDRV_PCM_STREAM_PLAYBACK; - return spcm; - } - if (spcm->stream[SNDRV_PCM_STREAM_CAPTURE].comp_id == comp_id) { - *direction = SNDRV_PCM_STREAM_CAPTURE; - return spcm; - } - } - - return NULL; -} - -struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev, - unsigned int pcm_id) -{ - struct snd_sof_pcm *spcm; - - list_for_each_entry(spcm, &sdev->pcm_list, list) { - if (le32_to_cpu(spcm->pcm.pcm_id) == pcm_id) - return spcm; - } - - return NULL; -} - -struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev, - const char *name) -{ - struct snd_sof_widget *swidget; - - list_for_each_entry(swidget, &sdev->widget_list, list) { - if (strcmp(name, swidget->widget->name) == 0) - return swidget; - } - - return NULL; -} - -/* find widget by stream name and direction */ -struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev, - const char *pcm_name, int dir) -{ - struct snd_sof_widget *swidget; - enum snd_soc_dapm_type type; - - if (dir == SNDRV_PCM_STREAM_PLAYBACK) - type = snd_soc_dapm_aif_in; - else - type = snd_soc_dapm_aif_out; - - list_for_each_entry(swidget, &sdev->widget_list, list) { - if (!strcmp(pcm_name, swidget->widget->sname) && swidget->id == type) - return swidget; - } - - return NULL; -} - -struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev, - const char *name) -{ - struct snd_sof_dai *dai; - - list_for_each_entry(dai, &sdev->dai_list, list) { - if (dai->name && (strcmp(name, dai->name) == 0)) - return dai; - } - - return NULL; -} - -bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev) -{ - struct snd_sof_pcm *spcm; - - list_for_each_entry(spcm, &sdev->pcm_list, list) { - if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored || - spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored) - return true; - } - - return false; -} - /* * FW Panic/fault handling. */ diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 8796f385be76c1..2d9ac0035bd2fc 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -11,6 +11,7 @@ #include #include #include "../sof-priv.h" +#include "../sof-audio.h" #include "hda.h" #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c index 575f5f5877d85a..23872f6e708dc6 100644 --- a/sound/soc/sof/intel/hda-pcm.c +++ b/sound/soc/sof/intel/hda-pcm.c @@ -17,6 +17,7 @@ #include #include +#include "../sof-audio.h" #include "../ops.h" #include "hda.h" @@ -147,12 +148,13 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *scomp = sdev->component; struct hdac_stream *hstream = substream->runtime->private_data; struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; struct snd_sof_pcm *spcm; snd_pcm_uframes_t pos; - spcm = snd_sof_find_spcm_dai(sdev, rtd); + spcm = snd_sof_find_spcm_dai(scomp, rtd); if (!spcm) { dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n", rtd->dai_link->id); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 29ab4328167016..92643a801f4f96 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -20,6 +20,7 @@ #include #include #include "../ops.h" +#include "../sof-audio.h" #include "hda.h" /* diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 5994e10733642a..293c5ae8e88274 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -15,6 +15,7 @@ #include #include "sof-priv.h" +#include "sof-audio.h" #include "ops.h" static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id); @@ -412,12 +413,13 @@ static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id) static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) { + struct snd_soc_component *scomp = sdev->component; struct snd_sof_pcm_stream *stream; struct sof_ipc_stream_posn posn; struct snd_sof_pcm *spcm; int direction; - spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction); + spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction); if (!spcm) { dev_err(sdev->dev, "error: period elapsed for unknown stream, msg_id %d\n", @@ -441,12 +443,13 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id) /* DSP notifies host of an XRUN within FW */ static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id) { + struct snd_soc_component *scomp = sdev->component; struct snd_sof_pcm_stream *stream; struct sof_ipc_stream_posn posn; struct snd_sof_pcm *spcm; int direction; - spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction); + spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction); if (!spcm) { dev_err(sdev->dev, "error: XRUN for unknown stream, msg_id %d\n", msg_id); @@ -488,10 +491,11 @@ static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd) } /* get stream position IPC - use faster MMIO method if available on platform */ -int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev, +int snd_sof_ipc_stream_posn(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm, int direction, struct sof_ipc_stream_posn *posn) { + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc_stream stream; int err; @@ -620,15 +624,15 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev, /* * IPC get()/set() for kcontrols. */ -int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc, - struct snd_sof_control *scontrol, +int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, u32 ipc_cmd, enum sof_ipc_ctrl_type ctrl_type, enum sof_ipc_ctrl_cmd ctrl_cmd, bool send) { + struct snd_soc_component *scomp = scontrol->scomp; struct sof_ipc_ctrl_data *cdata = scontrol->control_data; - struct snd_sof_dev *sdev = ipc->sdev; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc_fw_ready *ready = &sdev->fw_ready; struct sof_ipc_fw_version *v = &ready->version; struct sof_ipc_ctrl_data_params sparams; diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index a9c47f6bf657f8..54ec78799c30c5 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -14,38 +14,38 @@ #include #include #include "sof-priv.h" +#include "sof-audio.h" #include "ops.h" -#define DRV_NAME "sof-audio-component" - /* Create DMA buffer page table for DSP */ static int create_page_table(struct snd_soc_component *component, struct snd_pcm_substream *substream, unsigned char *dma_area, size_t size) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream); int stream = substream->stream; - spcm = snd_sof_find_spcm_dai(sdev, rtd); + spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) return -EINVAL; - return snd_sof_create_page_table(sdev->dev, dmab, + return snd_sof_create_page_table(component->dev, dmab, spcm->stream[stream].page_table.area, size); } static int sof_pcm_dsp_params(struct snd_sof_pcm *spcm, struct snd_pcm_substream *substream, const struct sof_ipc_pcm_params_reply *reply) { - struct snd_sof_dev *sdev = spcm->sdev; + struct snd_soc_component *scomp = spcm->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + /* validate offset */ int ret = snd_sof_ipc_pcm_params(sdev, substream, reply); if (ret < 0) - dev_err(sdev->dev, "error: got wrong reply for PCM %d\n", + dev_err(scomp->dev, "error: got wrong reply for PCM %d\n", spcm->pcm.pcm_id); return ret; @@ -70,13 +70,12 @@ void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); struct snd_sof_pcm *spcm; - spcm = snd_sof_find_spcm_dai(sdev, rtd); + spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) { - dev_err(sdev->dev, + dev_err(component->dev, "error: period elapsed for unknown stream!\n"); return; } @@ -110,11 +109,11 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, if (rtd->dai_link->no_pcm) return 0; - spcm = snd_sof_find_spcm_dai(sdev, rtd); + spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) return -EINVAL; - dev_dbg(sdev->dev, "pcm: hw params stream %d dir %d\n", + dev_dbg(component->dev, "pcm: hw params stream %d dir %d\n", spcm->pcm.pcm_id, substream->stream); memset(&pcm, 0, sizeof(pcm)); @@ -122,7 +121,7 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, /* allocate audio buffer pages */ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); if (ret < 0) { - dev_err(sdev->dev, "error: could not allocate %d bytes for PCM %d\n", + dev_err(component->dev, "error: could not allocate %d bytes for PCM %d\n", params_buffer_bytes(params), spcm->pcm.pcm_id); return ret; } @@ -187,17 +186,17 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, params, &pcm.params); if (ret < 0) { - dev_err(sdev->dev, "error: platform hw params failed\n"); + dev_err(component->dev, "error: platform hw params failed\n"); return ret; } - dev_dbg(sdev->dev, "stream_tag %d", pcm.params.stream_tag); + dev_dbg(component->dev, "stream_tag %d", pcm.params.stream_tag); /* send IPC to the DSP */ ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm), &ipc_params_reply, sizeof(ipc_params_reply)); if (ret < 0) { - dev_err(sdev->dev, "error: hw params ipc failed for stream %d\n", + dev_err(component->dev, "error: hw params ipc failed for stream %d\n", pcm.params.stream_tag); return ret; } @@ -247,12 +246,12 @@ static int sof_pcm_hw_free(struct snd_soc_component *component, if (rtd->dai_link->no_pcm) return 0; - spcm = snd_sof_find_spcm_dai(sdev, rtd); + spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) return -EINVAL; - dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id, - substream->stream); + dev_dbg(component->dev, "pcm: free stream %d dir %d\n", + spcm->pcm.pcm_id, substream->stream); if (spcm->prepared[substream->stream]) { ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); @@ -266,7 +265,7 @@ static int sof_pcm_hw_free(struct snd_soc_component *component, ret = snd_sof_pcm_platform_hw_free(sdev, substream); if (ret < 0) { - dev_err(sdev->dev, "error: platform hw free failed\n"); + dev_err(component->dev, "error: platform hw free failed\n"); err = ret; } @@ -277,7 +276,6 @@ static int sof_pcm_prepare(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_pcm *spcm; int ret; @@ -285,21 +283,22 @@ static int sof_pcm_prepare(struct snd_soc_component *component, if (rtd->dai_link->no_pcm) return 0; - spcm = snd_sof_find_spcm_dai(sdev, rtd); + spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) return -EINVAL; if (spcm->prepared[substream->stream]) return 0; - dev_dbg(sdev->dev, "pcm: prepare stream %d dir %d\n", spcm->pcm.pcm_id, - substream->stream); + dev_dbg(component->dev, "pcm: prepare stream %d dir %d\n", + spcm->pcm.pcm_id, substream->stream); /* set hw_params */ ret = sof_pcm_hw_params(component, substream, &spcm->params[substream->stream]); if (ret < 0) { - dev_err(sdev->dev, "error: set pcm hw_params after resume\n"); + dev_err(component->dev, + "error: set pcm hw_params after resume\n"); return ret; } @@ -326,11 +325,11 @@ static int sof_pcm_trigger(struct snd_soc_component *component, if (rtd->dai_link->no_pcm) return 0; - spcm = snd_sof_find_spcm_dai(sdev, rtd); + spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) return -EINVAL; - dev_dbg(sdev->dev, "pcm: trigger stream %d dir %d cmd %d\n", + dev_dbg(component->dev, "pcm: trigger stream %d dir %d cmd %d\n", spcm->pcm.pcm_id, substream->stream, cmd); stream.hdr.size = sizeof(stream); @@ -359,7 +358,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component, /* set up hw_params */ ret = sof_pcm_prepare(component, substream); if (ret < 0) { - dev_err(sdev->dev, + dev_err(component->dev, "error: failed to set up hw_params upon resume\n"); return ret; } @@ -396,7 +395,8 @@ static int sof_pcm_trigger(struct snd_soc_component *component, reset_hw_params = true; break; default: - dev_err(sdev->dev, "error: unhandled trigger cmd %d\n", cmd); + dev_err(component->dev, "error: unhandled trigger cmd %d\n", + cmd); return -EINVAL; } @@ -438,7 +438,7 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_soc_component *component, if (sof_ops(sdev)->pcm_pointer) return sof_ops(sdev)->pcm_pointer(sdev, substream); - spcm = snd_sof_find_spcm_dai(sdev, rtd); + spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) return -EINVAL; @@ -448,7 +448,8 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_soc_component *component, dai = bytes_to_frames(substream->runtime, spcm->stream[substream->stream].posn.dai_posn); - dev_dbg(sdev->dev, "PCM: stream %d dir %d DMA position %lu DAI position %lu\n", + dev_dbg(component->dev, + "PCM: stream %d dir %d DMA position %lu DAI position %lu\n", spcm->pcm.pcm_id, substream->stream, host, dai); return host; @@ -469,12 +470,12 @@ static int sof_pcm_open(struct snd_soc_component *component, if (rtd->dai_link->no_pcm) return 0; - spcm = snd_sof_find_spcm_dai(sdev, rtd); + spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) return -EINVAL; - dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id, - substream->stream); + dev_dbg(component->dev, "pcm: open stream %d dir %d\n", + spcm->pcm.pcm_id, substream->stream); INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work, sof_pcm_period_elapsed_work); @@ -504,13 +505,13 @@ static int sof_pcm_open(struct snd_soc_component *component, */ runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max); - dev_dbg(sdev->dev, "period min %zd max %zd bytes\n", + dev_dbg(component->dev, "period min %zd max %zd bytes\n", runtime->hw.period_bytes_min, runtime->hw.period_bytes_max); - dev_dbg(sdev->dev, "period count %d max %d\n", + dev_dbg(component->dev, "period count %d max %d\n", runtime->hw.periods_min, runtime->hw.periods_max); - dev_dbg(sdev->dev, "buffer max %zd bytes\n", + dev_dbg(component->dev, "buffer max %zd bytes\n", runtime->hw.buffer_bytes_max); /* set wait time - TODO: come from topology */ @@ -523,7 +524,7 @@ static int sof_pcm_open(struct snd_soc_component *component, ret = snd_sof_pcm_platform_open(sdev, substream); if (ret < 0) - dev_err(sdev->dev, "error: pcm open failed %d\n", ret); + dev_err(component->dev, "error: pcm open failed %d\n", ret); return ret; } @@ -540,16 +541,16 @@ static int sof_pcm_close(struct snd_soc_component *component, if (rtd->dai_link->no_pcm) return 0; - spcm = snd_sof_find_spcm_dai(sdev, rtd); + spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) return -EINVAL; - dev_dbg(sdev->dev, "pcm: close stream %d dir %d\n", spcm->pcm.pcm_id, - substream->stream); + dev_dbg(component->dev, "pcm: close stream %d dir %d\n", + spcm->pcm.pcm_id, substream->stream); err = snd_sof_pcm_platform_close(sdev, substream); if (err < 0) { - dev_err(sdev->dev, "error: pcm close failed %d\n", + dev_err(component->dev, "error: pcm close failed %d\n", err); /* * keep going, no point in preventing the close @@ -575,14 +576,14 @@ static int sof_pcm_new(struct snd_soc_component *component, int stream = SNDRV_PCM_STREAM_PLAYBACK; /* find SOF PCM for this RTD */ - spcm = snd_sof_find_spcm_dai(sdev, rtd); + spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) { - dev_warn(sdev->dev, "warn: can't find PCM with DAI ID %d\n", + dev_warn(component->dev, "warn: can't find PCM with DAI ID %d\n", rtd->dai_link->id); return 0; } - dev_dbg(sdev->dev, "creating new PCM %s\n", spcm->pcm.pcm_name); + dev_dbg(component->dev, "creating new PCM %s\n", spcm->pcm.pcm_name); /* do we need to pre-allocate playback audio buffer pages */ if (!spcm->pcm.playback) @@ -591,7 +592,8 @@ static int sof_pcm_new(struct snd_soc_component *component, caps = &spcm->pcm.caps[stream]; /* pre-allocate playback audio buffer pages */ - dev_dbg(sdev->dev, "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n", + dev_dbg(component->dev, + "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n", caps->name, caps->buffer_size_min, caps->buffer_size_max); snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream, @@ -608,7 +610,8 @@ static int sof_pcm_new(struct snd_soc_component *component, caps = &spcm->pcm.caps[stream]; /* pre-allocate capture audio buffer pages */ - dev_dbg(sdev->dev, "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n", + dev_dbg(component->dev, + "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n", caps->name, caps->buffer_size_min, caps->buffer_size_max); snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream, @@ -629,14 +632,14 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, SNDRV_PCM_HW_PARAM_CHANNELS); struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); + snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); struct snd_sof_dai *dai = - snd_sof_find_dai(sdev, (char *)rtd->dai_link->name); + snd_sof_find_dai(component, (char *)rtd->dai_link->name); /* no topology exists for this BE, try a common configuration */ if (!dai) { - dev_warn(sdev->dev, "warning: no topology found for BE DAI %s config\n", + dev_warn(component->dev, + "warning: no topology found for BE DAI %s config\n", rtd->dai_link->name); /* set 48k, stereo, 16bits by default */ @@ -666,7 +669,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); break; default: - dev_err(sdev->dev, "error: No available DAI format!\n"); + dev_err(component->dev, "error: No available DAI format!\n"); return -EINVAL; } @@ -678,9 +681,9 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = dai->dai_config->ssp.tdm_slots; channels->max = dai->dai_config->ssp.tdm_slots; - dev_dbg(sdev->dev, + dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max); - dev_dbg(sdev->dev, + dev_dbg(component->dev, "channels_min: %d channels_max: %d\n", channels->min, channels->max); @@ -688,7 +691,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, case SOF_DAI_INTEL_DMIC: /* DMIC only supports 16 or 32 bit formats */ if (dai->comp_dai.config.frame_fmt == SOF_IPC_FRAME_S24_4LE) { - dev_err(sdev->dev, + dev_err(component->dev, "error: invalid fmt %d for DAI type %d\n", dai->comp_dai.config.frame_fmt, dai->dai_config->type); @@ -704,12 +707,12 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = dai->dai_config->esai.tdm_slots; channels->max = dai->dai_config->esai.tdm_slots; - dev_dbg(sdev->dev, + dev_dbg(component->dev, "channels_min: %d channels_max: %d\n", channels->min, channels->max); break; default: - dev_err(sdev->dev, "error: invalid DAI type %d\n", + dev_err(component->dev, "error: invalid DAI type %d\n", dai->dai_config->type); break; } @@ -734,9 +737,9 @@ static int sof_pcm_probe(struct snd_soc_component *component) if (!tplg_filename) return -ENOMEM; - ret = snd_sof_load_topology(sdev, tplg_filename); + ret = snd_sof_load_topology(component, tplg_filename); if (ret < 0) { - dev_err(sdev->dev, "error: failed to load DSP topology %d\n", + dev_err(component->dev, "error: failed to load DSP topology %d\n", ret); return ret; } diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 0fd5567237a8d5..d1a7b98886d13b 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -10,192 +10,7 @@ #include "ops.h" #include "sof-priv.h" - -static int sof_restore_kcontrols(struct snd_sof_dev *sdev) -{ - struct snd_sof_control *scontrol; - int ipc_cmd, ctrl_type; - int ret = 0; - - /* restore kcontrol values */ - list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { - /* reset readback offset for scontrol after resuming */ - scontrol->readback_offset = 0; - - /* notify DSP of kcontrol values */ - switch (scontrol->cmd) { - case SOF_CTRL_CMD_VOLUME: - case SOF_CTRL_CMD_ENUM: - case SOF_CTRL_CMD_SWITCH: - ipc_cmd = SOF_IPC_COMP_SET_VALUE; - ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET; - ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - ipc_cmd, ctrl_type, - scontrol->cmd, - true); - break; - case SOF_CTRL_CMD_BINARY: - ipc_cmd = SOF_IPC_COMP_SET_DATA; - ctrl_type = SOF_CTRL_TYPE_DATA_SET; - ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, - ipc_cmd, ctrl_type, - scontrol->cmd, - true); - break; - - default: - break; - } - - if (ret < 0) { - dev_err(sdev->dev, - "error: failed kcontrol value set for widget: %d\n", - scontrol->comp_id); - - return ret; - } - } - - return 0; -} - -static int sof_restore_pipelines(struct snd_sof_dev *sdev) -{ - struct snd_sof_widget *swidget; - struct snd_sof_route *sroute; - struct sof_ipc_pipe_new *pipeline; - struct snd_sof_dai *dai; - struct sof_ipc_comp_dai *comp_dai; - struct sof_ipc_cmd_hdr *hdr; - int ret; - - /* restore pipeline components */ - list_for_each_entry_reverse(swidget, &sdev->widget_list, list) { - struct sof_ipc_comp_reply r; - - /* skip if there is no private data */ - if (!swidget->private) - continue; - - switch (swidget->id) { - case snd_soc_dapm_dai_in: - case snd_soc_dapm_dai_out: - dai = swidget->private; - comp_dai = &dai->comp_dai; - ret = sof_ipc_tx_message(sdev->ipc, - comp_dai->comp.hdr.cmd, - comp_dai, sizeof(*comp_dai), - &r, sizeof(r)); - break; - case snd_soc_dapm_scheduler: - - /* - * During suspend, all DSP cores are powered off. - * Therefore upon resume, create the pipeline comp - * and power up the core that the pipeline is - * scheduled on. - */ - pipeline = swidget->private; - ret = sof_load_pipeline_ipc(sdev, pipeline, &r); - break; - default: - hdr = swidget->private; - ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, - swidget->private, hdr->size, - &r, sizeof(r)); - break; - } - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to load widget type %d with ID: %d\n", - swidget->widget->id, swidget->comp_id); - - return ret; - } - } - - /* restore pipeline connections */ - list_for_each_entry_reverse(sroute, &sdev->route_list, list) { - struct sof_ipc_pipe_comp_connect *connect; - struct sof_ipc_reply reply; - - /* skip if there's no private data */ - if (!sroute->private) - continue; - - connect = sroute->private; - - /* send ipc */ - ret = sof_ipc_tx_message(sdev->ipc, - connect->hdr.cmd, - connect, sizeof(*connect), - &reply, sizeof(reply)); - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to load route sink %s control %s source %s\n", - sroute->route->sink, - sroute->route->control ? sroute->route->control - : "none", - sroute->route->source); - - return ret; - } - } - - /* restore dai links */ - list_for_each_entry_reverse(dai, &sdev->dai_list, list) { - struct sof_ipc_reply reply; - struct sof_ipc_dai_config *config = dai->dai_config; - - if (!config) { - dev_err(sdev->dev, "error: no config for DAI %s\n", - dai->name); - continue; - } - - /* - * The link DMA channel would be invalidated for running - * streams but not for streams that were in the PAUSED - * state during suspend. So invalidate it here before setting - * the dai config in the DSP. - */ - if (config->type == SOF_DAI_INTEL_HDA) - config->hda.link_dma_ch = DMA_CHAN_INVALID; - - ret = sof_ipc_tx_message(sdev->ipc, - config->hdr.cmd, config, - config->hdr.size, - &reply, sizeof(reply)); - - if (ret < 0) { - dev_err(sdev->dev, - "error: failed to set dai config for %s\n", - dai->name); - - return ret; - } - } - - /* complete pipeline */ - list_for_each_entry(swidget, &sdev->widget_list, list) { - switch (swidget->id) { - case snd_soc_dapm_scheduler: - swidget->complete = - snd_sof_complete_pipeline(sdev, swidget); - break; - default: - break; - } - } - - /* restore pipeline kcontrols */ - ret = sof_restore_kcontrols(sdev); - if (ret < 0) - dev_err(sdev->dev, - "error: restoring kcontrols after resume\n"); - - return ret; -} +#include "sof-audio.h" static int sof_send_pm_ctx_ipc(struct snd_sof_dev *sdev, int cmd) { @@ -213,34 +28,6 @@ static int sof_send_pm_ctx_ipc(struct snd_sof_dev *sdev, int cmd) sizeof(pm_ctx), &reply, sizeof(reply)); } -static int sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev) -{ - struct snd_pcm_substream *substream; - struct snd_sof_pcm *spcm; - snd_pcm_state_t state; - int dir; - - /* - * SOF requires hw_params to be set-up internally upon resume. - * So, set the flag to indicate this for those streams that - * have been suspended. - */ - list_for_each_entry(spcm, &sdev->pcm_list, list) { - for (dir = 0; dir <= SNDRV_PCM_STREAM_CAPTURE; dir++) { - substream = spcm->stream[dir].substream; - if (!substream || !substream->runtime) - continue; - - state = substream->runtime->status->state; - if (state == SNDRV_PCM_STATE_SUSPENDED) - spcm->prepared[dir] = false; - } - } - - /* set internal flag for BE */ - return snd_sof_dsp_hw_params_upon_resume(sdev); -} - #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) static void sof_cache_debugfs(struct snd_sof_dev *sdev) { @@ -311,7 +98,7 @@ static int sof_resume(struct device *dev, bool runtime_resume) } /* restore pipelines */ - ret = sof_restore_pipelines(sdev); + ret = sof_restore_pipelines(sdev->dev); if (ret < 0) { dev_err(sdev->dev, "error: failed to restore pipeline after resume %d\n", @@ -346,7 +133,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) /* set restore_stream for all streams during system suspend */ if (!runtime_suspend) { - ret = sof_set_hw_params_upon_resume(sdev); + ret = sof_set_hw_params_upon_resume(sdev->dev); if (ret < 0) { dev_err(sdev->dev, "error: setting hw_params flag during suspend %d\n", diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c new file mode 100644 index 00000000000000..bf99d040c9c195 --- /dev/null +++ b/sound/soc/sof/sof-audio.c @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2019 Intel Corporation. All rights reserved. +// +// Author: Ranjani Sridharan +// + +#include "sof-audio.h" +#include "ops.h" + +bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev) +{ + struct snd_sof_pcm *spcm; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored || + spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored) + return true; + } + + return false; +} + +int sof_set_hw_params_upon_resume(struct device *dev) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + struct snd_pcm_substream *substream; + struct snd_sof_pcm *spcm; + snd_pcm_state_t state; + int dir; + + /* + * SOF requires hw_params to be set-up internally upon resume. + * So, set the flag to indicate this for those streams that + * have been suspended. + */ + list_for_each_entry(spcm, &sdev->pcm_list, list) { + for (dir = 0; dir <= SNDRV_PCM_STREAM_CAPTURE; dir++) { + substream = spcm->stream[dir].substream; + if (!substream || !substream->runtime) + continue; + + state = substream->runtime->status->state; + if (state == SNDRV_PCM_STATE_SUSPENDED) + spcm->prepared[dir] = false; + } + } + + /* set internal flag for BE */ + return snd_sof_dsp_hw_params_upon_resume(sdev); +} + +static int sof_restore_kcontrols(struct device *dev) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + struct snd_sof_control *scontrol; + int ipc_cmd, ctrl_type; + int ret = 0; + + /* restore kcontrol values */ + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { + /* reset readback offset for scontrol after resuming */ + scontrol->readback_offset = 0; + + /* notify DSP of kcontrol values */ + switch (scontrol->cmd) { + case SOF_CTRL_CMD_VOLUME: + case SOF_CTRL_CMD_ENUM: + case SOF_CTRL_CMD_SWITCH: + ipc_cmd = SOF_IPC_COMP_SET_VALUE; + ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET; + ret = snd_sof_ipc_set_get_comp_data(scontrol, + ipc_cmd, ctrl_type, + scontrol->cmd, + true); + break; + case SOF_CTRL_CMD_BINARY: + ipc_cmd = SOF_IPC_COMP_SET_DATA; + ctrl_type = SOF_CTRL_TYPE_DATA_SET; + ret = snd_sof_ipc_set_get_comp_data(scontrol, + ipc_cmd, ctrl_type, + scontrol->cmd, + true); + break; + + default: + break; + } + + if (ret < 0) { + dev_err(dev, + "error: failed kcontrol value set for widget: %d\n", + scontrol->comp_id); + + return ret; + } + } + + return 0; +} + +int sof_restore_pipelines(struct device *dev) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + struct snd_sof_widget *swidget; + struct snd_sof_route *sroute; + struct sof_ipc_pipe_new *pipeline; + struct snd_sof_dai *dai; + struct sof_ipc_comp_dai *comp_dai; + struct sof_ipc_cmd_hdr *hdr; + int ret; + + /* restore pipeline components */ + list_for_each_entry_reverse(swidget, &sdev->widget_list, list) { + struct sof_ipc_comp_reply r; + + /* skip if there is no private data */ + if (!swidget->private) + continue; + + switch (swidget->id) { + case snd_soc_dapm_dai_in: + case snd_soc_dapm_dai_out: + dai = swidget->private; + comp_dai = &dai->comp_dai; + ret = sof_ipc_tx_message(sdev->ipc, + comp_dai->comp.hdr.cmd, + comp_dai, sizeof(*comp_dai), + &r, sizeof(r)); + break; + case snd_soc_dapm_scheduler: + + /* + * During suspend, all DSP cores are powered off. + * Therefore upon resume, create the pipeline comp + * and power up the core that the pipeline is + * scheduled on. + */ + pipeline = swidget->private; + ret = sof_load_pipeline_ipc(dev, pipeline, &r); + break; + default: + hdr = swidget->private; + ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd, + swidget->private, hdr->size, + &r, sizeof(r)); + break; + } + if (ret < 0) { + dev_err(dev, + "error: failed to load widget type %d with ID: %d\n", + swidget->widget->id, swidget->comp_id); + + return ret; + } + } + + /* restore pipeline connections */ + list_for_each_entry_reverse(sroute, &sdev->route_list, list) { + struct sof_ipc_pipe_comp_connect *connect; + struct sof_ipc_reply reply; + + /* skip if there's no private data */ + if (!sroute->private) + continue; + + connect = sroute->private; + + /* send ipc */ + ret = sof_ipc_tx_message(sdev->ipc, + connect->hdr.cmd, + connect, sizeof(*connect), + &reply, sizeof(reply)); + if (ret < 0) { + dev_err(dev, + "error: failed to load route sink %s control %s source %s\n", + sroute->route->sink, + sroute->route->control ? sroute->route->control + : "none", + sroute->route->source); + + return ret; + } + } + + /* restore dai links */ + list_for_each_entry_reverse(dai, &sdev->dai_list, list) { + struct sof_ipc_reply reply; + struct sof_ipc_dai_config *config = dai->dai_config; + + if (!config) { + dev_err(dev, "error: no config for DAI %s\n", + dai->name); + continue; + } + + /* + * The link DMA channel would be invalidated for running + * streams but not for streams that were in the PAUSED + * state during suspend. So invalidate it here before setting + * the dai config in the DSP. + */ + if (config->type == SOF_DAI_INTEL_HDA) + config->hda.link_dma_ch = DMA_CHAN_INVALID; + + ret = sof_ipc_tx_message(sdev->ipc, + config->hdr.cmd, config, + config->hdr.size, + &reply, sizeof(reply)); + + if (ret < 0) { + dev_err(dev, + "error: failed to set dai config for %s\n", + dai->name); + + return ret; + } + } + + /* complete pipeline */ + list_for_each_entry(swidget, &sdev->widget_list, list) { + switch (swidget->id) { + case snd_soc_dapm_scheduler: + swidget->complete = + snd_sof_complete_pipeline(dev, swidget); + break; + default: + break; + } + } + + /* restore pipeline kcontrols */ + ret = sof_restore_kcontrols(dev); + if (ret < 0) + dev_err(dev, + "error: restoring kcontrols after resume\n"); + + return ret; +} + +/* + * Generic object lookup APIs. + */ + +struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_soc_component *scomp, + const char *name) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_pcm *spcm; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + /* match with PCM dai name */ + if (strcmp(spcm->pcm.dai_name, name) == 0) + return spcm; + + /* match with playback caps name if set */ + if (*spcm->pcm.caps[0].name && + !strcmp(spcm->pcm.caps[0].name, name)) + return spcm; + + /* match with capture caps name if set */ + if (*spcm->pcm.caps[1].name && + !strcmp(spcm->pcm.caps[1].name, name)) + return spcm; + } + + return NULL; +} + +struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp, + unsigned int comp_id, + int *direction) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_pcm *spcm; + int dir; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + dir = SNDRV_PCM_STREAM_PLAYBACK; + if (spcm->stream[dir].comp_id == comp_id) { + *direction = dir; + return spcm; + } + + dir = SNDRV_PCM_STREAM_CAPTURE; + if (spcm->stream[dir].comp_id == comp_id) { + *direction = dir; + return spcm; + } + } + + return NULL; +} + +struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_soc_component *scomp, + unsigned int pcm_id) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_pcm *spcm; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + if (le32_to_cpu(spcm->pcm.pcm_id) == pcm_id) + return spcm; + } + + return NULL; +} + +struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp, + const char *name) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_widget *swidget; + + list_for_each_entry(swidget, &sdev->widget_list, list) { + if (strcmp(name, swidget->widget->name) == 0) + return swidget; + } + + return NULL; +} + +/* find widget by stream name and direction */ +struct snd_sof_widget * +snd_sof_find_swidget_sname(struct snd_soc_component *scomp, + const char *pcm_name, int dir) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_widget *swidget; + enum snd_soc_dapm_type type; + + if (dir == SNDRV_PCM_STREAM_PLAYBACK) + type = snd_soc_dapm_aif_in; + else + type = snd_soc_dapm_aif_out; + + list_for_each_entry(swidget, &sdev->widget_list, list) { + if (!strcmp(pcm_name, swidget->widget->sname) && + swidget->id == type) + return swidget; + } + + return NULL; +} + +struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp, + const char *name) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_sof_dai *dai; + + list_for_each_entry(dai, &sdev->dai_list, list) { + if (dai->name && (strcmp(name, dai->name) == 0)) + return dai; + } + + return NULL; +} + diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h new file mode 100644 index 00000000000000..d47d851d769334 --- /dev/null +++ b/sound/soc/sof/sof-audio.h @@ -0,0 +1,207 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2019 Intel Corporation. All rights reserved. + * + * Author: Ranjani Sridharan + */ + +#ifndef __SOUND_SOC_SOF_AUDIO_H +#define __SOUND_SOC_SOF_AUDIO_H + +#include +#include +#include /* needs to be included before control.h */ +#include +#include +#include +#include "sof-priv.h" + +#define SOF_AUDIO_PCM_DRV_NAME "sof-audio-component" + +/* max number of FE PCMs before BEs */ +#define SOF_BE_PCM_BASE 16 + +#define DMA_CHAN_INVALID 0xFFFFFFFF + +/* PCM stream, mapped to FW component */ +struct snd_sof_pcm_stream { + u32 comp_id; + struct snd_dma_buffer page_table; + struct sof_ipc_stream_posn posn; + struct snd_pcm_substream *substream; + struct work_struct period_elapsed_work; + bool d0i3_compatible; /* DSP can be in D0I3 when this pcm is opened */ + /* + * flag to indicate that the DSP pipelines should be kept + * active or not while suspending the stream + */ + bool suspend_ignored; +}; + +/* ALSA SOF PCM device */ +struct snd_sof_pcm { + struct snd_soc_component *scomp; + struct snd_soc_tplg_pcm pcm; + struct snd_sof_pcm_stream stream[2]; + struct list_head list; /* list in sdev pcm list */ + struct snd_pcm_hw_params params[2]; + bool prepared[2]; /* PCM_PARAMS set successfully */ +}; + +struct snd_sof_led_control { + unsigned int use_led; + unsigned int direction; + unsigned int led_value; +}; + +/* ALSA SOF Kcontrol device */ +struct snd_sof_control { + struct snd_soc_component *scomp; + int comp_id; + int min_volume_step; /* min volume step for volume_table */ + int max_volume_step; /* max volume step for volume_table */ + int num_channels; + u32 readback_offset; /* offset to mmaped data if used */ + struct sof_ipc_ctrl_data *control_data; + u32 size; /* cdata size */ + enum sof_ipc_ctrl_cmd cmd; + u32 *volume_table; /* volume table computed from tlv data*/ + + struct list_head list; /* list in sdev control list */ + + struct snd_sof_led_control led_ctl; +}; + +/* ASoC SOF DAPM widget */ +struct snd_sof_widget { + struct snd_soc_component *scomp; + int comp_id; + int pipeline_id; + int complete; + int id; + + struct snd_soc_dapm_widget *widget; + struct list_head list; /* list in sdev widget list */ + + void *private; /* core does not touch this */ +}; + +/* ASoC SOF DAPM route */ +struct snd_sof_route { + struct snd_soc_component *scomp; + + struct snd_soc_dapm_route *route; + struct list_head list; /* list in sdev route list */ + + void *private; +}; + +/* ASoC DAI device */ +struct snd_sof_dai { + struct snd_soc_component *scomp; + const char *name; + const char *cpu_dai_name; + + struct sof_ipc_comp_dai comp_dai; + struct sof_ipc_dai_config *dai_config; + struct list_head list; /* list in sdev dai list */ +}; + +/* + * Kcontrols. + */ + +int snd_sof_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, + const unsigned int __user *binary_data, + unsigned int size); +int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, + unsigned int __user *binary_data, + unsigned int size); + +/* + * Topology. + * There is no snd_sof_free_topology since topology components will + * be freed by snd_soc_unregister_component, + */ +int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file); +int snd_sof_complete_pipeline(struct device *dev, + struct snd_sof_widget *swidget); + +int sof_load_pipeline_ipc(struct device *dev, + struct sof_ipc_pipe_new *pipeline, + struct sof_ipc_comp_reply *r); + +/* + * Stream IPC + */ +int snd_sof_ipc_stream_posn(struct snd_soc_component *scomp, + struct snd_sof_pcm *spcm, int direction, + struct sof_ipc_stream_posn *posn); + +struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp, + const char *name); +struct snd_sof_widget * +snd_sof_find_swidget_sname(struct snd_soc_component *scomp, + const char *pcm_name, int dir); +struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp, + const char *name); + +static inline +struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_soc_component *scomp, + struct snd_soc_pcm_runtime *rtd) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + + struct snd_sof_pcm *spcm = NULL; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + if (le32_to_cpu(spcm->pcm.dai_id) == rtd->dai_link->id) + return spcm; + } + + return NULL; +} + +struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_soc_component *scomp, + const char *name); +struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp, + unsigned int comp_id, + int *direction); +struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_soc_component *scomp, + unsigned int pcm_id); +void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream); + +/* + * Mixer IPC + */ +int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, + u32 ipc_cmd, + enum sof_ipc_ctrl_type ctrl_type, + enum sof_ipc_ctrl_cmd ctrl_cmd, + bool send); + +/* PM */ +int sof_restore_pipelines(struct device *dev); +int sof_set_hw_params_upon_resume(struct device *dev); +bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev); + +#endif diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 18dd832f2053a8..eae1fc209a65cb 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -12,20 +12,11 @@ #define __SOUND_SOC_SOF_PRIV_H #include - #include -#include -#include - #include -#include /* needs to be included before control.h */ -#include -#include #include #include -#include #include - #include /* debug flags */ @@ -48,9 +39,6 @@ extern int sof_core_debug; /* DMA buffer size for trace */ #define DMA_BUF_SIZE_FOR_TRACE (PAGE_SIZE * 16) -/* max number of FE PCMs before BEs */ -#define SOF_BE_PCM_BASE 16 - #define SOF_IPC_DSP_REPLY 0 #define SOF_IPC_HOST_REPLY 1 @@ -66,8 +54,6 @@ extern int sof_core_debug; (IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) || \ IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST)) -#define DMA_CHAN_INVALID 0xFFFFFFFF - /* DSP D0ix sub-state */ enum sof_d0_substate { SOF_DSP_D0I0 = 0, /* DSP default D0 substate */ @@ -303,90 +289,6 @@ struct snd_sof_ipc_msg { bool ipc_complete; }; -/* PCM stream, mapped to FW component */ -struct snd_sof_pcm_stream { - u32 comp_id; - struct snd_dma_buffer page_table; - struct sof_ipc_stream_posn posn; - struct snd_pcm_substream *substream; - struct work_struct period_elapsed_work; - bool d0i3_compatible; /* DSP can be in D0I3 when this pcm is opened */ - /* - * flag to indicate that the DSP pipelines should be kept - * active or not while suspending the stream - */ - bool suspend_ignored; -}; - -/* ALSA SOF PCM device */ -struct snd_sof_pcm { - struct snd_sof_dev *sdev; - struct snd_soc_tplg_pcm pcm; - struct snd_sof_pcm_stream stream[2]; - struct list_head list; /* list in sdev pcm list */ - struct snd_pcm_hw_params params[2]; - bool prepared[2]; /* PCM_PARAMS set successfully */ -}; - -struct snd_sof_led_control { - unsigned int use_led; - unsigned int direction; - unsigned int led_value; -}; - -/* ALSA SOF Kcontrol device */ -struct snd_sof_control { - struct snd_sof_dev *sdev; - int comp_id; - int min_volume_step; /* min volume step for volume_table */ - int max_volume_step; /* max volume step for volume_table */ - int num_channels; - u32 readback_offset; /* offset to mmaped data if used */ - struct sof_ipc_ctrl_data *control_data; - u32 size; /* cdata size */ - enum sof_ipc_ctrl_cmd cmd; - u32 *volume_table; /* volume table computed from tlv data*/ - - struct list_head list; /* list in sdev control list */ - - struct snd_sof_led_control led_ctl; -}; - -/* ASoC SOF DAPM widget */ -struct snd_sof_widget { - struct snd_sof_dev *sdev; - int comp_id; - int pipeline_id; - int complete; - int id; - - struct snd_soc_dapm_widget *widget; - struct list_head list; /* list in sdev widget list */ - - void *private; /* core does not touch this */ -}; - -/* ASoC SOF DAPM route */ -struct snd_sof_route { - struct snd_sof_dev *sdev; - - struct snd_soc_dapm_route *route; - struct list_head list; /* list in sdev route list */ - - void *private; -}; - -/* ASoC DAI device */ -struct snd_sof_dai { - struct snd_sof_dev *sdev; - const char *name; - const char *cpu_dai_name; - - struct sof_ipc_comp_dai comp_dai; - struct sof_ipc_dai_config *dai_config; - struct list_head list; /* list in sdev dai list */ -}; - /* * SOF Device Level. */ @@ -531,67 +433,6 @@ int snd_sof_ipc_valid(struct snd_sof_dev *sdev); int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header, void *msg_data, size_t msg_bytes, void *reply_data, size_t reply_bytes); -struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev, - const char *name); -struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev, - const char *pcm_name, - int dir); -struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev, - const char *name); - -static inline -struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_sof_dev *sdev, - struct snd_soc_pcm_runtime *rtd) -{ - struct snd_sof_pcm *spcm = NULL; - - list_for_each_entry(spcm, &sdev->pcm_list, list) { - if (le32_to_cpu(spcm->pcm.dai_id) == rtd->dai_link->id) - return spcm; - } - - return NULL; -} - -bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev); - -struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev, - const char *name); -struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev, - unsigned int comp_id, - int *direction); -struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev, - unsigned int pcm_id); -void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream); - -/* - * Stream IPC - */ -int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev, - struct snd_sof_pcm *spcm, int direction, - struct sof_ipc_stream_posn *posn); - -/* - * Mixer IPC - */ -int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc, - struct snd_sof_control *scontrol, u32 ipc_cmd, - enum sof_ipc_ctrl_type ctrl_type, - enum sof_ipc_ctrl_cmd ctrl_cmd, - bool send); - -/* - * Topology. - * There is no snd_sof_free_topology since topology components will - * be freed by snd_soc_unregister_component, - */ -int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file); -int snd_sof_complete_pipeline(struct snd_sof_dev *sdev, - struct snd_sof_widget *swidget); - -int sof_load_pipeline_ipc(struct snd_sof_dev *sdev, - struct sof_ipc_pipe_new *pipeline, - struct sof_ipc_comp_reply *r); /* * Trace/debug @@ -623,40 +464,12 @@ void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev); */ extern struct snd_compr_ops sof_compressed_ops; -/* - * Kcontrols. - */ - -int snd_sof_volume_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -int snd_sof_volume_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -int snd_sof_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -int snd_sof_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -int snd_sof_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -int snd_sof_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, - const unsigned int __user *binary_data, - unsigned int size); -int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, - unsigned int __user *binary_data, - unsigned int size); - /* * DSP Architectures. */ static inline void sof_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack, u32 stack_words) { - if (sof_arch_ops(sdev)->dsp_stack) sof_arch_ops(sdev)->dsp_stack(sdev, oops, stack, stack_words); } diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index b8701d3407ad1e..987a781a2cd59d 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -13,6 +13,7 @@ #include #include #include "sof-priv.h" +#include "sof-audio.h" #include "ops.h" #define COMP_ID_UNASSIGNED 0xffffffff @@ -53,7 +54,8 @@ struct sof_widget_data { static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir) { struct sof_ipc_pcm_params_reply ipc_params_reply; - struct snd_sof_dev *sdev = swidget->sdev; + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc_pcm_params pcm; struct snd_pcm_hw_params *params; struct snd_sof_pcm *spcm; @@ -62,9 +64,9 @@ static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir) memset(&pcm, 0, sizeof(pcm)); /* get runtime PCM params using widget's stream name */ - spcm = snd_sof_find_spcm_name(sdev, swidget->widget->sname); + spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname); if (!spcm) { - dev_err(sdev->dev, "error: cannot find PCM for %s\n", + dev_err(scomp->dev, "error: cannot find PCM for %s\n", swidget->widget->name); return -EINVAL; } @@ -102,7 +104,7 @@ static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir) ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm), &ipc_params_reply, sizeof(ipc_params_reply)); if (ret < 0) - dev_err(sdev->dev, "error: pcm params failed for %s\n", + dev_err(scomp->dev, "error: pcm params failed for %s\n", swidget->widget->name); return ret; @@ -111,7 +113,8 @@ static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir) /* send stream trigger ipc */ static int ipc_trigger(struct snd_sof_widget *swidget, int cmd) { - struct snd_sof_dev *sdev = swidget->sdev; + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc_stream stream; struct sof_ipc_reply reply; int ret = 0; @@ -125,7 +128,7 @@ static int ipc_trigger(struct snd_sof_widget *swidget, int cmd) ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream, sizeof(stream), &reply, sizeof(reply)); if (ret < 0) - dev_err(sdev->dev, "error: failed to trigger %s\n", + dev_err(scomp->dev, "error: failed to trigger %s\n", swidget->widget->name); return ret; @@ -135,23 +138,21 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { struct snd_sof_widget *swidget = w->dobj.private; + struct snd_soc_component *scomp = swidget->scomp; int stream = SNDRV_PCM_STREAM_CAPTURE; - struct snd_sof_dev *sdev; struct snd_sof_pcm *spcm; int ret = 0; if (!swidget) return 0; - sdev = swidget->sdev; - - dev_dbg(sdev->dev, "received event %d for widget %s\n", + dev_dbg(scomp->dev, "received event %d for widget %s\n", event, w->name); /* get runtime PCM params using widget's stream name */ - spcm = snd_sof_find_spcm_name(sdev, swidget->widget->sname); + spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname); if (!spcm) { - dev_err(sdev->dev, "error: cannot find PCM for %s\n", + dev_err(scomp->dev, "error: cannot find PCM for %s\n", swidget->widget->name); return -EINVAL; } @@ -160,14 +161,14 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: if (spcm->stream[stream].suspend_ignored) { - dev_dbg(sdev->dev, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n"); + dev_dbg(scomp->dev, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n"); return 0; } /* set pcm params */ ret = ipc_pcm_params(swidget, stream); if (ret < 0) { - dev_err(sdev->dev, + dev_err(scomp->dev, "error: failed to set pcm params for widget %s\n", swidget->widget->name); break; @@ -176,27 +177,27 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, /* start trigger */ ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_START); if (ret < 0) - dev_err(sdev->dev, + dev_err(scomp->dev, "error: failed to trigger widget %s\n", swidget->widget->name); break; case SND_SOC_DAPM_POST_PMD: if (spcm->stream[stream].suspend_ignored) { - dev_dbg(sdev->dev, "POST_PMD even ignored, KWD pipeline will remain RUNNING\n"); + dev_dbg(scomp->dev, "POST_PMD even ignored, KWD pipeline will remain RUNNING\n"); return 0; } /* stop trigger */ ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP); if (ret < 0) - dev_err(sdev->dev, + dev_err(scomp->dev, "error: failed to trigger widget %s\n", swidget->widget->name); /* pcm free */ ret = ipc_trigger(swidget, SOF_IPC_STREAM_PCM_FREE); if (ret < 0) - dev_err(sdev->dev, + dev_err(scomp->dev, "error: failed to trigger widget %s\n", swidget->widget->name); break; @@ -838,7 +839,7 @@ static void sof_parse_word_tokens(struct snd_soc_component *scomp, /* check if array index is valid */ if (!index || *index == 0) { - dev_err(sdev->dev, + dev_err(scomp->dev, "error: invalid array offset\n"); continue; } else { @@ -866,7 +867,6 @@ static int sof_parse_tokens(struct snd_soc_component *scomp, struct snd_soc_tplg_vendor_array *array, int priv_size) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); int asize; while (priv_size > 0) { @@ -874,7 +874,7 @@ static int sof_parse_tokens(struct snd_soc_component *scomp, /* validate asize */ if (asize < 0) { /* FIXME: A zero-size array makes no sense */ - dev_err(sdev->dev, "error: invalid array size 0x%x\n", + dev_err(scomp->dev, "error: invalid array size 0x%x\n", asize); return -EINVAL; } @@ -882,7 +882,7 @@ static int sof_parse_tokens(struct snd_soc_component *scomp, /* make sure there is enough data before parsing */ priv_size -= asize; if (priv_size < 0) { - dev_err(sdev->dev, "error: invalid array size 0x%x\n", + dev_err(scomp->dev, "error: invalid array size 0x%x\n", asize); return -EINVAL; } @@ -905,7 +905,7 @@ static int sof_parse_tokens(struct snd_soc_component *scomp, array); break; default: - dev_err(sdev->dev, "error: unknown token type %d\n", + dev_err(scomp->dev, "error: unknown token type %d\n", array->type); return -EINVAL; } @@ -920,9 +920,7 @@ static int sof_parse_tokens(struct snd_soc_component *scomp, static void sof_dbg_comp_config(struct snd_soc_component *scomp, struct sof_ipc_comp_config *config) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - - dev_dbg(sdev->dev, " config: periods snk %d src %d fmt %d\n", + dev_dbg(scomp->dev, " config: periods snk %d src %d fmt %d\n", config->periods_sink, config->periods_source, config->frame_fmt); } @@ -974,7 +972,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, /* extract tlv data */ if (get_tlv_data(kc->tlv.p, tlv) < 0) { - dev_err(sdev->dev, "error: invalid TLV data\n"); + dev_err(scomp->dev, "error: invalid TLV data\n"); ret = -EINVAL; goto out_free; } @@ -982,7 +980,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, /* set up volume table */ ret = set_up_volume_table(scontrol, tlv, le32_to_cpu(mc->max) + 1); if (ret < 0) { - dev_err(sdev->dev, "error: setting up volume table\n"); + dev_err(scomp->dev, "error: setting up volume table\n"); goto out_free; } @@ -999,12 +997,12 @@ static int sof_control_load_volume(struct snd_soc_component *scomp, ARRAY_SIZE(led_tokens), mc->priv.array, le32_to_cpu(mc->priv.size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse led tokens failed %d\n", + dev_err(scomp->dev, "error: parse led tokens failed %d\n", le32_to_cpu(mc->priv.size)); goto out_free_table; } - dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", + dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d\n", scontrol->comp_id, scontrol->num_channels); return ret; @@ -1043,7 +1041,7 @@ static int sof_control_load_enum(struct snd_soc_component *scomp, scontrol->cmd = SOF_CTRL_CMD_ENUM; - dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d comp_id %d\n", + dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d comp_id %d\n", scontrol->comp_id, scontrol->num_channels, scontrol->comp_id); return 0; @@ -1067,7 +1065,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, le32_to_cpu(control->priv.size); if (scontrol->size > max_size) { - dev_err(sdev->dev, "err: bytes data size %d exceeds max %d.\n", + dev_err(scomp->dev, "err: bytes data size %d exceeds max %d.\n", scontrol->size, max_size); ret = -EINVAL; goto out; @@ -1083,7 +1081,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, scontrol->comp_id = sdev->next_comp_id; scontrol->cmd = SOF_CTRL_CMD_BINARY; - dev_dbg(sdev->dev, "tplg: load kcontrol index %d chans %d\n", + dev_dbg(scomp->dev, "tplg: load kcontrol index %d chans %d\n", scontrol->comp_id, scontrol->num_channels); if (le32_to_cpu(control->priv.size) > 0) { @@ -1091,14 +1089,14 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, le32_to_cpu(control->priv.size)); if (cdata->data->magic != SOF_ABI_MAGIC) { - dev_err(sdev->dev, "error: Wrong ABI magic 0x%08x.\n", + dev_err(scomp->dev, "error: Wrong ABI magic 0x%08x.\n", cdata->data->magic); ret = -EINVAL; goto out_free; } if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { - dev_err(sdev->dev, + dev_err(scomp->dev, "error: Incompatible ABI version 0x%08x.\n", cdata->data->abi); ret = -EINVAL; @@ -1106,7 +1104,7 @@ static int sof_control_load_bytes(struct snd_soc_component *scomp, } if (cdata->data->size + sizeof(const struct sof_abi_hdr) != le32_to_cpu(control->priv.size)) { - dev_err(sdev->dev, + dev_err(scomp->dev, "error: Conflict in bytes vs. priv size.\n"); ret = -EINVAL; goto out_free; @@ -1134,14 +1132,14 @@ static int sof_control_load(struct snd_soc_component *scomp, int index, struct snd_sof_control *scontrol; int ret = -EINVAL; - dev_dbg(sdev->dev, "tplg: load control type %d name : %s\n", + dev_dbg(scomp->dev, "tplg: load control type %d name : %s\n", hdr->type, hdr->name); scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL); if (!scontrol) return -ENOMEM; - scontrol->sdev = sdev; + scontrol->scomp = scomp; switch (le32_to_cpu(hdr->ops.info)) { case SND_SOC_TPLG_CTL_VOLSW: @@ -1170,7 +1168,7 @@ static int sof_control_load(struct snd_soc_component *scomp, int index, case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: case SND_SOC_TPLG_DAPM_CTL_PIN: default: - dev_warn(sdev->dev, "control type not supported %d:%d:%d\n", + dev_warn(scomp->dev, "control type not supported %d:%d:%d\n", hdr->ops.get, hdr->ops.put, hdr->ops.info); kfree(scontrol); return 0; @@ -1193,7 +1191,7 @@ static int sof_control_unload(struct snd_soc_component *scomp, struct sof_ipc_free fcomp; struct snd_sof_control *scontrol = dobj->private; - dev_dbg(sdev->dev, "tplg: unload control name : %s\n", scomp->name); + dev_dbg(scomp->dev, "tplg: unload control name : %s\n", scomp->name); fcomp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_FREE; fcomp.hdr.size = sizeof(fcomp); @@ -1217,12 +1215,11 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, struct snd_soc_tplg_dapm_widget *tw, struct snd_sof_dai *dai) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_card *card = scomp->card; struct snd_soc_pcm_runtime *rtd; list_for_each_entry(rtd, &card->rtd_list, list) { - dev_vdbg(sdev->dev, "tplg: check widget: %s stream: %s dai stream: %s\n", + dev_vdbg(scomp->dev, "tplg: check widget: %s stream: %s dai stream: %s\n", w->name, w->sname, rtd->dai_link->stream_name); if (!w->sname || !rtd->dai_link->stream_name) @@ -1236,13 +1233,13 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, case snd_soc_dapm_dai_out: rtd->cpu_dai->capture_widget = w; dai->name = rtd->dai_link->name; - dev_dbg(sdev->dev, "tplg: connected widget %s -> DAI link %s\n", + dev_dbg(scomp->dev, "tplg: connected widget %s -> DAI link %s\n", w->name, rtd->dai_link->name); break; case snd_soc_dapm_dai_in: rtd->cpu_dai->playback_widget = w; dai->name = rtd->dai_link->name; - dev_dbg(sdev->dev, "tplg: connected widget %s -> DAI link %s\n", + dev_dbg(scomp->dev, "tplg: connected widget %s -> DAI link %s\n", w->name, rtd->dai_link->name); break; default: @@ -1252,7 +1249,7 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp, /* check we have a connection */ if (!dai->name) { - dev_err(sdev->dev, "error: can't connect DAI %s stream %s\n", + dev_err(scomp->dev, "error: can't connect DAI %s stream %s\n", w->name, w->sname); return -EINVAL; } @@ -1284,7 +1281,7 @@ static int sof_widget_load_dai(struct snd_soc_component *scomp, int index, ARRAY_SIZE(dai_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse dai tokens failed %d\n", + dev_err(scomp->dev, "error: parse dai tokens failed %d\n", le32_to_cpu(private->size)); return ret; } @@ -1293,12 +1290,12 @@ static int sof_widget_load_dai(struct snd_soc_component *scomp, int index, ARRAY_SIZE(comp_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse dai.cfg tokens failed %d\n", + dev_err(scomp->dev, "error: parse dai.cfg tokens failed %d\n", private->size); return ret; } - dev_dbg(sdev->dev, "dai %s: type %d index %d\n", + dev_dbg(scomp->dev, "dai %s: type %d index %d\n", swidget->widget->name, comp_dai.type, comp_dai.dai_index); sof_dbg_comp_config(scomp, &comp_dai.config); @@ -1306,7 +1303,7 @@ static int sof_widget_load_dai(struct snd_soc_component *scomp, int index, &comp_dai, sizeof(comp_dai), r, sizeof(*r)); if (ret == 0 && dai) { - dai->sdev = sdev; + dai->scomp = scomp; memcpy(&dai->comp_dai, &comp_dai, sizeof(comp_dai)); } @@ -1342,13 +1339,13 @@ static int sof_widget_load_buffer(struct snd_soc_component *scomp, int index, ARRAY_SIZE(buffer_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse buffer tokens failed %d\n", + dev_err(scomp->dev, "error: parse buffer tokens failed %d\n", private->size); kfree(buffer); return ret; } - dev_dbg(sdev->dev, "buffer %s: size %d caps 0x%x\n", + dev_dbg(scomp->dev, "buffer %s: size %d caps 0x%x\n", swidget->widget->name, buffer->size, buffer->caps); swidget->private = buffer; @@ -1356,7 +1353,7 @@ static int sof_widget_load_buffer(struct snd_soc_component *scomp, int index, ret = sof_ipc_tx_message(sdev->ipc, buffer->comp.hdr.cmd, buffer, sizeof(*buffer), r, sizeof(*r)); if (ret < 0) { - dev_err(sdev->dev, "error: buffer %s load failed\n", + dev_err(scomp->dev, "error: buffer %s load failed\n", swidget->widget->name); kfree(buffer); } @@ -1365,16 +1362,16 @@ static int sof_widget_load_buffer(struct snd_soc_component *scomp, int index, } /* bind PCM ID to host component ID */ -static int spcm_bind(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, +static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm, int dir) { struct snd_sof_widget *host_widget; - host_widget = snd_sof_find_swidget_sname(sdev, + host_widget = snd_sof_find_swidget_sname(scomp, spcm->pcm.caps[dir].name, dir); if (!host_widget) { - dev_err(sdev->dev, "can't find host comp to bind pcm\n"); + dev_err(scomp->dev, "can't find host comp to bind pcm\n"); return -EINVAL; } @@ -1415,7 +1412,7 @@ static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index, ARRAY_SIZE(pcm_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse host tokens failed %d\n", + dev_err(scomp->dev, "error: parse host tokens failed %d\n", private->size); goto err; } @@ -1424,12 +1421,12 @@ static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index, ARRAY_SIZE(comp_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse host.cfg tokens failed %d\n", + dev_err(scomp->dev, "error: parse host.cfg tokens failed %d\n", le32_to_cpu(private->size)); goto err; } - dev_dbg(sdev->dev, "loaded host %s\n", swidget->widget->name); + dev_dbg(scomp->dev, "loaded host %s\n", swidget->widget->name); sof_dbg_comp_config(scomp, &host->config); swidget->private = host; @@ -1446,24 +1443,25 @@ static int sof_widget_load_pcm(struct snd_soc_component *scomp, int index, /* * Pipeline Topology */ -int sof_load_pipeline_ipc(struct snd_sof_dev *sdev, +int sof_load_pipeline_ipc(struct device *dev, struct sof_ipc_pipe_new *pipeline, struct sof_ipc_comp_reply *r) { + struct snd_sof_dev *sdev = dev_get_drvdata(dev); struct sof_ipc_pm_core_config pm_core_config; int ret; ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline, sizeof(*pipeline), r, sizeof(*r)); if (ret < 0) { - dev_err(sdev->dev, "error: load pipeline ipc failure\n"); + dev_err(dev, "error: load pipeline ipc failure\n"); return ret; } /* power up the core that this pipeline is scheduled on */ ret = snd_sof_dsp_core_power_up(sdev, 1 << pipeline->core); if (ret < 0) { - dev_err(sdev->dev, "error: powering up pipeline schedule core %d\n", + dev_err(dev, "error: powering up pipeline schedule core %d\n", pipeline->core); return ret; } @@ -1487,7 +1485,7 @@ int sof_load_pipeline_ipc(struct snd_sof_dev *sdev, &pm_core_config, sizeof(pm_core_config), &pm_core_config, sizeof(pm_core_config)); if (ret < 0) - dev_err(sdev->dev, "error: core enable ipc failure\n"); + dev_err(dev, "error: core enable ipc failure\n"); return ret; } @@ -1497,7 +1495,6 @@ static int sof_widget_load_pipeline(struct snd_soc_component *scomp, struct snd_soc_tplg_dapm_widget *tw, struct sof_ipc_comp_reply *r) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &tw->priv; struct sof_ipc_pipe_new *pipeline; struct snd_sof_widget *comp_swidget; @@ -1514,9 +1511,9 @@ static int sof_widget_load_pipeline(struct snd_soc_component *scomp, pipeline->comp_id = swidget->comp_id; /* component at start of pipeline is our stream id */ - comp_swidget = snd_sof_find_swidget(sdev, tw->sname); + comp_swidget = snd_sof_find_swidget(scomp, tw->sname); if (!comp_swidget) { - dev_err(sdev->dev, "error: widget %s refers to non existent widget %s\n", + dev_err(scomp->dev, "error: widget %s refers to non existent widget %s\n", tw->name, tw->sname); ret = -EINVAL; goto err; @@ -1524,26 +1521,26 @@ static int sof_widget_load_pipeline(struct snd_soc_component *scomp, pipeline->sched_id = comp_swidget->comp_id; - dev_dbg(sdev->dev, "tplg: pipeline id %d comp %d scheduling comp id %d\n", + dev_dbg(scomp->dev, "tplg: pipeline id %d comp %d scheduling comp id %d\n", pipeline->pipeline_id, pipeline->comp_id, pipeline->sched_id); ret = sof_parse_tokens(scomp, pipeline, sched_tokens, ARRAY_SIZE(sched_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse pipeline tokens failed %d\n", + dev_err(scomp->dev, "error: parse pipeline tokens failed %d\n", private->size); goto err; } - dev_dbg(sdev->dev, "pipeline %s: period %d pri %d mips %d core %d frames %d\n", + dev_dbg(scomp->dev, "pipeline %s: period %d pri %d mips %d core %d frames %d\n", swidget->widget->name, pipeline->period, pipeline->priority, pipeline->period_mips, pipeline->core, pipeline->frames_per_sched); swidget->private = pipeline; /* send ipc's to create pipeline comp and power up schedule core */ - ret = sof_load_pipeline_ipc(sdev, pipeline, r); + ret = sof_load_pipeline_ipc(scomp->dev, pipeline, r); if (ret >= 0) return ret; err: @@ -1581,7 +1578,7 @@ static int sof_widget_load_mixer(struct snd_soc_component *scomp, int index, ARRAY_SIZE(comp_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse mixer.cfg tokens failed %d\n", + dev_err(scomp->dev, "error: parse mixer.cfg tokens failed %d\n", private->size); kfree(mixer); return ret; @@ -1628,7 +1625,7 @@ static int sof_widget_load_mux(struct snd_soc_component *scomp, int index, ARRAY_SIZE(comp_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse mux.cfg tokens failed %d\n", + dev_err(scomp->dev, "error: parse mux.cfg tokens failed %d\n", private->size); kfree(mux); return ret; @@ -1668,7 +1665,7 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, return -ENOMEM; if (!le32_to_cpu(tw->num_kcontrols)) { - dev_err(sdev->dev, "error: invalid kcontrol count %d for volume\n", + dev_err(scomp->dev, "error: invalid kcontrol count %d for volume\n", tw->num_kcontrols); ret = -EINVAL; goto err; @@ -1686,7 +1683,7 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, ARRAY_SIZE(volume_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse volume tokens failed %d\n", + dev_err(scomp->dev, "error: parse volume tokens failed %d\n", private->size); goto err; } @@ -1694,7 +1691,7 @@ static int sof_widget_load_pga(struct snd_soc_component *scomp, int index, ARRAY_SIZE(comp_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse volume.cfg tokens failed %d\n", + dev_err(scomp->dev, "error: parse volume.cfg tokens failed %d\n", le32_to_cpu(private->size)); goto err; } @@ -1754,7 +1751,7 @@ static int sof_widget_load_src(struct snd_soc_component *scomp, int index, ARRAY_SIZE(src_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse src tokens failed %d\n", + dev_err(scomp->dev, "error: parse src tokens failed %d\n", private->size); goto err; } @@ -1763,12 +1760,12 @@ static int sof_widget_load_src(struct snd_soc_component *scomp, int index, ARRAY_SIZE(comp_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse src.cfg tokens failed %d\n", + dev_err(scomp->dev, "error: parse src.cfg tokens failed %d\n", le32_to_cpu(private->size)); goto err; } - dev_dbg(sdev->dev, "src %s: source rate %d sink rate %d\n", + dev_dbg(scomp->dev, "src %s: source rate %d sink rate %d\n", swidget->widget->name, src->source_rate, src->sink_rate); sof_dbg_comp_config(scomp, &src->config); @@ -1813,7 +1810,7 @@ static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index, ARRAY_SIZE(tone_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse tone tokens failed %d\n", + dev_err(scomp->dev, "error: parse tone tokens failed %d\n", le32_to_cpu(private->size)); goto err; } @@ -1822,12 +1819,12 @@ static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index, ARRAY_SIZE(comp_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse tone.cfg tokens failed %d\n", + dev_err(scomp->dev, "error: parse tone.cfg tokens failed %d\n", le32_to_cpu(private->size)); goto err; } - dev_dbg(sdev->dev, "tone %s: frequency %d amplitude %d\n", + dev_dbg(scomp->dev, "tone %s: frequency %d amplitude %d\n", swidget->widget->name, tone->frequency, tone->amplitude); sof_dbg_comp_config(scomp, &tone->config); @@ -1842,7 +1839,7 @@ static int sof_widget_load_siggen(struct snd_soc_component *scomp, int index, return ret; } -static int sof_get_control_data(struct snd_sof_dev *sdev, +static int sof_get_control_data(struct snd_soc_component *scomp, struct snd_soc_dapm_widget *widget, struct sof_widget_data *wdata, size_t *size) @@ -1872,14 +1869,14 @@ static int sof_get_control_data(struct snd_sof_dev *sdev, wdata[i].control = se->dobj.private; break; default: - dev_err(sdev->dev, "error: unknown kcontrol type %d in widget %s\n", + dev_err(scomp->dev, "error: unknown kcontrol type %d in widget %s\n", widget->dobj.widget.kcontrol_type, widget->name); return -EINVAL; } if (!wdata[i].control) { - dev_err(sdev->dev, "error: no scontrol for widget %s\n", + dev_err(scomp->dev, "error: no scontrol for widget %s\n", widget->name); return -EINVAL; } @@ -1932,7 +1929,7 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, int i; if (type == SOF_COMP_NONE) { - dev_err(sdev->dev, "error: invalid process comp type %d\n", + dev_err(scomp->dev, "error: invalid process comp type %d\n", type); return -EINVAL; } @@ -1947,7 +1944,7 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, return -ENOMEM; /* get possible component controls and get size of all pdata */ - ret = sof_get_control_data(sdev, widget, wdata, + ret = sof_get_control_data(scomp, widget, wdata, &ipc_data_size); if (ret < 0) @@ -1982,7 +1979,7 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, ARRAY_SIZE(comp_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse process.cfg tokens failed %d\n", + dev_err(scomp->dev, "error: parse process.cfg tokens failed %d\n", le32_to_cpu(private->size)); goto err; } @@ -2010,7 +2007,7 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, ipc_size, r, sizeof(*r)); if (ret < 0) { - dev_err(sdev->dev, "error: create process failed\n"); + dev_err(scomp->dev, "error: create process failed\n"); goto err; } @@ -2021,13 +2018,13 @@ static int sof_process_load(struct snd_soc_component *scomp, int index, /* send control data with large message supported method */ for (i = 0; i < widget->num_kcontrols; i++) { wdata[i].control->readback_offset = 0; - ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, wdata[i].control, + ret = snd_sof_ipc_set_get_comp_data(wdata[i].control, wdata[i].ipc_cmd, wdata[i].ctrl_type, wdata[i].control->cmd, true); if (ret != 0) { - dev_err(sdev->dev, "error: send control failed\n"); + dev_err(scomp->dev, "error: send control failed\n"); break; } } @@ -2050,14 +2047,13 @@ static int sof_widget_load_process(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_dapm_widget *tw, struct sof_ipc_comp_reply *r) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &tw->priv; struct sof_ipc_comp_process config; int ret; /* check we have some tokens - we need at least process type */ if (le32_to_cpu(private->size) == 0) { - dev_err(sdev->dev, "error: process tokens not found\n"); + dev_err(scomp->dev, "error: process tokens not found\n"); return -EINVAL; } @@ -2068,7 +2064,7 @@ static int sof_widget_load_process(struct snd_soc_component *scomp, int index, ARRAY_SIZE(process_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse process tokens failed %d\n", + dev_err(scomp->dev, "error: parse process tokens failed %d\n", le32_to_cpu(private->size)); return ret; } @@ -2077,14 +2073,14 @@ static int sof_widget_load_process(struct snd_soc_component *scomp, int index, ret = sof_process_load(scomp, index, swidget, tw, r, find_process_comp_type(config.type)); if (ret < 0) { - dev_err(sdev->dev, "error: process loading failed\n"); + dev_err(scomp->dev, "error: process loading failed\n"); return ret; } return 0; } -static int sof_widget_bind_event(struct snd_sof_dev *sdev, +static int sof_widget_bind_event(struct snd_soc_component *scomp, struct snd_sof_widget *swidget, u16 event_type) { @@ -2110,7 +2106,7 @@ static int sof_widget_bind_event(struct snd_sof_dev *sdev, break; } - dev_err(sdev->dev, + dev_err(scomp->dev, "error: invalid event type %d for widget %s\n", event_type, swidget->widget->name); return -EINVAL; @@ -2132,7 +2128,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, if (!swidget) return -ENOMEM; - swidget->sdev = sdev; + swidget->scomp = scomp; swidget->widget = w; swidget->comp_id = sdev->next_comp_id++; swidget->complete = 0; @@ -2141,7 +2137,7 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, swidget->private = NULL; memset(&reply, 0, sizeof(reply)); - dev_dbg(sdev->dev, "tplg: ready widget id %d pipe %d type %d name : %s stream %s\n", + dev_dbg(scomp->dev, "tplg: ready widget id %d pipe %d type %d name : %s stream %s\n", swidget->comp_id, index, swidget->id, tw->name, strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 ? tw->sname : "none"); @@ -2212,14 +2208,14 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, case snd_soc_dapm_dai_link: case snd_soc_dapm_kcontrol: default: - dev_warn(sdev->dev, "warning: widget type %d name %s not handled\n", + dev_warn(scomp->dev, "warning: widget type %d name %s not handled\n", swidget->id, tw->name); break; } /* check IPC reply */ if (ret < 0 || reply.rhdr.error < 0) { - dev_err(sdev->dev, + dev_err(scomp->dev, "error: DSP failed to add widget id %d type %d name : %s stream %s reply %d\n", tw->shift, swidget->id, tw->name, strnlen(tw->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) > 0 @@ -2230,10 +2226,10 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, /* bind widget to external event */ if (tw->event_type) { - ret = sof_widget_bind_event(sdev, swidget, + ret = sof_widget_bind_event(scomp, swidget, le16_to_cpu(tw->event_type)); if (ret) { - dev_err(sdev->dev, "error: widget event binding failed\n"); + dev_err(scomp->dev, "error: widget event binding failed\n"); kfree(swidget->private); kfree(swidget); return ret; @@ -2301,7 +2297,7 @@ static int sof_widget_unload(struct snd_soc_component *scomp, pipeline = swidget->private; ret = snd_sof_dsp_core_power_down(sdev, 1 << pipeline->core); if (ret < 0) - dev_err(sdev->dev, "error: powering down pipeline schedule core %d\n", + dev_err(scomp->dev, "error: powering down pipeline schedule core %d\n", pipeline->core); /* update enabled cores mask */ @@ -2329,7 +2325,7 @@ static int sof_widget_unload(struct snd_soc_component *scomp, scontrol = sbe->dobj.private; break; default: - dev_warn(sdev->dev, "unsupported kcontrol_type\n"); + dev_warn(scomp->dev, "unsupported kcontrol_type\n"); goto out; } kfree(scontrol->control_data); @@ -2372,12 +2368,12 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, if (!spcm) return -ENOMEM; - spcm->sdev = sdev; + spcm->scomp = scomp; spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id = COMP_ID_UNASSIGNED; spcm->stream[SNDRV_PCM_STREAM_CAPTURE].comp_id = COMP_ID_UNASSIGNED; spcm->pcm = *pcm; - dev_dbg(sdev->dev, "tplg: load pcm %s\n", pcm->dai_name); + dev_dbg(scomp->dev, "tplg: load pcm %s\n", pcm->dai_name); dai_drv->dobj.private = spcm; list_add(&spcm->list, &sdev->pcm_list); @@ -2386,7 +2382,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, ARRAY_SIZE(stream_tokens), private->array, le32_to_cpu(private->size)); if (ret) { - dev_err(sdev->dev, "error: parse stream tokens failed %d\n", + dev_err(scomp->dev, "error: parse stream tokens failed %d\n", le32_to_cpu(private->size)); return ret; } @@ -2395,7 +2391,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, if (!spcm->pcm.playback) goto capture; - dev_vdbg(sdev->dev, "tplg: pcm %s stream tokens: playback d0i3:%d\n", + dev_vdbg(scomp->dev, "tplg: pcm %s stream tokens: playback d0i3:%d\n", spcm->pcm.pcm_name, spcm->stream[0].d0i3_compatible); caps = &spcm->pcm.caps[stream]; @@ -2404,16 +2400,16 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev, PAGE_SIZE, &spcm->stream[stream].page_table); if (ret < 0) { - dev_err(sdev->dev, "error: can't alloc page table for %s %d\n", + dev_err(scomp->dev, "error: can't alloc page table for %s %d\n", caps->name, ret); return ret; } /* bind pcm to host comp */ - ret = spcm_bind(sdev, spcm, stream); + ret = spcm_bind(scomp, spcm, stream); if (ret) { - dev_err(sdev->dev, + dev_err(scomp->dev, "error: can't bind pcm to host\n"); goto free_playback_tables; } @@ -2425,7 +2421,7 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, if (!spcm->pcm.capture) return ret; - dev_vdbg(sdev->dev, "tplg: pcm %s stream tokens: capture d0i3:%d\n", + dev_vdbg(scomp->dev, "tplg: pcm %s stream tokens: capture d0i3:%d\n", spcm->pcm.pcm_name, spcm->stream[1].d0i3_compatible); caps = &spcm->pcm.caps[stream]; @@ -2434,15 +2430,15 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index, ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, sdev->dev, PAGE_SIZE, &spcm->stream[stream].page_table); if (ret < 0) { - dev_err(sdev->dev, "error: can't alloc page table for %s %d\n", + dev_err(scomp->dev, "error: can't alloc page table for %s %d\n", caps->name, ret); goto free_playback_tables; } /* bind pcm to host comp */ - ret = spcm_bind(sdev, spcm, stream); + ret = spcm_bind(scomp, spcm, stream); if (ret) { - dev_err(sdev->dev, + dev_err(scomp->dev, "error: can't bind pcm to host\n"); snd_dma_free_pages(&spcm->stream[stream].page_table); goto free_playback_tables; @@ -2568,7 +2564,7 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, ARRAY_SIZE(ssp_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse ssp tokens failed %d\n", + dev_err(scomp->dev, "error: parse ssp tokens failed %d\n", le32_to_cpu(private->size)); return ret; } @@ -2582,7 +2578,7 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, config->ssp.rx_slots = le32_to_cpu(hw_config->rx_slots); config->ssp.tx_slots = le32_to_cpu(hw_config->tx_slots); - dev_dbg(sdev->dev, "tplg: config SSP%d fmt 0x%x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d quirks %d\n", + dev_dbg(scomp->dev, "tplg: config SSP%d fmt 0x%x mclk %d bclk %d fclk %d width (%d)%d slots %d mclk id %d quirks %d\n", config->dai_index, config->format, config->ssp.mclk_rate, config->ssp.bclk_rate, config->ssp.fsync_rate, config->ssp.sample_valid_bits, @@ -2591,13 +2587,13 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, /* validate SSP fsync rate and channel count */ if (config->ssp.fsync_rate < 8000 || config->ssp.fsync_rate > 192000) { - dev_err(sdev->dev, "error: invalid fsync rate for SSP%d\n", + dev_err(scomp->dev, "error: invalid fsync rate for SSP%d\n", config->dai_index); return -EINVAL; } if (config->ssp.tdm_slots < 1 || config->ssp.tdm_slots > 8) { - dev_err(sdev->dev, "error: invalid channel count for SSP%d\n", + dev_err(scomp->dev, "error: invalid channel count for SSP%d\n", config->dai_index); return -EINVAL; } @@ -2608,7 +2604,7 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, sizeof(reply)); if (ret < 0) { - dev_err(sdev->dev, "error: failed to set DAI config for SSP%d\n", + dev_err(scomp->dev, "error: failed to set DAI config for SSP%d\n", config->dai_index); return ret; } @@ -2616,7 +2612,7 @@ static int sof_link_ssp_load(struct snd_soc_component *scomp, int index, /* set config for all DAI's with name matching the link name */ ret = sof_set_dai_config(sdev, size, link, config); if (ret < 0) - dev_err(sdev->dev, "error: failed to save DAI config for SSP%d\n", + dev_err(scomp->dev, "error: failed to save DAI config for SSP%d\n", config->dai_index); return ret; @@ -2655,7 +2651,7 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index, ARRAY_SIZE(esai_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse esai tokens failed %d\n", + dev_err(scomp->dev, "error: parse esai tokens failed %d\n", le32_to_cpu(private->size)); return ret; } @@ -2669,14 +2665,14 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index, config->esai.rx_slots = le32_to_cpu(hw_config->rx_slots); config->esai.tx_slots = le32_to_cpu(hw_config->tx_slots); - dev_info(sdev->dev, + dev_info(scomp->dev, "tplg: config ESAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n", config->dai_index, config->format, config->esai.mclk_rate, config->esai.tdm_slot_width, config->esai.tdm_slots, config->esai.mclk_id); if (config->esai.tdm_slots < 1 || config->esai.tdm_slots > 8) { - dev_err(sdev->dev, "error: invalid channel count for ESAI%d\n", + dev_err(scomp->dev, "error: invalid channel count for ESAI%d\n", config->dai_index); return -EINVAL; } @@ -2686,7 +2682,7 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index, config->hdr.cmd, config, size, &reply, sizeof(reply)); if (ret < 0) { - dev_err(sdev->dev, "error: failed to set DAI config for ESAI%d\n", + dev_err(scomp->dev, "error: failed to set DAI config for ESAI%d\n", config->dai_index); return ret; } @@ -2694,7 +2690,7 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index, /* set config for all DAI's with name matching the link name */ ret = sof_set_dai_config(sdev, size, link, config); if (ret < 0) - dev_err(sdev->dev, "error: failed to save DAI config for ESAI%d\n", + dev_err(scomp->dev, "error: failed to save DAI config for ESAI%d\n", config->dai_index); return ret; @@ -2727,7 +2723,7 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, ARRAY_SIZE(dmic_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse dmic tokens failed %d\n", + dev_err(scomp->dev, "error: parse dmic tokens failed %d\n", le32_to_cpu(private->size)); return ret; } @@ -2762,7 +2758,7 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, ARRAY_SIZE(dmic_pdm_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse dmic pdm tokens failed %d\n", + dev_err(scomp->dev, "error: parse dmic pdm tokens failed %d\n", le32_to_cpu(private->size)); goto err; } @@ -2771,27 +2767,27 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, ipc_config->hdr.size = size; /* debug messages */ - dev_dbg(sdev->dev, "tplg: config DMIC%d driver version %d\n", + dev_dbg(scomp->dev, "tplg: config DMIC%d driver version %d\n", ipc_config->dai_index, ipc_config->dmic.driver_ipc_version); - dev_dbg(sdev->dev, "pdmclk_min %d pdm_clkmax %d duty_min %hd\n", + dev_dbg(scomp->dev, "pdmclk_min %d pdm_clkmax %d duty_min %hd\n", ipc_config->dmic.pdmclk_min, ipc_config->dmic.pdmclk_max, ipc_config->dmic.duty_min); - dev_dbg(sdev->dev, "duty_max %hd fifo_fs %d num_pdms active %d\n", + dev_dbg(scomp->dev, "duty_max %hd fifo_fs %d num_pdms active %d\n", ipc_config->dmic.duty_max, ipc_config->dmic.fifo_fs, ipc_config->dmic.num_pdm_active); - dev_dbg(sdev->dev, "fifo word length %hd\n", + dev_dbg(scomp->dev, "fifo word length %hd\n", ipc_config->dmic.fifo_bits); for (j = 0; j < ipc_config->dmic.num_pdm_active; j++) { - dev_dbg(sdev->dev, "pdm %hd mic a %hd mic b %hd\n", + dev_dbg(scomp->dev, "pdm %hd mic a %hd mic b %hd\n", ipc_config->dmic.pdm[j].id, ipc_config->dmic.pdm[j].enable_mic_a, ipc_config->dmic.pdm[j].enable_mic_b); - dev_dbg(sdev->dev, "pdm %hd polarity a %hd polarity b %hd\n", + dev_dbg(scomp->dev, "pdm %hd polarity a %hd polarity b %hd\n", ipc_config->dmic.pdm[j].id, ipc_config->dmic.pdm[j].polarity_mic_a, ipc_config->dmic.pdm[j].polarity_mic_b); - dev_dbg(sdev->dev, "pdm %hd clk_edge %hd skew %hd\n", + dev_dbg(scomp->dev, "pdm %hd clk_edge %hd skew %hd\n", ipc_config->dmic.pdm[j].id, ipc_config->dmic.pdm[j].clk_edge, ipc_config->dmic.pdm[j].skew); @@ -2808,7 +2804,7 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, sizeof(reply)); if (ret < 0) { - dev_err(sdev->dev, + dev_err(scomp->dev, "error: failed to set DAI config for DMIC%d\n", config->dai_index); goto err; @@ -2817,7 +2813,7 @@ static int sof_link_dmic_load(struct snd_soc_component *scomp, int index, /* set config for all DAI's with name matching the link name */ ret = sof_set_dai_config(sdev, size, link, ipc_config); if (ret < 0) - dev_err(sdev->dev, "error: failed to save DAI config for DMIC%d\n", + dev_err(scomp->dev, "error: failed to save DAI config for DMIC%d\n", config->dai_index); err: @@ -2908,21 +2904,21 @@ static int sof_link_hda_load(struct snd_soc_component *scomp, int index, ARRAY_SIZE(hda_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse hda tokens failed %d\n", + dev_err(scomp->dev, "error: parse hda tokens failed %d\n", le32_to_cpu(private->size)); return ret; } dai = snd_soc_find_dai(link->cpus); if (!dai) { - dev_err(sdev->dev, "error: failed to find dai %s in %s", + dev_err(scomp->dev, "error: failed to find dai %s in %s", link->cpus->dai_name, __func__); return -EINVAL; } ret = sof_link_hda_process(sdev, link, config); if (ret < 0) - dev_err(sdev->dev, "error: failed to process hda dai link %s", + dev_err(scomp->dev, "error: failed to process hda dai link %s", link->name); return ret; @@ -2948,7 +2944,7 @@ static int sof_link_alh_load(struct snd_soc_component *scomp, int index, sizeof(reply)); if (ret < 0) { - dev_err(sdev->dev, "error: failed to set DAI config for ALH %d\n", + dev_err(scomp->dev, "error: failed to set DAI config for ALH %d\n", config->dai_index); return ret; } @@ -2956,7 +2952,7 @@ static int sof_link_alh_load(struct snd_soc_component *scomp, int index, /* set config for all DAI's with name matching the link name */ ret = sof_set_dai_config(sdev, size, link, config); if (ret < 0) - dev_err(sdev->dev, "error: failed to save DAI config for ALH %d\n", + dev_err(scomp->dev, "error: failed to save DAI config for ALH %d\n", config->dai_index); return ret; @@ -2967,7 +2963,6 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_soc_tplg_private *private = &cfg->priv; struct sof_ipc_dai_config config; struct snd_soc_tplg_hw_config *hw_config; @@ -2976,10 +2971,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, int i = 0; if (!link->platforms) { - dev_err(sdev->dev, "error: no platforms\n"); + dev_err(scomp->dev, "error: no platforms\n"); return -EINVAL; } - link->platforms->name = dev_name(sdev->dev); + link->platforms->name = dev_name(scomp->dev); /* * Set nonatomic property for FE dai links as their trigger action @@ -2998,7 +2993,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, /* check we have some tokens - we need at least DAI type */ if (le32_to_cpu(private->size) == 0) { - dev_err(sdev->dev, "error: expected tokens for DAI, none found\n"); + dev_err(scomp->dev, "error: expected tokens for DAI, none found\n"); return -EINVAL; } @@ -3010,7 +3005,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, ARRAY_SIZE(dai_link_tokens), private->array, le32_to_cpu(private->size)); if (ret != 0) { - dev_err(sdev->dev, "error: parse link tokens failed %d\n", + dev_err(scomp->dev, "error: parse link tokens failed %d\n", le32_to_cpu(private->size)); return ret; } @@ -3022,12 +3017,12 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, num_hw_configs = le32_to_cpu(cfg->num_hw_configs); if (!num_hw_configs) { if (config.type != SOF_DAI_INTEL_HDA) { - dev_err(sdev->dev, "error: unexpected DAI config count %d!\n", + dev_err(scomp->dev, "error: unexpected DAI config count %d!\n", le32_to_cpu(cfg->num_hw_configs)); return -EINVAL; } } else { - dev_dbg(sdev->dev, "tplg: %d hw_configs found, default id: %d!\n", + dev_dbg(scomp->dev, "tplg: %d hw_configs found, default id: %d!\n", cfg->num_hw_configs, le32_to_cpu(cfg->default_hw_config_id)); for (i = 0; i < num_hw_configs; i++) { @@ -3036,7 +3031,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, } if (i == num_hw_configs) { - dev_err(sdev->dev, "error: default hw_config id: %d not found!\n", + dev_err(scomp->dev, "error: default hw_config id: %d not found!\n", le32_to_cpu(cfg->default_hw_config_id)); return -EINVAL; } @@ -3075,7 +3070,8 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, &config); break; default: - dev_err(sdev->dev, "error: invalid DAI type %d\n", config.type); + dev_err(scomp->dev, "error: invalid DAI type %d\n", + config.type); ret = -EINVAL; break; } @@ -3123,7 +3119,7 @@ static int sof_link_unload(struct snd_soc_component *scomp, goto found; } - dev_err(sdev->dev, "error: failed to find dai %s in %s", + dev_err(scomp->dev, "error: failed to find dai %s in %s", link->name, __func__); return -EINVAL; found: @@ -3138,7 +3134,7 @@ static int sof_link_unload(struct snd_soc_component *scomp, ret = sof_link_hda_unload(sdev, link); break; default: - dev_err(sdev->dev, "error: invalid DAI type %d\n", + dev_err(scomp->dev, "error: invalid DAI type %d\n", sof_dai->dai_config->type); ret = -EINVAL; break; @@ -3164,7 +3160,7 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, if (!sroute) return -ENOMEM; - sroute->sdev = sdev; + sroute->scomp = scomp; connect = kzalloc(sizeof(*connect), GFP_KERNEL); if (!connect) { @@ -3175,14 +3171,14 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, connect->hdr.size = sizeof(*connect); connect->hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_CONNECT; - dev_dbg(sdev->dev, "sink %s control %s source %s\n", + dev_dbg(scomp->dev, "sink %s control %s source %s\n", route->sink, route->control ? route->control : "none", route->source); /* source component */ - source_swidget = snd_sof_find_swidget(sdev, (char *)route->source); + source_swidget = snd_sof_find_swidget(scomp, (char *)route->source); if (!source_swidget) { - dev_err(sdev->dev, "error: source %s not found\n", + dev_err(scomp->dev, "error: source %s not found\n", route->source); ret = -EINVAL; goto err; @@ -3201,9 +3197,9 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, connect->source_id = source_swidget->comp_id; /* sink component */ - sink_swidget = snd_sof_find_swidget(sdev, (char *)route->sink); + sink_swidget = snd_sof_find_swidget(scomp, (char *)route->sink); if (!sink_swidget) { - dev_err(sdev->dev, "error: sink %s not found\n", + dev_err(scomp->dev, "error: sink %s not found\n", route->sink); ret = -EINVAL; goto err; @@ -3227,7 +3223,7 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, */ if (source_swidget->id != snd_soc_dapm_buffer && sink_swidget->id != snd_soc_dapm_buffer) { - dev_dbg(sdev->dev, "warning: neither Linked source component %s nor sink component %s is of buffer type, ignoring link\n", + dev_dbg(scomp->dev, "warning: neither Linked source component %s nor sink component %s is of buffer type, ignoring link\n", route->source, route->sink); ret = 0; goto err; @@ -3239,7 +3235,7 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, /* check IPC return value */ if (ret < 0) { - dev_err(sdev->dev, "error: failed to add route sink %s control %s source %s\n", + dev_err(scomp->dev, "error: failed to add route sink %s control %s source %s\n", route->sink, route->control ? route->control : "none", route->source); @@ -3248,7 +3244,7 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, /* check IPC reply */ if (reply.error < 0) { - dev_err(sdev->dev, "error: DSP failed to add route sink %s control %s source %s result %d\n", + dev_err(scomp->dev, "error: DSP failed to add route sink %s control %s source %s result %d\n", route->sink, route->control ? route->control : "none", route->source, reply.error); @@ -3275,8 +3271,9 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, /* Function to set the initial value of SOF kcontrols. * The value will be stored in scontrol->control_data */ -static int snd_sof_cache_kcontrol_val(struct snd_sof_dev *sdev) +static int snd_sof_cache_kcontrol_val(struct snd_soc_component *scomp) { + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct snd_sof_control *scontrol = NULL; int ipc_cmd, ctrl_type; int ret = 0; @@ -3296,33 +3293,34 @@ static int snd_sof_cache_kcontrol_val(struct snd_sof_dev *sdev) ctrl_type = SOF_CTRL_TYPE_DATA_GET; break; default: - dev_err(sdev->dev, + dev_err(scomp->dev, "error: Invalid scontrol->cmd: %d\n", scontrol->cmd); return -EINVAL; } - ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol, + ret = snd_sof_ipc_set_get_comp_data(scontrol, ipc_cmd, ctrl_type, scontrol->cmd, false); if (ret < 0) { - dev_warn(sdev->dev, - "error: kcontrol value get for widget: %d\n", - scontrol->comp_id); + dev_warn(scomp->dev, + "error: kcontrol value get for widget: %d\n", + scontrol->comp_id); } } return ret; } -int snd_sof_complete_pipeline(struct snd_sof_dev *sdev, +int snd_sof_complete_pipeline(struct device *dev, struct snd_sof_widget *swidget) { + struct snd_sof_dev *sdev = dev_get_drvdata(dev); struct sof_ipc_pipe_ready ready; struct sof_ipc_reply reply; int ret; - dev_dbg(sdev->dev, "tplg: complete pipeline %s id %d\n", + dev_dbg(dev, "tplg: complete pipeline %s id %d\n", swidget->widget->name, swidget->comp_id); memset(&ready, 0, sizeof(ready)); @@ -3352,7 +3350,7 @@ static void sof_complete(struct snd_soc_component *scomp) switch (swidget->id) { case snd_soc_dapm_scheduler: swidget->complete = - snd_sof_complete_pipeline(sdev, swidget); + snd_sof_complete_pipeline(scomp->dev, swidget); break; default: break; @@ -3362,14 +3360,13 @@ static void sof_complete(struct snd_soc_component *scomp) * cache initial values of SOF kcontrols by reading DSP value over * IPC. It may be overwritten by alsa-mixer after booting up */ - snd_sof_cache_kcontrol_val(sdev); + snd_sof_cache_kcontrol_val(scomp); } /* manifest - optional to inform component of manifest */ static int sof_manifest(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_manifest *man) { - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); u32 size; u32 abi_version; @@ -3377,16 +3374,16 @@ static int sof_manifest(struct snd_soc_component *scomp, int index, /* backward compatible with tplg without ABI info */ if (!size) { - dev_dbg(sdev->dev, "No topology ABI info\n"); + dev_dbg(scomp->dev, "No topology ABI info\n"); return 0; } if (size != SOF_TPLG_ABI_SIZE) { - dev_err(sdev->dev, "error: invalid topology ABI size\n"); + dev_err(scomp->dev, "error: invalid topology ABI size\n"); return -EINVAL; } - dev_info(sdev->dev, + dev_info(scomp->dev, "Topology: ABI %d:%d:%d Kernel ABI %d:%d:%d\n", man->priv.data[0], man->priv.data[1], man->priv.data[2], SOF_ABI_MAJOR, SOF_ABI_MINOR, @@ -3397,15 +3394,15 @@ static int sof_manifest(struct snd_soc_component *scomp, int index, man->priv.data[2]); if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, abi_version)) { - dev_err(sdev->dev, "error: incompatible topology ABI version\n"); + dev_err(scomp->dev, "error: incompatible topology ABI version\n"); return -EINVAL; } if (abi_version > SOF_ABI_VERSION) { if (!IS_ENABLED(CONFIG_SND_SOC_SOF_STRICT_ABI_CHECKS)) { - dev_warn(sdev->dev, "warn: topology ABI is more recent than kernel\n"); + dev_warn(scomp->dev, "warn: topology ABI is more recent than kernel\n"); } else { - dev_err(sdev->dev, "error: topology ABI is more recent than kernel\n"); + dev_err(scomp->dev, "error: topology ABI is more recent than kernel\n"); return -EINVAL; } } @@ -3463,25 +3460,25 @@ static struct snd_soc_tplg_ops sof_tplg_ops = { .bytes_ext_ops_count = ARRAY_SIZE(sof_bytes_ext_ops), }; -int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file) +int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) { const struct firmware *fw; int ret; - dev_dbg(sdev->dev, "loading topology:%s\n", file); + dev_dbg(scomp->dev, "loading topology:%s\n", file); - ret = request_firmware(&fw, file, sdev->dev); + ret = request_firmware(&fw, file, scomp->dev); if (ret < 0) { - dev_err(sdev->dev, "error: tplg request firmware %s failed err: %d\n", + dev_err(scomp->dev, "error: tplg request firmware %s failed err: %d\n", file, ret); return ret; } - ret = snd_soc_tplg_component_load(sdev->component, + ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw, SND_SOC_TPLG_INDEX_ALL); if (ret < 0) { - dev_err(sdev->dev, "error: tplg component load failed %d\n", + dev_err(scomp->dev, "error: tplg component load failed %d\n", ret); ret = -EINVAL; } From 0dda56d6aedef2378c7d6ae6518afae349fb3da0 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 13 Nov 2019 10:26:09 -0800 Subject: [PATCH 1753/1995] ASoC: SOF: intel: hda: Modify signature for hda_codec_probe_bus() The machine driver selection for HDA platforms will be consolidated and moved out of the SOF DSP probe callback. In preparation for that, modify the signature for hda_codec_probe_bus() to pass the hda_codec_use_common_hdmi as a variable while probing the HDA codecs. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/intel/hda-codec.c | 16 ++++++---------- sound/soc/sof/intel/hda.c | 2 +- sound/soc/sof/intel/hda.h | 3 ++- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 827f84a0722e91..65761e09518413 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -80,12 +80,11 @@ EXPORT_SYMBOL(hda_codec_jack_wake_enable); EXPORT_SYMBOL(hda_codec_jack_check); /* probe individual codec */ -static int hda_codec_probe(struct snd_sof_dev *sdev, int address) +static int hda_codec_probe(struct snd_sof_dev *sdev, int address, + bool hda_codec_use_common_hdmi) { #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) struct hdac_hda_priv *hda_priv; - struct snd_soc_acpi_mach_params *mach_params = NULL; - struct snd_sof_pdata *pdata = sdev->pdata; #endif struct hda_bus *hbus = sof_to_hbus(sdev); struct hdac_device *hdev; @@ -115,10 +114,6 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) if (ret < 0) return ret; - if (pdata->machine) - mach_params = (struct snd_soc_acpi_mach_params *) - &pdata->machine->mach_params; - if ((resp & 0xFFFF0000) == IDISP_VID_INTEL) hda_priv->need_display_power = true; @@ -126,7 +121,7 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) * if common HDMI codec driver is not used, codec load * is skipped here and hdac_hdmi is used instead */ - if ((mach_params && mach_params->common_hdmi_codec_drv) || + if (hda_codec_use_common_hdmi || (resp & 0xFFFF0000) != IDISP_VID_INTEL) { hdev->type = HDA_DEV_LEGACY; hda_codec_load_module(&hda_priv->codec); @@ -145,7 +140,8 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) } /* Codec initialization */ -int hda_codec_probe_bus(struct snd_sof_dev *sdev) +int hda_codec_probe_bus(struct snd_sof_dev *sdev, + bool hda_codec_use_common_hdmi) { struct hdac_bus *bus = sof_to_bus(sdev); int i, ret; @@ -156,7 +152,7 @@ int hda_codec_probe_bus(struct snd_sof_dev *sdev) if (!(bus->codec_mask & (1 << i))) continue; - ret = hda_codec_probe(sdev, i); + ret = hda_codec_probe(sdev, i, hda_codec_use_common_hdmi); if (ret < 0) { dev_err(bus->dev, "error: codec #%d probe error, ret: %d\n", i, ret); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 91bd88fddac7aa..3ed0d847160c57 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -475,7 +475,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) } /* create codec instances */ - hda_codec_probe_bus(sdev); + hda_codec_probe_bus(sdev, hda_codec_use_common_hdmi); hda_codec_i915_put(sdev); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 18d7e72bf9b722..b7164a26984b0b 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -574,7 +574,8 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev); /* * HDA Codec operations. */ -int hda_codec_probe_bus(struct snd_sof_dev *sdev); +int hda_codec_probe_bus(struct snd_sof_dev *sdev, + bool hda_codec_use_common_hdmi); void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev); void hda_codec_jack_check(struct snd_sof_dev *sdev); From f948586b0a493e1f74a40441f85879638b2951a9 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 7 Nov 2019 18:54:01 +0200 Subject: [PATCH 1754/1995] ASoC: SOF: Make creation of machine device from SOF core optional Currently, SOF probes machine drivers by creating a platform device and passing the machine description as private data. This is driven by the ACPI restrictions. Ideally, ACPI tables should contain the description for the machine driver. This is not possible because ACPI tables are frozen and used on multiple OS-es (e.g Windows). In the case of Device Tree we don't have this restriction, so we choose to probe the machine drivers by creating a DT node as is the standard ALSA way. This patch makes the probing of machine drivers from SOF core optional allowing for Device Tree platforms to decouple the SOF core from machine driver probing. Along with this, it also consolidates the machine driver selection for Intel platforms by defining optional ops for selecting the machine driver based on the ACPI match for HDA and non-HDA platforms and setting the mach params. Signed-off-by: Daniel Baluta Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 59 +-------- sound/soc/sof/intel/apl.c | 7 ++ sound/soc/sof/intel/bdw.c | 33 +++++ sound/soc/sof/intel/byt.c | 45 +++++++ sound/soc/sof/intel/cnl.c | 7 ++ sound/soc/sof/intel/hda.c | 225 ++++++++++++++++++++--------------- sound/soc/sof/intel/hda.h | 5 + sound/soc/sof/nocodec.c | 1 - sound/soc/sof/ops.h | 34 ++++++ sound/soc/sof/sof-acpi-dev.c | 29 +---- sound/soc/sof/sof-audio.c | 78 ++++++++++++ sound/soc/sof/sof-audio.h | 4 + sound/soc/sof/sof-of-dev.c | 22 +--- sound/soc/sof/sof-pci-dev.c | 28 +---- sound/soc/sof/sof-priv.h | 11 ++ 15 files changed, 358 insertions(+), 230 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index 9832322adbec0e..e258f6a8e7a5c5 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -92,47 +92,9 @@ void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, } EXPORT_SYMBOL(snd_sof_get_status); -/* - * SOF Driver enumeration. - */ -static int sof_machine_check(struct snd_sof_dev *sdev) -{ - struct snd_sof_pdata *plat_data = sdev->pdata; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) - struct snd_soc_acpi_mach *machine; - int ret; -#endif - - if (plat_data->machine) - return 0; - -#if !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) - dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); - return -ENODEV; -#else - /* fallback to nocodec mode */ - dev_warn(sdev->dev, "No ASoC machine driver found - using nocodec\n"); - machine = devm_kzalloc(sdev->dev, sizeof(*machine), GFP_KERNEL); - if (!machine) - return -ENOMEM; - - ret = sof_nocodec_setup(sdev->dev, plat_data, machine, - plat_data->desc, plat_data->desc->ops); - if (ret < 0) - return ret; - - plat_data->machine = machine; - - return 0; -#endif -} - static int sof_probe_continue(struct snd_sof_dev *sdev) { struct snd_sof_pdata *plat_data = sdev->pdata; - const char *drv_name; - const void *mach; - int size; int ret; /* probe the DSP hardware */ @@ -218,22 +180,9 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) goto fw_run_err; } - drv_name = plat_data->machine->drv_name; - mach = (const void *)plat_data->machine; - size = sizeof(*plat_data->machine); - - /* register machine driver, pass machine info as pdata */ - plat_data->pdev_mach = - platform_device_register_data(sdev->dev, drv_name, - PLATFORM_DEVID_NONE, mach, size); - - if (IS_ERR(plat_data->pdev_mach)) { - ret = PTR_ERR(plat_data->pdev_mach); + ret = snd_sof_machine_register(sdev, plat_data); + if (ret < 0) goto fw_run_err; - } - - dev_dbg(sdev->dev, "created machine %s\n", - dev_name(&plat_data->pdev_mach->dev)); /* * Some platforms in SOF, ex: BYT, may not have their platform PM @@ -363,9 +312,7 @@ int snd_sof_device_remove(struct device *dev) * will remove the component driver and unload the topology * before freeing the snd_card. */ - if (!IS_ERR_OR_NULL(pdata->pdev_mach)) - platform_device_unregister(pdata->pdev_mach); - + snd_sof_machine_unregister(sdev, pdata); /* * Unregistering the machine driver results in unloading the topology. * Some widgets, ex: scheduler, attempt to power down the core they are diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 7daa8eb456c8d1..9e4d859b4dbab0 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -17,6 +17,7 @@ #include "../sof-priv.h" #include "hda.h" +#include "../sof-audio.h" static const struct snd_sof_debugfs_map apl_dsp_debugfs[] = { {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, @@ -53,6 +54,12 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .ipc_msg_data = hda_ipc_msg_data, .ipc_pcm_params = hda_ipc_pcm_params, + /* machine driver */ + .machine_select = hda_machine_select, + .machine_register = sof_machine_register, + .machine_unregister = sof_machine_unregister, + .set_mach_params = hda_set_mach_params, + /* debug */ .debug_map = apl_dsp_debugfs, .debug_map_count = ARRAY_SIZE(apl_dsp_debugfs), diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 141dad55476447..de3d14e37518ad 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -17,6 +17,7 @@ #include #include "../ops.h" #include "shim.h" +#include "../sof-audio.h" /* BARs */ #define BDW_DSP_BAR 0 @@ -536,6 +537,32 @@ static int bdw_probe(struct snd_sof_dev *sdev) return ret; } +static void bdw_machine_select(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *sof_pdata = sdev->pdata; + const struct sof_dev_desc *desc = sof_pdata->desc; + struct snd_soc_acpi_mach *mach; + + mach = snd_soc_acpi_find_machine(desc->machines); + if (!mach) { + dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n"); + return; + } + + sof_pdata->tplg_filename = mach->sof_tplg_filename; + mach->mach_params.acpi_ipc_irq_index = desc->irqindex_host_ipc; + sof_pdata->machine = mach; +} + +void bdw_set_mach_params(const struct snd_soc_acpi_mach *mach, + struct device *dev) +{ + struct snd_soc_acpi_mach_params *mach_params; + + mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params; + mach_params->platform = dev_name(dev); +} + /* Broadwell DAIs */ static struct snd_soc_dai_driver bdw_dai[] = { { @@ -574,6 +601,12 @@ const struct snd_sof_dsp_ops sof_bdw_ops = { .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, + /* machine driver */ + .machine_select = bdw_machine_select, + .machine_register = sof_machine_register, + .machine_unregister = sof_machine_unregister, + .set_mach_params = bdw_set_mach_params, + /* debug */ .debug_map = bdw_debugfs, .debug_map_count = ARRAY_SIZE(bdw_debugfs), diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 2abf80b3eb52fe..f13179c6b0474f 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -17,6 +17,7 @@ #include #include "../ops.h" #include "shim.h" +#include "../sof-audio.h" /* DSP memories */ #define IRAM_OFFSET 0x0C0000 @@ -382,6 +383,32 @@ static int byt_reset(struct snd_sof_dev *sdev) return 0; } +static void byt_machine_select(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *sof_pdata = sdev->pdata; + const struct sof_dev_desc *desc = sof_pdata->desc; + struct snd_soc_acpi_mach *mach; + + mach = snd_soc_acpi_find_machine(desc->machines); + if (!mach) { + dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n"); + return; + } + + sof_pdata->tplg_filename = mach->sof_tplg_filename; + mach->mach_params.acpi_ipc_irq_index = desc->irqindex_host_ipc; + sof_pdata->machine = mach; +} + +void byt_set_mach_params(const struct snd_soc_acpi_mach *mach, + struct device *dev) +{ + struct snd_soc_acpi_mach_params *mach_params; + + mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params; + mach_params->platform = dev_name(dev); +} + /* Baytrail DAIs */ static struct snd_soc_dai_driver byt_dai[] = { { @@ -514,6 +541,12 @@ const struct snd_sof_dsp_ops sof_tng_ops = { .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, + /* machine driver */ + .machine_select = byt_machine_select, + .machine_register = sof_machine_register, + .machine_unregister = sof_machine_unregister, + .set_mach_params = byt_set_mach_params, + /* debug */ .debug_map = byt_debugfs, .debug_map_count = ARRAY_SIZE(byt_debugfs), @@ -682,6 +715,12 @@ const struct snd_sof_dsp_ops sof_byt_ops = { .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, + /* machine driver */ + .machine_select = byt_machine_select, + .machine_register = sof_machine_register, + .machine_unregister = sof_machine_unregister, + .set_mach_params = byt_set_mach_params, + /* debug */ .debug_map = byt_debugfs, .debug_map_count = ARRAY_SIZE(byt_debugfs), @@ -748,6 +787,12 @@ const struct snd_sof_dsp_ops sof_cht_ops = { .ipc_msg_data = intel_ipc_msg_data, .ipc_pcm_params = intel_ipc_pcm_params, + /* machine driver */ + .machine_select = byt_machine_select, + .machine_register = sof_machine_register, + .machine_unregister = sof_machine_unregister, + .set_mach_params = byt_set_mach_params, + /* debug */ .debug_map = cht_debugfs, .debug_map_count = ARRAY_SIZE(cht_debugfs), diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 0e1e265f3f3b3b..3541063ba84c70 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -18,6 +18,7 @@ #include "../ops.h" #include "hda.h" #include "hda-ipc.h" +#include "../sof-audio.h" static const struct snd_sof_debugfs_map cnl_dsp_debugfs[] = { {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, @@ -243,6 +244,12 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .ipc_msg_data = hda_ipc_msg_data, .ipc_pcm_params = hda_ipc_pcm_params, + /* machine driver */ + .machine_select = hda_machine_select, + .machine_register = sof_machine_register, + .machine_unregister = sof_machine_unregister, + .set_mach_params = hda_set_mach_params, + /* debug */ .debug_map = cnl_dsp_debugfs, .debug_map_count = ARRAY_SIZE(cnl_dsp_debugfs), diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 3ed0d847160c57..4d35e03faef5bf 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -344,16 +344,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) struct hdac_bus *bus = sof_to_bus(sdev); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_ext_link *hlink; - struct snd_soc_acpi_mach_params *mach_params; - struct snd_soc_acpi_mach *hda_mach; - struct snd_sof_pdata *pdata = sdev->pdata; - struct snd_soc_acpi_mach *mach; - const char *tplg_filename; - const char *idisp_str; - const char *dmic_str; - int dmic_num; - int codec_num = 0; - int i; #endif int ret = 0; @@ -387,93 +377,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) if (bus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(bus); - /* codec detection */ - if (!bus->codec_mask) { - dev_info(bus->dev, "no hda codecs found!\n"); - } else { - dev_info(bus->dev, "hda codecs found, mask %lx\n", - bus->codec_mask); - - for (i = 0; i < HDA_MAX_CODECS; i++) { - if (bus->codec_mask & (1 << i)) - codec_num++; - } - - /* - * If no machine driver is found, then: - * - * hda machine driver is used if : - * 1. there is one HDMI codec and one external HDAudio codec - * 2. only HDMI codec - */ - if (!pdata->machine && codec_num <= 2 && - HDA_IDISP_CODEC(bus->codec_mask)) { - hda_mach = snd_soc_acpi_intel_hda_machines; - pdata->machine = hda_mach; - - /* topology: use the info from hda_machines */ - pdata->tplg_filename = - hda_mach->sof_tplg_filename; - - /* - * firmware: pick the first in machine list, - * or use nocodec firmware name if list is empty - */ - mach = pdata->desc->machines; - if (mach->id[0]) - pdata->fw_filename = mach->sof_fw_filename; - else - pdata->fw_filename = - pdata->desc->nocodec_fw_filename; - - dev_info(bus->dev, "using HDA machine driver %s now\n", - hda_mach->drv_name); - - if (codec_num == 1) - idisp_str = "-idisp"; - else - idisp_str = ""; - - /* first check NHLT for DMICs */ - dmic_num = check_nhlt_dmic(sdev); - - /* allow for module parameter override */ - if (hda_dmic_num != -1) - dmic_num = hda_dmic_num; - - switch (dmic_num) { - case 2: - dmic_str = "-2ch"; - break; - case 4: - dmic_str = "-4ch"; - break; - default: - dmic_num = 0; - dmic_str = ""; - break; - } - - tplg_filename = pdata->tplg_filename; - tplg_filename = fixup_tplg_name(sdev, tplg_filename, - idisp_str, dmic_str); - if (!tplg_filename) { - hda_codec_i915_exit(sdev); - return ret; - } - pdata->tplg_filename = tplg_filename; - } - } - - /* used by hda machine driver to create dai links */ - if (pdata->machine) { - mach_params = (struct snd_soc_acpi_mach_params *) - &pdata->machine->mach_params; - mach_params->codec_mask = bus->codec_mask; - mach_params->platform = dev_name(sdev->dev); - mach_params->common_hdmi_codec_drv = hda_codec_use_common_hdmi; - } - /* create codec instances */ hda_codec_probe_bus(sdev, hda_codec_use_common_hdmi); @@ -735,4 +638,132 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) return 0; } +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) +static int hda_generic_machine_select(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct snd_soc_acpi_mach_params *mach_params; + struct snd_soc_acpi_mach *hda_mach; + struct snd_sof_pdata *pdata = sdev->pdata; + const char *tplg_filename; + const char *idisp_str; + const char *dmic_str; + int dmic_num; + int codec_num = 0; + int i; + + /* codec detection */ + if (!bus->codec_mask) { + dev_info(bus->dev, "no hda codecs found!\n"); + } else { + dev_info(bus->dev, "hda codecs found, mask %lx\n", + bus->codec_mask); + + for (i = 0; i < HDA_MAX_CODECS; i++) { + if (bus->codec_mask & (1 << i)) + codec_num++; + } + + /* + * If no machine driver is found, then: + * + * hda machine driver is used if : + * 1. there is one HDMI codec and one external HDAudio codec + * 2. only HDMI codec + */ + if (!pdata->machine && codec_num <= 2 && + HDA_IDISP_CODEC(bus->codec_mask)) { + hda_mach = snd_soc_acpi_intel_hda_machines; + + /* topology: use the info from hda_machines */ + pdata->tplg_filename = + hda_mach->sof_tplg_filename; + + dev_info(bus->dev, "using HDA machine driver %s now\n", + hda_mach->drv_name); + + if (codec_num == 1) + idisp_str = "-idisp"; + else + idisp_str = ""; + + /* first check NHLT for DMICs */ + dmic_num = check_nhlt_dmic(sdev); + + /* allow for module parameter override */ + if (hda_dmic_num != -1) + dmic_num = hda_dmic_num; + + switch (dmic_num) { + case 2: + dmic_str = "-2ch"; + break; + case 4: + dmic_str = "-4ch"; + break; + default: + dmic_num = 0; + dmic_str = ""; + break; + } + + tplg_filename = pdata->tplg_filename; + tplg_filename = fixup_tplg_name(sdev, tplg_filename, + idisp_str, dmic_str); + if (!tplg_filename) + return -EINVAL; + + pdata->machine = hda_mach; + pdata->tplg_filename = tplg_filename; + } + } + + /* used by hda machine driver to create dai links */ + if (pdata->machine) { + mach_params = (struct snd_soc_acpi_mach_params *) + &pdata->machine->mach_params; + mach_params->codec_mask = bus->codec_mask; + mach_params->common_hdmi_codec_drv = hda_codec_use_common_hdmi; + } + + return 0; +} +#else +static int hda_generic_machine_select(struct snd_sof_dev *sdev) +{ + return 0; +} +#endif + +void hda_set_mach_params(const struct snd_soc_acpi_mach *mach, + struct device *dev) +{ + struct snd_soc_acpi_mach_params *mach_params; + + mach_params = (struct snd_soc_acpi_mach_params *)&mach->mach_params; + mach_params->platform = dev_name(dev); +} + +void hda_machine_select(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *sof_pdata = sdev->pdata; + const struct sof_dev_desc *desc = sof_pdata->desc; + struct snd_soc_acpi_mach *mach; + + mach = snd_soc_acpi_find_machine(desc->machines); + if (mach) { + sof_pdata->tplg_filename = mach->sof_tplg_filename; + sof_pdata->machine = mach; + } + + /* + * Choose HDA generic machine driver if mach is NULL. + * Otherwise, set certain mach params. + */ + hda_generic_machine_select(sdev); + + if (!sof_pdata->machine) + dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n"); +} + MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index b7164a26984b0b..97c3fcb23d1558 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -623,4 +623,9 @@ extern const struct sof_intel_dsp_desc tgl_chip_info; extern const struct sof_intel_dsp_desc ehl_chip_info; extern const struct sof_intel_dsp_desc jsl_chip_info; +/* machine driver select */ +void hda_machine_select(struct snd_sof_dev *sdev); +void hda_set_mach_params(const struct snd_soc_acpi_mach *mach, + struct device *dev); + #endif diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index 3d128e5a132c00..0a2167f19f251d 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -77,7 +77,6 @@ int sof_nocodec_setup(struct device *dev, sof_pdata->drv_name = "sof-nocodec"; mach->drv_name = "sof-nocodec"; - sof_pdata->fw_filename = desc->nocodec_fw_filename; sof_pdata->tplg_filename = desc->nocodec_tplg_filename; /* create dummy BE dai_links */ diff --git a/sound/soc/sof/ops.h b/sound/soc/sof/ops.h index 93512dcbaacdd0..e929a6e0058fc1 100644 --- a/sound/soc/sof/ops.h +++ b/sound/soc/sof/ops.h @@ -391,6 +391,40 @@ snd_sof_pcm_platform_pointer(struct snd_sof_dev *sdev, return 0; } +/* machine driver */ +static inline int +snd_sof_machine_register(struct snd_sof_dev *sdev, void *pdata) +{ + if (sof_ops(sdev) && sof_ops(sdev)->machine_register) + return sof_ops(sdev)->machine_register(sdev, pdata); + + return 0; +} + +static inline void +snd_sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata) +{ + if (sof_ops(sdev) && sof_ops(sdev)->machine_unregister) + sof_ops(sdev)->machine_unregister(sdev, pdata); +} + +static inline void +snd_sof_machine_select(struct snd_sof_dev *sdev) +{ + if (sof_ops(sdev) && sof_ops(sdev)->machine_select) + sof_ops(sdev)->machine_select(sdev); +} + +static inline void +snd_sof_set_mach_params(const struct snd_soc_acpi_mach *mach, + struct device *dev) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + + if (sof_ops(sdev) && sof_ops(sdev)->set_mach_params) + sof_ops(sdev)->set_mach_params(mach, dev); +} + static inline const struct snd_sof_dsp_ops *sof_get_ops(const struct sof_dev_desc *d, const struct sof_ops_table mach_ops[], int asize) diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 22e13ef098119a..8174b9a7da9579 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -145,7 +145,6 @@ static int sof_acpi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct sof_dev_desc *desc; - struct snd_soc_acpi_mach *mach; struct snd_sof_pdata *sof_pdata; const struct snd_sof_dsp_ops *ops; int ret; @@ -172,35 +171,9 @@ static int sof_acpi_probe(struct platform_device *pdev) return -ENODEV; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) - /* force nocodec mode */ - dev_warn(dev, "Force to use nocodec mode\n"); - mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); - if (!mach) - return -ENOMEM; - ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); - if (ret < 0) - return ret; -#else - /* find machine */ - mach = snd_soc_acpi_find_machine(desc->machines); - if (!mach) { - dev_warn(dev, "warning: No matching ASoC machine driver found\n"); - } else { - sof_pdata->fw_filename = mach->sof_fw_filename; - sof_pdata->tplg_filename = mach->sof_tplg_filename; - } -#endif - - if (mach) { - mach->mach_params.platform = dev_name(dev); - mach->mach_params.acpi_ipc_irq_index = desc->irqindex_host_ipc; - } - - sof_pdata->machine = mach; sof_pdata->desc = desc; sof_pdata->dev = &pdev->dev; - sof_pdata->platform = dev_name(dev); + sof_pdata->fw_filename = desc->default_fw_filename; /* alternate fw and tplg filenames ? */ if (fw_path) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index bf99d040c9c195..e8d0a3606cd7a7 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -360,3 +360,81 @@ struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp, return NULL; } +/* + * SOF Driver enumeration. + */ +int sof_machine_check(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *sof_pdata = sdev->pdata; + const struct sof_dev_desc *desc = sof_pdata->desc; + struct snd_soc_acpi_mach *mach; + int ret; + + /* force nocodec mode */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) + dev_warn(sdev->dev, "Force to use nocodec mode\n"); + goto nocodec; +#endif + + /* find machine */ + snd_sof_machine_select(sdev); + if (sof_pdata->machine) { + snd_sof_set_mach_params(sof_pdata->machine, sdev->dev); + return 0; + } + +#if !IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC) + dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); + return -ENODEV; +#endif +nocodec: + /* select nocodec mode */ + dev_warn(sdev->dev, "Using nocodec machine driver\n"); + mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL); + if (!mach) + return -ENOMEM; + + ret = sof_nocodec_setup(sdev->dev, sof_pdata, mach, desc, desc->ops); + if (ret < 0) + return ret; + + sof_pdata->machine = mach; + snd_sof_set_mach_params(sof_pdata->machine, sdev->dev); + + return 0; +} +EXPORT_SYMBOL(sof_machine_check); + +int sof_machine_register(struct snd_sof_dev *sdev, void *pdata) +{ + struct snd_sof_pdata *plat_data = (struct snd_sof_pdata *)pdata; + const char *drv_name; + const void *mach; + int size; + + drv_name = plat_data->machine->drv_name; + mach = (const void *)plat_data->machine; + size = sizeof(*plat_data->machine); + + /* register machine driver, pass machine info as pdata */ + plat_data->pdev_mach = + platform_device_register_data(sdev->dev, drv_name, + PLATFORM_DEVID_NONE, mach, size); + if (IS_ERR(plat_data->pdev_mach)) + return PTR_ERR(plat_data->pdev_mach); + + dev_dbg(sdev->dev, "created machine %s\n", + dev_name(&plat_data->pdev_mach->dev)); + + return 0; +} +EXPORT_SYMBOL(sof_machine_register); + +void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata) +{ + struct snd_sof_pdata *plat_data = (struct snd_sof_pdata *)pdata; + + if (!IS_ERR_OR_NULL(plat_data->pdev_mach)) + platform_device_unregister(plat_data->pdev_mach); +} +EXPORT_SYMBOL(sof_machine_unregister); diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index d47d851d769334..5352a22e7ddce1 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -204,4 +204,8 @@ int sof_restore_pipelines(struct device *dev); int sof_set_hw_params_upon_resume(struct device *dev); bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev); +/* Machine driver enumeration */ +int sof_machine_register(struct snd_sof_dev *sdev, void *pdata); +void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata); + #endif diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c index 81deb5582d7725..170a5839150fd3 100644 --- a/sound/soc/sof/sof-of-dev.c +++ b/sound/soc/sof/sof-of-dev.c @@ -44,8 +44,6 @@ static int sof_of_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct sof_dev_desc *desc; - /*TODO: create a generic snd_soc_xxx_mach */ - struct snd_soc_acpi_mach *mach; struct snd_sof_pdata *sof_pdata; const struct snd_sof_dsp_ops *ops; int ret; @@ -67,27 +65,9 @@ static int sof_of_probe(struct platform_device *pdev) return -ENODEV; } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) - /* force nocodec mode */ - dev_warn(dev, "Force to use nocodec mode\n"); - mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); - if (!mach) - return -ENOMEM; - ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); - if (ret < 0) - return ret; -#else - /* TODO: implement case where we actually have a codec */ - return -ENODEV; -#endif - - if (mach) - mach->mach_params.platform = dev_name(dev); - - sof_pdata->machine = mach; sof_pdata->desc = desc; sof_pdata->dev = &pdev->dev; - sof_pdata->platform = dev_name(dev); + sof_pdata->fw_filename = desc->default_fw_filename; /* TODO: read alternate fw and tplg filenames from DT */ sof_pdata->fw_filename_prefix = sof_pdata->desc->default_fw_path; diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 046bd57657ca3a..1c7b8739270819 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -275,7 +275,6 @@ static int sof_pci_probe(struct pci_dev *pci, struct device *dev = &pci->dev; const struct sof_dev_desc *desc = (const struct sof_dev_desc *)pci_id->driver_data; - struct snd_soc_acpi_mach *mach; struct snd_sof_pdata *sof_pdata; const struct snd_sof_dsp_ops *ops; int ret; @@ -306,35 +305,10 @@ static int sof_pci_probe(struct pci_dev *pci, if (ret < 0) return ret; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) - /* force nocodec mode */ - dev_warn(dev, "Force to use nocodec mode\n"); - mach = devm_kzalloc(dev, sizeof(*mach), GFP_KERNEL); - if (!mach) { - ret = -ENOMEM; - goto release_regions; - } - ret = sof_nocodec_setup(dev, sof_pdata, mach, desc, ops); - if (ret < 0) - goto release_regions; - -#else - /* find machine */ - mach = snd_soc_acpi_find_machine(desc->machines); - if (!mach) { - dev_warn(dev, "warning: No matching ASoC machine driver found\n"); - } else { - mach->mach_params.platform = dev_name(dev); - sof_pdata->fw_filename = mach->sof_fw_filename; - sof_pdata->tplg_filename = mach->sof_tplg_filename; - } -#endif /* CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE */ - sof_pdata->name = pci_name(pci); - sof_pdata->machine = mach; sof_pdata->desc = (struct sof_dev_desc *)pci_id->driver_data; sof_pdata->dev = dev; - sof_pdata->platform = dev_name(dev); + sof_pdata->fw_filename = desc->default_fw_filename; /* alternate fw and tplg filenames ? */ if (fw_path) diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index eae1fc209a65cb..54dd6d4b4c128e 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -202,6 +202,15 @@ struct snd_sof_dsp_ops { int (*get_window_offset)(struct snd_sof_dev *sdev, u32 id);/* mandatory for common loader code */ + /* machine driver ops */ + int (*machine_register)(struct snd_sof_dev *sdev, + void *pdata); /* optional */ + void (*machine_unregister)(struct snd_sof_dev *sdev, + void *pdata); /* optional */ + void (*machine_select)(struct snd_sof_dev *sdev); /* optional */ + void (*set_mach_params)(const struct snd_soc_acpi_mach *mach, + struct device *dev); /* optional */ + /* DAI ops */ struct snd_soc_dai_driver *drv; int num_drv; @@ -511,4 +520,6 @@ int intel_pcm_open(struct snd_sof_dev *sdev, int intel_pcm_close(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); +int sof_machine_check(struct snd_sof_dev *sdev); + #endif From 6f0927172ec2aef7ed3528168e45ff2b8738fd73 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Wed, 6 Nov 2019 12:51:06 -0800 Subject: [PATCH 1755/1995] ASoC: SOF: remove nocodec_fw_filename Remove nocodec_fw_filename from struct sof_dev_desc as it is not longer needed. Signed-off-by: Ranjani Sridharan --- include/sound/sof.h | 1 - sound/soc/sof/sof-acpi-dev.c | 5 ----- sound/soc/sof/sof-of-dev.c | 1 - sound/soc/sof/sof-pci-dev.c | 10 ---------- 4 files changed, 17 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index 1723478db4a21c..98a757d3a67db2 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -84,7 +84,6 @@ struct sof_dev_desc { const void *chip_info; /* defaults for no codec mode */ - const char *nocodec_fw_filename; const char *nocodec_tplg_filename; /* defaults paths for firmware and topology files */ diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 8174b9a7da9579..9c0a4eed5cc836 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -46,7 +46,6 @@ static const struct sof_dev_desc sof_acpi_haswell_desc = { .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-hsw.ri", - .nocodec_fw_filename = "sof-hsw.ri", .nocodec_tplg_filename = "sof-hsw-nocodec.tplg", .ops = &sof_hsw_ops, .arch_ops = &sof_xtensa_arch_ops @@ -64,7 +63,6 @@ static const struct sof_dev_desc sof_acpi_broadwell_desc = { .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-bdw.ri", - .nocodec_fw_filename = "sof-bdw.ri", .nocodec_tplg_filename = "sof-bdw-nocodec.tplg", .ops = &sof_bdw_ops, .arch_ops = &sof_xtensa_arch_ops @@ -84,7 +82,6 @@ static const struct sof_dev_desc sof_acpi_baytrailcr_desc = { .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-byt.ri", - .nocodec_fw_filename = "sof-byt.ri", .nocodec_tplg_filename = "sof-byt-nocodec.tplg", .ops = &sof_byt_ops, .arch_ops = &sof_xtensa_arch_ops @@ -100,7 +97,6 @@ static const struct sof_dev_desc sof_acpi_baytrail_desc = { .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-byt.ri", - .nocodec_fw_filename = "sof-byt.ri", .nocodec_tplg_filename = "sof-byt-nocodec.tplg", .ops = &sof_byt_ops, .arch_ops = &sof_xtensa_arch_ops @@ -116,7 +112,6 @@ static const struct sof_dev_desc sof_acpi_cherrytrail_desc = { .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-cht.ri", - .nocodec_fw_filename = "sof-cht.ri", .nocodec_tplg_filename = "sof-cht-nocodec.tplg", .ops = &sof_cht_ops, .arch_ops = &sof_xtensa_arch_ops diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c index 170a5839150fd3..39ea8af6213f32 100644 --- a/sound/soc/sof/sof-of-dev.c +++ b/sound/soc/sof/sof-of-dev.c @@ -20,7 +20,6 @@ static struct sof_dev_desc sof_of_imx8qxp_desc = { .default_fw_path = "imx/sof", .default_tplg_path = "imx/sof-tplg", .default_fw_filename = "sof-imx8.ri", - .nocodec_fw_filename = "sof-imx8.ri", .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", .ops = &sof_imx8_ops, }; diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 1c7b8739270819..5f08a9ca6bf87c 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -48,7 +48,6 @@ static const struct sof_dev_desc bxt_desc = { .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-apl.ri", - .nocodec_fw_filename = "sof-apl.ri", .nocodec_tplg_filename = "sof-apl-nocodec.tplg", .ops = &sof_apl_ops, .arch_ops = &sof_xtensa_arch_ops @@ -67,7 +66,6 @@ static const struct sof_dev_desc glk_desc = { .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-glk.ri", - .nocodec_fw_filename = "sof-glk.ri", .nocodec_tplg_filename = "sof-glk-nocodec.tplg", .ops = &sof_apl_ops, .arch_ops = &sof_xtensa_arch_ops @@ -96,7 +94,6 @@ static const struct sof_dev_desc tng_desc = { .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-byt.ri", - .nocodec_fw_filename = "sof-byt.ri", .nocodec_tplg_filename = "sof-byt.tplg", .ops = &sof_tng_ops, .arch_ops = &sof_xtensa_arch_ops @@ -115,7 +112,6 @@ static const struct sof_dev_desc cnl_desc = { .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-cnl.ri", - .nocodec_fw_filename = "sof-cnl.ri", .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops @@ -134,7 +130,6 @@ static const struct sof_dev_desc cfl_desc = { .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-cfl.ri", - .nocodec_fw_filename = "sof-cfl.ri", .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops @@ -155,7 +150,6 @@ static const struct sof_dev_desc cml_desc = { .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-cml.ri", - .nocodec_fw_filename = "sof-cml.ri", .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops @@ -174,7 +168,6 @@ static const struct sof_dev_desc icl_desc = { .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-icl.ri", - .nocodec_fw_filename = "sof-icl.ri", .nocodec_tplg_filename = "sof-icl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops @@ -193,7 +186,6 @@ static const struct sof_dev_desc tgl_desc = { .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-tgl.ri", - .nocodec_fw_filename = "sof-tgl.ri", .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops @@ -212,7 +204,6 @@ static const struct sof_dev_desc ehl_desc = { .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", .default_fw_filename = "sof-ehl.ri", - .nocodec_fw_filename = "sof-ehl.ri", .nocodec_tplg_filename = "sof-ehl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops @@ -230,7 +221,6 @@ static const struct sof_dev_desc jsl_desc = { .chip_info = &jsl_chip_info, .default_fw_path = "intel/sof", .default_tplg_path = "intel/sof-tplg", - .nocodec_fw_filename = "sof-jsl.ri", .nocodec_tplg_filename = "sof-jsl-nocodec.tplg", .ops = &sof_cnl_ops, .arch_ops = &sof_xtensa_arch_ops From 87d98b98dfed14520e2794c4746a291003e14209 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 7 Nov 2019 23:36:43 +0200 Subject: [PATCH 1756/1995] ASoC: SOF: Remove unused drv_name in sof_pdata This field is only set but never used. Let's remove it to make code cleaner. Signed-off-by: Daniel Baluta Signed-off-by: Ranjani Sridharan --- include/sound/sof.h | 1 - sound/soc/sof/nocodec.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index 98a757d3a67db2..96625355aa94ce 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -22,7 +22,6 @@ struct snd_sof_dsp_ops; */ struct snd_sof_pdata { const struct firmware *fw; - const char *drv_name; const char *name; const char *platform; diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index 0a2167f19f251d..56d887545da307 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -74,8 +74,6 @@ int sof_nocodec_setup(struct device *dev, if (!mach) return -EINVAL; - sof_pdata->drv_name = "sof-nocodec"; - mach->drv_name = "sof-nocodec"; sof_pdata->tplg_filename = desc->nocodec_tplg_filename; From 2824abb095dddf57debb935cd52f0895f99487bc Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Tue, 12 Nov 2019 23:59:57 -0800 Subject: [PATCH 1757/1995] ASoC: SOF: nocodec: Amend arguments for sof_nocodec_setup() Set the drv_name and tplg_filename for nocodec machine driver in sof_machine_check(). This means the sof_nocodec_setup() does not need the mach, plat_data or desc arguments any longer. Signed-off-by: Daniel Baluta Signed-off-by: Ranjani Sridharan --- include/sound/sof.h | 3 --- sound/soc/sof/nocodec.c | 9 --------- sound/soc/sof/sof-audio.c | 5 ++++- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/include/sound/sof.h b/include/sound/sof.h index 96625355aa94ce..6ea74f1a9ec274 100644 --- a/include/sound/sof.h +++ b/include/sound/sof.h @@ -97,8 +97,5 @@ struct sof_dev_desc { }; int sof_nocodec_setup(struct device *dev, - struct snd_sof_pdata *sof_pdata, - struct snd_soc_acpi_mach *mach, - const struct sof_dev_desc *desc, const struct snd_sof_dsp_ops *ops); #endif diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c index 56d887545da307..2233146386ccf4 100644 --- a/sound/soc/sof/nocodec.c +++ b/sound/soc/sof/nocodec.c @@ -63,20 +63,11 @@ static int sof_nocodec_bes_setup(struct device *dev, } int sof_nocodec_setup(struct device *dev, - struct snd_sof_pdata *sof_pdata, - struct snd_soc_acpi_mach *mach, - const struct sof_dev_desc *desc, const struct snd_sof_dsp_ops *ops) { struct snd_soc_dai_link *links; int ret; - if (!mach) - return -EINVAL; - - mach->drv_name = "sof-nocodec"; - sof_pdata->tplg_filename = desc->nocodec_tplg_filename; - /* create dummy BE dai_links */ links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * ops->num_drv, GFP_KERNEL); diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index e8d0a3606cd7a7..a62c2833ace2dd 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -394,7 +394,10 @@ int sof_machine_check(struct snd_sof_dev *sdev) if (!mach) return -ENOMEM; - ret = sof_nocodec_setup(sdev->dev, sof_pdata, mach, desc, desc->ops); + mach->drv_name = "sof-nocodec"; + sof_pdata->tplg_filename = desc->nocodec_tplg_filename; + + ret = sof_nocodec_setup(sdev->dev, desc->ops); if (ret < 0) return ret; From 6b5a6bccec745ea813cab40022b9fc970b535680 Mon Sep 17 00:00:00 2001 From: "Geoffrey D. Bennett" Date: Mon, 11 Nov 2019 00:13:56 +1030 Subject: [PATCH 1758/1995] ALSA: usb-audio: Fix Scarlett 6i6 Gen 2 port data The s6i6_gen2_info.ports[] array had the Mixer and PCM port type entries in the wrong place. Use designators to explicitly specify the array elements being set. Signed-off-by: Geoffrey D. Bennett Tested-by: Alex Fellows Tested-by: Markus Schroetter Fixes: 9e4d5c1be21f ("ALSA: usb-audio: Scarlett Gen 2 mixer interface") Link: https://lore.kernel.org/r/20191110134356.GA31589@b4.vu Signed-off-by: Takashi Iwai --- sound/usb/mixer_scarlett_gen2.c | 36 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/sound/usb/mixer_scarlett_gen2.c b/sound/usb/mixer_scarlett_gen2.c index 7d460b1f173512..94b903d95afaa8 100644 --- a/sound/usb/mixer_scarlett_gen2.c +++ b/sound/usb/mixer_scarlett_gen2.c @@ -261,34 +261,34 @@ static const struct scarlett2_device_info s6i6_gen2_info = { }, .ports = { - { + [SCARLETT2_PORT_TYPE_NONE] = { .id = 0x000, .num = { 1, 0, 8, 8, 8 }, .src_descr = "Off", .src_num_offset = 0, }, - { + [SCARLETT2_PORT_TYPE_ANALOGUE] = { .id = 0x080, .num = { 4, 4, 4, 4, 4 }, .src_descr = "Analogue %d", .src_num_offset = 1, .dst_descr = "Analogue Output %02d Playback" }, - { + [SCARLETT2_PORT_TYPE_SPDIF] = { .id = 0x180, .num = { 2, 2, 2, 2, 2 }, .src_descr = "S/PDIF %d", .src_num_offset = 1, .dst_descr = "S/PDIF Output %d Playback" }, - { + [SCARLETT2_PORT_TYPE_MIX] = { .id = 0x300, .num = { 10, 18, 18, 18, 18 }, .src_descr = "Mix %c", .src_num_offset = 65, .dst_descr = "Mixer Input %02d Capture" }, - { + [SCARLETT2_PORT_TYPE_PCM] = { .id = 0x600, .num = { 6, 6, 6, 6, 6 }, .src_descr = "PCM %d", @@ -317,44 +317,44 @@ static const struct scarlett2_device_info s18i8_gen2_info = { }, .ports = { - { + [SCARLETT2_PORT_TYPE_NONE] = { .id = 0x000, .num = { 1, 0, 8, 8, 4 }, .src_descr = "Off", .src_num_offset = 0, }, - { + [SCARLETT2_PORT_TYPE_ANALOGUE] = { .id = 0x080, .num = { 8, 6, 6, 6, 6 }, .src_descr = "Analogue %d", .src_num_offset = 1, .dst_descr = "Analogue Output %02d Playback" }, - { + [SCARLETT2_PORT_TYPE_SPDIF] = { + .id = 0x180, /* S/PDIF outputs aren't available at 192KHz * but are included in the USB mux I/O * assignment message anyway */ - .id = 0x180, .num = { 2, 2, 2, 2, 2 }, .src_descr = "S/PDIF %d", .src_num_offset = 1, .dst_descr = "S/PDIF Output %d Playback" }, - { + [SCARLETT2_PORT_TYPE_ADAT] = { .id = 0x200, .num = { 8, 0, 0, 0, 0 }, .src_descr = "ADAT %d", .src_num_offset = 1, }, - { + [SCARLETT2_PORT_TYPE_MIX] = { .id = 0x300, .num = { 10, 18, 18, 18, 18 }, .src_descr = "Mix %c", .src_num_offset = 65, .dst_descr = "Mixer Input %02d Capture" }, - { + [SCARLETT2_PORT_TYPE_PCM] = { .id = 0x600, .num = { 20, 18, 18, 14, 10 }, .src_descr = "PCM %d", @@ -387,20 +387,20 @@ static const struct scarlett2_device_info s18i20_gen2_info = { }, .ports = { - { + [SCARLETT2_PORT_TYPE_NONE] = { .id = 0x000, .num = { 1, 0, 8, 8, 6 }, .src_descr = "Off", .src_num_offset = 0, }, - { + [SCARLETT2_PORT_TYPE_ANALOGUE] = { .id = 0x080, .num = { 8, 10, 10, 10, 10 }, .src_descr = "Analogue %d", .src_num_offset = 1, .dst_descr = "Analogue Output %02d Playback" }, - { + [SCARLETT2_PORT_TYPE_SPDIF] = { /* S/PDIF outputs aren't available at 192KHz * but are included in the USB mux I/O * assignment message anyway @@ -411,21 +411,21 @@ static const struct scarlett2_device_info s18i20_gen2_info = { .src_num_offset = 1, .dst_descr = "S/PDIF Output %d Playback" }, - { + [SCARLETT2_PORT_TYPE_ADAT] = { .id = 0x200, .num = { 8, 8, 8, 4, 0 }, .src_descr = "ADAT %d", .src_num_offset = 1, .dst_descr = "ADAT Output %d Playback" }, - { + [SCARLETT2_PORT_TYPE_MIX] = { .id = 0x300, .num = { 10, 18, 18, 18, 18 }, .src_descr = "Mix %c", .src_num_offset = 65, .dst_descr = "Mixer Input %02d Capture" }, - { + [SCARLETT2_PORT_TYPE_PCM] = { .id = 0x600, .num = { 20, 18, 18, 14, 10 }, .src_descr = "PCM %d", From dbf48060e36a162f452bc5b5ea725b12eb5b435f Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 14 Nov 2019 13:08:08 +0800 Subject: [PATCH 1759/1995] ASoC: SOF: Intel: hda: fix MSI issues by merging ipc and stream irq handlers The existing code uses two handlers for a shared edge-based MSI interrupts. In corner cases, interrupts are lost, leading to IPC timeouts. Those timeouts do not appear in legacy mode. This patch merges the two handlers into a single one. Follow-up patches will extend this work to SoundWire interrupts which are also shared with IPC and stream interrupts. Signed-off-by: Bard Liao --- sound/soc/sof/intel/apl.c | 1 - sound/soc/sof/intel/cnl.c | 1 - sound/soc/sof/intel/hda-ipc.c | 14 +++++----- sound/soc/sof/intel/hda-stream.c | 16 ++++++----- sound/soc/sof/intel/hda.c | 48 ++++++++++++++++++-------------- sound/soc/sof/intel/hda.h | 6 ++-- 6 files changed, 45 insertions(+), 41 deletions(-) diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c index 9e4d859b4dbab0..aeed1422900b72 100644 --- a/sound/soc/sof/intel/apl.c +++ b/sound/soc/sof/intel/apl.c @@ -42,7 +42,6 @@ const struct snd_sof_dsp_ops sof_apl_ops = { .block_write = sof_block_write, /* doorbell */ - .irq_handler = hda_dsp_ipc_irq_handler, .irq_thread = hda_dsp_ipc_irq_thread, /* ipc */ diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index 3541063ba84c70..ceca776530af65 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -232,7 +232,6 @@ const struct snd_sof_dsp_ops sof_cnl_ops = { .block_write = sof_block_write, /* doorbell */ - .irq_handler = hda_dsp_ipc_irq_handler, .irq_thread = cnl_ipc_irq_thread, /* ipc */ diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 0fd2153c176953..fac9f9762bb22c 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -237,14 +237,14 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) return IRQ_HANDLED; } -/* is this IRQ for ADSP ? - we only care about IPC here */ -irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) +/* Check if it is an IPC and disable IPC interrupt if yes */ +bool check_ipc(struct snd_sof_dev *sdev) { - struct snd_sof_dev *sdev = context; - int ret = IRQ_NONE; + bool ret = false; u32 irq_status; - spin_lock(&sdev->hw_lock); + /* The function can be called at irq thread, so use spin_lock_irq */ + spin_lock_irq(&sdev->hw_lock); /* store status */ irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS); @@ -260,11 +260,11 @@ irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context) snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, HDA_DSP_ADSPIC_IPC, 0); - ret = IRQ_WAKE_THREAD; + ret = true; } out: - spin_unlock(&sdev->hw_lock); + spin_unlock_irq(&sdev->hw_lock); return ret; } diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 92643a801f4f96..53487b8da02717 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -550,22 +550,23 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, return 0; } -irqreturn_t hda_dsp_stream_interrupt(int irq, void *context) +bool is_stream_irq(struct snd_sof_dev *sdev) { - struct hdac_bus *bus = context; - int ret = IRQ_WAKE_THREAD; + struct hdac_bus *bus = sof_to_bus(sdev); + bool ret = true; u32 status; - spin_lock(&bus->reg_lock); + /* The function can be called at irq thread, so use spin_lock_irq */ + spin_lock_irq(&bus->reg_lock); status = snd_hdac_chip_readl(bus, INTSTS); dev_vdbg(bus->dev, "stream irq, INTSTS status: 0x%x\n", status); /* Register inaccessible, ignore it.*/ if (status == 0xffffffff) - ret = IRQ_NONE; + ret = false; - spin_unlock(&bus->reg_lock); + spin_unlock_irq(&bus->reg_lock); return ret; } @@ -603,7 +604,8 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status) irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context) { - struct hdac_bus *bus = context; + struct snd_sof_dev *sdev = context; + struct hdac_bus *bus = sof_to_bus(sdev); #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) u32 rirb_status; #endif diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 4d35e03faef5bf..527d7f3a27dff9 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -402,6 +402,28 @@ static const struct sof_intel_dsp_desc return chip_info; } +irqreturn_t hda_dsp_interrupt_handler(int irq, void *context) +{ + struct snd_sof_dev *sdev = context; + + if (check_ipc(sdev) || is_stream_irq(sdev)) + return IRQ_WAKE_THREAD; + + return IRQ_NONE; +} + +irqreturn_t hda_dsp_interrupt_thread(int irq, void *context) +{ + struct snd_sof_dev *sdev = context; + + if (check_ipc(sdev)) + sof_ops(sdev)->irq_thread(irq, sdev); + if (is_stream_irq(sdev)) + hda_dsp_stream_threaded_handler(irq, sdev); + + return IRQ_HANDLED; +} + int hda_dsp_probe(struct snd_sof_dev *sdev) { struct pci_dev *pci = to_pci_dev(sdev->dev); @@ -506,9 +528,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) */ if (hda_use_msi && pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI) > 0) { dev_info(sdev->dev, "use msi interrupt mode\n"); - hdev->irq = pci_irq_vector(pci, 0); - /* ipc irq number is the same of hda irq */ - sdev->ipc_irq = hdev->irq; + sdev->ipc_irq = pci_irq_vector(pci, 0); /* initialised to "false" by kzalloc() */ sdev->msi_enabled = true; } @@ -519,28 +539,17 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) * in IO-APIC mode, hda->irq and ipc_irq are using the same * irq number of pci->irq */ - hdev->irq = pci->irq; sdev->ipc_irq = pci->irq; } - dev_dbg(sdev->dev, "using HDA IRQ %d\n", hdev->irq); - ret = request_threaded_irq(hdev->irq, hda_dsp_stream_interrupt, - hda_dsp_stream_threaded_handler, - IRQF_SHARED, "AudioHDA", bus); - if (ret < 0) { - dev_err(sdev->dev, "error: failed to register HDA IRQ %d\n", - hdev->irq); - goto free_irq_vector; - } - dev_dbg(sdev->dev, "using IPC IRQ %d\n", sdev->ipc_irq); - ret = request_threaded_irq(sdev->ipc_irq, hda_dsp_ipc_irq_handler, - sof_ops(sdev)->irq_thread, IRQF_SHARED, - "AudioDSP", sdev); + ret = request_threaded_irq(sdev->ipc_irq, hda_dsp_interrupt_handler, + hda_dsp_interrupt_thread, + IRQF_SHARED, "AudioDSP", sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to register IPC IRQ %d\n", sdev->ipc_irq); - goto free_hda_irq; + goto free_irq_vector; } pci_set_master(pci); @@ -571,8 +580,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) free_ipc_irq: free_irq(sdev->ipc_irq, sdev); -free_hda_irq: - free_irq(hdev->irq, bus); free_irq_vector: if (sdev->msi_enabled) pci_free_irq_vectors(pci); @@ -618,7 +625,6 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) SOF_HDA_PPCTL_GPROCEN, 0); free_irq(sdev->ipc_irq, sdev); - free_irq(hda->irq, bus); if (sdev->msi_enabled) pci_free_irq_vectors(pci); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 97c3fcb23d1558..70b96f9ce736a0 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -406,8 +406,6 @@ struct sof_intel_hda_dev { /* the maximum number of streams (playback + capture) supported */ u32 stream_max; - int irq; - /* PM related */ bool l1_support_changed;/* during suspend, is L1SEN changed or not */ @@ -511,11 +509,12 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params); int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream, int cmd); -irqreturn_t hda_dsp_stream_interrupt(int irq, void *context); irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context); int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, struct hdac_stream *stream); +bool check_ipc(struct snd_sof_dev *sdev); +bool is_stream_irq(struct snd_sof_dev *sdev); struct hdac_ext_stream * hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction); @@ -540,7 +539,6 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev); int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev); int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id); -irqreturn_t hda_dsp_ipc_irq_handler(int irq, void *context); irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context); int hda_dsp_ipc_cmd_done(struct snd_sof_dev *sdev, int dir); From a4f85cd26ccb6dd9d87fa9f52fc1bbb1be67d35b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 18 Nov 2019 19:20:35 -0600 Subject: [PATCH 1760/1995] ASoC: SOF: Intel: add PCI ID for CometLake-S Mirror ID added for legacy HDaudio Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/Kconfig | 16 ++++++++++++++++ sound/soc/sof/sof-pci-dev.c | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index b27fd3fdf335d7..88a864eae077a0 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -27,6 +27,7 @@ config SND_SOC_SOF_INTEL_PCI select SND_SOC_SOF_ICELAKE if SND_SOC_SOF_ICELAKE_SUPPORT select SND_SOC_SOF_COMETLAKE_LP if SND_SOC_SOF_COMETLAKE_LP_SUPPORT select SND_SOC_SOF_COMETLAKE_H if SND_SOC_SOF_COMETLAKE_H_SUPPORT + select SND_SOC_SOF_COMETLAKE_S if SND_SOC_SOF_COMETLAKE_S_SUPPORT select SND_SOC_SOF_TIGERLAKE if SND_SOC_SOF_TIGERLAKE_SUPPORT select SND_SOC_SOF_ELKHARTLAKE if SND_SOC_SOF_ELKHARTLAKE_SUPPORT select SND_SOC_SOF_JASPERLAKE if SND_SOC_SOF_JASPERLAKE_SUPPORT @@ -231,6 +232,21 @@ config SND_SOC_SOF_COMETLAKE_H_SUPPORT Say Y if you have such a device. If unsure select "N". +config SND_SOC_SOF_COMETLAKE_S + tristate + select SND_SOC_SOF_HDA_COMMON + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_COMETLAKE_S_SUPPORT + bool "SOF support for CometLake-S" + help + This adds support for Sound Open Firmware for Intel(R) platforms + using the Cometlake-H processors. + Say Y if you have such a device. + If unsure select "N". + config SND_SOC_SOF_TIGERLAKE_SUPPORT bool "SOF support for Tigerlake" help diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 5f08a9ca6bf87c..c40256c70ea49f 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -390,6 +390,10 @@ static const struct pci_device_id sof_pci_ids[] = { { PCI_DEVICE(0x8086, 0x06c8), .driver_data = (unsigned long)&cml_desc}, #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_S) + { PCI_DEVICE(0x8086, 0xa3f0), + .driver_data = (unsigned long)&cml_desc}, +#endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) { PCI_DEVICE(0x8086, 0xa0c8), .driver_data = (unsigned long)&tgl_desc}, From b00354b79a6ff95ed5e01ea266c4d603d51ec12e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 21 Nov 2019 12:44:38 -0600 Subject: [PATCH 1761/1995] ASoC: SOF: Intel: hda: fix names for interrupt handling Add consistent hda_dsp_check_X_irq() name Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-ipc.c | 2 +- sound/soc/sof/intel/hda-stream.c | 2 +- sound/soc/sof/intel/hda.c | 7 ++++--- sound/soc/sof/intel/hda.h | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index fac9f9762bb22c..c61ca3a1d696ab 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -238,7 +238,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) } /* Check if it is an IPC and disable IPC interrupt if yes */ -bool check_ipc(struct snd_sof_dev *sdev) +bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev) { bool ret = false; u32 irq_status; diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 53487b8da02717..38f8bb3db4b946 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -550,7 +550,7 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, return 0; } -bool is_stream_irq(struct snd_sof_dev *sdev) +bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); bool ret = true; diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 527d7f3a27dff9..6e391a686fcc7f 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -406,7 +406,8 @@ irqreturn_t hda_dsp_interrupt_handler(int irq, void *context) { struct snd_sof_dev *sdev = context; - if (check_ipc(sdev) || is_stream_irq(sdev)) + if (hda_dsp_check_ipc_irq(sdev) || + hda_dsp_check_stream_irq(sdev)) return IRQ_WAKE_THREAD; return IRQ_NONE; @@ -416,9 +417,9 @@ irqreturn_t hda_dsp_interrupt_thread(int irq, void *context) { struct snd_sof_dev *sdev = context; - if (check_ipc(sdev)) + if (hda_dsp_check_ipc_irq(sdev)) sof_ops(sdev)->irq_thread(irq, sdev); - if (is_stream_irq(sdev)) + if (hda_dsp_check_stream_irq(sdev)) hda_dsp_stream_threaded_handler(irq, sdev); return IRQ_HANDLED; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 70b96f9ce736a0..41e3671406f9ff 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -513,8 +513,8 @@ irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context); int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, struct hdac_stream *stream); -bool check_ipc(struct snd_sof_dev *sdev); -bool is_stream_irq(struct snd_sof_dev *sdev); +bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev); +bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev); struct hdac_ext_stream * hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction); From 14796700fc4527edf964f6aa833d3fff76db9943 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 21 Nov 2019 12:46:03 -0600 Subject: [PATCH 1762/1995] ASoC: SOF: Intel: hda: make handler and thread static reported by sparse Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 6e391a686fcc7f..f2df5cc9197298 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -402,7 +402,7 @@ static const struct sof_intel_dsp_desc return chip_info; } -irqreturn_t hda_dsp_interrupt_handler(int irq, void *context) +static irqreturn_t hda_dsp_interrupt_handler(int irq, void *context) { struct snd_sof_dev *sdev = context; @@ -413,7 +413,7 @@ irqreturn_t hda_dsp_interrupt_handler(int irq, void *context) return IRQ_NONE; } -irqreturn_t hda_dsp_interrupt_thread(int irq, void *context) +static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context) { struct snd_sof_dev *sdev = context; From 4d1f570f6f923115a96b6059df3a049a36d10509 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 21 Nov 2019 12:48:54 -0600 Subject: [PATCH 1763/1995] ASoC: SOF: Intel: bdw: make set_mach_params static reported by sparse Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/bdw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index de3d14e37518ad..c09885c0eb7d45 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -554,8 +554,8 @@ static void bdw_machine_select(struct snd_sof_dev *sdev) sof_pdata->machine = mach; } -void bdw_set_mach_params(const struct snd_soc_acpi_mach *mach, - struct device *dev) +static void bdw_set_mach_params(const struct snd_soc_acpi_mach *mach, + struct device *dev) { struct snd_soc_acpi_mach_params *mach_params; From 67d5328f9fb5c0a22d657df2d580cee6176f61a1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 21 Nov 2019 12:50:08 -0600 Subject: [PATCH 1764/1995] ASoC: SOF: Intel: byt: make set_mach_params static reported by sparse Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/byt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index f13179c6b0474f..2f5db1a8c701df 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -400,8 +400,8 @@ static void byt_machine_select(struct snd_sof_dev *sdev) sof_pdata->machine = mach; } -void byt_set_mach_params(const struct snd_soc_acpi_mach *mach, - struct device *dev) +static void byt_set_mach_params(const struct snd_soc_acpi_mach *mach, + struct device *dev) { struct snd_soc_acpi_mach_params *mach_params; From b717ef00ea59bc095a608597ebeb5d315baff863 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 21 Nov 2019 12:55:32 -0600 Subject: [PATCH 1765/1995] ASoC: SOF: topology: fix possible dereference reported by cppcheck sound/soc/sof/topology.c:141:36: warning: Either the condition '!swidget' is redundant or there is possible null pointer dereference: swidget. [nullPointerRedundantCheck] struct snd_soc_component *scomp = swidget->scomp; ^ sound/soc/sof/topology.c:146:6: note: Assuming that condition '!swidget' is not redundant if (!swidget) ^ sound/soc/sof/topology.c:141:36: note: Null pointer dereference struct snd_soc_component *scomp = swidget->scomp; Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/topology.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 987a781a2cd59d..1ae06a1f9b0bbe 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -138,7 +138,7 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { struct snd_sof_widget *swidget = w->dobj.private; - struct snd_soc_component *scomp = swidget->scomp; + struct snd_soc_component *scomp; int stream = SNDRV_PCM_STREAM_CAPTURE; struct snd_sof_pcm *spcm; int ret = 0; @@ -146,6 +146,8 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, if (!swidget) return 0; + scomp = swidget->scomp; + dev_dbg(scomp->dev, "received event %d for widget %s\n", event, w->name); From e6b810377c7353b8b6c08df402c7acdb057df3c4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 21 Nov 2019 13:02:49 -0600 Subject: [PATCH 1766/1995] ASoC: SOF: sof-audio: fix unused label warning Reported by cppcheck and gcc. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-audio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index a62c2833ace2dd..0d8f65b9ae25c8 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -387,7 +387,9 @@ int sof_machine_check(struct snd_sof_dev *sdev) dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n"); return -ENODEV; #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE) nocodec: +#endif /* select nocodec mode */ dev_warn(sdev->dev, "Using nocodec machine driver\n"); mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL); From bc30957ca9edb0ab13b23793a40442f3d649ce16 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 15 Nov 2019 02:28:01 +0800 Subject: [PATCH 1767/1995] ASoC: SOF: Intel: BYT: fix a copy/paste mistake in byt_dump() The shim registers in BYT/CHT/BSW are 64bits based, correct the copy/paste (from bdw.c where the shim registers are 32bits based) error in byt_dump(). Fixes: 3a9e204d4e36 ("ASoC: SOF: Intel: Add context data to any IPC timeout") Signed-off-by: Keyon Jie --- sound/soc/sof/intel/byt.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 2f5db1a8c701df..b3a40d9ef7ce7b 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -146,33 +146,33 @@ static void byt_dump(struct snd_sof_dev *sdev, u32 flags) struct sof_ipc_dsp_oops_xtensa xoops; struct sof_ipc_panic_info panic_info; u32 stack[BYT_STACK_DUMP_SIZE]; - u32 status, panic, imrd, imrx; + u64 status, panic, imrd, imrx; /* now try generic SOF status messages */ - status = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IPCD); - panic = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IPCX); + status = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCD); + panic = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IPCX); byt_get_registers(sdev, &xoops, &panic_info, stack, BYT_STACK_DUMP_SIZE); snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, stack, BYT_STACK_DUMP_SIZE); /* provide some context for firmware debug */ - imrx = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IMRX); - imrd = snd_sof_dsp_read(sdev, BYT_DSP_BAR, SHIM_IMRD); + imrx = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IMRX); + imrd = snd_sof_dsp_read64(sdev, BYT_DSP_BAR, SHIM_IMRD); dev_err(sdev->dev, - "error: ipc host -> DSP: pending %s complete %s raw 0x%8.8x\n", + "error: ipc host -> DSP: pending %s complete %s raw 0x%llx\n", (panic & SHIM_IPCX_BUSY) ? "yes" : "no", (panic & SHIM_IPCX_DONE) ? "yes" : "no", panic); dev_err(sdev->dev, - "error: mask host: pending %s complete %s raw 0x%8.8x\n", + "error: mask host: pending %s complete %s raw 0x%llx\n", (imrx & SHIM_IMRX_BUSY) ? "yes" : "no", (imrx & SHIM_IMRX_DONE) ? "yes" : "no", imrx); dev_err(sdev->dev, - "error: ipc DSP -> host: pending %s complete %s raw 0x%8.8x\n", + "error: ipc DSP -> host: pending %s complete %s raw 0x%llx\n", (status & SHIM_IPCD_BUSY) ? "yes" : "no", (status & SHIM_IPCD_DONE) ? "yes" : "no", status); dev_err(sdev->dev, - "error: mask DSP: pending %s complete %s raw 0x%8.8x\n", + "error: mask DSP: pending %s complete %s raw 0x%llx\n", (imrd & SHIM_IMRD_BUSY) ? "yes" : "no", (imrd & SHIM_IMRD_DONE) ? "yes" : "no", imrd); From 817593b97716746785651c9094c1a03486088a07 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 15 Nov 2019 11:21:47 +0200 Subject: [PATCH 1768/1995] ASoC: Intel: tgl_rt1308: fix build issue with HDAC_HDMI not set Fix the ifdefs so that build does not fail if SND_SOC_HDAC_HDMI is not. Note: Only the common HDMI codec driver has support for TGL. Signed-off-by: Kai Vehmanen --- sound/soc/intel/boards/tgl_rt1308.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/tgl_rt1308.c b/sound/soc/intel/boards/tgl_rt1308.c index c9e3c479b27cd6..6f8b5b2be66d40 100644 --- a/sound/soc/intel/boards/tgl_rt1308.c +++ b/sound/soc/intel/boards/tgl_rt1308.c @@ -28,7 +28,7 @@ struct tgl_card_private { bool common_hdmi_codec_drv; }; -#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) +#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) static struct snd_soc_jack tgl_hdmi[4]; struct tgl_hdmi_pcm { @@ -173,6 +173,7 @@ SND_SOC_DAILINK_DEF(dmic_codec, SND_SOC_DAILINK_DEF(dmic16k, DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); +#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) SND_SOC_DAILINK_DEF(idisp1_pin, DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); SND_SOC_DAILINK_DEF(idisp1_codec, @@ -192,6 +193,7 @@ SND_SOC_DAILINK_DEF(idisp4_pin, DAILINK_COMP_ARRAY(COMP_CPU("iDisp4 Pin"))); SND_SOC_DAILINK_DEF(idisp4_codec, DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi4"))); +#endif static struct snd_soc_dai_link tgl_rt1308_dailink[] = { { @@ -219,7 +221,7 @@ static struct snd_soc_dai_link tgl_rt1308_dailink[] = { .no_pcm = 1, SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform), }, -#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) +#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) { .name = "iDisp1", .id = 3, @@ -283,7 +285,7 @@ static int tgl_rt1308_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) + if (IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)) INIT_LIST_HEAD(&ctx->hdmi_pcm_list); mach = (&pdev->dev)->platform_data; From aa49974f323fde1d35bfcf0893b0441b36f7b655 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 15 Nov 2019 11:04:39 +0200 Subject: [PATCH 1769/1995] ASoC: SOF: Intel: make common HDMI driver default Use the common HDMI driver by default if the codec driver is selected in kernel build. Signed-off-by: Kai Vehmanen --- sound/soc/sof/intel/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 91c8bbcc015a18..bc62d54c2d55bf 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -335,6 +335,7 @@ config SND_SOC_SOF_HDA_COMMON_HDMI_CODEC bool "SOF common HDA HDMI codec driver" depends on SND_SOC_SOF_HDA_LINK depends on SND_HDA_CODEC_HDMI + default SND_HDA_CODEC_HDMI help This adds support for HDMI audio by using the common HDA HDMI/DisplayPort codec driver. From 8591404e1d004feb0b73efb46176dfd311d82085 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 22 Nov 2019 18:19:48 +0200 Subject: [PATCH 1770/1995] ASoC: Intel: boards: make common HDMI driver the default for SOF Modify Kconfig rules for machine drivers used by SOF to pick SND_HDA_CODEC_HDMI by defeault if other conditions are met. For shared machine drivers used also by older SST driver, keep using HDAC_HDMI. Signed-off-by: Kai Vehmanen --- sound/soc/intel/boards/Kconfig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 5b6bc231db79bf..05aa22f42efc4b 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -261,6 +261,7 @@ config SND_SOC_INTEL_DA7219_MAX98357A_GENERIC select SND_SOC_DA7219 select SND_SOC_MAX98357A select SND_SOC_DMIC + select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_CODEC select SND_SOC_HDAC_HDMI config SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON @@ -301,6 +302,7 @@ config SND_SOC_INTEL_BXT_PCM512x_MACH tristate "Broxton with TI PCM512x codec" depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_PCM512x_I2C + select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_CODEC select SND_SOC_HDAC_HDMI if SND_SOC_SOF_HDA_LINK help This adds support for ASoC machine driver for Broxton platforms @@ -412,6 +414,7 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH select SND_SOC_RT5682 select SND_SOC_MAX98357A select SND_SOC_DMIC + select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_CODEC select SND_SOC_HDAC_HDMI help This adds support for ASoC machine driver for Geminilake platforms @@ -425,6 +428,7 @@ if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH tristate "SKL/KBL/BXT/APL with HDA Codecs" + select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_CODEC select SND_SOC_HDAC_HDMI select SND_SOC_DMIC # SND_SOC_HDAC_HDA is already selected @@ -444,6 +448,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH (SND_SOC_SOF_BAYTRAIL && (X86_INTEL_LPSS || COMPILE_TEST)) select SND_SOC_RT5682 select SND_SOC_DMIC + select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_CODEC select SND_SOC_HDAC_HDMI help This adds support for ASoC machine driver for SOF platforms @@ -473,6 +478,7 @@ config SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH select SND_SOC_RT5682 select SND_SOC_DMIC select SND_SOC_HDAC_HDMI + select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_CODEC help This adds support for ASoC machine driver for SOF platform with RT1011 + RT5682 I2S codec. @@ -489,6 +495,7 @@ config SND_SOC_INTEL_TGL_RT1308_MACH depends on MFD_INTEL_LPSS || COMPILE_TEST select SND_SOC_RT1308 select SND_SOC_DMIC + select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_CODEC select SND_SOC_HDAC_HDMI if SND_SOC_SOF_HDA_LINK help This adds support for ASoC machine driver for Tigerlake platforms From b090cc8abc83214b4810ba31ac70fe8d3b14e87b Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 15 Nov 2019 10:07:50 +0200 Subject: [PATCH 1771/1995] ASoC: hdac_hdmi: Drop support for Icelake This reverts commit 019033c854a2 ("ASoC: Intel: hdac_hdmi: add Icelake support"). Icelake HDMI audio is supported by the HDMI codec driver, which can be used both in non-DSP (legacy HDA) and with DSP (SOF) configurations. Signed-off-by: Kai Vehmanen --- sound/soc/codecs/hdac_hdmi.c | 63 ++++++------------------------------ 1 file changed, 9 insertions(+), 54 deletions(-) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 18c173e6a13b28..e6558475e006d0 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -115,16 +115,8 @@ struct hdac_hdmi_dai_port_map { struct hdac_hdmi_cvt *cvt; }; -/* - * pin to port mapping table where the value indicate the pin number and - * the index indicate the port number with 1 base. - */ -static const int icl_pin2port_map[] = {0x4, 0x6, 0x8, 0xa, 0xb}; - struct hdac_hdmi_drv_data { unsigned int vendor_nid; - const int *port_map; /* pin to port mapping table */ - int port_num; }; struct hdac_hdmi_priv { @@ -1374,12 +1366,11 @@ static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid) return 0; } -#define INTEL_VENDOR_NID_0x2 0x02 -#define INTEL_VENDOR_NID_0x8 0x08 -#define INTEL_VENDOR_NID_0xb 0x0b +#define INTEL_VENDOR_NID 0x08 +#define INTEL_GLK_VENDOR_NID 0x0b #define INTEL_GET_VENDOR_VERB 0xf81 #define INTEL_SET_VENDOR_VERB 0x781 -#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ +#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ #define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdev) @@ -1566,26 +1557,7 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev, static int hdac_hdmi_pin2port(void *aptr, int pin) { - struct hdac_device *hdev = aptr; - struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev); - const int *map = hdmi->drv_data->port_map; - int i; - - if (!hdmi->drv_data->port_num) - return pin - 4; /* map NID 0x05 -> port #1 */ - - /* - * looking for the pin number in the mapping table and return - * the index which indicate the port number - */ - for (i = 0; i < hdmi->drv_data->port_num; i++) { - if (pin == map[i]) - return i + 1; - } - - /* return -1 if pin number exceeds our expectation */ - dev_err(&hdev->dev, "Can't find the port for pin %d\n", pin); - return -1; + return pin - 4; /* map NID 0x05 -> port #1 */ } static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) @@ -1596,18 +1568,9 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) struct hdac_hdmi_port *hport = NULL; struct snd_soc_component *component = hdmi->component; int i; - hda_nid_t pin_nid; - - if (!hdmi->drv_data->port_num) { - /* for legacy platforms */ - pin_nid = port + 0x04; - } else if (port < hdmi->drv_data->port_num) { - /* get pin number from the pin2port mapping table */ - pin_nid = hdmi->drv_data->port_map[port - 1]; - } else { - dev_err(&hdev->dev, "Can't find the pin for port %d\n", port); - return; - } + + /* Don't know how this mapping is derived */ + hda_nid_t pin_nid = port + 0x04; dev_dbg(&hdev->dev, "%s: for pin:%d port=%d\n", __func__, pin_nid, pipe); @@ -2025,18 +1988,12 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdev, int pcm_idx) return port->eld.info.spk_alloc; } -static struct hdac_hdmi_drv_data intel_icl_drv_data = { - .vendor_nid = INTEL_VENDOR_NID_0x2, - .port_map = icl_pin2port_map, - .port_num = ARRAY_SIZE(icl_pin2port_map), -}; - static struct hdac_hdmi_drv_data intel_glk_drv_data = { - .vendor_nid = INTEL_VENDOR_NID_0xb, + .vendor_nid = INTEL_GLK_VENDOR_NID, }; static struct hdac_hdmi_drv_data intel_drv_data = { - .vendor_nid = INTEL_VENDOR_NID_0x8, + .vendor_nid = INTEL_VENDOR_NID, }; static int hdac_hdmi_dev_probe(struct hdac_device *hdev) @@ -2216,8 +2173,6 @@ static const struct hda_device_id hdmi_list[] = { &intel_glk_drv_data), HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI", &intel_glk_drv_data), - HDA_CODEC_EXT_ENTRY(0x8086280f, 0x100000, "Icelake HDMI", - &intel_icl_drv_data), {} }; From 58ed327217ba03698a14191fe17c540551bb956e Mon Sep 17 00:00:00 2001 From: Mihai Lindner Date: Mon, 25 Nov 2019 14:46:12 +0200 Subject: [PATCH 1772/1995] [DEBUG][CI]travis: KCFLAGS consistency Be consistent with KCFLAGS across `make` targets. The previous build output is ignored and everything gets rebuilt, when targeting 'bindeb-pkg' after removing the KCFLAGS. Signed-off-by: Mihai Lindner --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index f7a05d36d2c3d7..3a679f060adf7a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,13 +34,13 @@ jobs: - make coccicheck MODE=report M=sound/soc/sof - name: "BUILD SOF Kernel x86_64" script: - - export ARCH=x86_64 + - export ARCH=x86_64 KCFLAGS="-Wall -Werror" - make defconfig - scripts/kconfig/merge_config.sh .config kconfig/base-defconfig kconfig/sof-defconfig - make modules_prepare - - KCFLAGS="-Wall -Werror" make -j`getconf _NPROCESSORS_ONLN` M=sound/soc/sof W=1 - - KCFLAGS="-Wall -Werror" make -j`getconf _NPROCESSORS_ONLN` - - make bindeb-pkg -j`getconf _NPROCESSORS_ONLN` + - make -j`getconf _NPROCESSORS_ONLN` M=sound/soc/sof W=1 + - make -j`getconf _NPROCESSORS_ONLN` + - make -j`getconf _NPROCESSORS_ONLN` bindeb-pkg - name: "BUILD SST Kernel x86_64" script: - export ARCH=x86_64 From 376482cccfd1db011ac72f6c89d8dfa4e73e44c2 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Mon, 25 Nov 2019 17:56:43 +0200 Subject: [PATCH 1773/1995] ASoC: SOF: topology: Fix unload for SAI/ESAI Link unload now fails for ESAI/SAI DAIs with: "error: invalid DAI type 6" because DAI type is not properly handled. Fix this by correctly handling cases where type is ESAI or SAI. Fixes: a4eff5f86c9c5e7 ("ASoC: SOF: imx: Read ESAI parameters and send them to DSP") Signed-off-by: Daniel Baluta --- sound/soc/sof/topology.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 1ae06a1f9b0bbe..ff25d5c95b7001 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -3130,7 +3130,9 @@ static int sof_link_unload(struct snd_soc_component *scomp, case SOF_DAI_INTEL_SSP: case SOF_DAI_INTEL_DMIC: case SOF_DAI_INTEL_ALH: - /* no resource needs to be released for SSP, DMIC and ALH */ + case SOF_DAI_IMX_SAI: + case SOF_DAI_IMX_ESAI: + /* no resource needs to be released for all cases above */ break; case SOF_DAI_INTEL_HDA: ret = sof_link_hda_unload(sdev, link); From 12d411cd9399dd578752224c83a3791cdcbb1c25 Mon Sep 17 00:00:00 2001 From: Sathyanarayana Nujella Date: Sat, 16 Nov 2019 23:37:00 -0800 Subject: [PATCH 1774/1995] ASoC: intel: sof_rt5682: Add quirk for number of HDMI DAI's TGL supports one more HDMI DAI than previous models. So add quirk support for number of HDMI DAI's. Signed-off-by: Sathyanarayana Nujella Signed-off-by: Jairaj Arava --- sound/soc/intel/boards/sof_rt5682.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 751b8ea6ae1f5c..57adadacbf436d 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -35,6 +35,10 @@ #define SOF_RT5682_SSP_AMP(quirk) \ (((quirk) << SOF_RT5682_SSP_AMP_SHIFT) & SOF_RT5682_SSP_AMP_MASK) #define SOF_RT5682_MCLK_BYTCHT_EN BIT(9) +#define SOF_RT5682_NUM_HDMIDEV_SHIFT 10 +#define SOF_RT5682_NUM_HDMIDEV_MASK (GENMASK(12, 10)) +#define SOF_RT5682_NUM_HDMIDEV(quirk) \ + ((quirk << SOF_RT5682_NUM_HDMIDEV_SHIFT) & SOF_RT5682_NUM_HDMIDEV_MASK) /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | @@ -594,6 +598,8 @@ static int sof_audio_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; + dmi_check_system(sof_rt5682_quirk_table); + if (soc_intel_is_byt() || soc_intel_is_cht()) { is_legacy_cpu = 1; dmic_be_num = 0; @@ -604,11 +610,13 @@ static int sof_audio_probe(struct platform_device *pdev) SOF_RT5682_SSP_CODEC(2); } else { dmic_be_num = 2; - hdmi_num = 3; + hdmi_num = (sof_rt5682_quirk & SOF_RT5682_NUM_HDMIDEV_MASK) >> + SOF_RT5682_NUM_HDMIDEV_SHIFT; + /* default number of HDMI DAI's */ + if (!hdmi_num) + hdmi_num = 3; } - dmi_check_system(sof_rt5682_quirk_table); - /* need to get main clock from pmc */ if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { ctx->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); From a1cda7c4628d31b912326b337b41e26faaae41d4 Mon Sep 17 00:00:00 2001 From: Sathyanarayana Nujella Date: Sat, 16 Nov 2019 23:57:24 -0800 Subject: [PATCH 1775/1995] ASoC: intel: sof_rt5682: Add support for tgl-max98357a-rt5682 This patch adds the driver data and updates quirk info for tgl with max98357a speaker amp and ALC5682 headset codec. Signed-off-by: Sathyanarayana Nujella Signed-off-by: Jairaj Arava --- sound/soc/intel/boards/sof_rt5682.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 57adadacbf436d..ad8a2b4bc70928 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -598,6 +598,9 @@ static int sof_audio_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; + if (pdev->id_entry && pdev->id_entry->driver_data) + sof_rt5682_quirk = (unsigned long)pdev->id_entry->driver_data; + dmi_check_system(sof_rt5682_quirk_table); if (soc_intel_is_byt() || soc_intel_is_cht()) { @@ -691,6 +694,21 @@ static int sof_rt5682_remove(struct platform_device *pdev) return 0; } +static const struct platform_device_id board_ids[] = { + { + .name = "sof_rt5682", + }, + { + .name = "tgl_max98357a_rt5682", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_RT5682_SSP_CODEC(0) | + SOF_SPEAKER_AMP_PRESENT | + SOF_RT5682_SSP_AMP(1) | + SOF_RT5682_NUM_HDMIDEV(4)), + }, + { } +}; + static struct platform_driver sof_audio = { .probe = sof_audio_probe, .remove = sof_rt5682_remove, @@ -698,6 +716,7 @@ static struct platform_driver sof_audio = { .name = "sof_rt5682", .pm = &snd_soc_pm_ops, }, + .id_table = board_ids, }; module_platform_driver(sof_audio) @@ -707,3 +726,4 @@ MODULE_AUTHOR("Bard Liao "); MODULE_AUTHOR("Sathya Prakash M R "); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:sof_rt5682"); +MODULE_ALIAS("platform:tgl_max98357a_rt5682"); From 74dd135590b6fde1cd78d7017baaf2dc92ce8d14 Mon Sep 17 00:00:00 2001 From: Sathyanarayana Nujella Date: Sun, 17 Nov 2019 16:44:08 -0800 Subject: [PATCH 1776/1995] ASoC: Intel: common: Add mach table for tgl-max98357a-rt5682 Update tgl mach table to include machine with max98357a & ALC5682. Signed-off-by: Sathyanarayana Nujella Signed-off-by: Jairaj Arava --- sound/soc/intel/common/soc-acpi-intel-tgl-match.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c index 57a6298d6dca31..b4687a5d1962e6 100644 --- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -9,6 +9,11 @@ #include #include +static struct snd_soc_acpi_codecs tgl_codecs = { + .num_codecs = 1, + .codecs = {"MX98357A"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { { .id = "10EC1308", @@ -16,6 +21,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { .sof_fw_filename = "sof-tgl.ri", .sof_tplg_filename = "sof-tgl-rt1308.tplg", }, + { + .id = "10EC5682", + .drv_name = "tgl_max98357a_rt5682", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &tgl_codecs, + .sof_fw_filename = "sof-tgl.ri", + .sof_tplg_filename = "sof-tgl-max98357a-rt5682.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_machines); From c6423829589edfb05f5e0bf42e9982a39b00f5ed Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 25 Nov 2019 14:26:30 -0600 Subject: [PATCH 1777/1995] ASoC: SOF: Intel: hda: use global interrupt enable/disable We have a Global Interrupt Enable (GIE) flag, which can be used to mask all possible interrupts instead of disabling each possible source of interrupts. Since we have a shared interrupt, the proposal is to use a single mask, merge all handlers together and test the sources of interrupts without any racy behavior. Credits to Bard Liao for most of the ideas, I just experimented with the GIE flag. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/cnl.c | 4 ---- sound/soc/sof/intel/hda-ipc.c | 11 ++--------- sound/soc/sof/intel/hda-stream.c | 10 ++++++---- sound/soc/sof/intel/hda.c | 31 ++++++++++++++++++++++++++----- sound/soc/sof/intel/hda.h | 5 +++++ sound/soc/sof/sof-priv.h | 1 + 6 files changed, 40 insertions(+), 22 deletions(-) diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c index ceca776530af65..6b44f6d02082fe 100644 --- a/sound/soc/sof/intel/cnl.c +++ b/sound/soc/sof/intel/cnl.c @@ -107,10 +107,6 @@ static irqreturn_t cnl_ipc_irq_thread(int irq, void *context) "nothing to do in IPC IRQ thread\n"); } - /* re-enable IPC interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, - HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); - return IRQ_HANDLED; } diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index c61ca3a1d696ab..1a32e75f1ad755 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -230,14 +230,10 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context) "nothing to do in IPC IRQ thread\n"); } - /* re-enable IPC interrupt */ - snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC, - HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC); - return IRQ_HANDLED; } -/* Check if it is an IPC and disable IPC interrupt if yes */ +/* Check if an IPC IRQ occurred */ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev) { bool ret = false; @@ -256,10 +252,7 @@ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev) /* IPC message ? */ if (irq_status & HDA_DSP_ADSPIS_IPC) { - /* disable IPC interrupt */ - snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR, - HDA_DSP_REG_ADSPIC, - HDA_DSP_ADSPIC_IPC, 0); + sdev->irq_event |= SOF_HDA_IRQ_IPC; ret = true; } diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 38f8bb3db4b946..2f05b61cc332c2 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -553,7 +553,7 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev, bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); - bool ret = true; + bool ret = false; u32 status; /* The function can be called at irq thread, so use spin_lock_irq */ @@ -562,9 +562,11 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev) status = snd_hdac_chip_readl(bus, INTSTS); dev_vdbg(bus->dev, "stream irq, INTSTS status: 0x%x\n", status); - /* Register inaccessible, ignore it.*/ - if (status == 0xffffffff) - ret = false; + /* if Register inaccessible, ignore it.*/ + if (status != 0xffffffff) { + sdev->irq_event |= SOF_HDA_IRQ_STREAM; + ret = true; + } spin_unlock_irq(&bus->reg_lock); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index f2df5cc9197298..83dbfac9525e5e 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -406,9 +406,20 @@ static irqreturn_t hda_dsp_interrupt_handler(int irq, void *context) { struct snd_sof_dev *sdev = context; - if (hda_dsp_check_ipc_irq(sdev) || - hda_dsp_check_stream_irq(sdev)) + /* clear flags for interrupt sources */ + sdev->irq_event = 0; + + if (hda_dsp_check_stream_irq(sdev) || + hda_dsp_check_ipc_irq(sdev)) { + + /* disable GIE interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + SOF_HDA_INTCTL, + SOF_HDA_INT_GLOBAL_EN, + 0); + return IRQ_WAKE_THREAD; + } return IRQ_NONE; } @@ -417,11 +428,21 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context) { struct snd_sof_dev *sdev = context; - if (hda_dsp_check_ipc_irq(sdev)) - sof_ops(sdev)->irq_thread(irq, sdev); - if (hda_dsp_check_stream_irq(sdev)) + /* deal with streams and controller first */ + if (sdev->irq_event & SOF_HDA_IRQ_STREAM || + hda_dsp_check_stream_irq(sdev)) hda_dsp_stream_threaded_handler(irq, sdev); + if (sdev->irq_event & SOF_HDA_IRQ_IPC || + hda_dsp_check_ipc_irq(sdev)) + sof_ops(sdev)->irq_thread(irq, sdev); + + /* enable GIE interrupt */ + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, + SOF_HDA_INTCTL, + SOF_HDA_INT_GLOBAL_EN, + SOF_HDA_INT_GLOBAL_EN); + return IRQ_HANDLED; } diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 41e3671406f9ff..8b55e88412e345 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -389,6 +389,11 @@ struct sof_intel_dsp_bdl { #define SOF_HDA_PLAYBACK 0 #define SOF_HDA_CAPTURE 1 +/* flags to memorize IPC source (not hardware-defined) */ +#define SOF_HDA_IRQ_IPC BIT(0) +#define SOF_HDA_IRQ_STREAM BIT(1) +#define SOF_HDA_IRQ_SDW BIT(2) + /* represents DSP HDA controller frontend - i.e. host facing control */ struct sof_intel_hda_dev { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 54dd6d4b4c128e..65f006845cbf79 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -387,6 +387,7 @@ struct snd_sof_dev { u32 dtrace_draining; bool msi_enabled; + u32 irq_event; void *private; /* core does not touch this */ }; From 0bdbe73a44dacf0b3c3dc6d410379ac0c240a765 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 25 Nov 2019 11:20:09 +0200 Subject: [PATCH 1778/1995] ASoC: SOF: Intel: add codec_mask module parameter Add a module parameter 'codec_mask' to filter out unwanted HDA codecs from driver probe. E.g. on most systems, codec_mask=4 will limit to HDMI audio and exclude any external HDA codecs. Similar to 'probe_mask' module parameter of snd-hda-intel. Signed-off-by: Kai Vehmanen --- sound/soc/sof/intel/hda-ctrl.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index df1909e1d95060..92e9e4306301cd 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -20,6 +20,10 @@ #include "../ops.h" #include "hda.h" +static int hda_codec_mask = -1; +module_param_named(codec_mask, hda_codec_mask, int, 0444); +MODULE_PARM_DESC(codec_mask, "SOF HDA codec mask for probing"); + /* * HDA Operations. */ @@ -206,6 +210,12 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool full_reset) bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS); dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask); } + + if (hda_codec_mask != -1) { + bus->codec_mask &= hda_codec_mask; + dev_dbg(bus->dev, "filtered codec_mask = 0x%lx\n", + bus->codec_mask); + } #endif /* clear stream status */ From cb50445130d14a5a609d7cd88db9d0436313c881 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 2 Dec 2019 08:49:47 +0100 Subject: [PATCH 1779/1995] ALSA: hda: Modify stream stripe mask only when needed The recent commit in HD-audio stream management for changing the stripe control seems causing a regression on some platforms. The stripe control is currently used only by HDMI codec, and applying the stripe mask unconditionally may lead to scratchy and static noises as seen on some MacBooks. For addressing the regression, this patch changes the stream management code to apply the stripe mask conditionally only when the codec driver requested. Fixes: 9b6f7e7a296e ("ALSA: hda: program stripe bits for controller") BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=204477 Cc: Link: https://lore.kernel.org/r/20191202074947.1617-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 1 + sound/hda/hdac_stream.c | 19 ++++++++++++------- sound/pci/hda/patch_hdmi.c | 5 +++++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index b260c5fd23376c..e05b95e83d5a31 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -493,6 +493,7 @@ struct hdac_stream { bool prepared:1; bool no_period_wakeup:1; bool locked:1; + bool stripe:1; /* apply stripe control */ /* timestamp */ unsigned long start_wallclk; /* start + minimum wallclk */ diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index d8fe7ff0cd58c3..f9707fb05efe68 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -96,12 +96,14 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start) 1 << azx_dev->index, 1 << azx_dev->index); /* set stripe control */ - if (azx_dev->substream) - stripe_ctl = snd_hdac_get_stream_stripe_ctl(bus, azx_dev->substream); - else - stripe_ctl = 0; - snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, - stripe_ctl); + if (azx_dev->stripe) { + if (azx_dev->substream) + stripe_ctl = snd_hdac_get_stream_stripe_ctl(bus, azx_dev->substream); + else + stripe_ctl = 0; + snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, + stripe_ctl); + } /* set DMA start and interrupt mask */ snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_DMA_START | SD_INT_MASK); @@ -118,7 +120,10 @@ void snd_hdac_stream_clear(struct hdac_stream *azx_dev) snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_CTL_DMA_START | SD_INT_MASK, 0); snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ - snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0); + if (azx_dev->stripe) { + snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0); + azx_dev->stripe = 0; + } azx_dev->running = false; } EXPORT_SYMBOL_GPL(snd_hdac_stream_clear); diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 0032bba8cc9dc8..ed4e98a1057a4c 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -32,6 +32,7 @@ #include #include "hda_local.h" #include "hda_jack.h" +#include "hda_controller.h" static bool static_hdmi_pcm; module_param(static_hdmi_pcm, bool, 0644); @@ -1249,6 +1250,10 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, per_pin->cvt_nid = per_cvt->cvt_nid; hinfo->nid = per_cvt->cvt_nid; + /* flip stripe flag for the assigned stream if supported */ + if (get_wcaps(codec, per_cvt->cvt_nid) & AC_WCAP_STRIPE) + azx_stream(get_azx_dev(substream))->stripe = 1; + snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id); snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0, AC_VERB_SET_CONNECT_SEL, From 8cf708c874d1a1732a2ebc7adcbdd66adc0d9400 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Mon, 23 Sep 2019 17:09:28 +0300 Subject: [PATCH 1780/1995] ASoC: SOF: Add asynchronous sample rate converter topology support This patch adds into SOF topology the handling of ASRC DAPM type, adds the tokens to configure the ASRC, and implement component IPC into the driver. Signed-off-by: Seppo Ingalsuo --- include/sound/sof/topology.h | 27 ++++++++++++ include/uapi/sound/sof/abi.h | 2 +- include/uapi/sound/sof/tokens.h | 6 +++ sound/soc/sof/topology.c | 78 +++++++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+), 1 deletion(-) diff --git a/include/sound/sof/topology.h b/include/sound/sof/topology.h index c47b3624092030..8e76178fedf08a 100644 --- a/include/sound/sof/topology.h +++ b/include/sound/sof/topology.h @@ -36,6 +36,7 @@ enum sof_comp_type { SOF_COMP_KPB, /* A key phrase buffer component */ SOF_COMP_SELECTOR, /**< channel selector component */ SOF_COMP_DEMUX, + SOF_COMP_ASRC, /**< Asynchronous sample rate converter */ /* keep FILEREAD/FILEWRITE as the last ones */ SOF_COMP_FILEREAD = 10000, /**< host test based file IO */ SOF_COMP_FILEWRITE = 10001, /**< host test based file IO */ @@ -147,6 +148,32 @@ struct sof_ipc_comp_src { uint32_t rate_mask; /**< SOF_RATE_ supported rates */ } __packed; +/* generic ASRC component */ +struct sof_ipc_comp_asrc { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + /* either source or sink rate must be non zero */ + uint32_t source_rate; /**< Define fixed source rate or */ + /**< use 0 to indicate need to get */ + /**< the rate from stream */ + uint32_t sink_rate; /**< Define fixed sink rate or */ + /**< use 0 to indicate need to get */ + /**< the rate from stream */ + uint32_t asynchronous_mode; /**< synchronous 0, asynchronous 1 */ + /**< When 1 the ASRC tracks and */ + /**< compensates for drift. */ + uint32_t operation_mode; /**< push 0, pull 1, In push mode the */ + /**< ASRC consumes a defined number */ + /**< of frames at input, with varying */ + /**< number of frames at output. */ + /**< In pull mode the ASRC outputs */ + /**< a defined number of frames while */ + /**< number of input frames varies. */ + + /* reserved for future use */ + uint32_t reserved[4]; +} __attribute__((packed)); + /* generic MUX component */ struct sof_ipc_comp_mux { struct sof_ipc_comp comp; diff --git a/include/uapi/sound/sof/abi.h b/include/uapi/sound/sof/abi.h index ebfdc20ca08185..c0ef1643c75389 100644 --- a/include/uapi/sound/sof/abi.h +++ b/include/uapi/sound/sof/abi.h @@ -26,7 +26,7 @@ /* SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 11 +#define SOF_ABI_MINOR 12 #define SOF_ABI_PATCH 0 /* SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 76883e6fb75081..a9a5c4d0a89202 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -57,6 +57,12 @@ #define SOF_TKN_SRC_RATE_IN 300 #define SOF_TKN_SRC_RATE_OUT 301 +/* ASRC */ +#define SOF_TKN_ASRC_RATE_IN 320 +#define SOF_TKN_ASRC_RATE_OUT 321 +#define SOF_TKN_ASRC_ASYNCHRONOUS_MODE 322 +#define SOF_TKN_ASRC_OPERATION_MODE 323 + /* PCM */ #define SOF_TKN_PCM_DMAC_CONFIG 353 diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index ff25d5c95b7001..e06fa7c7e502c4 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -573,6 +573,20 @@ static const struct sof_topology_token src_tokens[] = { offsetof(struct sof_ipc_comp_src, sink_rate), 0}, }; +/* ASRC */ +static const struct sof_topology_token asrc_tokens[] = { + {SOF_TKN_ASRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_asrc, source_rate), 0}, + {SOF_TKN_ASRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc_comp_asrc, sink_rate), 0}, + {SOF_TKN_ASRC_ASYNCHRONOUS_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, + offsetof(struct sof_ipc_comp_asrc, asynchronous_mode), 0}, + {SOF_TKN_ASRC_OPERATION_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_u32, + offsetof(struct sof_ipc_comp_asrc, operation_mode), 0}, +}; + /* Tone */ static const struct sof_topology_token tone_tokens[] = { }; @@ -1782,6 +1796,67 @@ static int sof_widget_load_src(struct snd_soc_component *scomp, int index, return ret; } +/* + * ASRC Topology + */ + +static int sof_widget_load_asrc(struct snd_soc_component *scomp, int index, + struct snd_sof_widget *swidget, + struct snd_soc_tplg_dapm_widget *tw, + struct sof_ipc_comp_reply *r) +{ + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &tw->priv; + struct sof_ipc_comp_asrc *asrc; + int ret; + + asrc = kzalloc(sizeof(*asrc), GFP_KERNEL); + if (!asrc) + return -ENOMEM; + + /* configure ASRC IPC message */ + asrc->comp.hdr.size = sizeof(*asrc); + asrc->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW; + asrc->comp.id = swidget->comp_id; + asrc->comp.type = SOF_COMP_ASRC; + asrc->comp.pipeline_id = index; + asrc->config.hdr.size = sizeof(asrc->config); + + ret = sof_parse_tokens(scomp, asrc, asrc_tokens, + ARRAY_SIZE(asrc_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(scomp->dev, "error: parse asrc tokens failed %d\n", + private->size); + goto err; + } + + ret = sof_parse_tokens(scomp, &asrc->config, comp_tokens, + ARRAY_SIZE(comp_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(scomp->dev, "error: parse asrc.cfg tokens failed %d\n", + le32_to_cpu(private->size)); + goto err; + } + + dev_dbg(scomp->dev, "asrc %s: source rate %d sink rate %d " + "asynch %d operation %d\n", + swidget->widget->name, asrc->source_rate, asrc->sink_rate, + asrc->asynchronous_mode, asrc->operation_mode); + sof_dbg_comp_config(scomp, &asrc->config); + + swidget->private = asrc; + + ret = sof_ipc_tx_message(sdev->ipc, asrc->comp.hdr.cmd, asrc, + sizeof(*asrc), r, sizeof(*r)); + if (ret >= 0) + return ret; +err: + kfree(asrc); + return ret; +} + /* * Signal Generator Topology */ @@ -2195,6 +2270,9 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index, case snd_soc_dapm_src: ret = sof_widget_load_src(scomp, index, swidget, tw, &reply); break; + case snd_soc_dapm_asrc: + ret = sof_widget_load_asrc(scomp, index, swidget, tw, &reply); + break; case snd_soc_dapm_siggen: ret = sof_widget_load_siggen(scomp, index, swidget, tw, &reply); break; From 2cb8d264dea633159f035d4f881d324d6aed830a Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 25 Nov 2019 16:54:21 +0200 Subject: [PATCH 1781/1995] ASoC: SOF: fix fault at driver unload after failed probe If sof_machine_check() fails during driver probe, the IPC state is not initialized and this will lead to a NULL dereference at driver unload. Example log is as follows: [ 1535.980630] sof-audio-pci 0000:00:1f.3: error: no matching ASoC machine driver found - aborting probe [ 1535.980631] sof-audio-pci 0000:00:1f.3: error: failed to get machine info -19 [ 1535.980632] sof-audio-pci 0000:00:1f.3: error: sof_probe_work failed err: -19 [ 1550.798373] BUG: kernel NULL pointer dereference, address: 0000000000000008 ... [ 1550.798393] Call Trace: [ 1550.798397] snd_sof_ipc_free+0x15/0x30 [snd_sof] [ 1550.798399] snd_sof_device_remove+0x29/0xa0 [snd_sof] [ 1550.798400] sof_pci_remove+0x10/0x30 [snd_sof_pci] Signed-off-by: Kai Vehmanen --- sound/soc/sof/ipc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 293c5ae8e88274..1cede16aa7d8cd 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -830,6 +830,9 @@ void snd_sof_ipc_free(struct snd_sof_dev *sdev) { struct snd_sof_ipc *ipc = sdev->ipc; + if (!ipc) + return; + /* disable sending of ipc's */ mutex_lock(&ipc->tx_mutex); ipc->disable_ipc_tx = true; From 7d913c868f64dbbde9d46386f0f75992ae7a50b8 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Thu, 28 Nov 2019 13:52:04 +0200 Subject: [PATCH 1782/1995] ASoc: SOF: Intel: fix hda-ctrl.c build error on sparc64 Fix build error reported on sparc64 due to missing include for module.h. Also add #ifdefs to codec_mask to avoid unused variable warnings on builds with HDA disabled. Reported-by: kbuild test robot Signed-off-by: Kai Vehmanen --- sound/soc/sof/intel/hda-ctrl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 92e9e4306301cd..871b71a15a6331 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -15,14 +15,17 @@ * Hardware interface for generic Intel audio DSP HDA IP */ +#include #include #include #include "../ops.h" #include "hda.h" +#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) static int hda_codec_mask = -1; module_param_named(codec_mask, hda_codec_mask, int, 0444); MODULE_PARM_DESC(codec_mask, "SOF HDA codec mask for probing"); +#endif /* * HDA Operations. From bf2b84fcb0b801aec43c2f17b21b2be31c0c2c22 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Thu, 28 Nov 2019 13:02:27 +0200 Subject: [PATCH 1783/1995] ASoC: SOF: fix include dependencies in channel_map.h The external headers included in sound/sof/channel_map.h break CONFIG_KERNEL_HEADER_TEST. Signed-off-by: Kai Vehmanen --- include/sound/sof/channel_map.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/sound/sof/channel_map.h b/include/sound/sof/channel_map.h index 75e77b0b664bbc..21044eb5f377ce 100644 --- a/include/sound/sof/channel_map.h +++ b/include/sound/sof/channel_map.h @@ -9,8 +9,8 @@ #ifndef __IPC_CHANNEL_MAP_H__ #define __IPC_CHANNEL_MAP_H__ -#include -#include +#include +#include /** * \brief Channel map, specifies transformation of one-to-many or many-to-one. From 1d0681d61d096cfb816cc1f312f6992fd83b7496 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 2 Dec 2019 14:00:33 -0600 Subject: [PATCH 1784/1995] ASoC: SOF: sof-audio.h: fix typo in comment Make checkpatch.pl/codespell happy Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-audio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 5352a22e7ddce1..a62fb2da6a6ece 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -64,7 +64,7 @@ struct snd_sof_control { int min_volume_step; /* min volume step for volume_table */ int max_volume_step; /* max volume step for volume_table */ int num_channels; - u32 readback_offset; /* offset to mmaped data if used */ + u32 readback_offset; /* offset to mmapped data if used */ struct sof_ipc_ctrl_data *control_data; u32 size; /* cdata size */ enum sof_ipc_ctrl_cmd cmd; From 9c71ecd1d30b4a13ed4b16a8d7f28f45a946d464 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 26 Nov 2019 11:34:04 +0100 Subject: [PATCH 1785/1995] ASoC: intel/skl/hda - export number of digital microphones via control components It is required for the auto-detection in the user space (for UCM). Signed-off-by: Jaroslav Kysela Cc: Pierre-Louis Bossart Cc: Mark Brown --- sound/soc/intel/boards/skl_hda_dsp_generic.c | 8 ++++++++ sound/soc/sof/intel/hda.c | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 4e45901e3a2f1a..11eaee9ae41f72 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -100,6 +100,8 @@ static struct snd_soc_card hda_soc_card = { .late_probe = skl_hda_card_late_probe, }; +static char hda_soc_components[30]; + #define IDISP_DAI_COUNT 3 #define HDAC_DAI_COUNT 2 #define DMIC_DAI_COUNT 2 @@ -183,6 +185,12 @@ static int skl_hda_audio_probe(struct platform_device *pdev) hda_soc_card.dev = &pdev->dev; snd_soc_card_set_drvdata(&hda_soc_card, ctx); + if (mach->mach_params.dmic_num > 0) { + snprintf(hda_soc_components, sizeof(hda_soc_components), + "cfg-dmics:%d", mach->mach_params.dmic_num); + hda_soc_card.components = hda_soc_components; + } + return devm_snd_soc_register_card(&pdev->dev, &hda_soc_card); } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 91bd88fddac7aa..eea01f75d23d41 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -351,7 +351,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) const char *tplg_filename; const char *idisp_str; const char *dmic_str; - int dmic_num; + int dmic_num = 0; int codec_num = 0; int i; #endif @@ -472,6 +472,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev) mach_params->codec_mask = bus->codec_mask; mach_params->platform = dev_name(sdev->dev); mach_params->common_hdmi_codec_drv = hda_codec_use_common_hdmi; + mach_params->dmic_num = dmic_num; } /* create codec instances */ From c80a40f1e3b71dad46fb599ae5ad0d12ddb1819b Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 25 Nov 2019 15:36:35 +0100 Subject: [PATCH 1786/1995] ASoC: Intel - use control components to describe card config Use the control interface (field 'components' in the info structure) to pass the I/O configuration details. The goal is to replace the card long name with this. Signed-off-by: Jaroslav Kysela Cc: Pierre-Louis Bossart Cc: Mark Brown --- sound/soc/intel/boards/bytcht_es8316.c | 9 ++++++++- sound/soc/intel/boards/bytcr_rt5640.c | 6 ++++++ sound/soc/intel/boards/bytcr_rt5651.c | 18 +++++++++++------- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 46612331f5ea7a..efa33f30dcaceb 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -361,6 +361,7 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { /* SoC card */ static char codec_name[SND_ACPI_I2C_ID_LEN]; static char long_name[50]; /* = "bytcht-es8316-*-spk-*-mic" */ +static char components_string[32]; /* = "cfg-spk:* cfg-mic:* */ static int byt_cht_es8316_suspend(struct snd_soc_card *card) { @@ -572,11 +573,17 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) } } - /* register the soc card */ + snprintf(components_string, sizeof(components_string), + "cfg-spk:%s cfg-mic:%s", + (quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "1" : "2", + mic_name[BYT_CHT_ES8316_MAP(quirk)]); + byt_cht_es8316_card.components = components_string; snprintf(long_name, sizeof(long_name), "bytcht-es8316-%s-spk-%s-mic", (quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "mono" : "stereo", mic_name[BYT_CHT_ES8316_MAP(quirk)]); byt_cht_es8316_card.long_name = long_name; + + /* register the soc card */ snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); ret = devm_snd_soc_register_card(dev, &byt_cht_es8316_card); diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index dd2b5ad0865910..7bc6d3cec94c6d 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1083,6 +1083,7 @@ static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN]; static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ static char byt_rt5640_long_name[40]; /* = "bytcr-rt5640-*-spk-*-mic" */ +static char byt_rt5640_components[32]; /* = "cfg-spk:* cfg-mic:*" */ static int byt_rt5640_suspend(struct snd_soc_card *card) { @@ -1305,6 +1306,11 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) } } + snprintf(byt_rt5640_components, sizeof(byt_rt5640_components), + "cfg-spk:%s cfg-mic:%s", + (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? "1" : "2", + map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); + byt_rt5640_card.components = byt_rt5640_components; snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name), "bytcr-rt5640-%s-spk-%s-mic", (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 4606f6f582d6fb..80a5674ddb1bc4 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -798,6 +798,7 @@ static char byt_rt5651_codec_name[SND_ACPI_I2C_ID_LEN]; static char byt_rt5651_codec_aif_name[12]; /* = "rt5651-aif[1|2]" */ static char byt_rt5651_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ static char byt_rt5651_long_name[50]; /* = "bytcr-rt5651-*-spk-*-mic[-swapped-hp]" */ +static char byt_rt5651_components[50]; /* = "cfg-spk:* cfg-mic:*" */ static int byt_rt5651_suspend(struct snd_soc_card *card) { @@ -876,7 +877,6 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) const char *platform_name; struct acpi_device *adev; struct device *codec_dev; - const char *hp_swapped; bool is_bytcr = false; int ret_val = 0; int dai_index = 0; @@ -1080,16 +1080,20 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) } } - if (byt_rt5651_quirk & BYT_RT5651_HP_LR_SWAPPED) - hp_swapped = "-hp-swapped"; - else - hp_swapped = ""; - + snprintf(byt_rt5651_components, sizeof(byt_rt5651_components), + "cfg-spk:%s cfg-mic:%s%s", + (byt_rt5651_quirk & BYT_RT5651_MONO_SPEAKER) ? "1" : "2", + mic_name[BYT_RT5651_MAP(byt_rt5651_quirk)], + (byt_rt5651_quirk & BYT_RT5651_HP_LR_SWAPPED) ? + " cfg-hp:lrswap" : ""); + byt_rt5651_card.components = byt_rt5651_components; snprintf(byt_rt5651_long_name, sizeof(byt_rt5651_long_name), "bytcr-rt5651-%s-spk-%s-mic%s", (byt_rt5651_quirk & BYT_RT5651_MONO_SPEAKER) ? "mono" : "stereo", - mic_name[BYT_RT5651_MAP(byt_rt5651_quirk)], hp_swapped); + mic_name[BYT_RT5651_MAP(byt_rt5651_quirk)], + (byt_rt5651_quirk & BYT_RT5651_HP_LR_SWAPPED) ? + "-hp-swapped" : ""); byt_rt5651_card.long_name = byt_rt5651_long_name; /* override plaform name, if required */ From 06e3e09f29b93ac2b9defe3d0d37e887f23ccde1 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 25 Nov 2019 15:36:36 +0100 Subject: [PATCH 1787/1995] ASoC: Intel - do not describe I/O configuration in the long card name The long card name might be used in GUI. This information should be hidden. Add CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES configuration option. Signed-off-by: Jaroslav Kysela Cc: Pierre-Louis Bossart Cc: Mark Brown --- sound/soc/intel/boards/Kconfig | 13 +++++++++++++ sound/soc/intel/boards/bytcht_es8316.c | 4 ++++ sound/soc/intel/boards/bytcr_rt5640.c | 4 ++++ sound/soc/intel/boards/bytcr_rt5651.c | 4 ++++ 4 files changed, 25 insertions(+) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index ef20316e83d106..145eb55bd69173 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -13,6 +13,19 @@ menuconfig SND_SOC_INTEL_MACH if SND_SOC_INTEL_MACH +config SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES + bool "Use more user friendly long card names" + help + Some drivers report the I/O configuration to userspace through the + soundcard's long card name in the control user space AP. An unfortunate + side effect is that this long name may also be used by the GUI, + confusing users with information they don't need. + This option prevents the long name from being modified, and the I/O + configuration will be provided through a different component interface. + Select Y if userspace like UCM (Use Case Manager) uses the component + interface. + If unsure select N. + if SND_SOC_INTEL_HASWELL config SND_SOC_INTEL_HASWELL_MACH diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index efa33f30dcaceb..12a1c525548446 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -360,7 +360,9 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { /* SoC card */ static char codec_name[SND_ACPI_I2C_ID_LEN]; +#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES) static char long_name[50]; /* = "bytcht-es8316-*-spk-*-mic" */ +#endif static char components_string[32]; /* = "cfg-spk:* cfg-mic:* */ static int byt_cht_es8316_suspend(struct snd_soc_card *card) @@ -578,10 +580,12 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) (quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "1" : "2", mic_name[BYT_CHT_ES8316_MAP(quirk)]); byt_cht_es8316_card.components = components_string; +#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES) snprintf(long_name, sizeof(long_name), "bytcht-es8316-%s-spk-%s-mic", (quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "mono" : "stereo", mic_name[BYT_CHT_ES8316_MAP(quirk)]); byt_cht_es8316_card.long_name = long_name; +#endif /* register the soc card */ snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 7bc6d3cec94c6d..648fcc1d07b58c 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -1082,7 +1082,9 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { static char byt_rt5640_codec_name[SND_ACPI_I2C_ID_LEN]; static char byt_rt5640_codec_aif_name[12]; /* = "rt5640-aif[1|2]" */ static char byt_rt5640_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ +#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES) static char byt_rt5640_long_name[40]; /* = "bytcr-rt5640-*-spk-*-mic" */ +#endif static char byt_rt5640_components[32]; /* = "cfg-spk:* cfg-mic:*" */ static int byt_rt5640_suspend(struct snd_soc_card *card) @@ -1311,12 +1313,14 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? "1" : "2", map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); byt_rt5640_card.components = byt_rt5640_components; +#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES) snprintf(byt_rt5640_long_name, sizeof(byt_rt5640_long_name), "bytcr-rt5640-%s-spk-%s-mic", (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) ? "mono" : "stereo", map_name[BYT_RT5640_MAP(byt_rt5640_quirk)]); byt_rt5640_card.long_name = byt_rt5640_long_name; +#endif /* override plaform name, if required */ platform_name = mach->mach_params.platform; diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 80a5674ddb1bc4..c0d322a859f714 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -797,7 +797,9 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { static char byt_rt5651_codec_name[SND_ACPI_I2C_ID_LEN]; static char byt_rt5651_codec_aif_name[12]; /* = "rt5651-aif[1|2]" */ static char byt_rt5651_cpu_dai_name[10]; /* = "ssp[0|2]-port" */ +#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES) static char byt_rt5651_long_name[50]; /* = "bytcr-rt5651-*-spk-*-mic[-swapped-hp]" */ +#endif static char byt_rt5651_components[50]; /* = "cfg-spk:* cfg-mic:*" */ static int byt_rt5651_suspend(struct snd_soc_card *card) @@ -1087,6 +1089,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) (byt_rt5651_quirk & BYT_RT5651_HP_LR_SWAPPED) ? " cfg-hp:lrswap" : ""); byt_rt5651_card.components = byt_rt5651_components; +#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES) snprintf(byt_rt5651_long_name, sizeof(byt_rt5651_long_name), "bytcr-rt5651-%s-spk-%s-mic%s", (byt_rt5651_quirk & BYT_RT5651_MONO_SPEAKER) ? @@ -1095,6 +1098,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) (byt_rt5651_quirk & BYT_RT5651_HP_LR_SWAPPED) ? "-hp-swapped" : ""); byt_rt5651_card.long_name = byt_rt5651_long_name; +#endif /* override plaform name, if required */ platform_name = mach->mach_params.platform; From 2713bf38f6f223404c42e0d86d4a2896af25d0e1 Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Mon, 2 Dec 2019 17:07:46 -0800 Subject: [PATCH 1788/1995] ASoC: SOF: increase baytrail shim window The window contains definitions according to the firmware headers up to 0x114 which means that it is at least 0x118. Lets share the debug information. Signed-off-by: Curtis Malainey --- sound/soc/sof/intel/byt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index b3a40d9ef7ce7b..b6fc200ab6155b 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -25,7 +25,7 @@ #define DRAM_OFFSET 0x100000 #define DRAM_SIZE (160 * 1024) #define SHIM_OFFSET 0x140000 -#define SHIM_SIZE 0x100 +#define SHIM_SIZE 0x118 #define MBOX_OFFSET 0x144000 #define MBOX_SIZE 0x1000 #define EXCEPT_OFFSET 0x800 From 8dc8bf80ee23533f08ade330b735264e134d1668 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 26 Nov 2019 19:43:42 -0600 Subject: [PATCH 1789/1995] ASoC: SOF: Intel: byt: fixup topology filename for BYT-CR On Baytrail-CR, SSP0 needs to be used instead of SSP2. The substitution is assumed to be done in the topology file. When Baytrail-CR is detected, add -ssp0 suffix to the topology file name so that the topology code picks up the correct file. Tested on Asus T100TAF Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/byt.c | 47 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index b6fc200ab6155b..31c852f66e9c2d 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -18,6 +18,7 @@ #include "../ops.h" #include "shim.h" #include "../sof-audio.h" +#include "../../intel/common/soc-intel-quirks.h" /* DSP memories */ #define IRAM_OFFSET 0x0C0000 @@ -383,11 +384,37 @@ static int byt_reset(struct snd_sof_dev *sdev) return 0; } +static const char *fixup_tplg_name(struct snd_sof_dev *sdev, + const char *sof_tplg_filename, + const char *ssp_str) +{ + const char *tplg_filename = NULL; + char *filename; + char *split_ext; + + filename = devm_kstrdup(sdev->dev, sof_tplg_filename, GFP_KERNEL); + if (!filename) + return NULL; + + /* this assumes a .tplg extension */ + split_ext = strsep(&filename, "."); + if (split_ext) { + tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, + "%s-%s.tplg", + split_ext, ssp_str); + if (!tplg_filename) + return NULL; + } + return tplg_filename; +} + static void byt_machine_select(struct snd_sof_dev *sdev) { struct snd_sof_pdata *sof_pdata = sdev->pdata; const struct sof_dev_desc *desc = sof_pdata->desc; struct snd_soc_acpi_mach *mach; + struct platform_device *pdev; + const char *tplg_filename; mach = snd_soc_acpi_find_machine(desc->machines); if (!mach) { @@ -395,7 +422,25 @@ static void byt_machine_select(struct snd_sof_dev *sdev) return; } - sof_pdata->tplg_filename = mach->sof_tplg_filename; + pdev = to_platform_device(sdev->dev); + if (soc_intel_is_byt_cr(pdev)) { + dev_dbg(sdev->dev, + "BYT-CR detected, SSP0 used instead of SSP2\n"); + + tplg_filename = fixup_tplg_name(sdev, + mach->sof_tplg_filename, + "ssp0"); + } else { + tplg_filename = mach->sof_tplg_filename; + } + + if (!tplg_filename) { + dev_dbg(sdev->dev, + "error: no topology filename\n"); + return; + } + + sof_pdata->tplg_filename = tplg_filename; mach->mach_params.acpi_ipc_irq_index = desc->irqindex_host_ipc; sof_pdata->machine = mach; } From 0381455605c97b3f08cf1362e8e745b0c8e0a131 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 22 Nov 2019 14:34:55 -0600 Subject: [PATCH 1790/1995] ASoC: SOF: Intel: hda: hda-dai: fix oops on hda_link .free When the PCM_PARAM IPC fails, the kernel oopses in the HDaudio link DMA .free operation. The root cause is a NULL dma_data. This patches makes sure the dma_data is properly save in hw_params, even if there are additional errors and tested in hw_free. Opens: 1. the entire flow with hw_params used on system resume looks like a hack. 2. it's not clear why the problem actually happens on hw_free, maybe that's because of the -EBUSY call? Trace with this patch: 14.509636] sof-audio-pci 0000:00:1f.3: pcm: open stream 0 dir 1 [ 14.509643] sof-audio-pci 0000:00:1f.3: period min 192 max 16384 bytes [ 14.509646] sof-audio-pci 0000:00:1f.3: period count 2 max 16 [ 14.509648] sof-audio-pci 0000:00:1f.3: buffer max 65536 bytes [ 14.510003] sof-audio-pci 0000:00:1f.3: ipc tx: 0x80010000: GLB_DAI_MSG: CONFIG [ 14.510114] sof-audio-pci 0000:00:1f.3: ipc tx succeeded: 0x80010000: GLB_DAI_MSG: CONFIG [ 14.510135] sof-audio-pci 0000:00:1f.3: format_val=49, rate=48000, ch=2, format=10 [ 14.510144] sof-audio-pci 0000:00:1f.3: pcm: hw params stream 0 dir 1 [ 14.510149] sof-audio-pci 0000:00:1f.3: generating page table for 00000000ce69792e size 0x4b00 pages 5 [ 14.510157] sof-audio-pci 0000:00:1f.3: FW Poll Status: reg=0x40000 successful [ 14.510175] sof-audio-pci 0000:00:1f.3: FW Poll Status: reg=0x40000 successful [ 14.510179] sof-audio-pci 0000:00:1f.3: period_bytes:0x12c0 [ 14.510182] sof-audio-pci 0000:00:1f.3: periods:4 [ 14.510197] sof-audio-pci 0000:00:1f.3: stream_tag 2 [ 14.510209] sof-audio-pci 0000:00:1f.3: ipc tx: 0x60010000: GLB_STREAM_MSG: PCM_PARAMS [ 14.510513] sof-audio-pci 0000:00:1f.3: error: ipc error for 0x60010000 size 20 [ 14.510520] sof-audio-pci 0000:00:1f.3: error: hw params ipc failed for stream 2 [ 14.510525] sof-audio-pci 0000:00:1f.3: ASoC: 0000:00:1f.3 hw params failed: -22 [ 14.510530] HDA Analog: ASoC: hw_params FE failed -22 [ 14.510553] sof-audio-pci 0000:00:1f.3: ipc tx: 0x80010000: GLB_DAI_MSG: CONFIG [ 14.510668] sof-audio-pci 0000:00:1f.3: ipc tx succeeded: 0x80010000: GLB_DAI_MSG: CONFIG [ 14.510677] sof-audio-pci 0000:00:1f.3: pcm: free stream 0 dir 1 [ 14.510690] sof-audio-pci 0000:00:1f.3: hda_link_hw_free: link_dev is not assigned [ 14.510821] sof-audio-pc GitHub issue: https://github.com/thesofproject/linux/issues/1417 Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-dai.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 2d9ac0035bd2fc..7d2903a675034d 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -217,6 +217,8 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream, link_dev = hda_link_stream_assign(bus, substream); if (!link_dev) return -EBUSY; + + snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); } stream_tag = hdac_stream(link_dev)->stream_tag; @@ -229,8 +231,6 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); - link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name); if (!link) return -EINVAL; @@ -362,6 +362,13 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream, bus = hstream->bus; rtd = snd_pcm_substream_chip(substream); link_dev = snd_soc_dai_get_dma_data(dai, substream); + + if (!link_dev) { + dev_dbg(dai->dev, + "%s: link_dev is not assigned\n", __func__); + return -EINVAL; + } + hda_stream = hstream_to_sof_hda_stream(link_dev); /* free the link DMA channel in the FW */ From 709427e6ccd6dfc33bac14a39cbac14f89f2285c Mon Sep 17 00:00:00 2001 From: Curtis Malainey Date: Tue, 3 Dec 2019 14:06:27 -0800 Subject: [PATCH 1791/1995] ASoC: SOF: Split cht and byt debug window sizes Turns out SSP 3-5 are only available on cht, to avoid dumping on undefined registers let's split the definition. Signed-off-by: Curtis Malainey --- sound/soc/sof/intel/byt.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 31c852f66e9c2d..d43098a962c06a 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -26,7 +26,8 @@ #define DRAM_OFFSET 0x100000 #define DRAM_SIZE (160 * 1024) #define SHIM_OFFSET 0x140000 -#define SHIM_SIZE 0x118 +#define SHIM_SIZE_BYT 0x100 +#define SHIM_SIZE_CHT 0x118 #define MBOX_OFFSET 0x144000 #define MBOX_SIZE 0x1000 #define EXCEPT_OFFSET 0x800 @@ -77,7 +78,7 @@ static const struct snd_sof_debugfs_map byt_debugfs[] = { SOF_DEBUGFS_ACCESS_D0_ONLY}, {"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE, SOF_DEBUGFS_ACCESS_D0_ONLY}, - {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE, + {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE_BYT, SOF_DEBUGFS_ACCESS_ALWAYS}, }; @@ -104,7 +105,7 @@ static const struct snd_sof_debugfs_map cht_debugfs[] = { SOF_DEBUGFS_ACCESS_D0_ONLY}, {"dram", BYT_DSP_BAR, DRAM_OFFSET, DRAM_SIZE, SOF_DEBUGFS_ACCESS_D0_ONLY}, - {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE, + {"shim", BYT_DSP_BAR, SHIM_OFFSET, SHIM_SIZE_CHT, SOF_DEBUGFS_ACCESS_ALWAYS}, }; From 133315b2716ec1339b51a6c45f0073d375d0257f Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 27 Nov 2019 10:09:23 +0800 Subject: [PATCH 1792/1995] ASoC: SOF: Intel: remove irq_event flag The purpose of irq_event is to prevent double check the interrupt in both handler and thread. However, We can check Global Interrupt Status (GIS) in the handler and check each interrupt in the thread. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-ipc.c | 4 +--- sound/soc/sof/intel/hda-stream.c | 4 +--- sound/soc/sof/intel/hda.c | 17 ++++++++--------- sound/soc/sof/intel/hda.h | 10 ++++------ sound/soc/sof/sof-priv.h | 1 - 5 files changed, 14 insertions(+), 22 deletions(-) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index 1a32e75f1ad755..f97da5ff4f7ff0 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -251,10 +251,8 @@ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev) goto out; /* IPC message ? */ - if (irq_status & HDA_DSP_ADSPIS_IPC) { - sdev->irq_event |= SOF_HDA_IRQ_IPC; + if (irq_status & HDA_DSP_ADSPIS_IPC) ret = true; - } out: spin_unlock_irq(&sdev->hw_lock); diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 2f05b61cc332c2..c0ab9bb2a7978c 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -563,10 +563,8 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev) dev_vdbg(bus->dev, "stream irq, INTSTS status: 0x%x\n", status); /* if Register inaccessible, ignore it.*/ - if (status != 0xffffffff) { - sdev->irq_event |= SOF_HDA_IRQ_STREAM; + if (status != 0xffffffff) ret = true; - } spin_unlock_irq(&bus->reg_lock); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index ec467ec5cccbbc..8d27846d90486c 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -406,11 +406,12 @@ static irqreturn_t hda_dsp_interrupt_handler(int irq, void *context) { struct snd_sof_dev *sdev = context; - /* clear flags for interrupt sources */ - sdev->irq_event = 0; - - if (hda_dsp_check_stream_irq(sdev) || - hda_dsp_check_ipc_irq(sdev)) { + /* + * Get global interrupt status. It includes all hardware interrupt + * sources in the Intel HD Audio controller. + */ + if (snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTSTS) & + SOF_HDA_INTSTS_GIS) { /* disable GIE interrupt */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, @@ -429,12 +430,10 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context) struct snd_sof_dev *sdev = context; /* deal with streams and controller first */ - if (sdev->irq_event & SOF_HDA_IRQ_STREAM || - hda_dsp_check_stream_irq(sdev)) + if (hda_dsp_check_stream_irq(sdev)) hda_dsp_stream_threaded_handler(irq, sdev); - if (sdev->irq_event & SOF_HDA_IRQ_IPC || - hda_dsp_check_ipc_irq(sdev)) + if (hda_dsp_check_ipc_irq(sdev)) sof_ops(sdev)->irq_thread(irq, sdev); /* enable GIE interrupt */ diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 8b55e88412e345..01529c7058f33e 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -43,11 +43,14 @@ /* SOF_HDA_GCTL register bist */ #define SOF_HDA_GCTL_RESET BIT(0) -/* SOF_HDA_INCTL and SOF_HDA_INTSTS regs */ +/* SOF_HDA_INCTL regs */ #define SOF_HDA_INT_GLOBAL_EN BIT(31) #define SOF_HDA_INT_CTRL_EN BIT(30) #define SOF_HDA_INT_ALL_STREAM 0xff +/* SOF_HDA_INTSTS regs */ +#define SOF_HDA_INTSTS_GIS BIT(31) + #define SOF_HDA_MAX_CAPS 10 #define SOF_HDA_CAP_ID_OFF 16 #define SOF_HDA_CAP_ID_MASK GENMASK(SOF_HDA_CAP_ID_OFF + 11,\ @@ -389,11 +392,6 @@ struct sof_intel_dsp_bdl { #define SOF_HDA_PLAYBACK 0 #define SOF_HDA_CAPTURE 1 -/* flags to memorize IPC source (not hardware-defined) */ -#define SOF_HDA_IRQ_IPC BIT(0) -#define SOF_HDA_IRQ_STREAM BIT(1) -#define SOF_HDA_IRQ_SDW BIT(2) - /* represents DSP HDA controller frontend - i.e. host facing control */ struct sof_intel_hda_dev { diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 65f006845cbf79..54dd6d4b4c128e 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -387,7 +387,6 @@ struct snd_sof_dev { u32 dtrace_draining; bool msi_enabled; - u32 irq_event; void *private; /* core does not touch this */ }; From 1b347c6f4675aa5a9a7f93b62486007354b6864c Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 27 Nov 2019 13:57:37 +0800 Subject: [PATCH 1793/1995] ASoC: SOF: Intel: don't take hw_lock when checking irq status Taking the hw_lock spin lock is no longer needed in the check irq functions called from irq threads. The check functions do not modify interrupt status bits. Locking is not needed for a simple status read. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-ipc.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c index f97da5ff4f7ff0..1837f66e361fd5 100644 --- a/sound/soc/sof/intel/hda-ipc.c +++ b/sound/soc/sof/intel/hda-ipc.c @@ -239,9 +239,6 @@ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev) bool ret = false; u32 irq_status; - /* The function can be called at irq thread, so use spin_lock_irq */ - spin_lock_irq(&sdev->hw_lock); - /* store status */ irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS); dev_vdbg(sdev->dev, "irq handler: irq_status:0x%x\n", irq_status); @@ -255,7 +252,6 @@ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev) ret = true; out: - spin_unlock_irq(&sdev->hw_lock); return ret; } From 68ccd90e60c9aad324eb1c7e339f76a04fcae75c Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Tue, 3 Dec 2019 16:43:36 +0100 Subject: [PATCH 1794/1995] ASoC: SOF: snd_sof_fw_parse_ext_data log warning on unknown header Added warning log when found some unknown FW boot ext header, to improve debuggability. Signed-off-by: Karol Trzcinski --- sound/soc/sof/loader.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 9a9a381a908dee..a041adf0669de2 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -66,6 +66,8 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) ret = get_ext_windows(sdev, ext_hdr); break; default: + dev_warn(sdev->dev, "warning: unknown ext header type %d size 0x%x\n", + ext_hdr->type, ext_hdr->hdr.size); break; } From 54c96eae3e11b875f420855abfb4042a9a004903 Mon Sep 17 00:00:00 2001 From: Dragos Tarcatu Date: Wed, 4 Dec 2019 10:05:53 +0200 Subject: [PATCH 1795/1995] ASoC: topology: Prevent use-after-free in snd_soc_get_pcm_runtime() remove_link() is currently calling snd_soc_remove_dai_link() after it has already freed the memory for the link name. But this is later read from snd_soc_get_pcm_runtime() causing a KASAN use-after-free warning. Reorder the cleanups to fix this issue. Signed-off-by: Dragos Tarcatu --- sound/soc/soc-topology.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 81d2af000a5c80..248530d028a693 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -548,12 +548,12 @@ static void remove_link(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->link_unload) dobj->ops->link_unload(comp, dobj); + list_del(&dobj->list); + snd_soc_remove_dai_link(comp->card, link); + kfree(link->name); kfree(link->stream_name); kfree(link->cpus->dai_name); - - list_del(&dobj->list); - snd_soc_remove_dai_link(comp->card, link); kfree(link); } From 15b23fc78325c78a7db32a7b143dc19f559db01b Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Tue, 3 Dec 2019 08:00:06 +0100 Subject: [PATCH 1796/1995] ASoC: SOF: fix snd_sof_fw_parse_ext_data An error occurs during parsing more than one ext_data from the mailbox, because of invalid data offset handling. Fix by removing the incorrect duplicate increment of the offset. The return value is also reset in the switch case. This does not change the behavior but improves readability - there is no longer a need to check what the return value of get_ext_windows is. Signed-off-by: Karol Trzcinski Signed-off-by: Bartosz Kokoszko --- sound/soc/sof/loader.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index a041adf0669de2..432d12bd493791 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -50,8 +50,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) while (ext_hdr->hdr.cmd == SOF_IPC_FW_READY) { /* read in ext structure */ - offset += sizeof(*ext_hdr); - snd_sof_dsp_block_read(sdev, bar, offset, + snd_sof_dsp_block_read(sdev, bar, offset + sizeof(*ext_hdr), (void *)((u8 *)ext_data + sizeof(*ext_hdr)), ext_hdr->hdr.size - sizeof(*ext_hdr)); @@ -61,6 +60,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) /* process structure data */ switch (ext_hdr->type) { case SOF_IPC_EXT_DMA_BUFFER: + ret = 0; break; case SOF_IPC_EXT_WINDOW: ret = get_ext_windows(sdev, ext_hdr); @@ -68,6 +68,7 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) default: dev_warn(sdev->dev, "warning: unknown ext header type %d size 0x%x\n", ext_hdr->type, ext_hdr->hdr.size); + ret = 0; break; } From 7c7cc04539ce399ed91b9dbb238ce8be0d14e187 Mon Sep 17 00:00:00 2001 From: Amery Song Date: Fri, 29 Nov 2019 13:23:46 +0800 Subject: [PATCH 1797/1995] ASoC: Intel: common: work-around incorrect ACPI HID for CML boards On CML boards with the RT5682 headset codec and RT1011 speaker amplifier, the platform firmware exposes three ACPI HIDs (10EC5682, 10EC1011 and MX98357A). The last HID is a mistake in DSDT tables, which causes the wrong machine driver to be loaded. This patch changes the key used to identify boards and changes the order of entries in the table to load the correct machine driver. The order does matter and should not be modified to work-around this firmware issue. Signed-off-by: Amery Song Signed-off-by: Keyon Jie --- .../intel/common/soc-acpi-intel-cml-match.c | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c index 5d08ae0667380b..fb9ba881970604 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c @@ -9,45 +9,52 @@ #include #include -static struct snd_soc_acpi_codecs cml_codecs = { +static struct snd_soc_acpi_codecs rt1011_spk_codecs = { .num_codecs = 1, - .codecs = {"10EC5682"} + .codecs = {"10EC1011"} }; -static struct snd_soc_acpi_codecs cml_spk_codecs = { +static struct snd_soc_acpi_codecs max98357a_spk_codecs = { .num_codecs = 1, .codecs = {"MX98357A"} }; +/* + * The order of the three entries with .id = "10EC5682" matters + * here, because DSDT tables expose an ACPI HID for the MAX98357A + * speaker amplifier which is not populated on the board. + */ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = { { - .id = "DLGS7219", - .drv_name = "cml_da7219_max98357a", - .quirk_data = &cml_spk_codecs, + .id = "10EC5682", + .drv_name = "cml_rt1011_rt5682", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &rt1011_spk_codecs, .sof_fw_filename = "sof-cml.ri", - .sof_tplg_filename = "sof-cml-da7219-max98357a.tplg", + .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg", }, { - .id = "MX98357A", + .id = "10EC5682", .drv_name = "sof_rt5682", - .quirk_data = &cml_codecs, + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &max98357a_spk_codecs, .sof_fw_filename = "sof-cml.ri", .sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg", }, - { - .id = "10EC1011", - .drv_name = "cml_rt1011_rt5682", - .quirk_data = &cml_codecs, - .sof_fw_filename = "sof-cml.ri", - .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg", - }, { .id = "10EC5682", .drv_name = "sof_rt5682", .sof_fw_filename = "sof-cml.ri", .sof_tplg_filename = "sof-cml-rt5682.tplg", }, - + { + .id = "DLGS7219", + .drv_name = "cml_da7219_max98357a", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &max98357a_spk_codecs, + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-da7219-max98357a.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cml_machines); From c8026a1eb961a78ce112c9625d1f6fa1691ed879 Mon Sep 17 00:00:00 2001 From: Dragos Tarcatu Date: Thu, 5 Dec 2019 12:46:56 +0200 Subject: [PATCH 1798/1995] ASoC: topology: Check return value for snd_soc_add_dai_link() snd_soc_add_dai_link() might fail. This situation occurs for instance in a very specific use case where a PCM device and a Back End DAI link are given identical names in the topology. When this happens, soc_new_pcm_runtime() fails and then snd_soc_add_dai_link() returns -ENOMEM when called from soc_tplg_fe_link_create(). Because of that, the link will not get added into the card list, so any attempt to remove it later ends up in a panic. Fix that by checking the return status and free the memory in case of an error. Signed-off-by: Dragos Tarcatu --- sound/soc/soc-topology.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 248530d028a693..93ba6778ef273e 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1933,11 +1933,13 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, ret = soc_tplg_dai_link_load(tplg, link, NULL); if (ret < 0) { dev_err(tplg->comp->dev, "ASoC: FE link loading failed\n"); - kfree(link->name); - kfree(link->stream_name); - kfree(link->cpus->dai_name); - kfree(link); - return ret; + goto err; + } + + ret = snd_soc_add_dai_link(tplg->comp->card, link); + if (ret < 0) { + dev_err(tplg->comp->dev, "ASoC: adding FE link failed\n"); + goto err; } link->dobj.index = tplg->index; @@ -1945,8 +1947,13 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg, link->dobj.type = SND_SOC_DOBJ_DAI_LINK; list_add(&link->dobj.list, &tplg->comp->dobj_list); - snd_soc_add_dai_link(tplg->comp->card, link); return 0; +err: + kfree(link->name); + kfree(link->stream_name); + kfree(link->cpus->dai_name); + kfree(link); + return ret; } /* create a FE DAI and DAI link from the PCM object */ From 3c39107307b6200bbd1594ca07ed069ec59011f5 Mon Sep 17 00:00:00 2001 From: Dragos Tarcatu Date: Thu, 5 Dec 2019 13:28:55 +0200 Subject: [PATCH 1799/1995] ASoC: topology: Check return value for soc_tplg_pcm_create() The return value of soc_tplg_pcm_create() is currently not checked in soc_tplg_pcm_elems_load(). If an error is to occur there, the topology ignores it and continues loading. Fix that by checking the status and rejecting the topology on error. Signed-off-by: Dragos Tarcatu --- sound/soc/soc-topology.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 93ba6778ef273e..92e4f4d08bfad6 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -2046,6 +2046,7 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, int size; int i; bool abi_match; + int ret; count = le32_to_cpu(hdr->count); @@ -2087,7 +2088,12 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, } /* create the FE DAIs and DAI links */ - soc_tplg_pcm_create(tplg, _pcm); + ret = soc_tplg_pcm_create(tplg, _pcm); + if (ret < 0) { + if (!abi_match) + kfree(_pcm); + return ret; + } /* offset by version-specific struct size and * real priv data size From b89abb37a835ad19af64169f3ee1200b7c6665a0 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 10 Dec 2019 09:22:49 +0200 Subject: [PATCH 1800/1995] ASoC: Intel: boards: fix incorrect HDMI Kconfig dependency Fix typo in Kconfig dependencies. The correct dependency for HDMI is SND_SOC_SOF_HDA_AUDIO_CODEC. Reported-by: Yong Zhi Fixes: e3d8f8ae5b1e ("ASoC: Intel: boards: make common HDMI driver the default for SOF") Signed-off-by: Kai Vehmanen --- sound/soc/intel/boards/Kconfig | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 348cb0c4d003cf..0db4ae7c825916 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -274,7 +274,7 @@ config SND_SOC_INTEL_DA7219_MAX98357A_GENERIC select SND_SOC_DA7219 select SND_SOC_MAX98357A select SND_SOC_DMIC - select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_CODEC + select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_AUDIO_CODEC select SND_SOC_HDAC_HDMI config SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON @@ -315,7 +315,7 @@ config SND_SOC_INTEL_BXT_PCM512x_MACH tristate "Broxton with TI PCM512x codec" depends on MFD_INTEL_LPSS && I2C && ACPI select SND_SOC_PCM512x_I2C - select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_CODEC + select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_AUDIO_CODEC select SND_SOC_HDAC_HDMI if SND_SOC_SOF_HDA_LINK help This adds support for ASoC machine driver for Broxton platforms @@ -427,7 +427,7 @@ config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH select SND_SOC_RT5682 select SND_SOC_MAX98357A select SND_SOC_DMIC - select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_CODEC + select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_AUDIO_CODEC select SND_SOC_HDAC_HDMI help This adds support for ASoC machine driver for Geminilake platforms @@ -441,7 +441,7 @@ if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH tristate "SKL/KBL/BXT/APL with HDA Codecs" - select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_CODEC + select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_AUDIO_CODEC select SND_SOC_HDAC_HDMI select SND_SOC_DMIC # SND_SOC_HDAC_HDA is already selected @@ -461,7 +461,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH (SND_SOC_SOF_BAYTRAIL && (X86_INTEL_LPSS || COMPILE_TEST)) select SND_SOC_RT5682 select SND_SOC_DMIC - select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_CODEC + select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_AUDIO_CODEC select SND_SOC_HDAC_HDMI help This adds support for ASoC machine driver for SOF platforms @@ -491,7 +491,7 @@ config SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH select SND_SOC_RT5682 select SND_SOC_DMIC select SND_SOC_HDAC_HDMI - select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_CODEC + select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_AUDIO_CODEC help This adds support for ASoC machine driver for SOF platform with RT1011 + RT5682 I2S codec. @@ -508,7 +508,7 @@ config SND_SOC_INTEL_TGL_RT1308_MACH depends on MFD_INTEL_LPSS || COMPILE_TEST select SND_SOC_RT1308 select SND_SOC_DMIC - select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_CODEC + select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_AUDIO_CODEC select SND_SOC_HDAC_HDMI if SND_SOC_SOF_HDA_LINK help This adds support for ASoC machine driver for Tigerlake platforms From 429f60fb4414c124c5e840a178d44889f47fa0ab Mon Sep 17 00:00:00 2001 From: Guido Roncarolo Date: Wed, 13 Nov 2019 13:55:01 +0100 Subject: [PATCH 1801/1995] ASoC: SOF: imx: Describe SAI parameters to be sent to DSP Introduce sof_ipc_dai_sai_params to keep information that we get from topology and we send to DSP FW. For the moment it is identical to ESAI one but it will evolve shortly independently Signed-off-by: Guido Roncarolo --- include/sound/sof/dai-imx.h | 20 ++++++++++++++++++++ include/sound/sof/dai.h | 1 + include/uapi/sound/sof/tokens.h | 3 +-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/include/sound/sof/dai-imx.h b/include/sound/sof/dai-imx.h index e02fb0b0fae165..ff9088dcc6f2e9 100644 --- a/include/sound/sof/dai-imx.h +++ b/include/sound/sof/dai-imx.h @@ -31,4 +31,24 @@ struct sof_ipc_dai_esai_params { uint16_t reserved2; /* alignment */ } __packed; +/* SAI Configuration Request - SOF_IPC_DAI_SAI_CONFIG */ +struct sof_ipc_dai_sai_params { + struct sof_ipc_hdr hdr; + + /* MCLK */ + uint16_t reserved1; + uint16_t mclk_id; + uint32_t mclk_direction; + + uint32_t mclk_rate; /* MCLK frequency in Hz */ + uint32_t fsync_rate; /* FSYNC frequency in Hz */ + uint32_t bclk_rate; /* BCLK frequency in Hz */ + + /* TDM */ + uint32_t tdm_slots; + uint32_t rx_slots; + uint32_t tx_slots; + uint16_t tdm_slot_width; + uint16_t reserved2; /* alignment */ +} __packed; #endif diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index c229565767e53a..2565edd336f15d 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -75,6 +75,7 @@ struct sof_ipc_dai_config { struct sof_ipc_dai_hda_params hda; struct sof_ipc_dai_alh_params alh; struct sof_ipc_dai_esai_params esai; + struct sof_ipc_dai_sai_params sai; }; } __packed; diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index a9a5c4d0a89202..2a25cd8da5033e 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -113,8 +113,7 @@ #define SOF_TKN_EFFECT_TYPE SOF_TKN_PROCESS_TYPE /* SAI */ -#define SOF_TKN_IMX_SAI_FIRST_TOKEN 1000 -/* TODO: Add SAI tokens */ +#define SOF_TKN_IMX_SAI_MCLK_ID 1000 /* ESAI */ #define SOF_TKN_IMX_ESAI_MCLK_ID 1100 From 6714c4e127003acb2828cd8c5c1269bfa1bfa3bf Mon Sep 17 00:00:00 2001 From: Guido Roncarolo Date: Wed, 13 Nov 2019 14:37:14 +0100 Subject: [PATCH 1802/1995] ASoC: SOF: imx: Read SAI parameters and send them to DSP Signed-off-by: Guido Roncarolo --- sound/soc/sof/pcm.c | 8 +++++ sound/soc/sof/topology.c | 69 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 54ec78799c30c5..59446b329a0e67 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -707,6 +707,14 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = dai->dai_config->esai.tdm_slots; channels->max = dai->dai_config->esai.tdm_slots; + dev_dbg(component->dev, + "channels_min: %d channels_max: %d\n", + channels->min, channels->max); + break; + case SOF_DAI_IMX_SAI: + channels->min = dai->dai_config->sai.tdm_slots; + channels->max = dai->dai_config->sai.tdm_slots; + dev_dbg(component->dev, "channels_min: %d channels_max: %d\n", channels->min, channels->max); diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index e06fa7c7e502c4..9f4f8868b3860b 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -695,6 +695,13 @@ static const struct sof_topology_token esai_tokens[] = { offsetof(struct sof_ipc_dai_esai_params, mclk_id), 0}, }; +/* SAI */ +static const struct sof_topology_token sai_tokens[] = { + {SOF_TKN_IMX_SAI_MCLK_ID, + SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_sai_params, mclk_id), 0}, +}; + /* * DMIC PDM Tokens * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token @@ -2704,8 +2711,66 @@ static int sof_link_sai_load(struct snd_soc_component *scomp, int index, struct snd_soc_tplg_hw_config *hw_config, struct sof_ipc_dai_config *config) { - /*TODO: Add implementation */ - return 0; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct snd_soc_tplg_private *private = &cfg->priv; + struct sof_ipc_reply reply; + u32 size = sizeof(*config); + int ret; + + /* handle master/slave and inverted clocks */ + sof_dai_set_format(hw_config, config); + + /* init IPC */ + memset(&config->sai, 0, sizeof(struct sof_ipc_dai_sai_params)); + config->hdr.size = size; + + ret = sof_parse_tokens(scomp, &config->sai, sai_tokens, + ARRAY_SIZE(sai_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(scomp->dev, "error: parse sai tokens failed %d\n", + le32_to_cpu(private->size)); + return ret; + } + + config->sai.mclk_rate = le32_to_cpu(hw_config->mclk_rate); + config->sai.mclk_direction = hw_config->mclk_direction; + + config->sai.tdm_slots = le32_to_cpu(hw_config->tdm_slots); + config->sai.tdm_slot_width = le32_to_cpu(hw_config->tdm_slot_width); + config->sai.rx_slots = le32_to_cpu(hw_config->rx_slots); + config->sai.tx_slots = le32_to_cpu(hw_config->tx_slots); + + dev_info(scomp->dev, + "tplg: config SAI%d fmt 0x%x mclk %d width %d slots %d mclk id %d\n", + config->dai_index, config->format, + config->sai.mclk_rate, config->sai.tdm_slot_width, + config->sai.tdm_slots, config->sai.mclk_id); + + if (config->sai.tdm_slots < 1 || config->sai.tdm_slots > 8) { + dev_err(scomp->dev, "error: invalid channel count for SAI%d\n", + config->dai_index); + return -EINVAL; + } + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + config->hdr.cmd, config, size, &reply, + sizeof(reply)); + + if (ret < 0) { + dev_err(scomp->dev, "error: failed to set DAI config for SAI%d\n", + config->dai_index); + return ret; + } + + /* set config for all DAI's with name matching the link name */ + ret = sof_set_dai_config(sdev, size, link, config); + if (ret < 0) + dev_err(scomp->dev, "error: failed to save DAI config for SAI%d\n", + config->dai_index); + + return ret; } static int sof_link_esai_load(struct snd_soc_component *scomp, int index, From 9c0401ca2aa78f9f7f66dfeaeb507fc8ee60db1a Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 9 Dec 2019 18:10:23 +0200 Subject: [PATCH 1803/1995] ASoC: SOF: Intel: drop HDA codec upon probe failure In case a HDA codec probe fails, do not raise error immediately, but instead remove the codec from bus->codec_mask and continue probe for other codecs. This allows for more robust behaviour in cases where one codec in the system is faulty. SOF driver load can still proceed with the codecs that can be probed successfully. Probe may still fail if suitable machine driver is not found, but in many cases the generic HDA machine driver can operate with a subset of codecs. Signed-off-by: Kai Vehmanen --- sound/soc/sof/intel/hda-codec.c | 12 +++++------- sound/soc/sof/intel/hda.h | 4 ++-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 65761e09518413..d7855b1f8e2e2a 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -140,8 +140,8 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address, } /* Codec initialization */ -int hda_codec_probe_bus(struct snd_sof_dev *sdev, - bool hda_codec_use_common_hdmi) +void hda_codec_probe_bus(struct snd_sof_dev *sdev, + bool hda_codec_use_common_hdmi) { struct hdac_bus *bus = sof_to_bus(sdev); int i, ret; @@ -154,13 +154,11 @@ int hda_codec_probe_bus(struct snd_sof_dev *sdev, ret = hda_codec_probe(sdev, i, hda_codec_use_common_hdmi); if (ret < 0) { - dev_err(bus->dev, "error: codec #%d probe error, ret: %d\n", - i, ret); - return ret; + dev_warn(bus->dev, "codec #%d probe error, ret: %d\n", + i, ret); + bus->codec_mask &= ~BIT(i); } } - - return 0; } EXPORT_SYMBOL(hda_codec_probe_bus); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 01529c7058f33e..47408ec0de4046 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -575,8 +575,8 @@ void sof_hda_bus_init(struct hdac_bus *bus, struct device *dev); /* * HDA Codec operations. */ -int hda_codec_probe_bus(struct snd_sof_dev *sdev, - bool hda_codec_use_common_hdmi); +void hda_codec_probe_bus(struct snd_sof_dev *sdev, + bool hda_codec_use_common_hdmi); void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev); void hda_codec_jack_check(struct snd_sof_dev *sdev); From 857a7cb42d76ccc97d49ec7aff5c11847478ee7e Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 2 Dec 2019 15:25:33 -0800 Subject: [PATCH 1804/1995] ASoC: SOF: Introduce state machine for FW boot Add a state machine for FW boot to track the different stages of FW boot and replace the boot_complete field with fw_state field in struct snd_sof_dev. This will be used to determine the actions to be performed during system suspend. One of the main motivations for adding this change is the fact that errors during the top-level SOF device probe cannot be propagated and therefore suspending the SOF device normally during system suspend could potentially run into errors. For example, with the current flow, if the FW boot failed for some reason and the system suspends, the SOF device suspend could fail because the CTX_SAVE IPC would be attempted even though the FW never really booted successfully causing it to time out. Another scenario that the state machine fixes is when the runtime suspend for the SOF device fails and the DSP is powered down nevertheless, the CTX_SAVE IPC during system suspend would timeout because the DSP is already powered down. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/core.c | 50 +++++++++++++++++++++++++++++++- sound/soc/sof/intel/hda-loader.c | 1 - sound/soc/sof/intel/hda.c | 4 +-- sound/soc/sof/ipc.c | 17 ++++------- sound/soc/sof/loader.c | 19 ++++++++---- sound/soc/sof/pm.c | 21 +++++++++++++- sound/soc/sof/sof-priv.h | 11 ++++++- 7 files changed, 99 insertions(+), 24 deletions(-) diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c index e258f6a8e7a5c5..44f9c04d54aa02 100644 --- a/sound/soc/sof/core.c +++ b/sound/soc/sof/core.c @@ -92,6 +92,46 @@ void snd_sof_get_status(struct snd_sof_dev *sdev, u32 panic_code, } EXPORT_SYMBOL(snd_sof_get_status); +/* + * FW Boot State Transition Diagram + * + * +-----------------------------------------------------------------------+ + * | | + * ------------------ ------------------ | + * | | | | | + * | BOOT_FAILED | | READY_FAILED |-------------------------+ | + * | | | | | | + * ------------------ ------------------ | | + * ^ ^ | | + * | | | | + * (FW Boot Timeout) (FW_READY FAIL) | | + * | | | | + * | | | | + * ------------------ | ------------------ | | + * | | | | | | | + * | IN_PROGRESS |---------------+------------->| COMPLETE | | | + * | | (FW Boot OK) (FW_READY OK) | | | | + * ------------------ ------------------ | | + * ^ | | | + * | | | | + * (FW Loading OK) (System Suspend/Runtime Suspend) + * | | | | + * | | | | + * ------------------ ------------------ | | | + * | | | |<-----+ | | + * | PREPARE | | NOT_STARTED |<---------------------+ | + * | | | |<---------------------------+ + * ------------------ ------------------ + * | ^ | ^ + * | | | | + * | +-----------------------+ | + * | (DSP Probe OK) | + * | | + * | | + * +------------------------------------+ + * (System Suspend/Runtime Suspend) + */ + static int sof_probe_continue(struct snd_sof_dev *sdev) { struct snd_sof_pdata *plat_data = sdev->pdata; @@ -104,6 +144,8 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) return ret; } + sdev->fw_state = SOF_FW_BOOT_PREPARE; + /* check machine info */ ret = sof_machine_check(sdev); if (ret < 0) { @@ -143,7 +185,12 @@ static int sof_probe_continue(struct snd_sof_dev *sdev) goto fw_load_err; } - /* boot the firmware */ + sdev->fw_state = SOF_FW_BOOT_IN_PROGRESS; + + /* + * Boot the firmware. The FW boot status will be modified + * in snd_sof_run_firmware() depending on the outcome. + */ ret = snd_sof_run_firmware(sdev); if (ret < 0) { dev_err(sdev->dev, "error: failed to boot DSP firmware %d\n", @@ -254,6 +301,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data) sdev->pdata = plat_data; sdev->first_boot = true; + sdev->fw_state = SOF_FW_BOOT_NOT_STARTED; dev_set_drvdata(dev, sdev); /* check all mandatory ops */ diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index b1783360fe106b..1782f50926391c 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -295,7 +295,6 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) /* init for booting wait */ init_waitqueue_head(&sdev->boot_wait); - sdev->boot_complete = false; /* prepare DMA for code loader stream */ tag = cl_stream_prepare(sdev, 0x40, stripped_firmware.size, diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 8d27846d90486c..3335e0076180fe 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -168,7 +168,7 @@ void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags) panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_ADSP_ERROR_CODE_SKL + 0x4); - if (sdev->boot_complete) { + if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) { hda_dsp_get_registers(sdev, &xoops, &panic_info, stack, HDA_DSP_STACK_DUMP_SIZE); snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, @@ -195,7 +195,7 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags) HDA_DSP_SRAM_REG_FW_STATUS); panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_TRACEP); - if (sdev->boot_complete) { + if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) { hda_dsp_get_registers(sdev, &xoops, &panic_info, stack, HDA_DSP_STACK_DUMP_SIZE); snd_sof_get_status(sdev, status, panic, &xoops, &panic_info, diff --git a/sound/soc/sof/ipc.c b/sound/soc/sof/ipc.c index 1cede16aa7d8cd..b63fc529b4568e 100644 --- a/sound/soc/sof/ipc.c +++ b/sound/soc/sof/ipc.c @@ -347,19 +347,12 @@ void snd_sof_ipc_msgs_rx(struct snd_sof_dev *sdev) break; case SOF_IPC_FW_READY: /* check for FW boot completion */ - if (!sdev->boot_complete) { + if (sdev->fw_state == SOF_FW_BOOT_IN_PROGRESS) { err = sof_ops(sdev)->fw_ready(sdev, cmd); - if (err < 0) { - /* - * this indicates a mismatch in ABI - * between the driver and fw - */ - dev_err(sdev->dev, "error: ABI mismatch %d\n", - err); - } else { - /* firmware boot completed OK */ - sdev->boot_complete = true; - } + if (err < 0) + sdev->fw_state = SOF_FW_BOOT_READY_FAILED; + else + sdev->fw_state = SOF_FW_BOOT_COMPLETE; /* wake up firmware loader */ wake_up(&sdev->boot_wait); diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 432d12bd493791..31847aa3975dc5 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -512,7 +512,6 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) int init_core_mask; init_waitqueue_head(&sdev->boot_wait); - sdev->boot_complete = false; /* create read-only fw_version debugfs to store boot version info */ if (sdev->first_boot) { @@ -544,19 +543,27 @@ int snd_sof_run_firmware(struct snd_sof_dev *sdev) init_core_mask = ret; - /* now wait for the DSP to boot */ - ret = wait_event_timeout(sdev->boot_wait, sdev->boot_complete, + /* + * now wait for the DSP to boot. There are 3 possible outcomes: + * 1. Boot wait times out indicating FW boot failure. + * 2. FW boots successfully and fw_ready op succeeds. + * 3. FW boots but fw_ready op fails. + */ + ret = wait_event_timeout(sdev->boot_wait, + sdev->fw_state > SOF_FW_BOOT_IN_PROGRESS, msecs_to_jiffies(sdev->boot_timeout)); if (ret == 0) { dev_err(sdev->dev, "error: firmware boot failure\n"); snd_sof_dsp_dbg_dump(sdev, SOF_DBG_REGS | SOF_DBG_MBOX | SOF_DBG_TEXT | SOF_DBG_PCI); - /* after this point FW_READY msg should be ignored */ - sdev->boot_complete = true; + sdev->fw_state = SOF_FW_BOOT_FAILED; return -EIO; } - dev_info(sdev->dev, "firmware boot complete\n"); + if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) + dev_info(sdev->dev, "firmware boot complete\n"); + else + return -EIO; /* FW boots but fw_ready op failed */ /* perform post fw run operations */ ret = snd_sof_dsp_post_fw_run(sdev); diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index d1a7b98886d13b..84290bbeebddb0 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -70,6 +70,8 @@ static int sof_resume(struct device *dev, bool runtime_resume) return ret; } + sdev->fw_state = SOF_FW_BOOT_PREPARE; + /* load the firmware */ ret = snd_sof_load_firmware(sdev); if (ret < 0) { @@ -79,7 +81,12 @@ static int sof_resume(struct device *dev, bool runtime_resume) return ret; } - /* boot the firmware */ + sdev->fw_state = SOF_FW_BOOT_IN_PROGRESS; + + /* + * Boot the firmware. The FW boot status will be modified + * in snd_sof_run_firmware() depending on the outcome. + */ ret = snd_sof_run_firmware(sdev); if (ret < 0) { dev_err(sdev->dev, @@ -128,6 +135,9 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) if (!sof_ops(sdev)->suspend) return 0; + if (sdev->fw_state != SOF_FW_BOOT_COMPLETE) + goto power_down; + /* release trace */ snd_sof_release_trace(sdev); @@ -165,6 +175,12 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) ret); } +power_down: + + /* return if the DSP was not probed successfully */ + if (sdev->fw_state == SOF_FW_BOOT_NOT_STARTED) + return 0; + /* power down all DSP cores */ if (runtime_suspend) ret = snd_sof_dsp_runtime_suspend(sdev); @@ -175,6 +191,9 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) "error: failed to power down DSP during suspend %d\n", ret); + /* reset FW state */ + sdev->fw_state = SOF_FW_BOOT_NOT_STARTED; + return ret; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 54dd6d4b4c128e..220b35141c34a5 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -298,6 +298,15 @@ struct snd_sof_ipc_msg { bool ipc_complete; }; +enum snd_sof_fw_state { + SOF_FW_BOOT_NOT_STARTED = 0, + SOF_FW_BOOT_PREPARE, + SOF_FW_BOOT_IN_PROGRESS, + SOF_FW_BOOT_FAILED, + SOF_FW_BOOT_READY_FAILED, /* firmware booted but fw_ready op failed */ + SOF_FW_BOOT_COMPLETE, +}; + /* * SOF Device Level. */ @@ -319,7 +328,7 @@ struct snd_sof_dev { /* DSP firmware boot */ wait_queue_head_t boot_wait; - u32 boot_complete; + enum snd_sof_fw_state fw_state; u32 first_boot; /* work queue in case the probe is implemented in two steps */ From c233c25b206a18396aa7add6d0b724718198d4d2 Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Fri, 29 Nov 2019 13:36:11 +0100 Subject: [PATCH 1805/1995] ASoC: SOF: define struct with compiler name and version Add compiler information structure sof_ipc_cc_version. Add new enum value in sof_ipc_ext_data for new structure. This struct will be used to show more information about firmware in host system. It will be helpful during debugging. Signed-off-by: Karol Trzcinski --- include/sound/sof/info.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/sound/sof/info.h b/include/sound/sof/info.h index a9156b4a062c1b..1c560144996ca4 100644 --- a/include/sound/sof/info.h +++ b/include/sound/sof/info.h @@ -30,6 +30,7 @@ enum sof_ipc_ext_data { SOF_IPC_EXT_DMA_BUFFER = 0, SOF_IPC_EXT_WINDOW, + SOF_IPC_EXT_CC_INFO, }; /* FW version - SOF_IPC_GLB_VERSION */ @@ -115,4 +116,18 @@ struct sof_ipc_window { struct sof_ipc_window_elem window[]; } __packed; +struct sof_ipc_cc_version { + struct sof_ipc_ext_data_hdr ext_hdr; + uint32_t major; + uint32_t minor; + uint32_t micro; + + /* reserved for future use */ + uint32_t reserved[4]; + + char name[16]; /* null terminated compiler name */ + char optim[4]; /* null terminated compiler -O flag value */ + char desc[]; /* null terminated compiler description */ +} __packed; + #endif From c5e4a391133d87182dccb2ecb888d2f28507fcd2 Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Tue, 3 Dec 2019 07:58:22 +0100 Subject: [PATCH 1806/1995] ASoC: SOF: log compiler name and version information Log information about used compilator and optimization level in sof firmware to host system. It will be helful to catch some compiler dependent bugs. Signed-off-by: Karol Trzcinski --- sound/soc/sof/loader.c | 39 +++++++++++++++++++++++++++++++++++++++ sound/soc/sof/sof-priv.h | 1 + 2 files changed, 40 insertions(+) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 31847aa3975dc5..235be4fc0862b2 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -32,6 +32,42 @@ static int get_ext_windows(struct snd_sof_dev *sdev, return 0; } +static int get_cc_info(struct snd_sof_dev *sdev, + struct sof_ipc_ext_data_hdr *ext_hdr) +{ + int ret; + + struct sof_ipc_cc_version *cc = + container_of(ext_hdr, struct sof_ipc_cc_version, ext_hdr); + + dev_dbg(sdev->dev, "Firmware info: used compiler %s %d:%d:%d%s used optimization flags %s\n", + cc->name, cc->major, cc->minor, cc->micro, cc->desc, + cc->optim); + + /* create read-only cc_version debugfs to store compiler version info */ + /* use local copy of the cc_version to prevent data corruption */ + if (sdev->first_boot) { + sdev->cc_version = devm_kmalloc(sdev->dev, cc->ext_hdr.hdr.size, + GFP_KERNEL); + + if (!sdev->cc_version) + return -ENOMEM; + + memcpy(sdev->cc_version, cc, cc->ext_hdr.hdr.size); + ret = snd_sof_debugfs_buf_item(sdev, sdev->cc_version, + cc->ext_hdr.hdr.size, + "cc_version", 0444); + + /* errors are only due to memory allocation, not debugfs */ + if (ret < 0) { + dev_err(sdev->dev, "error: snd_sof_debugfs_buf_item failed\n"); + return ret; + } + } + + return 0; +} + /* parse the extended FW boot data structures from FW boot message */ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) { @@ -65,6 +101,9 @@ int snd_sof_fw_parse_ext_data(struct snd_sof_dev *sdev, u32 bar, u32 offset) case SOF_IPC_EXT_WINDOW: ret = get_ext_windows(sdev, ext_hdr); break; + case SOF_IPC_EXT_CC_INFO: + ret = get_cc_info(sdev, ext_hdr); + break; default: dev_warn(sdev->dev, "warning: unknown ext header type %d size 0x%x\n", ext_hdr->type, ext_hdr->hdr.size); diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index 220b35141c34a5..3f1e1eb7c55f04 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -361,6 +361,7 @@ struct snd_sof_dev { struct snd_dma_buffer dmab_bdl; struct sof_ipc_fw_ready fw_ready; struct sof_ipc_fw_version fw_version; + struct sof_ipc_cc_version *cc_version; /* topology */ struct snd_soc_tplg_ops *tplg_ops; From 98b6f21f7438b714490a6f0be2c48a9acca14634 Mon Sep 17 00:00:00 2001 From: Yong Zhi Date: Mon, 18 Nov 2019 14:41:22 -0800 Subject: [PATCH 1807/1995] ASoC: Intel: Add machine driver for da7219_max98373 This patch adds sof_da7219_max98373 machine driver. Tested on JasperLake platform with SOF only. Signed-off-by: Yong Zhi Signed-off-by: Bard Liao Signed-off-by: Vani Ganji --- sound/soc/intel/boards/Kconfig | 18 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/sof_da7219_max98373.c | 371 ++++++++++++++++++ .../intel/common/soc-acpi-intel-jsl-match.c | 7 + 4 files changed, 398 insertions(+) create mode 100644 sound/soc/intel/boards/sof_da7219_max98373.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 0db4ae7c825916..b149e28a20768b 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -518,4 +518,22 @@ config SND_SOC_INTEL_TGL_RT1308_MACH endif ## SND_SOC_SOF_TIGERLAKE +if SND_SOC_SOF_JASPERLAKE + +config SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH + tristate "SOF with DA7219 and MAX98373 in I2S Mode" + depends on I2C && ACPI + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_DA7219 + select SND_SOC_MAX98373 + select SND_SOC_DMIC + select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_AUDIO_CODEC + help + This adds support for ASoC machine driver for SOF platforms + with DA7219 + MAX98373 I2S audio codec. + Say Y if you have such a device. + If unsure select "N". + +endif ## SND_SOC_SOF_JASPERLAKE + endif ## SND_SOC_INTEL_MACH diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 2c2eaaf7e83e4d..bb34f6ac321f30 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -31,6 +31,7 @@ snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o hda_dsp_c snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o snd-soc-tgl-rt1308-objs := tgl_rt1308.o hda_dsp_common.o +snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o hda_dsp_common.o obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o @@ -64,3 +65,4 @@ obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max9 obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o obj-$(CONFIG_SND_SOC_INTEL_TGL_RT1308_MACH) += snd-soc-tgl-rt1308.o +obj-$(CONFIG_SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH) += snd-soc-sof_da7219_max98373.o diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219_max98373.c new file mode 100644 index 00000000000000..4e31f0a5274f6d --- /dev/null +++ b/sound/soc/intel/boards/sof_da7219_max98373.c @@ -0,0 +1,371 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright(c) 2019 Intel Corporation. + +/* + * Intel SOF Machine driver for DA7219 + MAX98373 codec + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/da7219.h" +#include "../../codecs/da7219-aad.h" +#include "hda_dsp_common.h" + +#define DIALOG_CODEC_DAI "da7219-hifi" +#define MAX98373_CODEC_DAI "max98373-aif1" +#define MAXIM_DEV0_NAME "i2c-MX98373:00" +#define MAXIM_DEV1_NAME "i2c-MX98373:01" + +struct hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +struct card_private { + struct snd_soc_jack headset; + struct list_head hdmi_pcm_list; + struct snd_soc_jack hdmi[3]; +}; + +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + int ret = 0; + + codec_dai = snd_soc_card_get_codec_dai(card, DIALOG_CODEC_DAI); + 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_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 controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), +}; + +static const struct snd_soc_dapm_widget widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", 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 audio_map[] = { + { "Headphone Jack", NULL, "HPL" }, + { "Headphone Jack", NULL, "HPR" }, + + { "Left Spk", NULL, "Left BE_OUT" }, + { "Right Spk", NULL, "Right BE_OUT" }, + + { "MIC", NULL, "Headset Mic" }, + + { "Headphone Jack", NULL, "Platform Clock" }, + { "Headset Mic", NULL, "Platform Clock" }, +}; + +static struct snd_soc_jack headset; + +static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_component *component = rtd->codec_dai->component; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_jack *jack; + int ret; + + /* Configure sysclk for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24000000, + SND_SOC_CLOCK_IN); + if (ret) { + dev_err(rtd->dev, "can't set codec sysclk configuration\n"); + return ret; + } + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3 | SND_JACK_LINEOUT, + &headset, NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); + return ret; + } + + jack = &headset; + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + da7219_aad_jack_det(component, jack); + + return ret; +} + +static int ssp1_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *runtime = substream->private_data; + int ret, j; + + for (j = 0; j < runtime->num_codecs; j++) { + struct snd_soc_dai *codec_dai = runtime->codec_dais[j]; + + if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { + /* vmon_slot_no = 0 imon_slot_no = 1 for TX slots */ + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 3, 4, 16); + if (ret < 0) { + dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret); + return ret; + } + } + if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { + /* vmon_slot_no = 2 imon_slot_no = 3 for TX slots */ + ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC, 3, 4, 16); + if (ret < 0) { + dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret); + return ret; + } + } + } + + return 0; +} + +static struct snd_soc_ops ssp1_ops = { + .hw_params = ssp1_hw_params, +}; + +static struct snd_soc_codec_conf max98373_codec_conf[] = { + { + .dev_name = MAXIM_DEV0_NAME, + .name_prefix = "Right", + }, + { + .dev_name = MAXIM_DEV1_NAME, + .name_prefix = "Left", + }, +}; + +static int hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + pcm->device = dai->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +static int card_late_probe(struct snd_soc_card *card) +{ + struct card_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_acpi_mach *mach = (card->dev)->platform_data; + struct hdmi_pcm *pcm; + + if (mach->mach_params.common_hdmi_codec_drv) { + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm, + head); + return hda_dsp_hdmi_build_controls(card, + pcm->codec_dai->component); + } + + return -EINVAL; +} + +SND_SOC_DAILINK_DEF(ssp0_pin, + DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); +SND_SOC_DAILINK_DEF(ssp0_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", DIALOG_CODEC_DAI))); + +SND_SOC_DAILINK_DEF(ssp1_pin, + DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); +SND_SOC_DAILINK_DEF(ssp1_amps, + DAILINK_COMP_ARRAY( + /* Left */ COMP_CODEC(MAXIM_DEV0_NAME, MAX98373_CODEC_DAI), + /* Right */ COMP_CODEC(MAXIM_DEV1_NAME, MAX98373_CODEC_DAI))); + +SND_SOC_DAILINK_DEF(dmic_pin, + DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); +SND_SOC_DAILINK_DEF(dmic_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); + +SND_SOC_DAILINK_DEF(idisp1_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); +SND_SOC_DAILINK_DEF(idisp1_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); + +SND_SOC_DAILINK_DEF(idisp2_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); +SND_SOC_DAILINK_DEF(idisp2_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); + +SND_SOC_DAILINK_DEF(idisp3_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); +SND_SOC_DAILINK_DEF(idisp3_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); + +SND_SOC_DAILINK_DEF(platform, /* subject to be overridden during probe */ + DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); + +static struct snd_soc_dai_link dais[] = { + /* Back End DAI links */ + { + .name = "SSP1-Codec", + .id = 0, + .ignore_pmdown_time = 1, + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, /* IV feedback */ + .ops = &ssp1_ops, + SND_SOC_DAILINK_REG(ssp1_pin, ssp1_amps, platform), + }, + { + .name = "SSP0-Codec", + .id = 1, + .no_pcm = 1, + .init = da7219_codec_init, + .ignore_pmdown_time = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), + }, + { + .name = "dmic01", + .id = 2, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), + }, + { + .name = "iDisp1", + .id = 3, + .init = hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), + }, + { + .name = "iDisp2", + .id = 4, + .init = hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), + }, + { + .name = "iDisp3", + .id = 5, + .init = hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), + }, +}; + +static struct snd_soc_card card_da7219_m98373 = { + .name = "da7219max", + .owner = THIS_MODULE, + .dai_link = dais, + .num_links = ARRAY_SIZE(dais), + .controls = controls, + .num_controls = ARRAY_SIZE(controls), + .dapm_widgets = widgets, + .num_dapm_widgets = ARRAY_SIZE(widgets), + .dapm_routes = audio_map, + .num_dapm_routes = ARRAY_SIZE(audio_map), + .codec_conf = max98373_codec_conf, + .num_configs = ARRAY_SIZE(max98373_codec_conf), + .fully_routed = true, + .late_probe = card_late_probe, +}; + +static int audio_probe(struct platform_device *pdev) +{ + static struct snd_soc_card *card; + struct snd_soc_acpi_mach *mach; + struct card_private *ctx; + int ret; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + if (!ctx) + return -ENOMEM; + + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + card = (struct snd_soc_card *)pdev->id_entry->driver_data; + card->dev = &pdev->dev; + + mach = (&pdev->dev)->platform_data; + ret = snd_soc_fixup_dai_links_platform_name(card, + mach->mach_params.platform); + if (ret) + return ret; + + snd_soc_card_set_drvdata(card, ctx); + + return devm_snd_soc_register_card(&pdev->dev, card); +} + +static const struct platform_device_id board_ids[] = { + { + .name = "sof_da7219_max98373", + .driver_data = (kernel_ulong_t)&card_da7219_m98373, + }, + { } +}; + +static struct platform_driver audio = { + .probe = audio_probe, + .driver = { + .name = "sof_da7219_max98373", + .pm = &snd_soc_pm_ops, + }, + .id_table = board_ids, +}; +module_platform_driver(audio) + +/* Module information */ +MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver"); +MODULE_AUTHOR("Yong Zhi "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:sof_da7219_max98373"); diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c index 1c68a04f0c6e6c..ed2b125f6a11a1 100644 --- a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c @@ -10,6 +10,13 @@ #include struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = { + { + .id = "DLGS7219", + .drv_name = "sof_da7219_max98373", + .machine_quirk = snd_soc_acpi_codec_list, + .sof_fw_filename = "sof-jsl.ri", + .sof_tplg_filename = "sof-jsl-da7219.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_jsl_machines); From 419edf53dfbe2a0f34b8e68bd5d3114222e5796a Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 17 Dec 2019 23:42:32 +0200 Subject: [PATCH 1808/1995] ASoC: SOF: imx8: Fix dsp_box offset dsp_box is used to keep DSP initiated messages. The value of dsp_offset is set by the DSP with the first message, so we need a way to boostrap it in order to get the first message. We do this by setting the correct default dsp_box offset which on i.MX8 is not zero. Very interesting is why it has worked until now. On i.MX8, DSP communicates with ARM core using a shared SDRAM memory area. Actually, there are two shared areas: * SDRAM0 - starting at 0x92400000, size 0x800000 * SDRAM1 - starting at 0x92C00000, size 0x800000 SDRAM0 keeps the data sections, starting with .rodata. By chance fw_ready structure was placed at the beginning of .rodata. dsp_box_base is defined as SDRAM0 + dsp_box_offset and it is placed at the begining of SDRAM1 (dsp_box_offset should be 0x800000). But because it is zero initialized by default it points to SDRAM0 where by chance the fw_ready was placed in the SOF firmware. Anyhow, SOF commit 7466bee378dd811b ("clk: make freq arrays constant") fw_ready is no longer at the beginning of SDRAM0 and everything shows how lucky we were until now. Fix this by properly setting the default dsp_box offset. Fixes 202acc565a1f050 ("ASoC: SOF: imx: Add i.MX8 HW support") Signed-off-by: Daniel Baluta --- sound/soc/sof/imx/imx8.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index cfefcfd927986d..dca85cf07ffa7e 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -304,6 +304,9 @@ static int imx8_probe(struct snd_sof_dev *sdev) } sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM; + /* set default mailbox offset for FW ready message */ + sdev->dsp_box.offset = MBOX_OFFSET; + return 0; exit_pdev_unregister: From ac42b142cd7652b3c9740cf81b8d8a3965e7a1e3 Mon Sep 17 00:00:00 2001 From: Sathyanarayana Nujella Date: Mon, 16 Dec 2019 15:53:06 -0800 Subject: [PATCH 1809/1995] ASoC: SOF: Intel: hda: Add iDisp4 DAI TGL supports more than three iDisp DAI's. Add support for iDisp4 CPU DAI. Without this patch, we saw the below error on our TGL DUT: sof_rt5682 tgl_max98357a_rt5682: ASoC: CPU DAI iDisp4 Pin not registered Signed-off-by: Sathyanarayana Nujella Signed-off-by: Jairaj Arava --- sound/soc/sof/intel/hda-dai.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 7d2903a675034d..313611dcb5e48c 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -447,6 +447,10 @@ struct snd_soc_dai_driver skl_dai[] = { .name = "iDisp3 Pin", .ops = &hda_link_dai_ops, }, +{ + .name = "iDisp4 Pin", + .ops = &hda_link_dai_ops, +}, { .name = "Analog CPU DAI", .ops = &hda_link_dai_ops, From 7fde47549cb1b305c4578d2b535b55b87905937d Mon Sep 17 00:00:00 2001 From: Sathyanarayana Nujella Date: Mon, 16 Dec 2019 15:54:13 -0800 Subject: [PATCH 1810/1995] ASoC: hdac_hda: Update hdac hda dai table to include intel-hdmi-hifi4 TGL supports more than three HDMI Dai's. So, update hdac_hda_dais table to include 4th DAI. Without this patch, we saw the below error in TGL DUT: sof_rt5682 tgl_max98357a_rt5682: ASoC: CODEC DAI intel-hdmi-hifi4 not Signed-off-by: Sathyanarayana Nujella Signed-off-by: Jairaj Arava --- sound/soc/codecs/hdac_hda.c | 16 ++++++++++++++++ sound/soc/codecs/hdac_hda.h | 3 ++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index 6803d39e09a5fe..4e0f4afe6ddc6c 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -164,6 +164,19 @@ static struct snd_soc_dai_driver hdac_hda_dais[] = { .sig_bits = 24, }, }, +{ + .id = HDAC_HDMI_3_DAI_ID, + .name = "intel-hdmi-hifi4", + .ops = &hdac_hda_dai_ops, + .playback = { + .stream_name = "hifi4", + .channels_min = 1, + .channels_max = 32, + .rates = STUB_HDMI_RATES, + .formats = STUB_FORMATS, + .sig_bits = 24, + }, +}, }; @@ -346,6 +359,9 @@ static struct hda_pcm *snd_soc_find_pcm_from_dai(struct hdac_hda_priv *hda_pvt, case HDAC_HDMI_2_DAI_ID: pcm_name = "HDMI 2"; break; + case HDAC_HDMI_3_DAI_ID: + pcm_name = "HDMI 3"; + break; default: dev_err(&hcodec->core.dev, "invalid dai id %d\n", dai->id); return NULL; diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h index e145cec085b8f5..598b07d9b6fea0 100644 --- a/sound/soc/codecs/hdac_hda.h +++ b/sound/soc/codecs/hdac_hda.h @@ -13,7 +13,8 @@ enum { HDAC_HDMI_0_DAI_ID, HDAC_HDMI_1_DAI_ID, HDAC_HDMI_2_DAI_ID, - HDAC_LAST_DAI_ID = HDAC_HDMI_2_DAI_ID, + HDAC_HDMI_3_DAI_ID, + HDAC_LAST_DAI_ID = HDAC_HDMI_3_DAI_ID, }; struct hdac_hda_pcm { From fa1e7b89e5765c6e7d538a4349da5a3bb6432f28 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 20 Dec 2019 12:45:06 -0600 Subject: [PATCH 1811/1995] ASoC: SOF: pci: change the default firmware path when the community key is used Since ApolloLake, Intel platforms require signed firmware. On all Windows platforms the default is to require the Intel production key be used. But some platforms allow for a community key to be used, which allows developers to compile/build their own firmware. In the linux-firmware tree, the default intel/sof path is used for firmwares signed for the production key, and files signed with the community key are located in intel/sof/community. Since we don't have an API to query which key is used on what platforms, we have to rely on DMI-based quirks. Developers can bypass this mechanism by setting a kernel 'fw_path' module parameter. Additional dynamic debug traces are provided to help debug cases where the wrong file might be used. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-pci-dev.c | 44 +++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index f501f42565743c..9d09131a6a56cd 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -9,6 +9,7 @@ // #include +#include #include #include #include @@ -36,6 +37,23 @@ MODULE_PARM_DESC(sof_pci_debug, "SOF PCI debug options (0x0 all off)"); #define SOF_PCI_DISABLE_PM_RUNTIME BIT(0) +static const struct dmi_system_id community_key_platforms[] = { + { + .ident = "Up Squared", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), + DMI_MATCH(DMI_BOARD_NAME, "UP-APL01"), + } + }, + { + .ident = "Google Chromebooks", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + } + }, + {}, +}; + #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) static const struct sof_dev_desc bxt_desc = { .machines = snd_soc_acpi_intel_bxt_machines, @@ -290,12 +308,34 @@ static int sof_pci_probe(struct pci_dev *pci, sof_pdata->dev = dev; sof_pdata->fw_filename = desc->default_fw_filename; + /* + * for platforms using the SOF community key, change the + * default path automatically to pick the right files from the + * linux-firmware tree. This can be overridden with the + * fw_path kernel parameter, e.g. for developers. + */ + /* alternate fw and tplg filenames ? */ - if (fw_path) + if (fw_path) { sof_pdata->fw_filename_prefix = fw_path; - else + + dev_dbg(dev, + "Module parameter used, changed fw path to %s\n", + sof_pdata->fw_filename_prefix); + + } else if (dmi_check_system(community_key_platforms)) { + sof_pdata->fw_filename_prefix = + devm_kasprintf(dev, GFP_KERNEL, "%s/%s", + sof_pdata->desc->default_fw_path, + "community"); + + dev_dbg(dev, + "Platform uses community key, changed fw path to %s\n", + sof_pdata->fw_filename_prefix); + } else { sof_pdata->fw_filename_prefix = sof_pdata->desc->default_fw_path; + } if (tplg_path) sof_pdata->tplg_filename_prefix = tplg_path; From 52ec20e276a6b49f74f77b18e04cf1b1359b75ae Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 20 Dec 2019 14:21:28 -0600 Subject: [PATCH 1812/1995] ASoC: SOF: loader: add dynamic debug trace We currently have no trace referring to the firmware path, add a trace to help debug cases where the wrong file might be used. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/loader.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/loader.c b/sound/soc/sof/loader.c index 235be4fc0862b2..fc4ab51bacf477 100644 --- a/sound/soc/sof/loader.c +++ b/sound/soc/sof/loader.c @@ -487,6 +487,9 @@ int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "error: request firmware %s failed err: %d\n", fw_filename, ret); + } else { + dev_dbg(sdev->dev, "request_firmware %s successful\n", + fw_filename); } kfree(fw_filename); From 8df5b14662666d33787976e8ea2d3762d0d777fd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 6 Jan 2020 15:42:13 -0600 Subject: [PATCH 1813/1995] ASoC: Intel: bdw-rt5677: fix Kconfig dependencies The existing machine driver depends on SPI Master capabilities, but the Kconfig does not model this dependency and the SPI controller needs to be selected as well. Without this patch the machine driver probe would fail with the spi-RT5677AA:00 component never registered by the ACPI/LPSS subsystem. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index cb7a52a62fab86..1e9701d9a56088 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -62,6 +62,9 @@ config SND_SOC_INTEL_BDW_RT5677_MACH depends on I2C_DESIGNWARE_PLATFORM || COMPILE_TEST depends on GPIOLIB || COMPILE_TEST depends on X86_INTEL_LPSS || COMPILE_TEST + depends on SPI_MASTER + select SPI_PXA2XX + select SND_SOC_RT5677_SPI select SND_SOC_RT5677 help This adds support for Intel Broadwell platform based boards with From 8d23d03f90b227259527499684b975ea607c8f68 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 6 Jan 2020 16:45:39 -0600 Subject: [PATCH 1814/1995] ASoC: Intel: bdw-rt5677: change cpu_dai and platform components for SOF The legacy driver uses dummy cpu_dai and platform, SOF requires actual values to bind. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bdw-rt5677.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 2af8e5a62da849..4ce8d2074fe7e0 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -295,6 +295,14 @@ SND_SOC_DAILINK_DEF(platform, SND_SOC_DAILINK_DEF(be, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RT5677CE:00", "rt5677-aif1"))); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) +SND_SOC_DAILINK_DEF(ssp0_port, + DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port"))); +#else +SND_SOC_DAILINK_DEF(ssp0_port, + DAILINK_COMP_ARRAY(COMP_DUMMY()))); +#endif + /* Wake on voice interface */ SND_SOC_DAILINK_DEFS(dsp, DAILINK_COMP_ARRAY(COMP_CPU("spi-RT5677AA:00")), @@ -342,7 +350,7 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { .dpcm_playback = 1, .dpcm_capture = 1, .init = bdw_rt5677_init, - SND_SOC_DAILINK_REG(dummy, be, dummy), + SND_SOC_DAILINK_REG(ssp0_port, be, platform), }, }; From 19a221f4f8bc62f38c4c2746465093cbabcc5c43 Mon Sep 17 00:00:00 2001 From: Pan Xiuli Date: Tue, 7 Jan 2020 10:54:06 +0800 Subject: [PATCH 1815/1995] ASoC: Intel: broadwell: change cpu_dai and platform components for SOF The legacy driver uses dummy cpu_dai and platform, SOF requires actual values to bind. Signed-off-by: Pan Xiuli --- sound/soc/intel/boards/broadwell.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index db7e1e87156d92..239f981c5cfdbf 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -164,6 +164,14 @@ SND_SOC_DAILINK_DEF(platform, SND_SOC_DAILINK_DEF(codec, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1"))); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) +SND_SOC_DAILINK_DEF(ssp0_port, + DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port"))); +#else +SND_SOC_DAILINK_DEF(ssp0_port, + DAILINK_COMP_ARRAY(COMP_DUMMY()))); +#endif + /* broadwell digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link broadwell_rt286_dais[] = { /* Front End DAI links */ @@ -218,7 +226,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { .ops = &broadwell_rt286_ops, .dpcm_playback = 1, .dpcm_capture = 1, - SND_SOC_DAILINK_REG(dummy, codec, dummy), + SND_SOC_DAILINK_REG(ssp0_port, codec, platform), }, }; From 4ab54ad018a622f37afe37b7cbb2a1350fbc0c1f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 3 Jan 2020 03:16:37 +0800 Subject: [PATCH 1816/1995] ASoC: soc-acpi: add _ADR-based link descriptors For SoundWire support, we added a 'link_mask' to describe the PCB hardware layout. This helped form a signature that can be used as a first-order way of detecting the hardware and selecting the machine driver. The concept of link_mask is however not enough. Some BIOS enable all links, even when there are no devices physically connected. We can also see variations with multiple devices attached on one link, or different types of devices connected on the same link. To accurately represent the hardware, we need to build static tables where each link exposes a list of expected devices represented by the 64-bit _ADR field (which uniquely identifies each device). The new 'links' field is optional when the link_mask is sufficient to represent a platform in a unique way. The existing mechanism to support I2C devices is left as is, it'd be too invasive to change the existing support for _HID and the notion of link is not relevant either. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Bard liao --- include/sound/soc-acpi.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index c4c997bd03792c..a217a87cae86fb 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -61,6 +61,8 @@ static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) * @platform: string used for HDaudio codec support * @codec_mask: used for HDAudio support * @common_hdmi_codec_drv: use commom HDAudio HDMI codec driver + * @link_mask: links enabled on the board + * @links: array of link _ADR descriptors, null terminated */ struct snd_soc_acpi_mach_params { u32 acpi_ipc_irq_index; @@ -68,6 +70,23 @@ struct snd_soc_acpi_mach_params { u32 codec_mask; u32 dmic_num; bool common_hdmi_codec_drv; + u32 link_mask; + const struct snd_soc_acpi_link_adr *links; +}; + +/** + * snd_soc_acpi_link_adr: ACPI-based list of _ADR, with a variable + * number of devices per link + * + * @mask: one bit set indicates the link this list applies to + * @num_adr: ARRAY_SIZE of adr + * @adr: array of _ADR (represented as u64). + */ + +struct snd_soc_acpi_link_adr { + const u32 mask; + const u32 num_adr; + const u64 *adr; }; /** @@ -78,6 +97,7 @@ struct snd_soc_acpi_mach_params { * * @id: ACPI ID (usually the codec's) used to find a matching machine driver. * @link_mask: describes required board layout, e.g. for SoundWire. + * @links: array of link _ADR descriptors, null terminated. * @drv_name: machine driver name * @fw_filename: firmware file name. Used when SOF is not enabled. * @board: board name @@ -94,6 +114,7 @@ struct snd_soc_acpi_mach_params { struct snd_soc_acpi_mach { const u8 id[ACPI_ID_LEN]; const u32 link_mask; + const struct snd_soc_acpi_link_adr *links; const char *drv_name; const char *fw_filename; const char *board; From 360168289d1e93dc2d67dfef104daed135147b34 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 27 Dec 2019 17:18:14 +0800 Subject: [PATCH 1817/1995] soundwire: intel: report slave_ids for each link to SOF driver The existing link_mask flag is no longer sufficient to detect the hardware and identify which topology file and a machine driver to load. By reporting the slave_ids exposed in ACPI tables, the parent SOF driver will be able to compare against a set of static configurations. This patch only adds the interface change, the functionality is added in future patches. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- include/linux/soundwire/sdw_intel.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index 93b83bdf803588..979b41b5dcb44b 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -5,6 +5,7 @@ #define __SDW_INTEL_H #include +#include /** * struct sdw_intel_stream_params_data: configuration passed during @@ -93,6 +94,11 @@ struct sdw_intel_link_res; */ #define SDW_INTEL_CLK_STOP_BUS_RESET BIT(3) +struct sdw_intel_slave_id { + int link_id; + struct sdw_slave_id id; +}; + /** * struct sdw_intel_ctx - context allocated by the controller * driver probe @@ -101,9 +107,12 @@ struct sdw_intel_link_res; * hardware capabilities after all power dependencies are settled. * @link_mask: bit-wise mask listing SoundWire links reported by the * Controller + * @num_slaves: total number of devices exposed across all enabled links * @handle: ACPI parent handle * @links: information for each link (controller-specific and kept * opaque here) + * @ids: array of slave_id, representing Slaves exposed across all enabled + * links * @link_list: list to handle interrupts across all links * @shim_lock: mutex to handle concurrent rmw access to shared SHIM registers. */ @@ -111,8 +120,10 @@ struct sdw_intel_ctx { int count; void __iomem *mmio_base; u32 link_mask; + int num_slaves; acpi_handle handle; struct sdw_intel_link_res *links; + struct sdw_intel_slave_id *ids; struct list_head link_list; struct mutex shim_lock; /* lock for access to shared SHIM registers */ }; From 4b4bf78833ac2e1392175a88c774a9eddb7e55d3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 Jan 2020 17:27:35 -0600 Subject: [PATCH 1818/1995] ASoC: Intel: bdw-rt5677: fix compilation without SOF too many parentheses Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bdw-rt5677.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 4ce8d2074fe7e0..bb643c99069dfd 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -300,7 +300,7 @@ SND_SOC_DAILINK_DEF(ssp0_port, DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port"))); #else SND_SOC_DAILINK_DEF(ssp0_port, - DAILINK_COMP_ARRAY(COMP_DUMMY()))); + DAILINK_COMP_ARRAY(COMP_DUMMY())); #endif /* Wake on voice interface */ From 7930232eeb17a2ccce0bef56b118b01922abb7c6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 Jan 2020 17:28:25 -0600 Subject: [PATCH 1819/1995] ASoC: Intel: broadwell: fix compilation without SOF too many parentheses Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/broadwell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 239f981c5cfdbf..b9c12e24c70bc0 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -169,7 +169,7 @@ SND_SOC_DAILINK_DEF(ssp0_port, DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port"))); #else SND_SOC_DAILINK_DEF(ssp0_port, - DAILINK_COMP_ARRAY(COMP_DUMMY()))); + DAILINK_COMP_ARRAY(COMP_DUMMY())); #endif /* broadwell digital audio interface glue - connects codec <--> CPU */ From 2ed00e58dd697bbe9d70d668cc21804a1a017588 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 Jan 2020 17:29:11 -0600 Subject: [PATCH 1820/1995] ASoC: Intel: bdw-rt5650: change cpu_dai and platform components for SOF The legacy driver uses dummy cpu_dai and platform, SOF requires actual values to bind. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/bdw-rt5650.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c index ba3fc1ef900aba..1a302436d45037 100644 --- a/sound/soc/intel/boards/bdw-rt5650.c +++ b/sound/soc/intel/boards/bdw-rt5650.c @@ -223,6 +223,14 @@ SND_SOC_DAILINK_DEF(platform, SND_SOC_DAILINK_DEF(be, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5650:00", "rt5645-aif1"))); +#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) +SND_SOC_DAILINK_DEF(ssp0_port, + DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port"))); +#else +SND_SOC_DAILINK_DEF(ssp0_port, + DAILINK_COMP_ARRAY(COMP_DUMMY())); +#endif + static struct snd_soc_dai_link bdw_rt5650_dais[] = { /* Front End DAI links */ { @@ -256,7 +264,7 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = { .dpcm_playback = 1, .dpcm_capture = 1, .init = bdw_rt5650_init, - SND_SOC_DAILINK_REG(dummy, be, dummy), + SND_SOC_DAILINK_REG(ssp0_port, be, platform), }, }; From b0ff8a39bf8c3ec6d7c40e2e8ebd09709e6a95b3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 11 Sep 2019 10:27:59 -0500 Subject: [PATCH 1821/1995] ASoC: SOF: Intel: add SoundWire configuration interface Now that the SoundWire core supports the multi-step initialization, call the relevant APIs. The actual hardware enablement can be done in two places, ideally we'd want to startup the SoundWire IP as soon as possible (while still taking power rail dependencies into account) However when suspend/resume is implemented, the DSP device will be resumed first, and only when the DSP firmware is downloaded/booted would the SoundWire child devices be resumed, so there are only marginal benefits in starting the IP earlier for the first probe. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-loader.c | 13 ++++ sound/soc/sof/intel/hda.c | 129 +++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 44 +++++++++++ 3 files changed, 186 insertions(+) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 1782f50926391c..257c47129f165f 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -396,6 +396,19 @@ int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev) /* post fw run operations */ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev) { + int ret; + + if (sdev->first_boot) { + ret = hda_sdw_startup(sdev); + if (ret < 0) { + dev_err(sdev->dev, + "error: could not startup SoundWire links\n"); + return ret; + } + } + + hda_sdw_int_enable(sdev, true); + /* re-enable clock gating and power gating */ return hda_dsp_ctrl_clock_power_gating(sdev, true); } diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index d08462f481de38..9bc7fdef161a8f 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -18,7 +18,9 @@ #include #include +#include #include +#include #include #include #include @@ -34,6 +36,98 @@ #define EXCEPT_MAX_HDR_SIZE 0x400 +#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) + +void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable) +{ + sdw_intel_enable_irq(sdev->bar[HDA_DSP_BAR], enable); +} + +static int hda_sdw_acpi_scan(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hdev; + acpi_handle handle; + int ret; + + handle = ACPI_HANDLE(sdev->dev); + + /* save ACPI info for the probe step */ + hdev = sdev->pdata->hw_pdata; + + ret = sdw_intel_acpi_scan(handle, &hdev->info); + if (ret < 0) { + dev_err(sdev->dev, "%s failed\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int hda_sdw_probe(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hdev; + struct sdw_intel_res res; + acpi_handle handle; + void *sdw; + + handle = ACPI_HANDLE(sdev->dev); + + hdev = sdev->pdata->hw_pdata; + + memset(&res, 0, sizeof(res)); + + res.mmio_base = sdev->bar[HDA_DSP_BAR]; + res.irq = sdev->ipc_irq; + res.handle = hdev->info.handle; + res.parent = sdev->dev; + + /* + * ops and arg fields are not populated for now, + * they will be needed when the DAI callbacks are + * provided + */ + + /* we could filter links here if needed, e.g for quirks */ + res.count = hdev->info.count; + res.link_mask = hdev->info.link_mask; + + sdw = sdw_intel_probe(&res); + if (!sdw) { + dev_err(sdev->dev, "error: SoundWire probe failed\n"); + return -EINVAL; + } + + /* save context */ + hdev->sdw = sdw; + + return 0; +} + +int hda_sdw_startup(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hdev; + + hdev = sdev->pdata->hw_pdata; + + return sdw_intel_startup(hdev->sdw); +} + +static int hda_sdw_exit(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hdev; + + hdev = sdev->pdata->hw_pdata; + + hda_sdw_int_enable(sdev, false); + + if (hdev->sdw) + sdw_intel_exit(hdev->sdw); + hdev->sdw = NULL; + + return 0; +} +#endif + /* * Debug */ @@ -342,9 +436,21 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev, static int hda_init_caps(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); + struct snd_sof_pdata *pdata = sdev->pdata; #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_ext_link *hlink; + struct snd_soc_acpi_mach_params *mach_params; + struct snd_soc_acpi_mach *hda_mach; + struct snd_soc_acpi_mach *mach; + const char *tplg_filename; + const char *idisp_str; + const char *dmic_str; + int dmic_num; + int codec_num = 0; + int i; #endif + struct sof_intel_hda_dev *hdev = pdata->hw_pdata; + u32 link_mask; int ret = 0; device_disable_async_suspend(bus->dev); @@ -373,6 +479,27 @@ static int hda_init_caps(struct snd_sof_dev *sdev) return ret; } + /* scan SoundWire capabilities exposed by DSDT */ + ret = hda_sdw_acpi_scan(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: SoundWire ACPI scan error\n"); + return ret; + } + + link_mask = hdev->info.link_mask; + if (!link_mask) { + /* + * probe/allocated SoundWire resources. + * The hardware configuration takes place in hda_sdw_startup + * after power rails are enabled. + */ + ret = hda_sdw_probe(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: SoundWire probe error\n"); + return ret; + } + } + #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) if (bus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(bus); @@ -626,6 +753,8 @@ int hda_dsp_remove(struct snd_sof_dev *sdev) snd_hdac_ext_bus_device_remove(bus); #endif + hda_sdw_exit(sdev); + if (!IS_ERR_OR_NULL(hda->dmic_dev)) platform_device_unregister(hda->dmic_dev); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 47408ec0de4046..ea8308c5e9bef6 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -11,6 +11,8 @@ #ifndef __SOF_INTEL_HDA_H #define __SOF_INTEL_HDA_H +#include +#include #include #include #include "shim.h" @@ -414,6 +416,12 @@ struct sof_intel_hda_dev { /* DMIC device */ struct platform_device *dmic_dev; + + /* ACPI information stored between scan and probe steps */ + struct sdw_intel_acpi_info info; + + /* sdw context allocated by SoundWire driver */ + struct sdw_intel_ctx *sdw; }; static inline struct hdac_bus *sof_to_bus(struct snd_sof_dev *s) @@ -607,6 +615,42 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag); int hda_dsp_trace_release(struct snd_sof_dev *sdev); int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd); +/* + * SoundWire support + */ +#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) + +int hda_sdw_startup(struct snd_sof_dev *sdev); +void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable); + +#else + +static inline int hda_sdw_acpi_scan(struct snd_sof_dev *sdev) +{ + return 0; +} + +static inline int hda_sdw_probe(struct snd_sof_dev *sdev) +{ + return 0; +} + +static inline int hda_sdw_startup(struct snd_sof_dev *sdev) +{ + return 0; +} + +static inline int hda_sdw_exit(struct snd_sof_dev *sdev) +{ + return 0; +} + +static inline void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable) +{ +} + +#endif + /* common dai driver */ extern struct snd_soc_dai_driver skl_dai[]; From 74abe801760f2140590d749c3af6cee54fc7aa35 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 16 Aug 2019 17:53:00 -0500 Subject: [PATCH 1822/1995] ASoC: SOF: IPC: dai-intel: move ALH declarations in header file ALH was inserted in the wrong place during integration, add after DMIC to mirror the file used by SOF firmware. No functional change, just text move in the same file to better track changes, if any. Signed-off-by: Pierre-Louis Bossart --- include/sound/sof/dai-intel.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/sound/sof/dai-intel.h b/include/sound/sof/dai-intel.h index 5f1ef5565be69f..04e48227f542b5 100644 --- a/include/sound/sof/dai-intel.h +++ b/include/sound/sof/dai-intel.h @@ -87,6 +87,15 @@ struct sof_ipc_dai_hda_params { uint32_t link_dma_ch; } __packed; +/* ALH Configuration Request - SOF_IPC_DAI_ALH_CONFIG */ +struct sof_ipc_dai_alh_params { + struct sof_ipc_hdr hdr; + uint32_t stream_id; + + /* reserved for future use */ + uint32_t reserved[15]; +} __packed; + /* DMIC Configuration Request - SOF_IPC_DAI_DMIC_CONFIG */ /* This struct is defined per 2ch PDM controller available in the platform. @@ -179,13 +188,4 @@ struct sof_ipc_dai_dmic_params { struct sof_ipc_dai_dmic_pdm_ctrl pdm[0]; } __packed; -/* ALH Configuration Request - SOF_IPC_DAI_ALH_CONFIG */ -struct sof_ipc_dai_alh_params { - struct sof_ipc_hdr hdr; - uint32_t stream_id; - - /* reserved for future use */ - uint32_t reserved[15]; -} __packed; - #endif From 4303172b3f078fb118fe763706cfc1867a6a9af1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 26 Jun 2019 02:45:55 -0500 Subject: [PATCH 1823/1995] ASoC: SOF: Intel: hda: add SoundWire stream config/free callbacks These callbacks are invoked when a matching hw_params/hw_free() DAI operation takes place, and will result in IPC operations with the SOF firmware. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 71 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 9bc7fdef161a8f..c47ff49f723bb4 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -24,6 +24,7 @@ #include #include #include +#include "../sof-audio.h" #include "../ops.h" #include "hda.h" @@ -38,6 +39,74 @@ #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) +static int sdw_params_stream(struct device *dev, + struct sdw_intel_stream_params_data *params_data) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + struct snd_soc_dai *d = params_data->dai; + struct sof_ipc_dai_config config; + struct sof_ipc_reply reply; + int link_id = params_data->link_id; + int alh_stream_id = params_data->alh_stream_id; + int ret; + u32 size = sizeof(config); + + memset(&config, 0, size); + config.hdr.size = size; + config.hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG; + config.type = SOF_DAI_INTEL_ALH; + config.dai_index = (link_id << 8) | (d->id); + config.alh.stream_id = alh_stream_id; + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + config.hdr.cmd, &config, size, &reply, + sizeof(reply)); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to set DAI hw_params for link %d dai->id %d ALH %d\n", + link_id, d->id, alh_stream_id); + } + + return ret; +} + +static int sdw_free_stream(struct device *dev, + struct sdw_intel_stream_free_data *free_data) +{ + struct snd_sof_dev *sdev = dev_get_drvdata(dev); + struct snd_soc_dai *d = free_data->dai; + struct sof_ipc_dai_config config; + struct sof_ipc_reply reply; + int link_id = free_data->link_id; + int ret; + u32 size = sizeof(config); + + memset(&config, 0, size); + config.hdr.size = size; + config.hdr.cmd = SOF_IPC_GLB_DAI_MSG | SOF_IPC_DAI_CONFIG; + config.type = SOF_DAI_INTEL_ALH; + config.dai_index = (link_id << 8) | d->id; + config.alh.stream_id = 0xFFFF; /* invalid value on purpose */ + + /* send message to DSP */ + ret = sof_ipc_tx_message(sdev->ipc, + config.hdr.cmd, &config, size, &reply, + sizeof(reply)); + if (ret < 0) { + dev_err(sdev->dev, + "error: failed to free stream for link %d dai->id %d\n", + link_id, d->id); + } + + return ret; +} + +static const struct sdw_intel_ops sdw_callback = { + .params_stream = sdw_params_stream, + .free_stream = sdw_free_stream, +}; + void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable) { sdw_intel_enable_irq(sdev->bar[HDA_DSP_BAR], enable); @@ -80,6 +149,8 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev) res.irq = sdev->ipc_irq; res.handle = hdev->info.handle; res.parent = sdev->dev; + res.ops = &sdw_callback; + res.dev = sdev->dev; /* * ops and arg fields are not populated for now, From e9a92e6c6ab968f016838bcc9105610367fc81b8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 12 Sep 2019 11:13:05 -0500 Subject: [PATCH 1824/1995] ASoC: SOF: Intel: hda: initial SoundWire machine driver autodetect For now we have a limited number of machine driver configurations, and we can detect them based on the link configuration returned after checking hardware and firmware (BIOS) configurations. It's likely that in the future we will need to check for _ADR match as well, which can easily be done by extending the acpi_info structure. There is a chance that in extreme cases where the BIOS contains too much information we would need to detect which Slave devices actually report as 'attached'. This would be more accurate than static table-based solutions, but it also introduces timing dependencies since we don't know when those devices might become attached, so will only be only be looked at if we see limitations with static methods and the usual quirks based e.g. on DMI information. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 93 ++++++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 21 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index c47ff49f723bb4..93b71b38faed0b 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -180,6 +180,9 @@ int hda_sdw_startup(struct snd_sof_dev *sdev) hdev = sdev->pdata->hw_pdata; + if (!hdev->sdw) + return 0; + return sdw_intel_startup(hdev->sdw); } @@ -510,15 +513,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev) struct snd_sof_pdata *pdata = sdev->pdata; #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) struct hdac_ext_link *hlink; - struct snd_soc_acpi_mach_params *mach_params; - struct snd_soc_acpi_mach *hda_mach; - struct snd_soc_acpi_mach *mach; - const char *tplg_filename; - const char *idisp_str; - const char *dmic_str; - int dmic_num; - int codec_num = 0; - int i; #endif struct sof_intel_hda_dev *hdev = pdata->hw_pdata; u32 link_mask; @@ -553,24 +547,31 @@ static int hda_init_caps(struct snd_sof_dev *sdev) /* scan SoundWire capabilities exposed by DSDT */ ret = hda_sdw_acpi_scan(sdev); if (ret < 0) { - dev_err(sdev->dev, "error: SoundWire ACPI scan error\n"); - return ret; + dev_dbg(sdev->dev, "skipping SoundWire, ACPI scan error\n"); + goto skip_soundwire; } link_mask = hdev->info.link_mask; if (!link_mask) { - /* - * probe/allocated SoundWire resources. - * The hardware configuration takes place in hda_sdw_startup - * after power rails are enabled. - */ - ret = hda_sdw_probe(sdev); - if (ret < 0) { - dev_err(sdev->dev, "error: SoundWire probe error\n"); - return ret; - } + dev_dbg(sdev->dev, "skipping SoundWire, no links enabled\n"); + goto skip_soundwire; + } + + /* + * probe/allocate SoundWire resources. + * The hardware configuration takes place in hda_sdw_startup + * after power rails are enabled. + * It's entirely possible to have a mix of I2S/DMIC/SoundWire + * devices, so we allocate the resources in all cases. + */ + ret = hda_sdw_probe(sdev); + if (ret < 0) { + dev_err(sdev->dev, "error: SoundWire probe error\n"); + return ret; } +skip_soundwire: + #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) if (bus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(bus); @@ -963,6 +964,51 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev) } #endif +#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) +static int hda_sdw_machine_select(struct snd_sof_dev *sdev) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct snd_soc_acpi_mach *mach; + struct snd_sof_pdata *pdata = sdev->pdata; + struct sof_intel_hda_dev *hdev = pdata->hw_pdata; + u32 link_mask; + + link_mask = hdev->info.link_mask; + + /* + * Select SoundWire machine driver if needed using the + * alternate tables. This case deals with SoundWire-only + * machines, for mixed cases with I2C/I2S the detection relies + * on the HID list. + */ + if (link_mask && !pdata->machine) { + mach = pdata->desc->alt_machines; + while (mach && mach->link_mask && mach->link_mask != link_mask) + mach++; + if (mach && mach->link_mask) { + dev_dbg(bus->dev, + "SoundWire machine driver %s topology %s\n", + mach->drv_name, + mach->sof_tplg_filename); + pdata->machine = mach; + mach->mach_params.platform = dev_name(sdev->dev); + pdata->fw_filename = mach->sof_fw_filename; + pdata->tplg_filename = mach->sof_tplg_filename; + } else { + dev_info(sdev->dev, + "No SoundWire machine driver found\n"); + } + } + + return 0; +} +#else +static int hda_sdw_machine_select(struct snd_sof_dev *sdev) +{ + return 0; +} +#endif + void hda_set_mach_params(const struct snd_soc_acpi_mach *mach, struct device *dev) { @@ -984,6 +1030,11 @@ void hda_machine_select(struct snd_sof_dev *sdev) sof_pdata->machine = mach; } + /* + * If I2S fails, try SoundWire + */ + hda_sdw_machine_select(sdev); + /* * Choose HDA generic machine driver if mach is NULL. * Otherwise, set certain mach params. From a406145993f00e8d9119655252d039475ca3bb68 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 24 Sep 2019 10:36:44 -0500 Subject: [PATCH 1825/1995] ASoC: SOF: Intel: hda: disable SoundWire interrupts on suspend Doing this avoid conflicts and errors reported on the bus. The interrupts are only re-enabled on resume after the firmware is downloaded, so the behavior is not fully symmetric Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-dsp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 4a4d318f97ffa5..58388bccf27f30 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -390,6 +390,8 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) #endif int ret; + hda_sdw_int_enable(sdev, false); + /* disable IPC interrupts */ hda_dsp_ipc_int_disable(sdev); From c68804af1b6f21b51a065ca918b0a6a1ea1fff6f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 4 Sep 2019 09:42:38 -0500 Subject: [PATCH 1826/1995] ASoC: SOF: Intel: add build support for SoundWire Select SoundWire capabilities on newer Intel platforms, starting with CannonLake/CoffeeLake/CometLake. As done for HDaudio, the SoundWire link is an opt-in capability. We explicitly test for ACPI to avoid warnings on unmet dependencies on the SoundWire side. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/Kconfig | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index bc62d54c2d55bf..8c2da6a2c9df45 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -168,6 +168,7 @@ config SND_SOC_SOF_CANNONLAKE_SUPPORT config SND_SOC_SOF_CANNONLAKE tristate select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -183,6 +184,7 @@ config SND_SOC_SOF_COFFEELAKE_SUPPORT config SND_SOC_SOF_COFFEELAKE tristate select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -198,6 +200,7 @@ config SND_SOC_SOF_ICELAKE_SUPPORT config SND_SOC_SOF_ICELAKE tristate select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -205,6 +208,7 @@ config SND_SOC_SOF_ICELAKE config SND_SOC_SOF_COMETLAKE_LP tristate select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -220,6 +224,7 @@ config SND_SOC_SOF_COMETLAKE_LP_SUPPORT config SND_SOC_SOF_COMETLAKE_H tristate select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -258,6 +263,7 @@ config SND_SOC_SOF_TIGERLAKE_SUPPORT config SND_SOC_SOF_TIGERLAKE tristate select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -273,6 +279,7 @@ config SND_SOC_SOF_ELKHARTLAKE_SUPPORT config SND_SOC_SOF_ELKHARTLAKE tristate select SND_SOC_SOF_HDA_COMMON + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE help This option is not user-selectable but automagically handled by 'select' statements at a higher level @@ -360,6 +367,29 @@ config SND_SOC_SOF_HDA This option is not user-selectable but automagically handled by 'select' statements at a higher level +config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK + bool "SOF support for SoundWire" + depends on SOUNDWIRE && ACPI + help + This adds support for SoundWire with Sound Open Firmware + for Intel(R) platforms. + Say Y if you want to enable SoundWire links with SOF. + If unsure select "N". + +config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE + tristate + select SND_SOC_SOF_INTEL_SOUNDWIRE if SND_SOC_SOF_INTEL_SOUNDWIRE_LINK + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + +config SND_SOC_SOF_INTEL_SOUNDWIRE + tristate + select SOUNDWIRE_INTEL + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level + endif ## SND_SOC_SOF_INTEL_PCI endif ## SND_SOC_SOF_INTEL_TOPLEVEL From 6d5b2f44e757525a0bf8d33d39133a3e0d0ef69e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 21 Oct 2019 11:27:21 -0500 Subject: [PATCH 1827/1995] ASoC: SOF: Intel: hda-ctrl: add reset cycle before parsing capabilities Without this cycle, HDaudio capability parsing fails on some devices. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-ctrl.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c index 871b71a15a6331..ff9e8f3782065c 100644 --- a/sound/soc/sof/intel/hda-ctrl.c +++ b/sound/soc/sof/intel/hda-ctrl.c @@ -64,15 +64,32 @@ int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev) struct hdac_bus *bus = sof_to_bus(sdev); u32 cap, offset, feature; int count = 0; + int ret; + + /* + * On some devices, one reset cycle is necessary before reading + * capabilities + */ + ret = hda_dsp_ctrl_link_reset(sdev, true); + if (ret < 0) + return ret; + ret = hda_dsp_ctrl_link_reset(sdev, false); + if (ret < 0) + return ret; offset = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, SOF_HDA_LLCH); do { - cap = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, offset); - dev_dbg(sdev->dev, "checking for capabilities at offset 0x%x\n", offset & SOF_HDA_CAP_NEXT_MASK); + cap = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, offset); + + if (cap == -1) { + dev_dbg(bus->dev, "Invalid capability reg read\n"); + break; + } + feature = (cap & SOF_HDA_CAP_ID_MASK) >> SOF_HDA_CAP_ID_OFF; switch (feature) { @@ -105,8 +122,8 @@ int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev) bus->mlcap = bus->remap_addr + offset; break; default: - dev_vdbg(sdev->dev, "found capability %d at 0x%x\n", - feature, offset); + dev_dbg(sdev->dev, "found capability %d at 0x%x\n", + feature, offset); break; } From bf8973ba75a25babf1a44c762d7cbaa7e36325d6 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 21 Nov 2019 18:11:52 -0600 Subject: [PATCH 1828/1995] ASoC: SOF: Intel: hda: merge IPC, stream and SoundWire interrupt handlers We have a single irq handler for SOF interrupts. We can further merge SoundWire ones to completely remove MSI interrupts handling issues leading to timeouts. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 36 ++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 11 +++++++++++ 2 files changed, 47 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 93b71b38faed0b..3ec8416fc6317f 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -200,6 +200,38 @@ static int hda_sdw_exit(struct snd_sof_dev *sdev) return 0; } + +static bool hda_dsp_check_sdw_irq(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hdev; + bool ret = false; + u32 irq_status; + + hdev = sdev->pdata->hw_pdata; + + if (!hdev->sdw) + return ret; + + /* store status */ + irq_status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIS2); + + /* invalid message ? */ + if (irq_status == 0xffffffff) + goto out; + + /* SDW message ? */ + if (irq_status & HDA_DSP_REG_ADSPIS2_SNDW) + ret = true; + +out: + return ret; +} + +static irqreturn_t hda_dsp_sdw_thread(int irq, void *context) +{ + return sdw_intel_thread(irq, context); +} + #endif /* @@ -627,6 +659,7 @@ static irqreturn_t hda_dsp_interrupt_handler(int irq, void *context) static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context) { struct snd_sof_dev *sdev = context; + struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; /* deal with streams and controller first */ if (hda_dsp_check_stream_irq(sdev)) @@ -635,6 +668,9 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context) if (hda_dsp_check_ipc_irq(sdev)) sof_ops(sdev)->irq_thread(irq, sdev); + if (hda_dsp_check_sdw_irq(sdev)) + hda_dsp_sdw_thread(irq, hdev->sdw); + /* enable GIE interrupt */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index ea8308c5e9bef6..724103626fe37a 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -232,6 +232,8 @@ #define HDA_DSP_REG_ADSPIC2 (HDA_DSP_GEN_BASE + 0x10) #define HDA_DSP_REG_ADSPIS2 (HDA_DSP_GEN_BASE + 0x14) +#define HDA_DSP_REG_ADSPIS2_SNDW BIT(5) + /* Intel HD Audio Inter-Processor Communication Registers */ #define HDA_DSP_IPC_BASE 0x40 #define HDA_DSP_REG_HIPCT (HDA_DSP_IPC_BASE + 0x00) @@ -649,6 +651,15 @@ static inline void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable) { } +static inline bool hda_dsp_check_sdw_irq(struct snd_sof_dev *sdev) +{ + return false; +} + +static inline irqreturn_t hda_dsp_sdw_thread(int irq, void *context) +{ + return IRQ_HANDLED; +} #endif /* common dai driver */ From 7526143e14f2384a36492e099c3ccb2c2f857741 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 3 Dec 2019 17:14:28 -0600 Subject: [PATCH 1829/1995] ASoC: SOF: Intel: hda: specify behavior for clock stop For now we only support a complete teardown. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 3ec8416fc6317f..452d73be1299bb 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -151,6 +151,7 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev) res.parent = sdev->dev; res.ops = &sdw_callback; res.dev = sdev->dev; + res.clock_stop_quirks = SDW_INTEL_CLK_STOP_TEARDOWN; /* * ops and arg fields are not populated for now, From 5925d5957b7326d2bd50f6471eb21c3fe7342c02 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Thu, 5 Dec 2019 14:48:39 +0800 Subject: [PATCH 1830/1995] ASoC: SOF: Intel: hda: add WAKEEN interrupt support for SoundWire When a SoundWire link is in clock stop state, a Slave device may wake up the Master for some events such as jack detection. The WAKEEN interrupt will be triggered and processed by the audio pci device. If audio device is in D3, the interrupt will be routed to PME, or aggregated at cAVS level as interrupt when audio device is in D0. This patch only supports D3 case, where the audio pci device will be resumed by a PME event and the WAKEEN interrupt will be processed after audio pci device is powered up and ROM is initialized successfully. The WAKEEN handling is only enabled after the first boot due to dependencies on a shim_lock mutex being initialized. Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda-loader.c | 18 ++++++++++++++++++ sound/soc/sof/intel/hda.c | 11 +++++++++++ sound/soc/sof/intel/hda.h | 5 +++++ 3 files changed, 34 insertions(+) diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index 257c47129f165f..d7e1990610ec7a 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -343,6 +343,24 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev) goto cleanup; } + /* + * When a SoundWire link is in clock stop state, a Slave + * device may trigger in-band wakes for events such as jack + * insertion or acoustic event detection. This event will lead + * to a WAKEEN interrupt, handled by the PCI device and routed + * to PME if the PCI device is in D3. The resume function in + * audio PCI driver will be invoked by ACPI for PME event and + * initialize the device and process WAKEEN interrupt. + * + * The WAKEEN interrupt should be processed ASAP to prevent an + * interrupt flood, otherwise other interrupts, such IPC, + * cannot work normally. The WAKEEN is handled after the ROM + * is initialized successfully, which ensures power rails are + * enabled before accessing the SoundWire SHIM registers + */ + if (!sdev->first_boot) + hda_sdw_process_wakeen(sdev); + /* * at this point DSP ROM has been initialized and * should be ready for code loading and firmware boot diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 452d73be1299bb..70c43f190d5003 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -233,6 +233,17 @@ static irqreturn_t hda_dsp_sdw_thread(int irq, void *context) return sdw_intel_thread(irq, context); } +void hda_sdw_process_wakeen(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hdev; + + hdev = sdev->pdata->hw_pdata; + if (!hdev->sdw) + return; + + sdw_intel_process_wakeen_event(hdev->sdw); +} + #endif /* diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 724103626fe37a..339d9690cf1047 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -624,6 +624,7 @@ int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd); int hda_sdw_startup(struct snd_sof_dev *sdev); void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable); +void hda_sdw_process_wakeen(struct snd_sof_dev *sdev); #else @@ -660,6 +661,10 @@ static inline irqreturn_t hda_dsp_sdw_thread(int irq, void *context) { return IRQ_HANDLED; } + +static void hda_sdw_process_wakeen(struct snd_sof_dev *sdev) +{ +} #endif /* common dai driver */ From a107ca2f9ec63468fe613e880489d6b048b019a4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 5 Dec 2019 13:30:22 -0600 Subject: [PATCH 1831/1995] ASoC: SOF: Intel: hda: add parameter to control SoundWire clock stop quirks Add module parameter so that the different modes can be quickly tested. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 70c43f190d5003..037c27e73301bb 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -39,6 +39,16 @@ #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) +/* + * The default for SoundWire clock stop quirks is to power gate the IP + * and do a Bus Reset, this will need to be modified when the DSP + * needs to remain in D0i3 so that the Master does not lose context + * and enumeration is not required on clock restart + */ +static int sdw_clock_stop_quirks = SDW_INTEL_CLK_STOP_BUS_RESET; +module_param(sdw_clock_stop_quirks, int, 0444); +MODULE_PARM_DESC(sdw_clock_stop_quirks, "SOF SoundWire clock stop quirks"); + static int sdw_params_stream(struct device *dev, struct sdw_intel_stream_params_data *params_data) { @@ -151,7 +161,7 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev) res.parent = sdev->dev; res.ops = &sdw_callback; res.dev = sdev->dev; - res.clock_stop_quirks = SDW_INTEL_CLK_STOP_TEARDOWN; + res.clock_stop_quirks = sdw_clock_stop_quirks; /* * ops and arg fields are not populated for now, From 62690a8aaa3d2bc2ee44656a9ae5c6b5500cc267 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 6 Dec 2019 17:24:41 +0800 Subject: [PATCH 1832/1995] Asoc: SOF: Intel: hda: check SoundWire wakeen interrupt in irq thread If pci device is in D0, wakeen interrupt will be aggregated at cAVS level as interrupt. This commit check the wakeen status and process it in irq thread Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 16 ++++++++++++++++ sound/soc/sof/intel/hda.h | 6 ++++++ 2 files changed, 22 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 037c27e73301bb..c3722368f9081a 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -243,6 +243,19 @@ static irqreturn_t hda_dsp_sdw_thread(int irq, void *context) return sdw_intel_thread(irq, context); } +static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) +{ + struct sof_intel_hda_dev *hdev; + + hdev = sdev->pdata->hw_pdata; + if (hdev->sdw && + snd_sof_dsp_read(sdev, HDA_DSP_BAR, + HDA_DSP_REG_SNDW_WAKE_STS)) + return true; + + return false; +} + void hda_sdw_process_wakeen(struct snd_sof_dev *sdev) { struct sof_intel_hda_dev *hdev; @@ -693,6 +706,9 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context) if (hda_dsp_check_sdw_irq(sdev)) hda_dsp_sdw_thread(irq, hdev->sdw); + if (hda_sdw_check_wakeen_irq(sdev)) + hda_sdw_process_wakeen(sdev); + /* enable GIE interrupt */ snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL, diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 339d9690cf1047..75da16e1aa7bad 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -233,6 +233,7 @@ #define HDA_DSP_REG_ADSPIS2 (HDA_DSP_GEN_BASE + 0x14) #define HDA_DSP_REG_ADSPIS2_SNDW BIT(5) +#define HDA_DSP_REG_SNDW_WAKE_STS 0x2C192 /* Intel HD Audio Inter-Processor Communication Registers */ #define HDA_DSP_IPC_BASE 0x40 @@ -662,6 +663,11 @@ static inline irqreturn_t hda_dsp_sdw_thread(int irq, void *context) return IRQ_HANDLED; } +static inline bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) +{ + return false; +} + static void hda_sdw_process_wakeen(struct snd_sof_dev *sdev) { } From 1e6d66a9192f340a0e6657e3c66ee263cf6ba817 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 16 Dec 2019 13:50:53 -0600 Subject: [PATCH 1833/1995] ASoC: SOF: Intel: hda: import SOUNDWIRE_INIT namespace Make sure the SoundWire driver can be loaded Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index c3722368f9081a..f469d3bdbca183 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1123,3 +1123,4 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC); MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC_I915); MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); +MODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT); From d1cf8580f8b7e562d0f1ebcb2f1e01c7fee108c6 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 18 Apr 2018 10:35:14 +0530 Subject: [PATCH 1834/1995] ASoC: codecs: rt700: add Soundwire support Initial support for ALC/RT700 in SoundWire mode This codec is present on Intel CNL/CML and ICL RVP boards and the code was tested by both Realtek and Intel. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Shuming Fan --- sound/soc/codecs/Kconfig | 9 + sound/soc/codecs/Makefile | 3 + sound/soc/codecs/rt700-sdw.c | 530 +++++++++++++++ sound/soc/codecs/rt700-sdw.h | 335 ++++++++++ sound/soc/codecs/rt700.c | 1217 ++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt700.h | 176 +++++ 6 files changed, 2270 insertions(+) create mode 100644 sound/soc/codecs/rt700-sdw.c create mode 100644 sound/soc/codecs/rt700-sdw.h create mode 100644 sound/soc/codecs/rt700.c create mode 100644 sound/soc/codecs/rt700.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 14668204900790..a0cb17a06efa6e 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1058,6 +1058,15 @@ config SND_SOC_RT5677_SPI config SND_SOC_RT5682 tristate +config SND_SOC_RT700 + tristate + +config SND_SOC_RT700_SDW + tristate "Realtek RT700 Codec - SDW" + depends on SOUNDWIRE + select SND_SOC_RT700 + select REGMAP_SOUNDWIRE + #Freescale sgtl5000 codec config SND_SOC_SGTL5000 tristate "Freescale SGTL5000 CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 0290fb3898359e..985717ed133c6c 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -279,6 +279,8 @@ snd-soc-wm9712-objs := wm9712.o snd-soc-wm9713-objs := wm9713.o snd-soc-wm-hubs-objs := wm_hubs.o snd-soc-zx-aud96p22-objs := zx_aud96p22.o +snd-soc-rt700-objs := rt700.o rt700-sdw.o + # Amp snd-soc-max9877-objs := max9877.o snd-soc-max98504-objs := max98504.o @@ -569,6 +571,7 @@ obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.o +obj-$(CONFIG_SND_SOC_RT700) += snd-soc-rt700.o # Amp obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c new file mode 100644 index 00000000000000..2ec16a5b9015aa --- /dev/null +++ b/sound/soc/codecs/rt700-sdw.c @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// rt700-sdw.c -- rt700 ALSA SoC audio driver +// +// Copyright(c) 2019 Realtek Semiconductor Corp. +// +// ALC700 ASoC Codec Driver based Intel Dummy SdW codec driver +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rt700.h" +#include "rt700-sdw.h" + +static bool rt700_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x00e0: + case 0x00f0: + case 0x2000 ... 0x200e: + case 0x2012 ... 0x2016: + case 0x201a ... 0x2027: + case 0x2029 ... 0x202a: + case 0x202d ... 0x2034: + case 0x2200 ... 0x2204: + case 0x2206 ... 0x2212: + case 0x2220 ... 0x2223: + case 0x2230 ... 0x2231: + case 0x3000 ... 0x3fff: + case 0x7000 ... 0x7fff: + case 0x8300 ... 0x83ff: + case 0x9c00 ... 0x9cff: + case 0xb900 ... 0xb9ff: + case 0x7520001a: + case 0x75200045: + case 0x75200046: + case 0x75200048: + case 0x7520004a: + case 0x7520006b: + case 0x75200080: + case 0x75200081: + return true; + default: + return false; + } +} + +static bool rt700_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2009: + case 0x2016: + case 0x201b: + case 0x201c: + case 0x201d: + case 0x201f: + case 0x2021: + case 0x2023: + case 0x2230: + case 0x200b ... 0x200e: /* i2c read */ + case 0x2012 ... 0x2015: /* HD-A read */ + case 0x202d ... 0x202f: /* BRA */ + case 0x2201 ... 0x2212: /* i2c debug */ + case 0x2220 ... 0x2223: /* decoded HD-A */ + case 0x9c00 ... 0x9cff: + case 0xb900 ... 0xb9ff: + case 0xff01: + case 0x7520001a: + case 0x75200046: + case 0x75200080: + case 0x75200081: + return true; + default: + return false; + } +} + +static int rt700_sdw_read(void *context, unsigned int reg, unsigned int *val) +{ + struct device *dev = context; + struct rt700_priv *rt700 = dev_get_drvdata(dev); + unsigned int sdw_data_3, sdw_data_2, sdw_data_1, sdw_data_0; + unsigned int reg2 = 0, reg3 = 0, reg4 = 0, mask, nid, val2; + unsigned int is_hda_reg = 1, is_index_reg = 0; + int ret; + + if (reg > 0xffff) + is_index_reg = 1; + + mask = reg & 0xf000; + + if (is_index_reg) { /* index registers */ + val2 = reg & 0xffff; + reg = reg >> 16; + nid = reg & 0xff; + ret = regmap_write(rt700->sdw_regmap, reg, ((val2 >> 8) & 0xff)); + if (ret < 0) + return ret; + reg2 = reg + 0x1000; + reg2 |= 0x80; + ret = regmap_write(rt700->sdw_regmap, reg2, (val2 & 0xff)); + if (ret < 0) + return ret; + + reg3 = RT700_PRIV_DATA_R_H | nid; + ret = regmap_write(rt700->sdw_regmap, reg3, ((*val >> 8) & 0xff)); + if (ret < 0) + return ret; + reg4 = reg3 + 0x1000; + reg4 |= 0x80; + ret = regmap_write(rt700->sdw_regmap, reg4, (*val & 0xff)); + if (ret < 0) + return ret; + } else if (mask == 0x3000) { + reg += 0x8000; + ret = regmap_write(rt700->sdw_regmap, reg, *val); + if (ret < 0) + return ret; + } else if (mask == 0x7000) { + reg += 0x2000; + reg |= 0x800; + ret = regmap_write(rt700->sdw_regmap, reg, ((*val >> 8) & 0xff)); + if (ret < 0) + return ret; + reg2 = reg + 0x1000; + reg2 |= 0x80; + ret = regmap_write(rt700->sdw_regmap, reg2, (*val & 0xff)); + if (ret < 0) + return ret; + } else if ((reg & 0xff00) == 0x8300) { /* for R channel */ + reg2 = reg - 0x1000; + reg2 &= ~0x80; + ret = regmap_write(rt700->sdw_regmap, reg2, ((*val >> 8) & 0xff)); + if (ret < 0) + return ret; + ret = regmap_write(rt700->sdw_regmap, reg, (*val & 0xff)); + if (ret < 0) + return ret; + } else if (mask == 0x9000) { + ret = regmap_write(rt700->sdw_regmap, reg, ((*val >> 8) & 0xff)); + if (ret < 0) + return ret; + reg2 = reg + 0x1000; + reg2 |= 0x80; + ret = regmap_write(rt700->sdw_regmap, reg2, (*val & 0xff)); + if (ret < 0) + return ret; + } else if (mask == 0xb000) { + ret = regmap_write(rt700->sdw_regmap, reg, *val); + if (ret < 0) + return ret; + } else { + ret = regmap_read(rt700->sdw_regmap, reg, val); + if (ret < 0) + return ret; + is_hda_reg = 0; + } + + if (is_hda_reg || is_index_reg) { + sdw_data_3 = 0; + sdw_data_2 = 0; + sdw_data_1 = 0; + sdw_data_0 = 0; + ret = regmap_read(rt700->sdw_regmap, RT700_READ_HDA_3, &sdw_data_3); + if (ret < 0) + return ret; + ret = regmap_read(rt700->sdw_regmap, RT700_READ_HDA_2, &sdw_data_2); + if (ret < 0) + return ret; + ret = regmap_read(rt700->sdw_regmap, RT700_READ_HDA_1, &sdw_data_1); + if (ret < 0) + return ret; + ret = regmap_read(rt700->sdw_regmap, RT700_READ_HDA_0, &sdw_data_0); + if (ret < 0) + return ret; + *val = ((sdw_data_3 & 0xff) << 24) | ((sdw_data_2 & 0xff) << 16) | + ((sdw_data_1 & 0xff) << 8) | (sdw_data_0 & 0xff); + } + + if (is_hda_reg == 0) + dev_dbg(dev, "[%s] %04x => %08x\n", __func__, reg, *val); + else if (is_index_reg) + dev_dbg(dev, "[%s] %04x %04x %04x %04x => %08x\n", __func__, + reg, reg2, reg3, reg4, *val); + else + dev_dbg(dev, "[%s] %04x %04x => %08x\n", __func__, reg, reg2, *val); + + return 0; +} + +static int rt700_sdw_write(void *context, unsigned int reg, unsigned int val) +{ + struct device *dev = context; + struct rt700_priv *rt700 = dev_get_drvdata(dev); + unsigned int reg2 = 0, reg3, reg4, nid, mask, val2; + unsigned int is_index_reg = 0; + int ret; + + if (reg > 0xffff) + is_index_reg = 1; + + mask = reg & 0xf000; + + if (is_index_reg) { /* index registers */ + val2 = reg & 0xffff; + reg = reg >> 16; + nid = reg & 0xff; + ret = regmap_write(rt700->sdw_regmap, reg, ((val2 >> 8) & 0xff)); + if (ret < 0) + return ret; + reg2 = reg + 0x1000; + reg2 |= 0x80; + ret = regmap_write(rt700->sdw_regmap, reg2, (val2 & 0xff)); + if (ret < 0) + return ret; + + reg3 = RT700_PRIV_DATA_W_H | nid; + ret = regmap_write(rt700->sdw_regmap, reg3, ((val >> 8) & 0xff)); + if (ret < 0) + return ret; + reg4 = reg3 + 0x1000; + reg4 |= 0x80; + ret = regmap_write(rt700->sdw_regmap, reg4, (val & 0xff)); + if (ret < 0) + return ret; + is_index_reg = 1; + } else if (reg < 0x4fff) { + ret = regmap_write(rt700->sdw_regmap, reg, val); + if (ret < 0) + return ret; + } else if (reg == 0xff01) { + ret = regmap_write(rt700->sdw_regmap, reg, val); + if (ret < 0) + return ret; + } else if (mask == 0x7000) { + ret = regmap_write(rt700->sdw_regmap, reg, ((val >> 8) & 0xff)); + if (ret < 0) + return ret; + reg2 = reg + 0x1000; + reg2 |= 0x80; + ret = regmap_write(rt700->sdw_regmap, reg2, (val & 0xff)); + if (ret < 0) + return ret; + } else if ((reg & 0xff00) == 0x8300) { /* for R channel */ + reg2 = reg - 0x1000; + reg2 &= ~0x80; + ret = regmap_write(rt700->sdw_regmap, reg2, ((val >> 8) & 0xff)); + if (ret < 0) + return ret; + ret = regmap_write(rt700->sdw_regmap, reg, (val & 0xff)); + if (ret < 0) + return ret; + } + + if (reg2 == 0) + dev_dbg(dev, "[%s] %04x <= %04x\n", __func__, reg, val); + else if (is_index_reg) + dev_dbg(dev, "[%s] %04x %04x %04x %04x <= %04x %04x\n", __func__, + reg, reg2, reg3, reg4, val2, val); + else + dev_dbg(dev, "[%s] %04x %04x <= %04x\n", __func__, reg, reg2, val); + + return 0; +} + +static const struct regmap_config rt700_regmap = { + .reg_bits = 32, + .val_bits = 32, + .readable_reg = rt700_readable_register, /* Readable registers */ + .volatile_reg = rt700_volatile_register, /* volatile register */ + .max_register = 0x75580000, /* Maximum number of register */ + .reg_defaults = rt700_reg_defaults, /* Defaults */ + .num_reg_defaults = ARRAY_SIZE(rt700_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, + .reg_read = rt700_sdw_read, + .reg_write = rt700_sdw_write, +}; + +static const struct regmap_config rt700_sdw_regmap = { + .name = "sdw", + .reg_bits = 32, /* Total register space for SDW */ + .val_bits = 8, /* Total number of bits in register */ + .readable_reg = rt700_readable_register, /* Readable registers */ + .max_register = 0xff01, /* Maximum number of register */ + .cache_type = REGCACHE_NONE, + .use_single_read = true, + .use_single_write = true, +}; + +static int rt700_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev); + + /* Update the status */ + rt700->status = status; + + if (status == SDW_SLAVE_UNATTACHED) + rt700->hw_init = false; + + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt700->hw_init || rt700->status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt700_io_init(&slave->dev, slave); +} + +static int rt700_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int nval, i, num_of_ports = 1; + u32 bit; + unsigned long addr; + struct sdw_dpn_prop *dpn; + + prop->paging_support = false; + + /* first we need to allocate memory for set bits in port lists */ + prop->source_ports = 0x14; /* BITMAP: 00010100 */ + prop->sink_ports = 0xA; /* BITMAP: 00001010 */ + + nval = hweight32(prop->source_ports); + num_of_ports += nval; + prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->src_dpn_prop), + GFP_KERNEL); + if (!prop->src_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->src_dpn_prop; + addr = prop->source_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].type = SDW_DPN_FULL; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* do this again for sink now */ + nval = hweight32(prop->sink_ports); + num_of_ports += nval; + prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->sink_dpn_prop), + GFP_KERNEL); + if (!prop->sink_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->sink_dpn_prop; + addr = prop->sink_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].type = SDW_DPN_FULL; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* Allocate port_ready based on num_of_ports */ + slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports, + sizeof(*slave->port_ready), + GFP_KERNEL); + if (!slave->port_ready) + return -ENOMEM; + + /* Initialize completion */ + for (i = 0; i < num_of_ports; i++) + init_completion(&slave->port_ready[i]); + + /* set the timeout values */ + prop->clk_stop_timeout = 20; + + return 0; +} + +static int rt700_bus_config(struct sdw_slave *slave, + struct sdw_bus_params *params) +{ + struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev); + int ret; + + memcpy(&rt700->params, params, sizeof(*params)); + + ret = rt700_clock_config(&slave->dev); + if (ret < 0) + dev_err(&slave->dev, "Invalid clk config"); + + return ret; +} + +static int rt700_interrupt_callback(struct sdw_slave *slave, + struct sdw_slave_intr_status *status) +{ + struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev); + + dev_dbg(&slave->dev, + "%s control_port_stat=%x", __func__, status->control_port); + + if (status->control_port & 0x4) { + mod_delayed_work(system_power_efficient_wq, + &rt700->jack_detect_work, msecs_to_jiffies(250)); + } + + return 0; +} + +/* + * slave_ops: callbacks for get_clock_stop_mode, clock_stop and + * port_prep are not defined for now + */ +static struct sdw_slave_ops rt700_slave_ops = { + .read_prop = rt700_read_prop, + .interrupt_callback = rt700_interrupt_callback, + .update_status = rt700_update_status, + .bus_config = rt700_bus_config, +}; + +static int rt700_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *sdw_regmap, *regmap; + + /* Assign ops */ + slave->ops = &rt700_slave_ops; + + /* Regmap Initialization */ + sdw_regmap = devm_regmap_init_sdw(slave, &rt700_sdw_regmap); + if (!sdw_regmap) + return -EINVAL; + + regmap = devm_regmap_init(&slave->dev, NULL, &slave->dev, &rt700_regmap); + if (!regmap) + return -EINVAL; + + rt700_init(&slave->dev, sdw_regmap, regmap, slave); + + return 0; +} + +static int rt700_sdw_remove(struct sdw_slave *slave) +{ + struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev); + + if (rt700 && rt700->hw_init) { + cancel_delayed_work(&rt700->jack_detect_work); + cancel_delayed_work(&rt700->jack_btn_check_work); + } + + return 0; +} + +static const struct sdw_device_id rt700_id[] = { + SDW_SLAVE_ENTRY(0x025d, 0x700, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt700_id); + +static int rt700_dev_suspend(struct device *dev) +{ + struct rt700_priv *rt700 = dev_get_drvdata(dev); + + if (!rt700->hw_init) + return 0; + + regcache_cache_only(rt700->regmap, true); + + return 0; +} + +#define RT700_PROBE_TIMEOUT 2000 + +static int rt700_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = to_sdw_slave_device(dev); + struct rt700_priv *rt700 = dev_get_drvdata(dev); + unsigned long time; + + if (!rt700->hw_init) + return 0; + + time = wait_for_completion_timeout(&slave->enumeration_complete, + msecs_to_jiffies(RT700_PROBE_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "Enumeration not complete, timed out\n"); + return -ETIMEDOUT; + } + + regcache_cache_only(rt700->regmap, false); + regcache_sync_region(rt700->regmap, 0x3000, 0x8fff); + regcache_sync_region(rt700->regmap, 0x75200010, 0x7520006b); + + return 0; +} + +static const struct dev_pm_ops rt700_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt700_dev_suspend, rt700_dev_resume) + SET_RUNTIME_PM_OPS(rt700_dev_suspend, rt700_dev_resume, NULL) +}; + +static struct sdw_driver rt700_sdw_driver = { + .driver = { + .name = "rt700", + .owner = THIS_MODULE, + .pm = &rt700_pm, + }, + .probe = rt700_sdw_probe, + .remove = rt700_sdw_remove, + .ops = &rt700_slave_ops, + .id_table = rt700_id, +}; +module_sdw_driver(rt700_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT700 driver SDW"); +MODULE_AUTHOR("Shuming Fan "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt700-sdw.h b/sound/soc/codecs/rt700-sdw.h new file mode 100644 index 00000000000000..2f5301b0bd8dff --- /dev/null +++ b/sound/soc/codecs/rt700-sdw.h @@ -0,0 +1,335 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * rt700-sdw.h -- RT700 ALSA SoC audio driver header + * + * Copyright(c) 2019 Realtek Semiconductor Corp. + */ + +#ifndef __RT700_SDW_H__ +#define __RT700_SDW_H__ + +static const struct reg_default rt700_reg_defaults[] = { + { 0x0000, 0x0000 }, + { 0x0001, 0x0000 }, + { 0x0002, 0x0000 }, + { 0x0003, 0x0000 }, + { 0x0004, 0x0000 }, + { 0x0005, 0x0001 }, + { 0x0020, 0x0000 }, + { 0x0022, 0x0000 }, + { 0x0023, 0x0000 }, + { 0x0024, 0x0000 }, + { 0x0025, 0x0000 }, + { 0x0026, 0x0000 }, + { 0x0030, 0x0000 }, + { 0x0032, 0x0000 }, + { 0x0033, 0x0000 }, + { 0x0034, 0x0000 }, + { 0x0035, 0x0000 }, + { 0x0036, 0x0000 }, + { 0x0040, 0x0000 }, + { 0x0041, 0x0000 }, + { 0x0042, 0x0000 }, + { 0x0043, 0x0000 }, + { 0x0044, 0x0020 }, + { 0x0045, 0x0001 }, + { 0x0046, 0x0000 }, + { 0x0050, 0x0000 }, + { 0x0051, 0x0000 }, + { 0x0052, 0x0000 }, + { 0x0053, 0x0000 }, + { 0x0054, 0x0000 }, + { 0x0055, 0x0000 }, + { 0x0060, 0x0000 }, + { 0x0070, 0x0000 }, + { 0x00e0, 0x0000 }, + { 0x00f0, 0x0000 }, + { 0x0100, 0x0000 }, + { 0x0101, 0x0000 }, + { 0x0102, 0x0000 }, + { 0x0103, 0x0000 }, + { 0x0104, 0x0000 }, + { 0x0105, 0x0000 }, + { 0x0120, 0x0000 }, + { 0x0121, 0x0000 }, + { 0x0122, 0x0000 }, + { 0x0123, 0x0000 }, + { 0x0124, 0x0000 }, + { 0x0125, 0x0000 }, + { 0x0126, 0x0000 }, + { 0x0127, 0x0000 }, + { 0x0130, 0x0000 }, + { 0x0131, 0x0000 }, + { 0x0132, 0x0000 }, + { 0x0133, 0x0000 }, + { 0x0134, 0x0000 }, + { 0x0135, 0x0000 }, + { 0x0136, 0x0000 }, + { 0x0137, 0x0000 }, + { 0x0200, 0x0000 }, + { 0x0201, 0x0000 }, + { 0x0202, 0x0000 }, + { 0x0203, 0x0000 }, + { 0x0204, 0x0000 }, + { 0x0205, 0x0000 }, + { 0x0220, 0x0000 }, + { 0x0221, 0x0000 }, + { 0x0222, 0x0000 }, + { 0x0223, 0x0000 }, + { 0x0224, 0x0000 }, + { 0x0225, 0x0000 }, + { 0x0226, 0x0000 }, + { 0x0227, 0x0000 }, + { 0x0230, 0x0000 }, + { 0x0231, 0x0000 }, + { 0x0232, 0x0000 }, + { 0x0233, 0x0000 }, + { 0x0234, 0x0000 }, + { 0x0235, 0x0000 }, + { 0x0236, 0x0000 }, + { 0x0237, 0x0000 }, + { 0x0300, 0x0000 }, + { 0x0301, 0x0000 }, + { 0x0302, 0x0000 }, + { 0x0303, 0x0000 }, + { 0x0304, 0x0000 }, + { 0x0305, 0x0000 }, + { 0x0320, 0x0000 }, + { 0x0321, 0x0000 }, + { 0x0322, 0x0000 }, + { 0x0323, 0x0000 }, + { 0x0324, 0x0000 }, + { 0x0325, 0x0000 }, + { 0x0326, 0x0000 }, + { 0x0327, 0x0000 }, + { 0x0330, 0x0000 }, + { 0x0331, 0x0000 }, + { 0x0332, 0x0000 }, + { 0x0333, 0x0000 }, + { 0x0334, 0x0000 }, + { 0x0335, 0x0000 }, + { 0x0336, 0x0000 }, + { 0x0337, 0x0000 }, + { 0x0400, 0x0000 }, + { 0x0401, 0x0000 }, + { 0x0402, 0x0000 }, + { 0x0403, 0x0000 }, + { 0x0404, 0x0000 }, + { 0x0405, 0x0000 }, + { 0x0420, 0x0000 }, + { 0x0421, 0x0000 }, + { 0x0422, 0x0000 }, + { 0x0423, 0x0000 }, + { 0x0424, 0x0000 }, + { 0x0425, 0x0000 }, + { 0x0426, 0x0000 }, + { 0x0427, 0x0000 }, + { 0x0430, 0x0000 }, + { 0x0431, 0x0000 }, + { 0x0432, 0x0000 }, + { 0x0433, 0x0000 }, + { 0x0434, 0x0000 }, + { 0x0435, 0x0000 }, + { 0x0436, 0x0000 }, + { 0x0437, 0x0000 }, + { 0x0500, 0x0000 }, + { 0x0501, 0x0000 }, + { 0x0502, 0x0000 }, + { 0x0503, 0x0000 }, + { 0x0504, 0x0000 }, + { 0x0505, 0x0000 }, + { 0x0520, 0x0000 }, + { 0x0521, 0x0000 }, + { 0x0522, 0x0000 }, + { 0x0523, 0x0000 }, + { 0x0524, 0x0000 }, + { 0x0525, 0x0000 }, + { 0x0526, 0x0000 }, + { 0x0527, 0x0000 }, + { 0x0530, 0x0000 }, + { 0x0531, 0x0000 }, + { 0x0532, 0x0000 }, + { 0x0533, 0x0000 }, + { 0x0534, 0x0000 }, + { 0x0535, 0x0000 }, + { 0x0536, 0x0000 }, + { 0x0537, 0x0000 }, + { 0x0600, 0x0000 }, + { 0x0601, 0x0000 }, + { 0x0602, 0x0000 }, + { 0x0603, 0x0000 }, + { 0x0604, 0x0000 }, + { 0x0605, 0x0000 }, + { 0x0620, 0x0000 }, + { 0x0621, 0x0000 }, + { 0x0622, 0x0000 }, + { 0x0623, 0x0000 }, + { 0x0624, 0x0000 }, + { 0x0625, 0x0000 }, + { 0x0626, 0x0000 }, + { 0x0627, 0x0000 }, + { 0x0630, 0x0000 }, + { 0x0631, 0x0000 }, + { 0x0632, 0x0000 }, + { 0x0633, 0x0000 }, + { 0x0634, 0x0000 }, + { 0x0635, 0x0000 }, + { 0x0636, 0x0000 }, + { 0x0637, 0x0000 }, + { 0x0700, 0x0000 }, + { 0x0701, 0x0000 }, + { 0x0702, 0x0000 }, + { 0x0703, 0x0000 }, + { 0x0704, 0x0000 }, + { 0x0705, 0x0000 }, + { 0x0720, 0x0000 }, + { 0x0721, 0x0000 }, + { 0x0722, 0x0000 }, + { 0x0723, 0x0000 }, + { 0x0724, 0x0000 }, + { 0x0725, 0x0000 }, + { 0x0726, 0x0000 }, + { 0x0727, 0x0000 }, + { 0x0730, 0x0000 }, + { 0x0731, 0x0000 }, + { 0x0732, 0x0000 }, + { 0x0733, 0x0000 }, + { 0x0734, 0x0000 }, + { 0x0735, 0x0000 }, + { 0x0736, 0x0000 }, + { 0x0737, 0x0000 }, + { 0x0800, 0x0000 }, + { 0x0801, 0x0000 }, + { 0x0802, 0x0000 }, + { 0x0803, 0x0000 }, + { 0x0804, 0x0000 }, + { 0x0805, 0x0000 }, + { 0x0820, 0x0000 }, + { 0x0821, 0x0000 }, + { 0x0822, 0x0000 }, + { 0x0823, 0x0000 }, + { 0x0824, 0x0000 }, + { 0x0825, 0x0000 }, + { 0x0826, 0x0000 }, + { 0x0827, 0x0000 }, + { 0x0830, 0x0000 }, + { 0x0831, 0x0000 }, + { 0x0832, 0x0000 }, + { 0x0833, 0x0000 }, + { 0x0834, 0x0000 }, + { 0x0835, 0x0000 }, + { 0x0836, 0x0000 }, + { 0x0837, 0x0000 }, + { 0x0f00, 0x0000 }, + { 0x0f01, 0x0000 }, + { 0x0f02, 0x0000 }, + { 0x0f03, 0x0000 }, + { 0x0f04, 0x0000 }, + { 0x0f05, 0x0000 }, + { 0x0f20, 0x0000 }, + { 0x0f21, 0x0000 }, + { 0x0f22, 0x0000 }, + { 0x0f23, 0x0000 }, + { 0x0f24, 0x0000 }, + { 0x0f25, 0x0000 }, + { 0x0f26, 0x0000 }, + { 0x0f27, 0x0000 }, + { 0x0f30, 0x0000 }, + { 0x0f31, 0x0000 }, + { 0x0f32, 0x0000 }, + { 0x0f33, 0x0000 }, + { 0x0f34, 0x0000 }, + { 0x0f35, 0x0000 }, + { 0x0f36, 0x0000 }, + { 0x0f37, 0x0000 }, + { 0x2000, 0x0000 }, + { 0x2001, 0x0000 }, + { 0x2002, 0x0000 }, + { 0x2003, 0x0000 }, + { 0x2004, 0x0000 }, + { 0x2005, 0x0000 }, + { 0x2006, 0x0000 }, + { 0x2007, 0x0000 }, + { 0x2008, 0x0000 }, + { 0x2009, 0x0003 }, + { 0x200a, 0x0003 }, + { 0x200b, 0x0000 }, + { 0x200c, 0x0000 }, + { 0x200d, 0x0000 }, + { 0x200e, 0x0000 }, + { 0x2012, 0x0000 }, + { 0x2013, 0x0000 }, + { 0x2014, 0x0000 }, + { 0x2015, 0x0000 }, + { 0x2016, 0x0000 }, + { 0x201a, 0x0000 }, + { 0x201b, 0x0000 }, + { 0x201c, 0x0000 }, + { 0x201d, 0x0000 }, + { 0x201e, 0x0000 }, + { 0x201f, 0x0000 }, + { 0x2020, 0x0000 }, + { 0x2021, 0x0000 }, + { 0x2022, 0x0000 }, + { 0x2023, 0x0000 }, + { 0x2024, 0x0000 }, + { 0x2025, 0x0002 }, + { 0x2026, 0x0000 }, + { 0x2027, 0x0000 }, + { 0x2029, 0x0000 }, + { 0x202a, 0x0000 }, + { 0x202d, 0x0000 }, + { 0x202e, 0x0000 }, + { 0x202f, 0x0000 }, + { 0x2030, 0x0000 }, + { 0x2031, 0x0000 }, + { 0x2032, 0x0000 }, + { 0x2033, 0x0000 }, + { 0x2034, 0x0000 }, + { 0x2200, 0x0000 }, + { 0x2201, 0x0000 }, + { 0x2202, 0x0000 }, + { 0x2203, 0x0000 }, + { 0x2204, 0x0000 }, + { 0x2206, 0x0000 }, + { 0x2207, 0x0000 }, + { 0x2208, 0x0000 }, + { 0x2209, 0x0000 }, + { 0x220a, 0x0000 }, + { 0x220b, 0x0000 }, + { 0x220c, 0x0000 }, + { 0x220d, 0x0000 }, + { 0x220e, 0x0000 }, + { 0x220f, 0x0000 }, + { 0x2211, 0x0000 }, + { 0x2212, 0x0000 }, + { 0x2220, 0x0000 }, + { 0x2221, 0x0000 }, + { 0x2222, 0x0000 }, + { 0x2223, 0x0000 }, + { 0x2230, 0x0000 }, + { 0x2231, 0x0000 }, + { 0x3121, 0x0001 }, + { 0x3122, 0x0000 }, + { 0x3123, 0x0000 }, + { 0x7303, 0x0057 }, + { 0x7303, 0x0057 }, + { 0x8383, 0x0057 }, + { 0x7308, 0x0097 }, + { 0x8388, 0x0097 }, + { 0x7309, 0x0097 }, + { 0x8389, 0x0097 }, + { 0x7312, 0x0000 }, + { 0x8392, 0x0000 }, + { 0x7313, 0x0000 }, + { 0x8393, 0x0000 }, + { 0x7319, 0x0000 }, + { 0x8399, 0x0000 }, + { 0x7520001a, 0x8003 }, + { 0x75200045, 0x5289 }, + { 0x75200048, 0xd049 }, + { 0x7520004a, 0xa83b }, + { 0x7520006b, 0x5064 }, +}; + +#endif /* __RT700_H__ */ diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c new file mode 100644 index 00000000000000..2bfa9b180e431d --- /dev/null +++ b/sound/soc/codecs/rt700.c @@ -0,0 +1,1217 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// rt700.c -- rt700 ALSA SoC audio driver +// +// Copyright(c) 2019 Realtek Semiconductor Corp. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt700.h" + +static int rt700_index_write(struct regmap *regmap, + unsigned int reg, unsigned int value) +{ + int ret; + unsigned int addr = (RT700_PRIV_INDEX_W_H << 16) | reg; + + ret = regmap_write(regmap, addr, value); + if (ret < 0) + pr_err("Failed to set private value: %08x <= %04x %d\n", ret, addr, value); + + return ret; +} + +static int rt700_index_read(struct regmap *regmap, + unsigned int reg, unsigned int *value) +{ + int ret; + unsigned int addr = (RT700_PRIV_INDEX_W_H << 16) | reg; + + *value = 0; + ret = regmap_read(regmap, addr, value); + if (ret < 0) + pr_err("Failed to get private value: %08x => %04x %d\n", ret, addr, *value); + + return ret; +} + +static unsigned int rt700_button_detect(struct rt700_priv *rt700) +{ + unsigned int btn_type = 0, val80, val81; + int ret; + + ret = rt700_index_read(rt700->regmap, RT700_IRQ_FLAG_TABLE1, &val80); + if (ret < 0) + goto read_error; + ret = rt700_index_read(rt700->regmap, RT700_IRQ_FLAG_TABLE2, &val81); + if (ret < 0) + goto read_error; + + val80 &= 0x0381; + val81 &= 0xff00; + + switch (val80) { + case 0x0200: + case 0x0100: + case 0x0080: + btn_type |= SND_JACK_BTN_0; + break; + case 0x0001: + btn_type |= SND_JACK_BTN_3; + break; + } + switch (val81) { + case 0x8000: + case 0x4000: + case 0x2000: + btn_type |= SND_JACK_BTN_1; + break; + case 0x1000: + case 0x0800: + case 0x0400: + btn_type |= SND_JACK_BTN_2; + break; + case 0x0200: + case 0x0100: + btn_type |= SND_JACK_BTN_3; + break; + } +read_error: + return btn_type; +} + +static int rt700_headset_detect(struct rt700_priv *rt700) +{ + unsigned int buf, loop = 0; + int ret; + + ret = rt700_index_read(rt700->regmap, + RT700_COMBO_JACK_AUTO_CTL2, &buf); + if (ret < 0) + goto io_error; + + while (loop < 500 && + (buf & RT700_COMBOJACK_AUTO_DET_STATUS) == 0) { + loop++; + + usleep_range(9000, 10000); + ret = rt700_index_read(rt700->regmap, + RT700_COMBO_JACK_AUTO_CTL2, &buf); + if (ret < 0) + goto io_error; + } + + if (loop >= 500) + goto to_error; + + if (buf & RT700_COMBOJACK_AUTO_DET_TRS) + rt700->jack_type = SND_JACK_HEADPHONE; + else if ((buf & RT700_COMBOJACK_AUTO_DET_CTIA) || + (buf & RT700_COMBOJACK_AUTO_DET_OMTP)) + rt700->jack_type = SND_JACK_HEADSET; + + return 0; + +to_error: + ret = -ETIMEDOUT; + pr_err_ratelimited("Time-out error in %s\n", __func__); + return ret; +io_error: + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); + return ret; +} + +static void rt700_jack_detect_handler(struct work_struct *work) +{ + struct rt700_priv *rt700 = + container_of(work, struct rt700_priv, jack_detect_work.work); + int btn_type = 0, ret; + unsigned int jack_status = 0, reg; + + if (!rt700->hs_jack) + return; + + if (!rt700->component->card->instantiated) + return; + + reg = RT700_VERB_GET_PIN_SENSE | RT700_HP_OUT; + ret = regmap_read(rt700->regmap, reg, &jack_status); + if (ret < 0) + goto io_error; + + /* pin attached */ + if (jack_status & (1 << 31)) { + /* jack in */ + if (rt700->jack_type == 0) { + ret = rt700_headset_detect(rt700); + if (ret < 0) + return; + if (rt700->jack_type == SND_JACK_HEADSET) + btn_type = rt700_button_detect(rt700); + } else if (rt700->jack_type == SND_JACK_HEADSET) { + /* jack is already in, report button event */ + btn_type = rt700_button_detect(rt700); + } + } else { + /* jack out */ + rt700->jack_type = 0; + } + + dev_dbg(&rt700->slave->dev, + "in %s, jack_type=0x%x\n", __func__, rt700->jack_type); + dev_dbg(&rt700->slave->dev, + "in %s, btn_type=0x%x\n", __func__, btn_type); + + snd_soc_jack_report(rt700->hs_jack, rt700->jack_type | btn_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + if (btn_type) { + /* button released */ + snd_soc_jack_report(rt700->hs_jack, rt700->jack_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + mod_delayed_work(system_power_efficient_wq, + &rt700->jack_btn_check_work, msecs_to_jiffies(200)); + } + + return; + +io_error: + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); +} + +static void rt700_btn_check_handler(struct work_struct *work) +{ + struct rt700_priv *rt700 = container_of(work, struct rt700_priv, + jack_btn_check_work.work); + int btn_type = 0, ret; + unsigned int jack_status = 0, reg; + + reg = RT700_VERB_GET_PIN_SENSE | RT700_HP_OUT; + ret = regmap_read(rt700->regmap, reg, &jack_status); + if (ret < 0) + goto io_error; + + /* pin attached */ + if (jack_status & (1 << 31)) { + if (rt700->jack_type == SND_JACK_HEADSET) { + /* jack is already in, report button event */ + btn_type = rt700_button_detect(rt700); + } + } else { + rt700->jack_type = 0; + } + + /* cbj comparator */ + ret = rt700_index_read(rt700->regmap, RT700_COMBO_JACK_AUTO_CTL2, ®); + if (ret < 0) + goto io_error; + + if ((reg & 0xf0) == 0xf0) + btn_type = 0; + + dev_dbg(&rt700->slave->dev, + "%s, btn_type=0x%x\n", __func__, btn_type); + snd_soc_jack_report(rt700->hs_jack, rt700->jack_type | btn_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + if (btn_type) { + /* button released */ + snd_soc_jack_report(rt700->hs_jack, rt700->jack_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + mod_delayed_work(system_power_efficient_wq, + &rt700->jack_btn_check_work, msecs_to_jiffies(200)); + } + + return; + +io_error: + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); +} + +static void rt700_jack_init(struct rt700_priv *rt700) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(rt700->component); + + /* power on */ + if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) + regmap_write(rt700->regmap, + RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D0); + + if (rt700->hs_jack) { + /* Enable Jack Detection */ + regmap_write(rt700->regmap, + RT700_SET_MIC2_UNSOLICITED_ENABLE, 0x82); + regmap_write(rt700->regmap, + RT700_SET_HP_UNSOLICITED_ENABLE, 0x81); + regmap_write(rt700->regmap, + RT700_SET_INLINE_UNSOLICITED_ENABLE, 0x83); + rt700_index_write(rt700->regmap, 0x10, 0x2420); + rt700_index_write(rt700->regmap, 0x19, 0x2e11); + + dev_dbg(&rt700->slave->dev, "in %s enable\n", __func__); + + mod_delayed_work(system_power_efficient_wq, + &rt700->jack_detect_work, msecs_to_jiffies(250)); + } else { + regmap_write(rt700->regmap, + RT700_SET_MIC2_UNSOLICITED_ENABLE, 0x00); + regmap_write(rt700->regmap, + RT700_SET_HP_UNSOLICITED_ENABLE, 0x00); + regmap_write(rt700->regmap, + RT700_SET_INLINE_UNSOLICITED_ENABLE, 0x00); + + dev_dbg(&rt700->slave->dev, "in %s disable\n", __func__); + } + + /* power off */ + if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) + regmap_write(rt700->regmap, + RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3); +} + +static int rt700_set_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *hs_jack, void *data) +{ + struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + + rt700->hs_jack = hs_jack; + + if (!rt700->hw_init) { + dev_dbg(&rt700->slave->dev, + "%s hw_init not ready yet\n", __func__); + return 0; + } + + rt700_jack_init(rt700); + + return 0; +} + +static void rt700_get_gain(struct rt700_priv *rt700, unsigned int addr_h, + unsigned int addr_l, unsigned int val_h, + unsigned int *r_val, unsigned int *l_val) +{ + /* R Channel */ + *r_val = (val_h << 8); + regmap_read(rt700->regmap, addr_l, r_val); + + /* L Channel */ + val_h |= 0x20; + *l_val = (val_h << 8); + regmap_read(rt700->regmap, addr_h, l_val); +} + +/* For Verb-Set Amplifier Gain (Verb ID = 3h) */ +static int rt700_set_amp_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + unsigned int addr_h, addr_l, val_h, val_ll, val_lr; + unsigned int read_ll, read_rl; + int i; + + /* Can't use update bit function, so read the original value first */ + addr_h = mc->reg; + addr_l = mc->rreg; + if (mc->shift == RT700_DIR_OUT_SFT) /* output */ + val_h = 0x80; + else /* input */ + val_h = 0x0; + + rt700_get_gain(rt700, addr_h, addr_l, val_h, &read_rl, &read_ll); + + /* L Channel */ + if (mc->invert) { + /* for mute */ + val_ll = (mc->max - ucontrol->value.integer.value[0]) << 7; + /* keep gain */ + read_ll = read_ll & 0x7f; + val_ll |= read_ll; + } else { + /* for gain */ + val_ll = ((ucontrol->value.integer.value[0]) & 0x7f); + if (val_ll > mc->max) + val_ll = mc->max; + /* keep mute status */ + read_ll = read_ll & 0x80; + val_ll |= read_ll; + } + + if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) + regmap_write(rt700->regmap, + RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D0); + + /* R Channel */ + if (mc->invert) { + /* for mute */ + val_lr = (mc->max - ucontrol->value.integer.value[1]) << 7; + /* keep gain */ + read_rl = read_rl & 0x7f; + val_lr |= read_rl; + } else { + /* for gain */ + val_lr = ((ucontrol->value.integer.value[1]) & 0x7f); + if (val_lr > mc->max) + val_lr = mc->max; + /* keep mute status */ + read_rl = read_rl & 0x80; + val_lr |= read_rl; + } + + for (i = 0; i < 3; i++) { /* retry 3 times at most */ + if (val_ll == val_lr) { + /* Set both L/R channels at the same time */ + val_h = (1 << mc->shift) | (3 << 4); + regmap_write(rt700->regmap, addr_h, (val_h << 8 | val_ll)); + regmap_write(rt700->regmap, addr_l, (val_h << 8 | val_ll)); + } else { + /* Lch*/ + val_h = (1 << mc->shift) | (1 << 5); + regmap_write(rt700->regmap, addr_h, (val_h << 8 | val_ll)); + + /* Rch */ + val_h = (1 << mc->shift) | (1 << 4); + regmap_write(rt700->regmap, addr_l, (val_h << 8 | val_lr)); + } + /* check result */ + if (mc->shift == RT700_DIR_OUT_SFT) /* output */ + val_h = 0x80; + else /* input */ + val_h = 0x0; + + rt700_get_gain(rt700, addr_h, addr_l, val_h, + &read_rl, &read_ll); + if (read_rl == val_lr && read_ll == val_ll) + break; + } + + if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) + regmap_write(rt700->regmap, + RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3); + return 0; +} + +static int rt700_set_amp_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int addr_h, addr_l, val_h; + unsigned int read_ll, read_rl; + + addr_h = mc->reg; + addr_l = mc->rreg; + if (mc->shift == RT700_DIR_OUT_SFT) /* output */ + val_h = 0x80; + else /* input */ + val_h = 0x0; + + rt700_get_gain(rt700, addr_h, addr_l, val_h, &read_rl, &read_ll); + + if (mc->invert) { + /* for mute status */ + read_ll = !((read_ll & 0x80) >> RT700_MUTE_SFT); + read_rl = !((read_rl & 0x80) >> RT700_MUTE_SFT); + } else { + /* for gain */ + read_ll = read_ll & 0x7f; + read_rl = read_rl & 0x7f; + } + ucontrol->value.integer.value[0] = read_ll; + ucontrol->value.integer.value[1] = read_rl; + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); +static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); + +static const struct snd_kcontrol_new rt700_snd_controls[] = { + SOC_DOUBLE_R_EXT_TLV("DAC Front Playback Volume", RT700_SET_GAIN_DAC1_H, + RT700_SET_GAIN_DAC1_L, RT700_DIR_OUT_SFT, 0x57, 0, + rt700_set_amp_gain_get, rt700_set_amp_gain_put, + out_vol_tlv), + SOC_DOUBLE_R_EXT("ADC 08 Capture Switch", RT700_SET_GAIN_ADC2_H, + RT700_SET_GAIN_ADC2_L, RT700_DIR_IN_SFT, 1, 1, + rt700_set_amp_gain_get, rt700_set_amp_gain_put), + SOC_DOUBLE_R_EXT("ADC 09 Capture Switch", RT700_SET_GAIN_ADC1_H, + RT700_SET_GAIN_ADC1_L, RT700_DIR_IN_SFT, 1, 1, + rt700_set_amp_gain_get, rt700_set_amp_gain_put), + SOC_DOUBLE_R_EXT_TLV("ADC 08 Capture Volume", RT700_SET_GAIN_ADC2_H, + RT700_SET_GAIN_ADC2_L, RT700_DIR_IN_SFT, 0x3f, 0, + rt700_set_amp_gain_get, rt700_set_amp_gain_put, + in_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("ADC 09 Capture Volume", RT700_SET_GAIN_ADC1_H, + RT700_SET_GAIN_ADC1_L, RT700_DIR_IN_SFT, 0x3f, 0, + rt700_set_amp_gain_get, rt700_set_amp_gain_put, + in_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("AMIC Volume", RT700_SET_GAIN_AMIC_H, + RT700_SET_GAIN_AMIC_L, RT700_DIR_IN_SFT, 3, 0, + rt700_set_amp_gain_get, rt700_set_amp_gain_put, + mic_vol_tlv), +}; + +static int rt700_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + unsigned int reg, val = 0, nid; + int ret; + + if (strstr(ucontrol->id.name, "HPO Mux")) + nid = RT700_HP_OUT; + else if (strstr(ucontrol->id.name, "ADC 22 Mux")) + nid = RT700_MIXER_IN1; + else if (strstr(ucontrol->id.name, "ADC 23 Mux")) + nid = RT700_MIXER_IN2; + else + return -EINVAL; + + /* vid = 0xf01 */ + reg = RT700_VERB_SET_CONNECT_SEL | nid; + ret = regmap_read(rt700->regmap, reg, &val); + if (ret < 0) + return ret; + + ucontrol->value.enumerated.item[0] = val; + + return 0; +} + +static int rt700_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + unsigned int val, val2 = 0, change, reg, nid; + int ret; + + if (item[0] >= e->items) + return -EINVAL; + + if (strstr(ucontrol->id.name, "HPO Mux")) + nid = RT700_HP_OUT; + else if (strstr(ucontrol->id.name, "ADC 22 Mux")) + nid = RT700_MIXER_IN1; + else if (strstr(ucontrol->id.name, "ADC 23 Mux")) + nid = RT700_MIXER_IN2; + else + return -EINVAL; + + /* Verb ID = 0x701h */ + val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; + + reg = RT700_VERB_SET_CONNECT_SEL | nid; + ret = regmap_read(rt700->regmap, reg, &val2); + if (ret < 0) + return ret; + + if (val == val2) + change = 0; + else + change = 1; + + if (change) { + reg = RT700_VERB_SET_CONNECT_SEL | nid; + regmap_write(rt700->regmap, reg, val); + } + + snd_soc_dapm_mux_update_power(dapm, kcontrol, + item[0], e, NULL); + + return change; +} + +static const char * const adc_mux_text[] = { + "MIC2", + "LINE1", + "LINE2", + "DMIC", +}; + +static SOC_ENUM_SINGLE_DECL( + rt700_adc22_enum, SND_SOC_NOPM, 0, adc_mux_text); + +static SOC_ENUM_SINGLE_DECL( + rt700_adc23_enum, SND_SOC_NOPM, 0, adc_mux_text); + +static const struct snd_kcontrol_new rt700_adc22_mux = + SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt700_adc22_enum, + rt700_mux_get, rt700_mux_put); + +static const struct snd_kcontrol_new rt700_adc23_mux = + SOC_DAPM_ENUM_EXT("ADC 23 Mux", rt700_adc23_enum, + rt700_mux_get, rt700_mux_put); + +static const char * const out_mux_text[] = { + "Front", + "Surround", +}; + +static SOC_ENUM_SINGLE_DECL( + rt700_hp_enum, SND_SOC_NOPM, 0, out_mux_text); + +static const struct snd_kcontrol_new rt700_hp_mux = + SOC_DAPM_ENUM_EXT("HP Mux", rt700_hp_enum, + rt700_mux_get, rt700_mux_put); + +static int rt700_dac_front_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt700->regmap, + RT700_SET_STREAMID_DAC1, 0x10); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt700->regmap, + RT700_SET_STREAMID_DAC1, 0x00); + break; + } + return 0; +} + +static int rt700_dac_surround_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt700->regmap, + RT700_SET_STREAMID_DAC2, 0x10); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt700->regmap, + RT700_SET_STREAMID_DAC2, 0x00); + break; + } + return 0; +} + +static int rt700_adc_09_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt700->regmap, + RT700_SET_STREAMID_ADC1, 0x10); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt700->regmap, + RT700_SET_STREAMID_ADC1, 0x00); + break; + } + return 0; +} + +static int rt700_adc_08_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt700->regmap, + RT700_SET_STREAMID_ADC2, 0x10); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt700->regmap, + RT700_SET_STREAMID_ADC2, 0x00); + break; + } + return 0; +} + +static int rt700_hpo_mux_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + unsigned int val_h = (1 << RT700_DIR_OUT_SFT) | (0x3 << 4); + unsigned int val_l; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + val_l = 0x00; + regmap_write(rt700->regmap, + RT700_SET_GAIN_HP_H, (val_h << 8 | val_l)); + break; + case SND_SOC_DAPM_PRE_PMD: + val_l = (1 << RT700_MUTE_SFT); + regmap_write(rt700->regmap, + RT700_SET_GAIN_HP_H, (val_h << 8 | val_l)); + break; + } + return 0; +} + +static int rt700_spk_pga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + unsigned int val_h = (1 << RT700_DIR_OUT_SFT) | (0x3 << 4); + unsigned int val_l; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + val_l = 0x00; + regmap_write(rt700->regmap, + RT700_SET_GAIN_SPK_H, (val_h << 8 | val_l)); + break; + case SND_SOC_DAPM_PRE_PMD: + val_l = (1 << RT700_MUTE_SFT); + regmap_write(rt700->regmap, + RT700_SET_GAIN_SPK_H, (val_h << 8 | val_l)); + break; + } + return 0; +} + +static const struct snd_soc_dapm_widget rt700_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("HP"), + SND_SOC_DAPM_OUTPUT("SPK"), + SND_SOC_DAPM_INPUT("DMIC1"), + SND_SOC_DAPM_INPUT("DMIC2"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("LINE1"), + SND_SOC_DAPM_INPUT("LINE2"), + SND_SOC_DAPM_DAC_E("DAC Front", NULL, SND_SOC_NOPM, 0, 0, + rt700_dac_front_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_DAC_E("DAC Surround", NULL, SND_SOC_NOPM, 0, 0, + rt700_dac_surround_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MUX_E("HPO Mux", SND_SOC_NOPM, 0, 0, &rt700_hp_mux, + rt700_hpo_mux_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_E("SPK PGA", SND_SOC_NOPM, 0, 0, NULL, 0, + rt700_spk_pga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("ADC 09", NULL, SND_SOC_NOPM, 0, 0, + rt700_adc_09_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("ADC 08", NULL, SND_SOC_NOPM, 0, 0, + rt700_adc_08_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0, + &rt700_adc22_mux), + SND_SOC_DAPM_MUX("ADC 23 Mux", SND_SOC_NOPM, 0, 0, + &rt700_adc23_mux), + SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route rt700_audio_map[] = { + {"DAC Front", NULL, "DP1RX"}, + {"DAC Surround", NULL, "DP3RX"}, + {"DP2TX", NULL, "ADC 09"}, + {"DP4TX", NULL, "ADC 08"}, + {"ADC 09", NULL, "ADC 22 Mux"}, + {"ADC 08", NULL, "ADC 23 Mux"}, + {"ADC 22 Mux", "DMIC", "DMIC1"}, + {"ADC 22 Mux", "LINE1", "LINE1"}, + {"ADC 22 Mux", "LINE2", "LINE2"}, + {"ADC 22 Mux", "MIC2", "MIC2"}, + {"ADC 23 Mux", "DMIC", "DMIC2"}, + {"ADC 23 Mux", "LINE1", "LINE1"}, + {"ADC 23 Mux", "LINE2", "LINE2"}, + {"ADC 23 Mux", "MIC2", "MIC2"}, + {"HPO Mux", "Front", "DAC Front"}, + {"HPO Mux", "Surround", "DAC Surround"}, + {"HP", NULL, "HPO Mux"}, + {"SPK PGA", NULL, "DAC Front"}, + {"SPK", NULL, "SPK PGA"}, +}; + +static int rt700_probe(struct snd_soc_component *component) +{ + struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + + rt700->component = component; + + return 0; +} + +static int rt700_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + + switch (level) { + case SND_SOC_BIAS_PREPARE: + if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { + regmap_write(rt700->regmap, + RT700_SET_AUDIO_POWER_STATE, + AC_PWRST_D0); + } + break; + + case SND_SOC_BIAS_STANDBY: + regmap_write(rt700->regmap, + RT700_SET_AUDIO_POWER_STATE, + AC_PWRST_D3); + break; + + default: + break; + } + dapm->bias_level = level; + return 0; +} + +static const struct snd_soc_component_driver soc_codec_dev_rt700 = { + .probe = rt700_probe, + .set_bias_level = rt700_set_bias_level, + .controls = rt700_snd_controls, + .num_controls = ARRAY_SIZE(rt700_snd_controls), + .dapm_widgets = rt700_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt700_dapm_widgets), + .dapm_routes = rt700_audio_map, + .num_dapm_routes = ARRAY_SIZE(rt700_audio_map), + .set_jack = rt700_set_jack_detect, +}; + +static int rt700_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, + int direction) +{ + struct sdw_stream_data *stream; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; + + stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream; + + /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + dai->playback_dma_data = stream; + else + dai->capture_dma_data = stream; + + return 0; +} + +static void rt700_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sdw_stream_data *stream; + + stream = snd_soc_dai_get_dma_data(dai, substream); + snd_soc_dai_set_dma_data(dai, substream, NULL); + kfree(stream); +} + +static int rt700_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; + enum sdw_data_direction direction; + struct sdw_stream_data *stream; + int retval, port, num_channels; + unsigned int val = 0; + + dev_dbg(dai->dev, "%s %s", __func__, dai->name); + stream = snd_soc_dai_get_dma_data(dai, substream); + + if (!stream) + return -EINVAL; + + if (!rt700->slave) + return -EINVAL; + + /* SoundWire specific configuration */ + /* This code assumes port 1 for playback and port 2 for capture */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + direction = SDW_DATA_DIR_RX; + port = 1; + } else { + direction = SDW_DATA_DIR_TX; + port = 2; + } + + switch (dai->id) { + case RT700_AIF1: + break; + case RT700_AIF2: + port += 2; + break; + default: + dev_err(component->dev, "Invalid DAI id %d\n", dai->id); + return -EINVAL; + } + + stream_config.frame_rate = params_rate(params); + stream_config.ch_count = params_channels(params); + stream_config.bps = snd_pcm_format_width(params_format(params)); + stream_config.direction = direction; + + num_channels = params_channels(params); + port_config.ch_mask = (1 << (num_channels)) - 1; + port_config.num = port; + + retval = sdw_stream_add_slave(rt700->slave, &stream_config, + &port_config, 1, stream->sdw_stream); + if (retval) { + dev_err(dai->dev, "Unable to configure port\n"); + return retval; + } + + if (params_channels(params) <= 16) { + /* bit 3:0 Number of Channel */ + val |= (params_channels(params) - 1); + } else { + dev_err(component->dev, "Unsupported channels %d\n", + params_channels(params)); + return -EINVAL; + } + + switch (params_width(params)) { + /* bit 6:4 Bits per Sample */ + case 8: + break; + case 16: + val |= (0x1 << 4); + break; + case 20: + val |= (0x2 << 4); + break; + case 24: + val |= (0x3 << 4); + break; + case 32: + val |= (0x4 << 4); + break; + default: + return -EINVAL; + } + + /* 48Khz */ + regmap_write(rt700->regmap, RT700_DAC_FORMAT_H, val); + regmap_write(rt700->regmap, RT700_ADC_FORMAT_H, val); + + return retval; +} + +static int rt700_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); + struct sdw_stream_data *stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt700->slave) + return -EINVAL; + + sdw_stream_remove_slave(rt700->slave, stream->sdw_stream); + return 0; +} + +#define RT700_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define RT700_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static struct snd_soc_dai_ops rt700_ops = { + .hw_params = rt700_pcm_hw_params, + .hw_free = rt700_pcm_hw_free, + .set_sdw_stream = rt700_set_sdw_stream, + .shutdown = rt700_shutdown, +}; + +static struct snd_soc_dai_driver rt700_dai[] = { + { + .name = "rt700-aif1", + .id = RT700_AIF1, + .playback = { + .stream_name = "DP1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT700_STEREO_RATES, + .formats = RT700_FORMATS, + }, + .capture = { + .stream_name = "DP2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT700_STEREO_RATES, + .formats = RT700_FORMATS, + }, + .ops = &rt700_ops, + }, + { + .name = "rt700-aif2", + .id = RT700_AIF2, + .playback = { + .stream_name = "DP3 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT700_STEREO_RATES, + .formats = RT700_FORMATS, + }, + .capture = { + .stream_name = "DP4 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT700_STEREO_RATES, + .formats = RT700_FORMATS, + }, + .ops = &rt700_ops, + }, +}; + +/* Bus clock frequency */ +#define RT700_CLK_FREQ_9600000HZ 9600000 +#define RT700_CLK_FREQ_12000000HZ 12000000 +#define RT700_CLK_FREQ_6000000HZ 6000000 +#define RT700_CLK_FREQ_4800000HZ 4800000 +#define RT700_CLK_FREQ_2400000HZ 2400000 +#define RT700_CLK_FREQ_12288000HZ 12288000 + +int rt700_clock_config(struct device *dev) +{ + struct rt700_priv *rt700 = dev_get_drvdata(dev); + unsigned int clk_freq, value; + + clk_freq = (rt700->params.curr_dr_freq >> 1); + + switch (clk_freq) { + case RT700_CLK_FREQ_12000000HZ: + value = 0x0; + break; + case RT700_CLK_FREQ_6000000HZ: + value = 0x1; + break; + case RT700_CLK_FREQ_9600000HZ: + value = 0x2; + break; + case RT700_CLK_FREQ_4800000HZ: + value = 0x3; + break; + case RT700_CLK_FREQ_2400000HZ: + value = 0x4; + break; + case RT700_CLK_FREQ_12288000HZ: + value = 0x5; + break; + default: + return -EINVAL; + } + + regmap_write(rt700->regmap, 0xe0, value); + regmap_write(rt700->regmap, 0xf0, value); + + dev_dbg(dev, "%s complete, clk_freq=%d\n", __func__, clk_freq); + + return 0; +} + +int rt700_init(struct device *dev, struct regmap *sdw_regmap, + struct regmap *regmap, struct sdw_slave *slave) + +{ + struct rt700_priv *rt700; + int ret; + + rt700 = devm_kzalloc(dev, sizeof(*rt700), GFP_KERNEL); + if (!rt700) + return -ENOMEM; + + dev_set_drvdata(dev, rt700); + rt700->slave = slave; + rt700->sdw_regmap = sdw_regmap; + rt700->regmap = regmap; + + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt700->hw_init = false; + rt700->first_init = false; + + ret = devm_snd_soc_register_component(dev, + &soc_codec_dev_rt700, + rt700_dai, + ARRAY_SIZE(rt700_dai)); + + dev_dbg(&slave->dev, "%s\n", __func__); + + return ret; +} + +int rt700_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt700_priv *rt700 = dev_get_drvdata(dev); + + if (rt700->hw_init) + return 0; + + /* + * PM runtime is only enabled when a Slave reports as Attached + */ + if (!rt700->first_init) { + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(&slave->dev, 3000); + pm_runtime_use_autosuspend(&slave->dev); + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(&slave->dev); + + pm_runtime_enable(&slave->dev); + + rt700->first_init = true; + } + + pm_runtime_get_noresume(&slave->dev); + + /* reset */ + regmap_write(rt700->regmap, 0xff01, 0x0000); + regmap_write(rt700->regmap, 0x7520, 0x001a); + regmap_write(rt700->regmap, 0x7420, 0xc003); + + /* power on */ + regmap_write(rt700->regmap, RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D0); + /* Set Pin Widget */ + regmap_write(rt700->regmap, RT700_SET_PIN_HP, 0x40); + regmap_write(rt700->regmap, RT700_SET_PIN_SPK, 0x40); + regmap_write(rt700->regmap, RT700_SET_EAPD_SPK, RT700_EAPD_HIGH); + regmap_write(rt700->regmap, RT700_SET_PIN_DMIC1, 0x20); + regmap_write(rt700->regmap, RT700_SET_PIN_DMIC2, 0x20); + regmap_write(rt700->regmap, RT700_SET_PIN_MIC2, 0x20); + + /* Set Configuration Default */ + regmap_write(rt700->regmap, 0x4f12, 0x91); + regmap_write(rt700->regmap, 0x4e12, 0xd6); + regmap_write(rt700->regmap, 0x4d12, 0x11); + regmap_write(rt700->regmap, 0x4c12, 0x20); + regmap_write(rt700->regmap, 0x4f13, 0x91); + regmap_write(rt700->regmap, 0x4e13, 0xd6); + regmap_write(rt700->regmap, 0x4d13, 0x11); + regmap_write(rt700->regmap, 0x4c13, 0x21); + + regmap_write(rt700->regmap, 0x4f19, 0x02); + regmap_write(rt700->regmap, 0x4e19, 0xa1); + regmap_write(rt700->regmap, 0x4d19, 0x90); + regmap_write(rt700->regmap, 0x4c19, 0x80); + + /* Enable Line2 */ + regmap_write(rt700->regmap, 0x371b, 0x40); + regmap_write(rt700->regmap, 0x731b, 0xb0); + regmap_write(rt700->regmap, 0x839b, 0x00); + + /* Set index */ + rt700_index_write(rt700->regmap, 0x4a, 0x201b); + rt700_index_write(rt700->regmap, 0x45, 0x5089); + rt700_index_write(rt700->regmap, 0x6b, 0x5064); + rt700_index_write(rt700->regmap, 0x48, 0xd249); + + /* Finish Initial Settings, set power to D3 */ + regmap_write(rt700->regmap, RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3); + + INIT_DELAYED_WORK(&rt700->jack_detect_work, + rt700_jack_detect_handler); + INIT_DELAYED_WORK(&rt700->jack_btn_check_work, + rt700_btn_check_handler); + + /* + * if set_jack callback occurred early than io_init, + * we set up the jack detection function now + */ + if (rt700->hs_jack) + rt700_jack_init(rt700); + + /* Mark Slave initialization complete */ + rt700->hw_init = true; + + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + + dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); + + return 0; +} + +MODULE_DESCRIPTION("ASoC RT700 driver SDW"); +MODULE_AUTHOR("Shuming Fan "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt700.h b/sound/soc/codecs/rt700.h new file mode 100644 index 00000000000000..11f046e6255e29 --- /dev/null +++ b/sound/soc/codecs/rt700.h @@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * rt700.h -- RT700 ALSA SoC audio driver header + * + * Copyright(c) 2019 Realtek Semiconductor Corp. + */ + +#ifndef __RT700_H__ +#define __RT700_H__ + +#include + +extern const struct dev_pm_ops rt700_runtime_pm; + +struct rt700_priv { + struct snd_soc_component *component; + struct regmap *regmap; + struct regmap *sdw_regmap; + struct sdw_slave *slave; + enum sdw_slave_status status; + struct sdw_bus_params params; + bool hw_init; + bool first_init; + struct snd_soc_jack *hs_jack; + struct delayed_work jack_detect_work; + struct delayed_work jack_btn_check_work; + int jack_type; +}; + +struct sdw_stream_data { + struct sdw_stream_runtime *sdw_stream; +}; + +/* NID */ +#define RT700_AUDIO_FUNCTION_GROUP 0x01 +#define RT700_DAC_OUT1 0x02 +#define RT700_DAC_OUT2 0x03 +#define RT700_ADC_IN1 0x09 +#define RT700_ADC_IN2 0x08 +#define RT700_DMIC1 0x12 +#define RT700_DMIC2 0x13 +#define RT700_SPK_OUT 0x14 +#define RT700_MIC2 0x19 +#define RT700_LINE1 0x1a +#define RT700_LINE2 0x1b +#define RT700_BEEP 0x1d +#define RT700_SPDIF 0x1e +#define RT700_VENDOR_REGISTERS 0x20 +#define RT700_HP_OUT 0x21 +#define RT700_MIXER_IN1 0x22 +#define RT700_MIXER_IN2 0x23 +#define RT700_INLINE_CMD 0x55 + +/* Index (NID:20h) */ +#define RT700_DAC_DC_CALI_CTL1 0x00 +#define RT700_PARA_VERB_CTL 0x1a +#define RT700_COMBO_JACK_AUTO_CTL1 0x45 +#define RT700_COMBO_JACK_AUTO_CTL2 0x46 +#define RT700_INLINE_CMD_CTL 0x48 +#define RT700_DIGITAL_MISC_CTRL4 0x4a +#define RT700_VREFOUT_CTL 0x6b +#define RT700_FSM_CTL 0x6f +#define RT700_IRQ_FLAG_TABLE1 0x80 +#define RT700_IRQ_FLAG_TABLE2 0x81 +#define RT700_IRQ_FLAG_TABLE3 0x82 + +/* Verb */ +#define RT700_VERB_SET_CONNECT_SEL 0x3100 +#define RT700_VERB_SET_EAPD_BTLENABLE 0x3c00 +#define RT700_VERB_GET_CONNECT_SEL 0xb100 +#define RT700_VERB_SET_POWER_STATE 0x3500 +#define RT700_VERB_SET_CHANNEL_STREAMID 0x3600 +#define RT700_VERB_SET_PIN_WIDGET_CONTROL 0x3700 +#define RT700_VERB_SET_UNSOLICITED_ENABLE 0x3800 +#define RT700_SET_AMP_GAIN_MUTE_H 0x7300 +#define RT700_SET_AMP_GAIN_MUTE_L 0x8380 +#define RT700_VERB_GET_PIN_SENSE 0xb900 + +#define RT700_READ_HDA_3 0x2012 +#define RT700_READ_HDA_2 0x2013 +#define RT700_READ_HDA_1 0x2014 +#define RT700_READ_HDA_0 0x2015 +#define RT700_PRIV_INDEX_W_H 0x7520 +#define RT700_PRIV_INDEX_W_L 0x85a0 +#define RT700_PRIV_DATA_W_H 0x7420 +#define RT700_PRIV_DATA_W_L 0x84a0 +#define RT700_PRIV_INDEX_R_H 0x9d20 +#define RT700_PRIV_INDEX_R_L 0xada0 +#define RT700_PRIV_DATA_R_H 0x9c20 +#define RT700_PRIV_DATA_R_L 0xaca0 +#define RT700_DAC_FORMAT_H 0x7203 +#define RT700_DAC_FORMAT_L 0x8283 +#define RT700_ADC_FORMAT_H 0x7209 +#define RT700_ADC_FORMAT_L 0x8289 +#define RT700_SET_AUDIO_POWER_STATE\ + (RT700_VERB_SET_POWER_STATE | RT700_AUDIO_FUNCTION_GROUP) +#define RT700_SET_PIN_DMIC1\ + (RT700_VERB_SET_PIN_WIDGET_CONTROL | RT700_DMIC1) +#define RT700_SET_PIN_DMIC2\ + (RT700_VERB_SET_PIN_WIDGET_CONTROL | RT700_DMIC2) +#define RT700_SET_PIN_SPK\ + (RT700_VERB_SET_PIN_WIDGET_CONTROL | RT700_SPK_OUT) +#define RT700_SET_PIN_HP\ + (RT700_VERB_SET_PIN_WIDGET_CONTROL | RT700_HP_OUT) +#define RT700_SET_PIN_MIC2\ + (RT700_VERB_SET_PIN_WIDGET_CONTROL | RT700_MIC2) +#define RT700_SET_PIN_LINE1\ + (RT700_VERB_SET_PIN_WIDGET_CONTROL | RT700_LINE1) +#define RT700_SET_PIN_LINE2\ + (RT700_VERB_SET_PIN_WIDGET_CONTROL | RT700_LINE2) +#define RT700_SET_MIC2_UNSOLICITED_ENABLE\ + (RT700_VERB_SET_UNSOLICITED_ENABLE | RT700_MIC2) +#define RT700_SET_HP_UNSOLICITED_ENABLE\ + (RT700_VERB_SET_UNSOLICITED_ENABLE | RT700_HP_OUT) +#define RT700_SET_INLINE_UNSOLICITED_ENABLE\ + (RT700_VERB_SET_UNSOLICITED_ENABLE | RT700_INLINE_CMD) +#define RT700_SET_STREAMID_DAC1\ + (RT700_VERB_SET_CHANNEL_STREAMID | RT700_DAC_OUT1) +#define RT700_SET_STREAMID_DAC2\ + (RT700_VERB_SET_CHANNEL_STREAMID | RT700_DAC_OUT2) +#define RT700_SET_STREAMID_ADC1\ + (RT700_VERB_SET_CHANNEL_STREAMID | RT700_ADC_IN1) +#define RT700_SET_STREAMID_ADC2\ + (RT700_VERB_SET_CHANNEL_STREAMID | RT700_ADC_IN2) +#define RT700_SET_GAIN_DAC1_L\ + (RT700_SET_AMP_GAIN_MUTE_L | RT700_DAC_OUT1) +#define RT700_SET_GAIN_DAC1_H\ + (RT700_SET_AMP_GAIN_MUTE_H | RT700_DAC_OUT1) +#define RT700_SET_GAIN_ADC1_L\ + (RT700_SET_AMP_GAIN_MUTE_L | RT700_ADC_IN1) +#define RT700_SET_GAIN_ADC1_H\ + (RT700_SET_AMP_GAIN_MUTE_H | RT700_ADC_IN1) +#define RT700_SET_GAIN_ADC2_L\ + (RT700_SET_AMP_GAIN_MUTE_L | RT700_ADC_IN2) +#define RT700_SET_GAIN_ADC2_H\ + (RT700_SET_AMP_GAIN_MUTE_H | RT700_ADC_IN2) +#define RT700_SET_GAIN_AMIC_L\ + (RT700_SET_AMP_GAIN_MUTE_L | RT700_MIC2) +#define RT700_SET_GAIN_AMIC_H\ + (RT700_SET_AMP_GAIN_MUTE_H | RT700_MIC2) +#define RT700_SET_GAIN_HP_L\ + (RT700_SET_AMP_GAIN_MUTE_L | RT700_HP_OUT) +#define RT700_SET_GAIN_HP_H\ + (RT700_SET_AMP_GAIN_MUTE_H | RT700_HP_OUT) +#define RT700_SET_GAIN_SPK_L\ + (RT700_SET_AMP_GAIN_MUTE_L | RT700_SPK_OUT) +#define RT700_SET_GAIN_SPK_H\ + (RT700_SET_AMP_GAIN_MUTE_H | RT700_SPK_OUT) +#define RT700_SET_EAPD_SPK\ + (RT700_VERB_SET_EAPD_BTLENABLE | RT700_SPK_OUT) + +/* combo jack auto switch control 2 (0x46)(NID:20h) */ +#define RT700_COMBOJACK_AUTO_DET_STATUS (0x1 << 11) +#define RT700_COMBOJACK_AUTO_DET_TRS (0x1 << 10) +#define RT700_COMBOJACK_AUTO_DET_CTIA (0x1 << 9) +#define RT700_COMBOJACK_AUTO_DET_OMTP (0x1 << 8) + +#define RT700_EAPD_HIGH 0x2 +#define RT700_EAPD_LOW 0x0 +#define RT700_MUTE_SFT 7 +#define RT700_DIR_IN_SFT 6 +#define RT700_DIR_OUT_SFT 7 + +enum { + RT700_AIF1, + RT700_AIF2, + RT700_AIFS, +}; + +int rt700_io_init(struct device *dev, struct sdw_slave *slave); +int rt700_init(struct device *dev, struct regmap *sdw_regmap, + struct regmap *regmap, struct sdw_slave *slave); + +int rt700_jack_detect(struct rt700_priv *rt700, bool *hp, bool *mic); +int rt700_clock_config(struct device *dev); +#endif /* __RT700_H__ */ From 28c3c6d31f6149d03e7448237ee48e966c221c2e Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Fri, 2 Aug 2019 10:26:02 +0800 Subject: [PATCH 1835/1995] ASoC: codecs: rt1308: add SoundWire support The driver for this amplifier was tested by Realtek and Intel using the Realtek 3-in-1 add-on boards connected to CometLake and IceLake platforms Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Shuming Fan --- sound/soc/codecs/Kconfig | 6 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt1308-sdw.c | 702 ++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt1308-sdw.h | 169 ++++++++ sound/soc/codecs/rt1308.c | 13 +- 5 files changed, 886 insertions(+), 6 deletions(-) create mode 100644 sound/soc/codecs/rt1308-sdw.c create mode 100644 sound/soc/codecs/rt1308-sdw.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a0cb17a06efa6e..aea61b6ede1b07 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1067,6 +1067,12 @@ config SND_SOC_RT700_SDW select SND_SOC_RT700 select REGMAP_SOUNDWIRE +config SND_SOC_RT1308_SDW + tristate "Realtek RT1308 Codec - SDW" + depends on SOUNDWIRE + select SND_SOC_RT1308 + select REGMAP_SOUNDWIRE + #Freescale sgtl5000 codec config SND_SOC_SGTL5000 tristate "Freescale SGTL5000 CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 985717ed133c6c..653c7d9e94e638 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -280,6 +280,7 @@ snd-soc-wm9713-objs := wm9713.o snd-soc-wm-hubs-objs := wm_hubs.o snd-soc-zx-aud96p22-objs := zx_aud96p22.o snd-soc-rt700-objs := rt700.o rt700-sdw.o +snd-soc-rt1308-sdw-objs := rt1308-sdw.o # Amp snd-soc-max9877-objs := max9877.o @@ -572,6 +573,7 @@ obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.o obj-$(CONFIG_SND_SOC_RT700) += snd-soc-rt700.o +obj-$(CONFIG_SND_SOC_RT1308_SDW) += snd-soc-rt1308-sdw.o # Amp obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c new file mode 100644 index 00000000000000..5730f59ae08022 --- /dev/null +++ b/sound/soc/codecs/rt1308-sdw.c @@ -0,0 +1,702 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// rt1308-sdw.c -- rt1308 ALSA SoC audio driver +// +// Copyright(c) 2019 Realtek Semiconductor Corp. +// +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt1308.h" +#include "rt1308-sdw.h" + +static bool rt1308_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x00e0: + case 0x00f0: + case 0x2f01 ... 0x2f07: + case 0x3000 ... 0x3001: + case 0x3004 ... 0x3005: + case 0x3008: + case 0x300a: + case 0xc000 ... 0xcff3: + return true; + default: + return false; + } +} + +static bool rt1308_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2f01 ... 0x2f07: + case 0x3000 ... 0x3001: + case 0x3004 ... 0x3005: + case 0x3008: + case 0x300a: + case 0xc000: + return true; + default: + return false; + } +} + +static const struct regmap_config rt1308_sdw_regmap = { + .reg_bits = 32, /* Total register space for SDW */ + .val_bits = 8, /* Total number of bits in register */ + .readable_reg = rt1308_readable_register, /* Readable registers */ + .volatile_reg = rt1308_volatile_register, /* volatile register */ + .max_register = 0xcfff, /* Maximum number of register */ + .reg_defaults = rt1308_reg_defaults, /* Defaults */ + .num_reg_defaults = ARRAY_SIZE(rt1308_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, +}; + +/* Bus clock frequency */ +#define RT1308_CLK_FREQ_9600000HZ 9600000 +#define RT1308_CLK_FREQ_12000000HZ 12000000 +#define RT1308_CLK_FREQ_6000000HZ 6000000 +#define RT1308_CLK_FREQ_4800000HZ 4800000 +#define RT1308_CLK_FREQ_2400000HZ 2400000 +#define RT1308_CLK_FREQ_12288000HZ 12288000 + +static int rt1308_clock_config(struct device *dev) +{ + struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev); + unsigned int clk_freq, value; + + clk_freq = (rt1308->params.curr_dr_freq >> 1); + + switch (clk_freq) { + case RT1308_CLK_FREQ_12000000HZ: + value = 0x0; + break; + case RT1308_CLK_FREQ_6000000HZ: + value = 0x1; + break; + case RT1308_CLK_FREQ_9600000HZ: + value = 0x2; + break; + case RT1308_CLK_FREQ_4800000HZ: + value = 0x3; + break; + case RT1308_CLK_FREQ_2400000HZ: + value = 0x4; + break; + case RT1308_CLK_FREQ_12288000HZ: + value = 0x5; + break; + default: + return -EINVAL; + } + + regmap_write(rt1308->regmap, 0xe0, value); + regmap_write(rt1308->regmap, 0xf0, value); + + dev_dbg(dev, "%s complete, clk_freq=%d\n", __func__, clk_freq); + + return 0; +} + +static int rt1308_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int nval, i, num_of_ports = 1; + u32 bit; + unsigned long addr; + struct sdw_dpn_prop *dpn; + + prop->paging_support = true; + + /* first we need to allocate memory for set bits in port lists */ + prop->source_ports = 0x00; /* BITMAP: 00010100 (not enable yet) */ + prop->sink_ports = 0x2; /* BITMAP: 00000010 */ + + /* for sink */ + nval = hweight32(prop->sink_ports); + num_of_ports += nval; + prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->sink_dpn_prop), + GFP_KERNEL); + if (!prop->sink_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->sink_dpn_prop; + addr = prop->sink_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].type = SDW_DPN_FULL; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* Allocate port_ready based on num_of_ports */ + slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports, + sizeof(*slave->port_ready), + GFP_KERNEL); + if (!slave->port_ready) + return -ENOMEM; + + /* Initialize completion */ + for (i = 0; i < num_of_ports; i++) + init_completion(&slave->port_ready[i]); + + /* set the timeout values */ + prop->clk_stop_timeout = 20; + + dev_dbg(&slave->dev, "%s\n", __func__); + + return 0; +} + +static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev); + int ret = 0; + + if (rt1308->hw_init) + return 0; + + ret = rt1308_read_prop(slave); + if (ret < 0) + goto _io_init_err_; + + /* + * PM runtime is only enabled when a Slave reports as Attached + */ + if (!rt1308->first_init) { + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(&slave->dev, 3000); + pm_runtime_use_autosuspend(&slave->dev); + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(&slave->dev); + + pm_runtime_enable(&slave->dev); + + rt1308->first_init = true; + } + + pm_runtime_get_noresume(&slave->dev); + + /* sw reset */ + regmap_write(rt1308->regmap, RT1308_SDW_RESET, 0); + + /* read efuse */ + regmap_write(rt1308->regmap, 0xc360, 0x01); + regmap_write(rt1308->regmap, 0xc360, 0x80); + regmap_write(rt1308->regmap, 0xc7f0, 0x04); + regmap_write(rt1308->regmap, 0xc7f1, 0xfe); + msleep(100); + regmap_write(rt1308->regmap, 0xc7f0, 0x44); + msleep(20); + regmap_write(rt1308->regmap, 0xc240, 0x10); + + /* initial settings */ + regmap_write(rt1308->regmap, 0xc103, 0xc0); + regmap_write(rt1308->regmap, 0xc030, 0x17); + regmap_write(rt1308->regmap, 0xc031, 0x81); + regmap_write(rt1308->regmap, 0xc032, 0x26); + regmap_write(rt1308->regmap, 0xc040, 0x80); + regmap_write(rt1308->regmap, 0xc041, 0x80); + regmap_write(rt1308->regmap, 0xc042, 0x06); + regmap_write(rt1308->regmap, 0xc052, 0x0a); + regmap_write(rt1308->regmap, 0xc080, 0x0a); + regmap_write(rt1308->regmap, 0xc060, 0x02); + regmap_write(rt1308->regmap, 0xc061, 0x75); + regmap_write(rt1308->regmap, 0xc062, 0x05); + regmap_write(rt1308->regmap, 0xc171, 0x07); + regmap_write(rt1308->regmap, 0xc173, 0x0d); + regmap_write(rt1308->regmap, 0xc311, 0x7f); + regmap_write(rt1308->regmap, 0xc900, 0x90); + regmap_write(rt1308->regmap, 0xc1a0, 0x84); + regmap_write(rt1308->regmap, 0xc1a1, 0x01); + regmap_write(rt1308->regmap, 0xc360, 0x78); + regmap_write(rt1308->regmap, 0xc361, 0x87); + regmap_write(rt1308->regmap, 0xc0a1, 0x71); + regmap_write(rt1308->regmap, 0xc210, 0x00); + regmap_write(rt1308->regmap, 0xc070, 0x00); + regmap_write(rt1308->regmap, 0xc100, 0xaf); + regmap_write(rt1308->regmap, 0xc101, 0xaf); + regmap_write(rt1308->regmap, 0xc310, 0x24); + + /* Mark Slave initialization complete */ + rt1308->hw_init = true; + + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + + dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); + +_io_init_err_: + return ret; +} + +static int rt1308_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev); + + /* Update the status */ + rt1308->status = status; + + if (status == SDW_SLAVE_UNATTACHED) + rt1308->hw_init = false; + + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt1308->hw_init || rt1308->status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt1308_io_init(&slave->dev, slave); +} + +static int rt1308_bus_config(struct sdw_slave *slave, + struct sdw_bus_params *params) +{ + struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev); + int ret; + + memcpy(&rt1308->params, params, sizeof(*params)); + + ret = rt1308_clock_config(&slave->dev); + if (ret < 0) + dev_err(&slave->dev, "Invalid clk config"); + + return ret; +} + +static int rt1308_interrupt_callback(struct sdw_slave *slave, + struct sdw_slave_intr_status *status) +{ + dev_dbg(&slave->dev, + "%s control_port_stat=%x", __func__, status->control_port); + + return 0; +} + +static int rt1308_classd_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + msleep(30); + snd_soc_component_update_bits(component, + RT1308_SDW_OFFSET | (RT1308_POWER_STATUS << 4), + 0x3, 0x3); + msleep(40); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_component_update_bits(component, + RT1308_SDW_OFFSET | (RT1308_POWER_STATUS << 4), + 0x3, 0); + usleep_range(150000, 200000); + break; + + default: + break; + } + + return 0; +} + +static const char * const rt1308_rx_data_ch_select[] = { + "LR", + "LL", + "RL", + "RR", +}; + +static SOC_ENUM_SINGLE_DECL(rt1308_rx_data_ch_enum, + RT1308_SDW_OFFSET | (RT1308_DATA_PATH << 4), 0, + rt1308_rx_data_ch_select); + +static const struct snd_kcontrol_new rt1308_snd_controls[] = { + + /* I2S Data Channel Selection */ + SOC_ENUM("RX Channel Select", rt1308_rx_data_ch_enum), +}; + +static const struct snd_kcontrol_new rt1308_sto_dac_l = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", + RT1308_SDW_OFFSET_BYTE3 | (RT1308_DAC_SET << 4), + RT1308_DVOL_MUTE_L_EN_SFT, 1, 1); + +static const struct snd_kcontrol_new rt1308_sto_dac_r = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", + RT1308_SDW_OFFSET_BYTE3 | (RT1308_DAC_SET << 4), + RT1308_DVOL_MUTE_R_EN_SFT, 1, 1); + +static const struct snd_soc_dapm_widget rt1308_dapm_widgets[] = { + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0), + + /* Supply Widgets */ + SND_SOC_DAPM_SUPPLY("MBIAS20U", + RT1308_SDW_OFFSET | (RT1308_POWER << 4), 7, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ALDO", + RT1308_SDW_OFFSET | (RT1308_POWER << 4), 6, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DBG", + RT1308_SDW_OFFSET | (RT1308_POWER << 4), 5, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DACL", + RT1308_SDW_OFFSET | (RT1308_POWER << 4), 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CLK25M", + RT1308_SDW_OFFSET | (RT1308_POWER << 4), 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC_R", + RT1308_SDW_OFFSET | (RT1308_POWER << 4), 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC_L", + RT1308_SDW_OFFSET | (RT1308_POWER << 4), 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Power", + RT1308_SDW_OFFSET | (RT1308_POWER << 4), 3, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DLDO", + RT1308_SDW_OFFSET_BYTE1 | (RT1308_POWER << 4), 5, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("VREF", + RT1308_SDW_OFFSET_BYTE1 | (RT1308_POWER << 4), 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MIXER_R", + RT1308_SDW_OFFSET_BYTE1 | (RT1308_POWER << 4), 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MIXER_L", + RT1308_SDW_OFFSET_BYTE1 | (RT1308_POWER << 4), 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MBIAS4U", + RT1308_SDW_OFFSET_BYTE1 | (RT1308_POWER << 4), 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("PLL2_LDO", + RT1308_SDW_OFFSET_BYTE2 | (RT1308_POWER << 4), 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL2B", + RT1308_SDW_OFFSET_BYTE2 | (RT1308_POWER << 4), 3, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL2F", + RT1308_SDW_OFFSET_BYTE2 | (RT1308_POWER << 4), 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL2F2", + RT1308_SDW_OFFSET_BYTE2 | (RT1308_POWER << 4), 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL2B2", + RT1308_SDW_OFFSET_BYTE2 | (RT1308_POWER << 4), 0, 0, NULL, 0), + + /* Digital Interface */ + SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_SWITCH("DAC L", SND_SOC_NOPM, 0, 0, &rt1308_sto_dac_l), + SND_SOC_DAPM_SWITCH("DAC R", SND_SOC_NOPM, 0, 0, &rt1308_sto_dac_r), + + /* Output Lines */ + SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0, + rt1308_classd_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_OUTPUT("SPOL"), + SND_SOC_DAPM_OUTPUT("SPOR"), +}; + +static const struct snd_soc_dapm_route rt1308_dapm_routes[] = { + + { "DAC", NULL, "AIF1RX" }, + + { "DAC", NULL, "MBIAS20U" }, + { "DAC", NULL, "ALDO" }, + { "DAC", NULL, "DBG" }, + { "DAC", NULL, "DACL" }, + { "DAC", NULL, "CLK25M" }, + { "DAC", NULL, "ADC_R" }, + { "DAC", NULL, "ADC_L" }, + { "DAC", NULL, "DLDO" }, + { "DAC", NULL, "VREF" }, + { "DAC", NULL, "MIXER_R" }, + { "DAC", NULL, "MIXER_L" }, + { "DAC", NULL, "MBIAS4U" }, + { "DAC", NULL, "PLL2_LDO" }, + { "DAC", NULL, "PLL2B" }, + { "DAC", NULL, "PLL2F" }, + { "DAC", NULL, "PLL2F2" }, + { "DAC", NULL, "PLL2B2" }, + + { "DAC L", "Switch", "DAC" }, + { "DAC R", "Switch", "DAC" }, + { "DAC L", NULL, "DAC Power" }, + { "DAC R", NULL, "DAC Power" }, + + { "CLASS D", NULL, "DAC L" }, + { "CLASS D", NULL, "DAC R" }, + { "SPOL", NULL, "CLASS D" }, + { "SPOR", NULL, "CLASS D" }, +}; + +static int rt1308_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, + int direction) +{ + struct sdw_stream_data *stream; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; + + stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream; + + /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + dai->playback_dma_data = stream; + else + dai->capture_dma_data = stream; + + return 0; +} + +static void rt1308_sdw_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sdw_stream_data *stream; + + stream = snd_soc_dai_get_dma_data(dai, substream); + snd_soc_dai_set_dma_data(dai, substream, NULL); + kfree(stream); +} + +static int rt1308_sdw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt1308_sdw_priv *rt1308 = + snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; + enum sdw_data_direction direction; + struct sdw_stream_data *stream; + int retval, port, num_channels; + + dev_dbg(dai->dev, "%s %s", __func__, dai->name); + stream = snd_soc_dai_get_dma_data(dai, substream); + + if (!stream) + return -EINVAL; + + if (!rt1308->sdw_slave) + return -EINVAL; + + /* SoundWire specific configuration */ + /* port 1 for playback */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + direction = SDW_DATA_DIR_RX; + port = 1; + } else { + return -EINVAL; + } + + stream_config.frame_rate = params_rate(params); + stream_config.ch_count = params_channels(params); + stream_config.bps = snd_pcm_format_width(params_format(params)); + stream_config.direction = direction; + + num_channels = params_channels(params); + port_config.ch_mask = (1 << (num_channels)) - 1; + port_config.num = port; + + retval = sdw_stream_add_slave(rt1308->sdw_slave, &stream_config, + &port_config, 1, stream->sdw_stream); + if (retval) { + dev_err(dai->dev, "Unable to configure port\n"); + return retval; + } + + return retval; +} + +static int rt1308_sdw_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt1308_sdw_priv *rt1308 = + snd_soc_component_get_drvdata(component); + struct sdw_stream_data *stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt1308->sdw_slave) + return -EINVAL; + + sdw_stream_remove_slave(rt1308->sdw_slave, stream->sdw_stream); + return 0; +} + +/* + * slave_ops: callbacks for get_clock_stop_mode, clock_stop and + * port_prep are not defined for now + */ +static struct sdw_slave_ops rt1308_slave_ops = { + .read_prop = rt1308_read_prop, + .interrupt_callback = rt1308_interrupt_callback, + .update_status = rt1308_update_status, + .bus_config = rt1308_bus_config, +}; + +static const struct snd_soc_component_driver soc_component_sdw_rt1308 = { + .controls = rt1308_snd_controls, + .num_controls = ARRAY_SIZE(rt1308_snd_controls), + .dapm_widgets = rt1308_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt1308_dapm_widgets), + .dapm_routes = rt1308_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt1308_dapm_routes), +}; + +static const struct snd_soc_dai_ops rt1308_aif_dai_ops = { + .hw_params = rt1308_sdw_hw_params, + .hw_free = rt1308_sdw_pcm_hw_free, + .set_sdw_stream = rt1308_set_sdw_stream, + .shutdown = rt1308_sdw_shutdown, +}; + +#define RT1308_STEREO_RATES SNDRV_PCM_RATE_48000 +#define RT1308_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_driver rt1308_sdw_dai[] = { + { + .name = "rt1308-aif", + .playback = { + .stream_name = "DP1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT1308_STEREO_RATES, + .formats = RT1308_FORMATS, + }, + .ops = &rt1308_aif_dai_ops, + }, +}; + +static int rt1308_sdw_init(struct device *dev, struct regmap *regmap, + struct sdw_slave *slave) +{ + struct rt1308_sdw_priv *rt1308; + int ret; + + rt1308 = devm_kzalloc(dev, sizeof(*rt1308), GFP_KERNEL); + if (!rt1308) + return -ENOMEM; + + dev_set_drvdata(dev, rt1308); + rt1308->sdw_slave = slave; + rt1308->regmap = regmap; + + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt1308->hw_init = false; + rt1308->first_init = false; + + ret = devm_snd_soc_register_component(dev, + &soc_component_sdw_rt1308, + rt1308_sdw_dai, + ARRAY_SIZE(rt1308_sdw_dai)); + + dev_dbg(&slave->dev, "%s\n", __func__); + + return ret; +} + +static int rt1308_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *regmap; + + /* Assign ops */ + slave->ops = &rt1308_slave_ops; + + /* Regmap Initialization */ + regmap = devm_regmap_init_sdw(slave, &rt1308_sdw_regmap); + if (!regmap) + return -EINVAL; + + rt1308_sdw_init(&slave->dev, regmap, slave); + + return 0; +} + +static const struct sdw_device_id rt1308_id[] = { + SDW_SLAVE_ENTRY(0x025d, 0x1308, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt1308_id); + +static int rt1308_dev_suspend(struct device *dev) +{ + struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev); + + if (!rt1308->hw_init) + return 0; + + regcache_cache_only(rt1308->regmap, true); + + return 0; +} + +#define RT1308_PROBE_TIMEOUT 2000 + +static int rt1308_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = to_sdw_slave_device(dev); + struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev); + unsigned long time; + + if (!rt1308->hw_init) + return 0; + + time = wait_for_completion_timeout(&slave->enumeration_complete, + msecs_to_jiffies(RT1308_PROBE_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "Enumeration not complete, timed out\n"); + return -ETIMEDOUT; + } + + regcache_cache_only(rt1308->regmap, false); + regcache_sync_region(rt1308->regmap, 0xc000, 0xcfff); + + return 0; +} + +static const struct dev_pm_ops rt1308_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt1308_dev_suspend, rt1308_dev_resume) + SET_RUNTIME_PM_OPS(rt1308_dev_suspend, rt1308_dev_resume, NULL) +}; + +static struct sdw_driver rt1308_sdw_driver = { + .driver = { + .name = "rt1308", + .owner = THIS_MODULE, + .pm = &rt1308_pm, + }, + .probe = rt1308_sdw_probe, + .ops = &rt1308_slave_ops, + .id_table = rt1308_id, +}; +module_sdw_driver(rt1308_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT1308 driver SDW"); +MODULE_AUTHOR("Shuming Fan "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt1308-sdw.h b/sound/soc/codecs/rt1308-sdw.h new file mode 100644 index 00000000000000..e83440be32f240 --- /dev/null +++ b/sound/soc/codecs/rt1308-sdw.h @@ -0,0 +1,169 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * rt1308-sdw.h -- RT1308 ALSA SoC audio driver header + * + * Copyright(c) 2019 Realtek Semiconductor Corp. + */ + +#ifndef __RT1308_SDW_H__ +#define __RT1308_SDW_H__ + +static const struct reg_default rt1308_reg_defaults[] = { + { 0x0000, 0x00 }, + { 0x0001, 0x00 }, + { 0x0002, 0x00 }, + { 0x0003, 0x00 }, + { 0x0004, 0x00 }, + { 0x0005, 0x01 }, + { 0x0020, 0x00 }, + { 0x0022, 0x00 }, + { 0x0023, 0x00 }, + { 0x0024, 0x00 }, + { 0x0025, 0x00 }, + { 0x0026, 0x00 }, + { 0x0030, 0x00 }, + { 0x0032, 0x00 }, + { 0x0033, 0x00 }, + { 0x0034, 0x00 }, + { 0x0035, 0x00 }, + { 0x0036, 0x00 }, + { 0x0040, 0x00 }, + { 0x0041, 0x00 }, + { 0x0042, 0x00 }, + { 0x0043, 0x00 }, + { 0x0044, 0x20 }, + { 0x0045, 0x01 }, + { 0x0046, 0x01 }, + { 0x0048, 0x00 }, + { 0x0049, 0x00 }, + { 0x0050, 0x20 }, + { 0x0051, 0x02 }, + { 0x0052, 0x5D }, + { 0x0053, 0x13 }, + { 0x0054, 0x08 }, + { 0x0055, 0x00 }, + { 0x0060, 0x00 }, + { 0x0070, 0x00 }, + { 0x00E0, 0x00 }, + { 0x00F0, 0x00 }, + { 0x0100, 0x00 }, + { 0x0101, 0x00 }, + { 0x0102, 0x20 }, + { 0x0103, 0x00 }, + { 0x0104, 0x00 }, + { 0x0105, 0x03 }, + { 0x0120, 0x00 }, + { 0x0122, 0x00 }, + { 0x0123, 0x00 }, + { 0x0124, 0x00 }, + { 0x0125, 0x00 }, + { 0x0126, 0x00 }, + { 0x0127, 0x00 }, + { 0x0130, 0x00 }, + { 0x0132, 0x00 }, + { 0x0133, 0x00 }, + { 0x0134, 0x00 }, + { 0x0135, 0x00 }, + { 0x0136, 0x00 }, + { 0x0137, 0x00 }, + { 0x0200, 0x00 }, + { 0x0201, 0x00 }, + { 0x0202, 0x00 }, + { 0x0203, 0x00 }, + { 0x0204, 0x00 }, + { 0x0205, 0x03 }, + { 0x0220, 0x00 }, + { 0x0222, 0x00 }, + { 0x0223, 0x00 }, + { 0x0224, 0x00 }, + { 0x0225, 0x00 }, + { 0x0226, 0x00 }, + { 0x0227, 0x00 }, + { 0x0230, 0x00 }, + { 0x0232, 0x00 }, + { 0x0233, 0x00 }, + { 0x0234, 0x00 }, + { 0x0235, 0x00 }, + { 0x0236, 0x00 }, + { 0x0237, 0x00 }, + { 0x0400, 0x00 }, + { 0x0401, 0x00 }, + { 0x0402, 0x00 }, + { 0x0403, 0x00 }, + { 0x0404, 0x00 }, + { 0x0405, 0x03 }, + { 0x0420, 0x00 }, + { 0x0422, 0x00 }, + { 0x0423, 0x00 }, + { 0x0424, 0x00 }, + { 0x0425, 0x00 }, + { 0x0426, 0x00 }, + { 0x0427, 0x00 }, + { 0x0430, 0x00 }, + { 0x0432, 0x00 }, + { 0x0433, 0x00 }, + { 0x0434, 0x00 }, + { 0x0435, 0x00 }, + { 0x0436, 0x00 }, + { 0x0437, 0x00 }, + { 0x0f00, 0x00 }, + { 0x0f01, 0x00 }, + { 0x0f02, 0x00 }, + { 0x0f03, 0x00 }, + { 0x0f04, 0x00 }, + { 0x0f05, 0x00 }, + { 0x0f20, 0x00 }, + { 0x0f22, 0x00 }, + { 0x0f23, 0x00 }, + { 0x0f24, 0x00 }, + { 0x0f25, 0x00 }, + { 0x0f26, 0x00 }, + { 0x0f27, 0x00 }, + { 0x0f30, 0x00 }, + { 0x0f32, 0x00 }, + { 0x0f33, 0x00 }, + { 0x0f34, 0x00 }, + { 0x0f35, 0x00 }, + { 0x0f36, 0x00 }, + { 0x0f37, 0x00 }, + { 0x2f01, 0x01 }, + { 0x2f02, 0x09 }, + { 0x2f03, 0x00 }, + { 0x2f04, 0x0f }, + { 0x2f05, 0x0b }, + { 0x2f06, 0x01 }, + { 0x2f07, 0x8e }, + { 0x3000, 0x00 }, + { 0x3001, 0x00 }, + { 0x3004, 0x01 }, + { 0x3005, 0x23 }, + { 0x3008, 0x02 }, + { 0x300a, 0x00 }, + { 0xc003 | (RT1308_DAC_SET << 4), 0x00 }, + { 0xc001 | (RT1308_POWER << 4), 0x00 }, + { 0xc002 | (RT1308_POWER << 4), 0x00 }, +}; + +#define RT1308_SDW_OFFSET 0xc000 +#define RT1308_SDW_OFFSET_BYTE0 0xc000 +#define RT1308_SDW_OFFSET_BYTE1 0xc001 +#define RT1308_SDW_OFFSET_BYTE2 0xc002 +#define RT1308_SDW_OFFSET_BYTE3 0xc003 + +#define RT1308_SDW_RESET (RT1308_SDW_OFFSET | (RT1308_RESET << 4)) + +struct rt1308_sdw_priv { + struct snd_soc_component *component; + struct regmap *regmap; + struct sdw_slave *sdw_slave; + enum sdw_slave_status status; + struct sdw_bus_params params; + bool hw_init; + bool first_init; +}; + +struct sdw_stream_data { + struct sdw_stream_runtime *sdw_stream; +}; + +#endif /* __RT1308_SDW_H__ */ diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c index b75931a69a1cc0..462fd668753bd6 100644 --- a/sound/soc/codecs/rt1308.c +++ b/sound/soc/codecs/rt1308.c @@ -1,10 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 -// -// rt1308.c -- RT1308 ALSA SoC amplifier component driver -// -// Copyright 2019 Realtek Semiconductor Corp. -// Author: Derek Fang -// +/* + * rt1308.c -- RT1308 ALSA SoC amplifier component driver + * + * Copyright 2019 Realtek Semiconductor Corp. + * Author: Derek Fang + * + */ #include #include From cde9fc3f92947f1f1c6ddc39f9842604123a5456 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 15 Aug 2019 10:49:56 +0800 Subject: [PATCH 1836/1995] ASoC: codecs: rt711: add SoundWire support The driver for this codec was tested by Realtek and Intel using the Realtek 3-in-1 add-on board connected to CometLake and IceLake platforms. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Shuming Fan --- sound/soc/codecs/Kconfig | 9 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt711-sdw.c | 528 +++++++++++++++ sound/soc/codecs/rt711-sdw.h | 279 ++++++++ sound/soc/codecs/rt711.c | 1225 ++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt711.h | 212 ++++++ 6 files changed, 2255 insertions(+) create mode 100644 sound/soc/codecs/rt711-sdw.c create mode 100644 sound/soc/codecs/rt711-sdw.h create mode 100644 sound/soc/codecs/rt711.c create mode 100644 sound/soc/codecs/rt711.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index aea61b6ede1b07..c2dd6eb7c7f3ab 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1073,6 +1073,15 @@ config SND_SOC_RT1308_SDW select SND_SOC_RT1308 select REGMAP_SOUNDWIRE +config SND_SOC_RT711 + tristate + +config SND_SOC_RT711_SDW + tristate "Realtek RT711 Codec - SDW" + depends on SOUNDWIRE + select SND_SOC_RT711 + select REGMAP_SOUNDWIRE + #Freescale sgtl5000 codec config SND_SOC_SGTL5000 tristate "Freescale SGTL5000 CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 653c7d9e94e638..b64a387a14d641 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -281,6 +281,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o snd-soc-zx-aud96p22-objs := zx_aud96p22.o snd-soc-rt700-objs := rt700.o rt700-sdw.o snd-soc-rt1308-sdw-objs := rt1308-sdw.o +snd-soc-rt711-objs := rt711.o rt711-sdw.o # Amp snd-soc-max9877-objs := max9877.o @@ -574,6 +575,7 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.o obj-$(CONFIG_SND_SOC_RT700) += snd-soc-rt700.o obj-$(CONFIG_SND_SOC_RT1308_SDW) += snd-soc-rt1308-sdw.o +obj-$(CONFIG_SND_SOC_RT711) += snd-soc-rt711.o # Amp obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c new file mode 100644 index 00000000000000..b044d12a515dd2 --- /dev/null +++ b/sound/soc/codecs/rt711-sdw.c @@ -0,0 +1,528 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// rt711-sdw.c -- rt711 ALSA SoC audio driver +// +// Copyright(c) 2019 Realtek Semiconductor Corp. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rt711.h" +#include "rt711-sdw.h" + +static bool rt711_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x00e0: + case 0x00f0: + case 0x2012 ... 0x2016: + case 0x201a ... 0x2027: + case 0x2029 ... 0x202a: + case 0x202d ... 0x2034: + case 0x2201 ... 0x2204: + case 0x2206 ... 0x2212: + case 0x2220 ... 0x2223: + case 0x2230 ... 0x2239: + case 0x2f01 ... 0x2f0f: + case 0x3000 ... 0x3fff: + case 0x7000 ... 0x7fff: + case 0x8300 ... 0x83ff: + case 0x9c00 ... 0x9cff: + case 0xb900 ... 0xb9ff: + case 0x7520001a: + case 0x75200045: + case 0x75200046: + case 0x75200048: + case 0x7520004a: + case 0x7520006b: + case 0x7520006f: + case 0x75200080: + case 0x75200081: + case 0x75200091: + case 0x75580000: + return true; + default: + return false; + } +} + +static bool rt711_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x2016: + case 0x201b: + case 0x201c: + case 0x201d: + case 0x201f: + case 0x2021: + case 0x2023: + case 0x2230: + case 0x2012 ... 0x2015: /* HD-A read */ + case 0x202d ... 0x202f: /* BRA */ + case 0x2201 ... 0x2212: /* i2c debug */ + case 0x2220 ... 0x2223: /* decoded HD-A */ + case 0x9c00 ... 0x9cff: + case 0xb900 ... 0xb9ff: + case 0xff01: + case 0x7520001a: + case 0x75200046: + case 0x75200080: + case 0x75200081: + case 0x75580000: + return true; + default: + return false; + } +} + +static int rt711_sdw_read(void *context, unsigned int reg, unsigned int *val) +{ + struct device *dev = context; + struct rt711_priv *rt711 = dev_get_drvdata(dev); + unsigned int sdw_data_3, sdw_data_2, sdw_data_1, sdw_data_0; + unsigned int reg2 = 0, reg3 = 0, reg4 = 0, mask, nid, val2; + unsigned int is_hda_reg = 1, is_index_reg = 0; + int ret; + + if (reg > 0xffff) + is_index_reg = 1; + + mask = reg & 0xf000; + + if (is_index_reg) { /* index registers */ + val2 = reg & 0xffff; + reg = reg >> 16; + nid = reg & 0xff; + ret = regmap_write(rt711->sdw_regmap, reg, ((val2 >> 8) & 0xff)); + if (ret < 0) + return ret; + reg2 = reg + 0x1000; + reg2 |= 0x80; + ret = regmap_write(rt711->sdw_regmap, reg2, (val2 & 0xff)); + if (ret < 0) + return ret; + + reg3 = RT711_PRIV_DATA_R_H | nid; + ret = regmap_write(rt711->sdw_regmap, reg3, ((*val >> 8) & 0xff)); + if (ret < 0) + return ret; + reg4 = reg3 + 0x1000; + reg4 |= 0x80; + ret = regmap_write(rt711->sdw_regmap, reg4, (*val & 0xff)); + if (ret < 0) + return ret; + } else if (mask == 0x3000) { + reg += 0x8000; + ret = regmap_write(rt711->sdw_regmap, reg, *val); + if (ret < 0) + return ret; + } else if (mask == 0x7000) { + reg += 0x2000; + reg |= 0x800; + ret = regmap_write(rt711->sdw_regmap, reg, ((*val >> 8) & 0xff)); + if (ret < 0) + return ret; + reg2 = reg + 0x1000; + reg2 |= 0x80; + ret = regmap_write(rt711->sdw_regmap, reg2, (*val & 0xff)); + if (ret < 0) + return ret; + } else if ((reg & 0xff00) == 0x8300) { /* for R channel */ + reg2 = reg - 0x1000; + reg2 &= ~0x80; + ret = regmap_write(rt711->sdw_regmap, reg2, ((*val >> 8) & 0xff)); + if (ret < 0) + return ret; + ret = regmap_write(rt711->sdw_regmap, reg, (*val & 0xff)); + if (ret < 0) + return ret; + } else if (mask == 0x9000) { + ret = regmap_write(rt711->sdw_regmap, reg, ((*val >> 8) & 0xff)); + if (ret < 0) + return ret; + reg2 = reg + 0x1000; + reg2 |= 0x80; + ret = regmap_write(rt711->sdw_regmap, reg2, (*val & 0xff)); + if (ret < 0) + return ret; + } else if (mask == 0xb000) { + ret = regmap_write(rt711->sdw_regmap, reg, *val); + if (ret < 0) + return ret; + } else { + ret = regmap_read(rt711->sdw_regmap, reg, val); + if (ret < 0) + return ret; + is_hda_reg = 0; + } + + if (is_hda_reg || is_index_reg) { + sdw_data_3 = 0; + sdw_data_2 = 0; + sdw_data_1 = 0; + sdw_data_0 = 0; + ret = regmap_read(rt711->sdw_regmap, RT711_READ_HDA_3, &sdw_data_3); + if (ret < 0) + return ret; + ret = regmap_read(rt711->sdw_regmap, RT711_READ_HDA_2, &sdw_data_2); + if (ret < 0) + return ret; + ret = regmap_read(rt711->sdw_regmap, RT711_READ_HDA_1, &sdw_data_1); + if (ret < 0) + return ret; + ret = regmap_read(rt711->sdw_regmap, RT711_READ_HDA_0, &sdw_data_0); + if (ret < 0) + return ret; + *val = ((sdw_data_3 & 0xff) << 24) | ((sdw_data_2 & 0xff) << 16) | + ((sdw_data_1 & 0xff) << 8) | (sdw_data_0 & 0xff); + } + + if (is_hda_reg == 0) + dev_dbg(dev, "[%s] %04x => %08x\n", __func__, reg, *val); + else if (is_index_reg) + dev_dbg(dev, "[%s] %04x %04x %04x %04x => %08x\n", __func__, + reg, reg2, reg3, reg4, *val); + else + dev_dbg(dev, "[%s] %04x %04x => %08x\n", __func__, reg, reg2, *val); + + return 0; +} + +static int rt711_sdw_write(void *context, unsigned int reg, unsigned int val) +{ + struct device *dev = context; + struct rt711_priv *rt711 = dev_get_drvdata(dev); + unsigned int reg2 = 0, reg3, reg4, nid, mask, val2; + unsigned int is_index_reg = 0; + int ret; + + if (reg > 0xffff) + is_index_reg = 1; + + mask = reg & 0xf000; + + if (is_index_reg) { /* index registers */ + val2 = reg & 0xffff; + reg = reg >> 16; + nid = reg & 0xff; + ret = regmap_write(rt711->sdw_regmap, reg, ((val2 >> 8) & 0xff)); + if (ret < 0) + return ret; + reg2 = reg + 0x1000; + reg2 |= 0x80; + ret = regmap_write(rt711->sdw_regmap, reg2, (val2 & 0xff)); + if (ret < 0) + return ret; + + reg3 = RT711_PRIV_DATA_W_H | nid; + ret = regmap_write(rt711->sdw_regmap, reg3, ((val >> 8) & 0xff)); + if (ret < 0) + return ret; + reg4 = reg3 + 0x1000; + reg4 |= 0x80; + ret = regmap_write(rt711->sdw_regmap, reg4, (val & 0xff)); + if (ret < 0) + return ret; + is_index_reg = 1; + } else if (reg < 0x4fff) { + ret = regmap_write(rt711->sdw_regmap, reg, val); + if (ret < 0) + return ret; + } else if (reg == RT711_FUNC_RESET) { + ret = regmap_write(rt711->sdw_regmap, reg, val); + if (ret < 0) + return ret; + } else if (mask == 0x7000) { + ret = regmap_write(rt711->sdw_regmap, reg, ((val >> 8) & 0xff)); + if (ret < 0) + return ret; + reg2 = reg + 0x1000; + reg2 |= 0x80; + ret = regmap_write(rt711->sdw_regmap, reg2, (val & 0xff)); + if (ret < 0) + return ret; + } else if ((reg & 0xff00) == 0x8300) { /* for R channel */ + reg2 = reg - 0x1000; + reg2 &= ~0x80; + ret = regmap_write(rt711->sdw_regmap, reg2, ((val >> 8) & 0xff)); + if (ret < 0) + return ret; + ret = regmap_write(rt711->sdw_regmap, reg, (val & 0xff)); + if (ret < 0) + return ret; + } + + if (reg2 == 0) + dev_dbg(dev, "[%s] %04x <= %04x\n", __func__, reg, val); + else if (is_index_reg) + dev_dbg(dev, "[%s] %04x %04x %04x %04x <= %04x %04x\n", __func__, + reg, reg2, reg3, reg4, val2, val); + else + dev_dbg(dev, "[%s] %04x %04x <= %04x\n", __func__, reg, reg2, val); + + return 0; +} + +static const struct regmap_config rt711_regmap = { + .reg_bits = 32, + .val_bits = 32, + .readable_reg = rt711_readable_register, /* Readable registers */ + .volatile_reg = rt711_volatile_register, /* volatile register */ + .max_register = 0x75580000, /* Maximum number of register */ + .reg_defaults = rt711_reg_defaults, /* Defaults */ + .num_reg_defaults = ARRAY_SIZE(rt711_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, + .reg_read = rt711_sdw_read, + .reg_write = rt711_sdw_write, +}; + +static const struct regmap_config rt711_sdw_regmap = { + .name = "sdw", + .reg_bits = 32, /* Total register space for SDW */ + .val_bits = 8, /* Total number of bits in register */ + .readable_reg = rt711_readable_register, /* Readable registers */ + .max_register = 0xff01, /* Maximum number of register */ + .cache_type = REGCACHE_NONE, + .use_single_read = true, + .use_single_write = true, +}; + +static int rt711_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev); + + /* Update the status */ + rt711->status = status; + + if (status == SDW_SLAVE_UNATTACHED) + rt711->hw_init = false; + + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt711->hw_init || rt711->status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt711_io_init(&slave->dev, slave); +} + +static int rt711_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int nval, i, num_of_ports = 1; + u32 bit; + unsigned long addr; + struct sdw_dpn_prop *dpn; + + prop->paging_support = false; + + /* first we need to allocate memory for set bits in port lists */ + prop->source_ports = 0x14; /* BITMAP: 00010100 */ + prop->sink_ports = 0x8; /* BITMAP: 00001000 */ + + nval = hweight32(prop->source_ports); + num_of_ports += nval; + prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->src_dpn_prop), + GFP_KERNEL); + if (!prop->src_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->src_dpn_prop; + addr = prop->source_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].type = SDW_DPN_FULL; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* do this again for sink now */ + nval = hweight32(prop->sink_ports); + num_of_ports += nval; + prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->sink_dpn_prop), + GFP_KERNEL); + if (!prop->sink_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->sink_dpn_prop; + addr = prop->sink_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].type = SDW_DPN_FULL; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* Allocate port_ready based on num_of_ports */ + slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports, + sizeof(*slave->port_ready), + GFP_KERNEL); + if (!slave->port_ready) + return -ENOMEM; + + /* Initialize completion */ + for (i = 0; i < num_of_ports; i++) + init_completion(&slave->port_ready[i]); + + /* set the timeout values */ + prop->clk_stop_timeout = 20; + + return 0; +} + +static int rt711_bus_config(struct sdw_slave *slave, + struct sdw_bus_params *params) +{ + struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev); + int ret; + + memcpy(&rt711->params, params, sizeof(*params)); + + ret = rt711_clock_config(&slave->dev); + if (ret < 0) + dev_err(&slave->dev, "Invalid clk config"); + + return ret; +} + +static int rt711_interrupt_callback(struct sdw_slave *slave, + struct sdw_slave_intr_status *status) +{ + struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev); + + dev_dbg(&slave->dev, + "%s control_port_stat=%x", __func__, status->control_port); + + if (status->control_port & 0x4) { + mod_delayed_work(system_power_efficient_wq, + &rt711->jack_detect_work, msecs_to_jiffies(250)); + } + + return 0; +} + +static struct sdw_slave_ops rt711_slave_ops = { + .read_prop = rt711_read_prop, + .interrupt_callback = rt711_interrupt_callback, + .update_status = rt711_update_status, + .bus_config = rt711_bus_config, +}; + +static int rt711_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *sdw_regmap, *regmap; + + /* Assign ops */ + slave->ops = &rt711_slave_ops; + + /* Regmap Initialization */ + sdw_regmap = devm_regmap_init_sdw(slave, &rt711_sdw_regmap); + if (!sdw_regmap) + return -EINVAL; + + regmap = devm_regmap_init(&slave->dev, NULL, &slave->dev, &rt711_regmap); + if (!regmap) + return -EINVAL; + + rt711_init(&slave->dev, sdw_regmap, regmap, slave); + + return 0; +} + +static int rt711_sdw_remove(struct sdw_slave *slave) +{ + struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev); + + if (rt711 && rt711->hw_init) { + cancel_delayed_work(&rt711->jack_detect_work); + cancel_delayed_work(&rt711->jack_btn_check_work); + cancel_work_sync(&rt711->calibration_work); + } + + return 0; +} + +static const struct sdw_device_id rt711_id[] = { + SDW_SLAVE_ENTRY(0x025d, 0x711, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt711_id); + +static int rt711_dev_suspend(struct device *dev) +{ + struct rt711_priv *rt711 = dev_get_drvdata(dev); + + if (!rt711->hw_init) + return 0; + + regcache_cache_only(rt711->regmap, true); + + return 0; +} + +#define RT711_PROBE_TIMEOUT 2000 + +static int rt711_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = to_sdw_slave_device(dev); + struct rt711_priv *rt711 = dev_get_drvdata(dev); + unsigned long time; + + if (!rt711->hw_init) + return 0; + + time = wait_for_completion_timeout(&slave->enumeration_complete, + msecs_to_jiffies(RT711_PROBE_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "Enumeration not complete, timed out\n"); + return -ETIMEDOUT; + } + + regcache_cache_only(rt711->regmap, false); + regcache_sync_region(rt711->regmap, 0x3000, 0x8fff); + regcache_sync_region(rt711->regmap, 0x75200010, 0x75200091); + + return 0; +} + +static const struct dev_pm_ops rt711_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt711_dev_suspend, rt711_dev_resume) + SET_RUNTIME_PM_OPS(rt711_dev_suspend, rt711_dev_resume, NULL) +}; + +static struct sdw_driver rt711_sdw_driver = { + .driver = { + .name = "rt711", + .owner = THIS_MODULE, + .pm = &rt711_pm, + }, + .probe = rt711_sdw_probe, + .remove = rt711_sdw_remove, + .ops = &rt711_slave_ops, + .id_table = rt711_id, +}; +module_sdw_driver(rt711_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT711 SDW driver"); +MODULE_AUTHOR("Shuming Fan "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt711-sdw.h b/sound/soc/codecs/rt711-sdw.h new file mode 100644 index 00000000000000..7d0a2a3c699470 --- /dev/null +++ b/sound/soc/codecs/rt711-sdw.h @@ -0,0 +1,279 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * rt711-sdw.h -- RT711 ALSA SoC audio driver header + * + * Copyright(c) 2019 Realtek Semiconductor Corp. + */ + +#ifndef __RT711_SDW_H__ +#define __RT711_SDW_H__ + +static const struct reg_default rt711_reg_defaults[] = { + { 0x0000, 0x00 }, + { 0x0001, 0x00 }, + { 0x0002, 0x00 }, + { 0x0003, 0x00 }, + { 0x0004, 0x00 }, + { 0x0005, 0x01 }, + { 0x0020, 0x00 }, + { 0x0022, 0x00 }, + { 0x0023, 0x00 }, + { 0x0024, 0x00 }, + { 0x0025, 0x00 }, + { 0x0026, 0x00 }, + { 0x0030, 0x00 }, + { 0x0032, 0x00 }, + { 0x0033, 0x00 }, + { 0x0034, 0x00 }, + { 0x0035, 0x00 }, + { 0x0036, 0x00 }, + { 0x0040, 0x00 }, + { 0x0041, 0x00 }, + { 0x0042, 0x00 }, + { 0x0043, 0x00 }, + { 0x0044, 0x20 }, + { 0x0045, 0x01 }, + { 0x0046, 0x01 }, + { 0x0050, 0x20 }, + { 0x0051, 0x02 }, + { 0x0052, 0x5d }, + { 0x0053, 0x07 }, + { 0x0054, 0x11 }, + { 0x0055, 0x00 }, + { 0x0060, 0x00 }, + { 0x0070, 0x00 }, + { 0x0080, 0xc0 }, + { 0x0088, 0x00 }, + { 0x00e0, 0x00 }, + { 0x00e1, 0x00 }, + { 0x00e2, 0x00 }, + { 0x00e3, 0x00 }, + { 0x00e5, 0x00 }, + { 0x00ee, 0x00 }, + { 0x00ef, 0x00 }, + { 0x00f0, 0x00 }, + { 0x00f1, 0x00 }, + { 0x00f2, 0x00 }, + { 0x00f3, 0x00 }, + { 0x00f4, 0x00 }, + { 0x00f5, 0x00 }, + { 0x00fe, 0x00 }, + { 0x00ff, 0x00 }, + { 0x0100, 0x00 }, + { 0x0101, 0x00 }, + { 0x0102, 0x00 }, + { 0x0103, 0x00 }, + { 0x0104, 0x00 }, + { 0x0105, 0x00 }, + { 0x0120, 0x00 }, + { 0x0122, 0x00 }, + { 0x0123, 0x00 }, + { 0x0124, 0x00 }, + { 0x0125, 0x00 }, + { 0x0126, 0x00 }, + { 0x0127, 0x00 }, + { 0x0130, 0x00 }, + { 0x0132, 0x00 }, + { 0x0133, 0x00 }, + { 0x0134, 0x00 }, + { 0x0135, 0x00 }, + { 0x0136, 0x00 }, + { 0x0137, 0x00 }, + { 0x0200, 0x00 }, + { 0x0201, 0x00 }, + { 0x0202, 0x00 }, + { 0x0203, 0x00 }, + { 0x0204, 0x00 }, + { 0x0205, 0x03 }, + { 0x0220, 0x00 }, + { 0x0222, 0x00 }, + { 0x0223, 0x00 }, + { 0x0224, 0x00 }, + { 0x0225, 0x00 }, + { 0x0226, 0x00 }, + { 0x0227, 0x00 }, + { 0x0230, 0x00 }, + { 0x0232, 0x00 }, + { 0x0233, 0x00 }, + { 0x0234, 0x00 }, + { 0x0235, 0x00 }, + { 0x0236, 0x00 }, + { 0x0237, 0x00 }, + { 0x0300, 0x00 }, + { 0x0301, 0x00 }, + { 0x0302, 0x20 }, + { 0x0303, 0x00 }, + { 0x0304, 0x00 }, + { 0x0305, 0x03 }, + { 0x0320, 0x00 }, + { 0x0322, 0x00 }, + { 0x0323, 0x00 }, + { 0x0324, 0x00 }, + { 0x0325, 0x00 }, + { 0x0326, 0x00 }, + { 0x0327, 0x00 }, + { 0x0330, 0x00 }, + { 0x0332, 0x00 }, + { 0x0333, 0x00 }, + { 0x0334, 0x00 }, + { 0x0335, 0x00 }, + { 0x0336, 0x00 }, + { 0x0337, 0x00 }, + { 0x0400, 0x00 }, + { 0x0401, 0x00 }, + { 0x0402, 0x00 }, + { 0x0403, 0x00 }, + { 0x0404, 0x00 }, + { 0x0405, 0x03 }, + { 0x0420, 0x00 }, + { 0x0422, 0x00 }, + { 0x0423, 0x00 }, + { 0x0424, 0x00 }, + { 0x0425, 0x00 }, + { 0x0426, 0x00 }, + { 0x0427, 0x00 }, + { 0x0430, 0x00 }, + { 0x0432, 0x00 }, + { 0x0433, 0x00 }, + { 0x0434, 0x00 }, + { 0x0435, 0x00 }, + { 0x0436, 0x00 }, + { 0x0437, 0x00 }, + { 0x0f00, 0x00 }, + { 0x0f01, 0x00 }, + { 0x0f02, 0x20 }, + { 0x0f03, 0x00 }, + { 0x0f04, 0x00 }, + { 0x0f05, 0x03 }, + { 0x0f06, 0x00 }, + { 0x0f07, 0x00 }, + { 0x0f08, 0x00 }, + { 0x0f09, 0x00 }, + { 0x0f10, 0x00 }, + { 0x0f11, 0x00 }, + { 0x0f12, 0x00 }, + { 0x0f13, 0x00 }, + { 0x0f14, 0x00 }, + { 0x0f15, 0x00 }, + { 0x0f16, 0x00 }, + { 0x0f17, 0x00 }, + { 0x0f18, 0x00 }, + { 0x0f19, 0x00 }, + { 0x0f1a, 0x00 }, + { 0x0f1b, 0x00 }, + { 0x0f1c, 0x00 }, + { 0x0f1d, 0x00 }, + { 0x0f1e, 0x00 }, + { 0x0f1f, 0x00 }, + { 0x0f20, 0x00 }, + { 0x0f22, 0x00 }, + { 0x0f23, 0x00 }, + { 0x0f24, 0x00 }, + { 0x0f25, 0x00 }, + { 0x0f26, 0x00 }, + { 0x0f27, 0x00 }, + { 0x0f30, 0x00 }, + { 0x0f32, 0x00 }, + { 0x0f33, 0x00 }, + { 0x0f34, 0x00 }, + { 0x0f35, 0x00 }, + { 0x0f36, 0x00 }, + { 0x0f37, 0x00 }, + { 0x2012, 0x00 }, + { 0x2013, 0x00 }, + { 0x2014, 0x00 }, + { 0x2015, 0x00 }, + { 0x2016, 0x00 }, + { 0x201a, 0x00 }, + { 0x201b, 0x00 }, + { 0x201c, 0x0c }, + { 0x201d, 0x00 }, + { 0x201e, 0x00 }, + { 0x201f, 0x00 }, + { 0x2020, 0x00 }, + { 0x2021, 0x00 }, + { 0x2022, 0x00 }, + { 0x2023, 0x00 }, + { 0x2024, 0x00 }, + { 0x2025, 0x01 }, + { 0x2026, 0x00 }, + { 0x2027, 0x00 }, + { 0x2029, 0x00 }, + { 0x202a, 0x00 }, + { 0x202d, 0x00 }, + { 0x202e, 0x00 }, + { 0x202f, 0x00 }, + { 0x2030, 0x00 }, + { 0x2031, 0x00 }, + { 0x2032, 0x00 }, + { 0x2033, 0x00 }, + { 0x2034, 0x00 }, + { 0x2201, 0xc7 }, + { 0x2202, 0x0c }, + { 0x2203, 0x22 }, + { 0x2204, 0x04 }, + { 0x2206, 0x00 }, + { 0x2207, 0x00 }, + { 0x2208, 0x00 }, + { 0x2209, 0x00 }, + { 0x220a, 0x00 }, + { 0x220b, 0x00 }, + { 0x220c, 0x00 }, + { 0x220d, 0x04 }, + { 0x220e, 0x00 }, + { 0x220f, 0x00 }, + { 0x2211, 0x01 }, + { 0x2212, 0x00 }, + { 0x2220, 0x00 }, + { 0x2221, 0x00 }, + { 0x2222, 0x00 }, + { 0x2223, 0x00 }, + { 0x2230, 0x00 }, + { 0x2231, 0x2f }, + { 0x2232, 0x80 }, + { 0x2233, 0x00 }, + { 0x2234, 0x00 }, + { 0x2235, 0x00 }, + { 0x2236, 0x00 }, + { 0x2237, 0x00 }, + { 0x2238, 0x00 }, + { 0x2239, 0x00 }, + { 0x2f01, 0x00 }, + { 0x2f02, 0x09 }, + { 0x2f03, 0x00 }, + { 0x2f04, 0x00 }, + { 0x2f05, 0x0b }, + { 0x2f06, 0x01 }, + { 0x2f07, 0xcf }, + { 0x2f08, 0x00 }, + { 0x2f09, 0x00 }, + { 0x2f0a, 0x00 }, + { 0x2f0b, 0x00 }, + { 0x2f0c, 0x00 }, + { 0x2f0d, 0x00 }, + { 0x2f0e, 0x00 }, + { 0x2f0f, 0x00 }, + { 0x3122, 0x00 }, + { 0x3123, 0x00 }, + { 0x7303, 0x57 }, + { 0x8383, 0x57 }, + { 0x7308, 0x97 }, + { 0x8388, 0x97 }, + { 0x7309, 0x97 }, + { 0x8389, 0x97 }, + { 0x7312, 0x00 }, + { 0x8392, 0x00 }, + { 0x7313, 0x00 }, + { 0x8393, 0x00 }, + { 0x7319, 0x00 }, + { 0x8399, 0x00 }, + { 0x7520001a, 0x8003 }, + { 0x75200045, 0x5289 }, + { 0x75200048, 0xd049 }, + { 0x7520004a, 0xa83b }, + { 0x7520006b, 0x5064 }, + { 0x7520006f, 0x058b }, + { 0x75200091, 0x0000 }, +}; + +#endif /* __RT711_SDW_H__ */ diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c new file mode 100644 index 00000000000000..183201f7212f52 --- /dev/null +++ b/sound/soc/codecs/rt711.c @@ -0,0 +1,1225 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// rt711.c -- rt711 ALSA SoC audio driver +// +// Copyright(c) 2019 Realtek Semiconductor Corp. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt711.h" + +static int rt711_index_write(struct regmap *regmap, + unsigned int nid, unsigned int reg, unsigned int value) +{ + int ret; + unsigned int addr = ((RT711_PRIV_INDEX_W_H | nid) << 16) | reg; + + ret = regmap_write(regmap, addr, value); + if (ret < 0) + pr_err("Failed to set private value: %08x <= %04x %d\n", ret, addr, value); + + return ret; +} + +static unsigned int rt711_index_read(struct regmap *regmap, + unsigned int nid, unsigned int reg, unsigned int *value) +{ + int ret; + unsigned int addr = ((RT711_PRIV_INDEX_W_H | nid) << 16) | reg; + + *value = 0; + ret = regmap_read(regmap, addr, value); + if (ret < 0) + pr_err("Failed to get private value: %08x => %04x %d\n", ret, addr, *value); + + return ret; +} + +static void rt711_reset(struct regmap *regmap) +{ + unsigned int val; + + regmap_write(regmap, RT711_FUNC_RESET, 0); + rt711_index_read(regmap, RT711_VENDOR_REG, RT711_PARA_VERB_CTL, &val); + rt711_index_write(regmap, RT711_VENDOR_REG, + RT711_PARA_VERB_CTL, (val | RT711_HIDDEN_REG_SW_RESET)); +} + +static int rt711_calibration(struct rt711_priv *rt711) +{ + unsigned int val, loop = 0; + struct device *dev; + struct regmap *regmap = rt711->regmap; + int ret = 0; + + mutex_lock(&rt711->calibrate_mutex); + regmap_write(rt711->regmap, + RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); + + dev = regmap_get_device(regmap); + + /* Calibration manual mode */ + rt711_index_read(regmap, RT711_VENDOR_REG, RT711_FSM_CTL, &val); + val &= 0xfffffff0; + rt711_index_write(regmap, RT711_VENDOR_REG, RT711_FSM_CTL, val); + + /* trigger */ + rt711_index_read(regmap, RT711_VENDOR_CALI, + RT711_DAC_DC_CALI_CTL1, &val); + val |= RT711_DAC_DC_CALI_TRIGGER; + rt711_index_write(regmap, RT711_VENDOR_CALI, + RT711_DAC_DC_CALI_CTL1, val); + + /* wait for calibration process */ + rt711_index_read(regmap, RT711_VENDOR_CALI, + RT711_DAC_DC_CALI_CTL1, &val); + + while (val & RT711_DAC_DC_CALI_TRIGGER) { + if (loop >= 500) { + pr_err("%s, calibration time-out!\n", + __func__); + ret = -ETIMEDOUT; + break; + } + loop++; + + usleep_range(10000, 11000); + rt711_index_read(regmap, RT711_VENDOR_CALI, + RT711_DAC_DC_CALI_CTL1, &val); + } + + /* depop mode */ + rt711_index_read(regmap, RT711_VENDOR_REG, RT711_FSM_CTL, &val); + val &= 0xfffffff0; + val |= RT711_DEPOP_CTL; + rt711_index_write(regmap, RT711_VENDOR_REG, RT711_FSM_CTL, val); + + regmap_write(rt711->regmap, + RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); + mutex_unlock(&rt711->calibrate_mutex); + + dev_dbg(dev, "%s calibration complete, ret=%d\n", __func__, ret); + return ret; +} + +static unsigned int rt711_button_detect(struct rt711_priv *rt711) +{ + unsigned int btn_type = 0, val80, val81; + int ret; + + ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG, + RT711_IRQ_FLAG_TABLE1, &val80); + if (ret < 0) + goto read_error; + ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG, + RT711_IRQ_FLAG_TABLE2, &val81); + if (ret < 0) + goto read_error; + + val80 &= 0x0381; + val81 &= 0xff00; + + switch (val80) { + case 0x0200: + case 0x0100: + case 0x0080: + btn_type |= SND_JACK_BTN_0; + break; + case 0x0001: + btn_type |= SND_JACK_BTN_3; + break; + } + switch (val81) { + case 0x8000: + case 0x4000: + case 0x2000: + btn_type |= SND_JACK_BTN_1; + break; + case 0x1000: + case 0x0800: + case 0x0400: + btn_type |= SND_JACK_BTN_2; + break; + case 0x0200: + case 0x0100: + btn_type |= SND_JACK_BTN_3; + break; + } +read_error: + return btn_type; +} + +static int rt711_headset_detect(struct rt711_priv *rt711) +{ + unsigned int buf, loop = 0; + int ret; + + ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG, + RT711_COMBO_JACK_AUTO_CTL2, &buf); + if (ret < 0) + goto io_error; + + while (loop < 500 && + (buf & RT711_COMBOJACK_AUTO_DET_STATUS) == 0) { + loop++; + + usleep_range(9000, 10000); + ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG, + RT711_COMBO_JACK_AUTO_CTL2, &buf); + if (ret < 0) + goto io_error; + } + + if (loop >= 500) + goto to_error; + + if (buf & RT711_COMBOJACK_AUTO_DET_TRS) + rt711->jack_type = SND_JACK_HEADPHONE; + else if ((buf & RT711_COMBOJACK_AUTO_DET_CTIA) || + (buf & RT711_COMBOJACK_AUTO_DET_OMTP)) + rt711->jack_type = SND_JACK_HEADSET; + + return 0; + +to_error: + ret = -ETIMEDOUT; + pr_err_ratelimited("Time-out error in %s\n", __func__); + return ret; +io_error: + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); + return ret; +} + +static void rt711_jack_detect_handler(struct work_struct *work) +{ + struct rt711_priv *rt711 = + container_of(work, struct rt711_priv, jack_detect_work.work); + int btn_type = 0, ret; + unsigned int jack_status = 0, reg; + + if (!rt711->hs_jack) + return; + + if (!rt711->component->card->instantiated) + return; + + reg = RT711_VERB_GET_PIN_SENSE | RT711_HP_OUT; + ret = regmap_read(rt711->regmap, reg, &jack_status); + if (ret < 0) + goto io_error; + + /* pin attached */ + if (jack_status & (1 << 31)) { + /* jack in */ + if (rt711->jack_type == 0) { + ret = rt711_headset_detect(rt711); + if (ret < 0) + return; + if (rt711->jack_type == SND_JACK_HEADSET) + btn_type = rt711_button_detect(rt711); + } else if (rt711->jack_type == SND_JACK_HEADSET) { + /* jack is already in, report button event */ + btn_type = rt711_button_detect(rt711); + } + } else { + /* jack out */ + rt711->jack_type = 0; + } + + dev_dbg(&rt711->slave->dev, + "in %s, jack_type=0x%x\n", __func__, rt711->jack_type); + dev_dbg(&rt711->slave->dev, + "in %s, btn_type=0x%x\n", __func__, btn_type); + + snd_soc_jack_report(rt711->hs_jack, rt711->jack_type | btn_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + if (btn_type) { + /* button released */ + snd_soc_jack_report(rt711->hs_jack, rt711->jack_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + mod_delayed_work(system_power_efficient_wq, + &rt711->jack_btn_check_work, msecs_to_jiffies(200)); + } + + return; + +io_error: + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); +} + +static void rt711_btn_check_handler(struct work_struct *work) +{ + struct rt711_priv *rt711 = container_of(work, struct rt711_priv, + jack_btn_check_work.work); + int btn_type = 0, ret; + unsigned int jack_status = 0, reg; + + reg = RT711_VERB_GET_PIN_SENSE | RT711_HP_OUT; + ret = regmap_read(rt711->regmap, reg, &jack_status); + if (ret < 0) + goto io_error; + + /* pin attached */ + if (jack_status & (1 << 31)) { + if (rt711->jack_type == SND_JACK_HEADSET) { + /* jack is already in, report button event */ + btn_type = rt711_button_detect(rt711); + } + } else { + rt711->jack_type = 0; + } + + /* cbj comparator */ + ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG, + RT711_COMBO_JACK_AUTO_CTL2, ®); + if (ret < 0) + goto io_error; + + if ((reg & 0xf0) == 0xf0) + btn_type = 0; + + dev_dbg(&rt711->slave->dev, + "%s, btn_type=0x%x\n", __func__, btn_type); + snd_soc_jack_report(rt711->hs_jack, rt711->jack_type | btn_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + if (btn_type) { + /* button released */ + snd_soc_jack_report(rt711->hs_jack, rt711->jack_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + mod_delayed_work(system_power_efficient_wq, + &rt711->jack_btn_check_work, msecs_to_jiffies(200)); + } + + return; + +io_error: + pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); +} + +static void rt711_jack_init(struct rt711_priv *rt711) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(rt711->component); + + mutex_lock(&rt711->calibrate_mutex); + /* power on */ + if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) + regmap_write(rt711->regmap, + RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); + + if (rt711->hs_jack) { + /* unsolicited response & IRQ control */ + regmap_write(rt711->regmap, + RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x82); + regmap_write(rt711->regmap, + RT711_SET_HP_UNSOLICITED_ENABLE, 0x81); + regmap_write(rt711->regmap, + RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x83); + rt711_index_write(rt711->regmap, RT711_VENDOR_REG, + 0x10, 0x2420); + rt711_index_write(rt711->regmap, RT711_VENDOR_REG, + 0x19, 0x2e11); + + dev_dbg(&rt711->slave->dev, "in %s enable\n", __func__); + + mod_delayed_work(system_power_efficient_wq, + &rt711->jack_detect_work, msecs_to_jiffies(250)); + } else { + regmap_write(rt711->regmap, + RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x00); + regmap_write(rt711->regmap, + RT711_SET_HP_UNSOLICITED_ENABLE, 0x00); + regmap_write(rt711->regmap, + RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x00); + + dev_dbg(&rt711->slave->dev, "in %s disable\n", __func__); + } + + /* power off */ + if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) + regmap_write(rt711->regmap, + RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); + mutex_unlock(&rt711->calibrate_mutex); +} + +static int rt711_set_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *hs_jack, void *data) +{ + struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + + rt711->hs_jack = hs_jack; + + if (!rt711->hw_init) { + dev_dbg(&rt711->slave->dev, + "%s hw_init not ready yet\n", __func__); + return 0; + } + + rt711_jack_init(rt711); + + return 0; +} + +static void rt711_get_gain(struct rt711_priv *rt711, unsigned int addr_h, + unsigned int addr_l, unsigned int val_h, + unsigned int *r_val, unsigned int *l_val) +{ + /* R Channel */ + *r_val = (val_h << 8); + regmap_read(rt711->regmap, addr_l, r_val); + + /* L Channel */ + val_h |= 0x20; + *l_val = (val_h << 8); + regmap_read(rt711->regmap, addr_h, l_val); +} + +/* For Verb-Set Amplifier Gain (Verb ID = 3h) */ +static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + unsigned int addr_h, addr_l, val_h, val_ll, val_lr; + unsigned int read_ll, read_rl; + int i; + + /* Can't use update bit function, so read the original value first */ + addr_h = mc->reg; + addr_l = mc->rreg; + if (mc->shift == RT711_DIR_OUT_SFT) /* output */ + val_h = 0x80; + else /* input */ + val_h = 0x0; + + rt711_get_gain(rt711, addr_h, addr_l, val_h, &read_rl, &read_ll); + + /* L Channel */ + if (mc->invert) { + /* for mute/unmute */ + val_ll = (mc->max - ucontrol->value.integer.value[0]) + << RT711_MUTE_SFT; + /* keep gain */ + read_ll = read_ll & 0x7f; + val_ll |= read_ll; + } else { + /* for gain */ + val_ll = ((ucontrol->value.integer.value[0]) & 0x7f); + if (val_ll > mc->max) + val_ll = mc->max; + /* keep mute status */ + read_ll = read_ll & (1 << RT711_MUTE_SFT); + val_ll |= read_ll; + } + + if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) + regmap_write(rt711->regmap, + RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); + + /* R Channel */ + if (mc->invert) { + /* for mute/unmute */ + val_lr = (mc->max - ucontrol->value.integer.value[1]) + << RT711_MUTE_SFT; + /* keep gain */ + read_rl = read_rl & 0x7f; + val_lr |= read_rl; + } else { + /* for gain */ + val_lr = ((ucontrol->value.integer.value[1]) & 0x7f); + if (val_lr > mc->max) + val_lr = mc->max; + /* keep mute status */ + read_rl = read_rl & (1 << RT711_MUTE_SFT); + val_lr |= read_rl; + } + + for (i = 0; i < 3; i++) { /* retry 3 times at most */ + + if (val_ll == val_lr) { + /* Set both L/R channels at the same time */ + val_h = (1 << mc->shift) | (3 << 4); + regmap_write(rt711->regmap, addr_h, (val_h << 8 | val_ll)); + regmap_write(rt711->regmap, addr_l, (val_h << 8 | val_ll)); + } else { + /* Lch*/ + val_h = (1 << mc->shift) | (1 << 5); + regmap_write(rt711->regmap, addr_h, (val_h << 8 | val_ll)); + + /* Rch */ + val_h = (1 << mc->shift) | (1 << 4); + regmap_write(rt711->regmap, addr_l, (val_h << 8 | val_lr)); + } + /* check result */ + if (mc->shift == RT711_DIR_OUT_SFT) /* output */ + val_h = 0x80; + else /* input */ + val_h = 0x0; + + rt711_get_gain(rt711, addr_h, addr_l, val_h, + &read_rl, &read_ll); + if (read_rl == val_lr && read_ll == val_ll) + break; + } + + if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) + regmap_write(rt711->regmap, + RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); + return 0; +} + +static int rt711_set_amp_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int addr_h, addr_l, val_h; + unsigned int read_ll, read_rl; + + /* switch to get command */ + addr_h = mc->reg; + addr_l = mc->rreg; + if (mc->shift == RT711_DIR_OUT_SFT) /* output */ + val_h = 0x80; + else /* input */ + val_h = 0x0; + + rt711_get_gain(rt711, addr_h, addr_l, val_h, &read_rl, &read_ll); + + if (mc->invert) { + /* mute/unmute for switch controls */ + read_ll = !((read_ll & 0x80) >> RT711_MUTE_SFT); + read_rl = !((read_rl & 0x80) >> RT711_MUTE_SFT); + } else { + /* for gain volume controls */ + read_ll = read_ll & 0x7f; + read_rl = read_rl & 0x7f; + } + ucontrol->value.integer.value[0] = read_ll; + ucontrol->value.integer.value[1] = read_rl; + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); +static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); + +static const struct snd_kcontrol_new rt711_snd_controls[] = { + SOC_DOUBLE_R_EXT_TLV("DAC Surr Playback Volume", RT711_SET_GAIN_DAC2_H, + RT711_SET_GAIN_DAC2_L, RT711_DIR_OUT_SFT, 0x57, 0, + rt711_set_amp_gain_get, rt711_set_amp_gain_put, + out_vol_tlv), + SOC_DOUBLE_R_EXT("ADC 08 Capture Switch", RT711_SET_GAIN_ADC2_H, + RT711_SET_GAIN_ADC2_L, RT711_DIR_IN_SFT, 1, 1, + rt711_set_amp_gain_get, rt711_set_amp_gain_put), + SOC_DOUBLE_R_EXT("ADC 09 Capture Switch", RT711_SET_GAIN_ADC1_H, + RT711_SET_GAIN_ADC1_L, RT711_DIR_IN_SFT, 1, 1, + rt711_set_amp_gain_get, rt711_set_amp_gain_put), + SOC_DOUBLE_R_EXT_TLV("ADC 08 Capture Volume", RT711_SET_GAIN_ADC2_H, + RT711_SET_GAIN_ADC2_L, RT711_DIR_IN_SFT, 0x3f, 0, + rt711_set_amp_gain_get, rt711_set_amp_gain_put, + in_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("ADC 09 Capture Volume", RT711_SET_GAIN_ADC1_H, + RT711_SET_GAIN_ADC1_L, RT711_DIR_IN_SFT, 0x3f, 0, + rt711_set_amp_gain_get, rt711_set_amp_gain_put, + in_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("AMIC Volume", RT711_SET_GAIN_AMIC_H, + RT711_SET_GAIN_AMIC_L, RT711_DIR_IN_SFT, 3, 0, + rt711_set_amp_gain_get, rt711_set_amp_gain_put, + mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("DMIC1 Volume", RT711_SET_GAIN_DMIC1_H, + RT711_SET_GAIN_DMIC1_L, RT711_DIR_IN_SFT, 3, 0, + rt711_set_amp_gain_get, rt711_set_amp_gain_put, + mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("DMIC2 Volume", RT711_SET_GAIN_DMIC2_H, + RT711_SET_GAIN_DMIC2_L, RT711_DIR_IN_SFT, 3, 0, + rt711_set_amp_gain_get, rt711_set_amp_gain_put, + mic_vol_tlv), +}; + +static int rt711_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + unsigned int reg, val = 0, nid; + int ret; + + if (strstr(ucontrol->id.name, "ADC 22 Mux")) + nid = RT711_MIXER_IN1; + else if (strstr(ucontrol->id.name, "ADC 23 Mux")) + nid = RT711_MIXER_IN2; + else + return -EINVAL; + + /* vid = 0xf01 */ + reg = RT711_VERB_SET_CONNECT_SEL | nid; + ret = regmap_read(rt711->regmap, reg, &val); + if (ret < 0) { + dev_err(component->dev, "%s: sdw read failed: %d\n", __func__, ret); + return ret; + } + + ucontrol->value.enumerated.item[0] = val; + + return 0; +} + +static int rt711_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + unsigned int val, val2 = 0, change, reg, nid; + int ret; + + if (item[0] >= e->items) + return -EINVAL; + + if (strstr(ucontrol->id.name, "ADC 22 Mux")) + nid = RT711_MIXER_IN1; + else if (strstr(ucontrol->id.name, "ADC 23 Mux")) + nid = RT711_MIXER_IN2; + else + return -EINVAL; + + /* Verb ID = 0x701h */ + val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; + + reg = RT711_VERB_SET_CONNECT_SEL | nid; + ret = regmap_read(rt711->regmap, reg, &val2); + if (ret < 0) { + dev_err(component->dev, "%s: sdw read failed: %d\n", __func__, ret); + return ret; + } + + if (val == val2) + change = 0; + else + change = 1; + + if (change) { + reg = RT711_VERB_SET_CONNECT_SEL | nid; + regmap_write(rt711->regmap, reg, val); + } + + snd_soc_dapm_mux_update_power(dapm, kcontrol, + item[0], e, NULL); + + return change; +} + +static const char * const adc_mux_text[] = { + "MIC2", + "LINE1", + "LINE2", + "DMIC", +}; + +static SOC_ENUM_SINGLE_DECL( + rt711_adc22_enum, SND_SOC_NOPM, 0, adc_mux_text); + +static SOC_ENUM_SINGLE_DECL( + rt711_adc23_enum, SND_SOC_NOPM, 0, adc_mux_text); + +static const struct snd_kcontrol_new rt711_adc22_mux = + SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt711_adc22_enum, + rt711_mux_get, rt711_mux_put); + +static const struct snd_kcontrol_new rt711_adc23_mux = + SOC_DAPM_ENUM_EXT("ADC 23 Mux", rt711_adc23_enum, + rt711_mux_get, rt711_mux_put); + +static int rt711_dac_surround_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + unsigned int val_h = (1 << RT711_DIR_OUT_SFT) | (0x3 << 4); + unsigned int val_l; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt711->regmap, + RT711_SET_STREAMID_DAC2, 0x10); + + val_l = 0x00; + regmap_write(rt711->regmap, + RT711_SET_GAIN_HP_H, (val_h << 8 | val_l)); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt711->regmap, + RT711_SET_STREAMID_DAC2, 0x00); + + val_l = (1 << RT711_MUTE_SFT); + regmap_write(rt711->regmap, + RT711_SET_GAIN_HP_H, (val_h << 8 | val_l)); + break; + } + return 0; +} + +static int rt711_adc_09_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt711->regmap, + RT711_SET_STREAMID_ADC1, 0x10); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt711->regmap, + RT711_SET_STREAMID_ADC1, 0x00); + break; + } + return 0; +} + +static int rt711_adc_08_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt711->regmap, + RT711_SET_STREAMID_ADC2, 0x10); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt711->regmap, + RT711_SET_STREAMID_ADC2, 0x00); + break; + } + return 0; +} + +static const struct snd_soc_dapm_widget rt711_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("HP"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("DMIC1"), + SND_SOC_DAPM_INPUT("DMIC2"), + SND_SOC_DAPM_INPUT("LINE1"), + SND_SOC_DAPM_INPUT("LINE2"), + + SND_SOC_DAPM_DAC_E("DAC Surround", NULL, SND_SOC_NOPM, 0, 0, + rt711_dac_surround_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("ADC 09", NULL, SND_SOC_NOPM, 0, 0, + rt711_adc_09_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("ADC 08", NULL, SND_SOC_NOPM, 0, 0, + rt711_adc_08_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0, + &rt711_adc22_mux), + SND_SOC_DAPM_MUX("ADC 23 Mux", SND_SOC_NOPM, 0, 0, + &rt711_adc23_mux), + + SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route rt711_audio_map[] = { + {"DAC Surround", NULL, "DP3RX"}, + {"DP2TX", NULL, "ADC 09"}, + {"DP4TX", NULL, "ADC 08"}, + + {"ADC 09", NULL, "ADC 22 Mux"}, + {"ADC 08", NULL, "ADC 23 Mux"}, + {"ADC 22 Mux", "DMIC", "DMIC1"}, + {"ADC 22 Mux", "LINE1", "LINE1"}, + {"ADC 22 Mux", "LINE2", "LINE2"}, + {"ADC 22 Mux", "MIC2", "MIC2"}, + {"ADC 23 Mux", "DMIC", "DMIC2"}, + {"ADC 23 Mux", "LINE1", "LINE1"}, + {"ADC 23 Mux", "LINE2", "LINE2"}, + {"ADC 23 Mux", "MIC2", "MIC2"}, + + {"HP", NULL, "DAC Surround"}, +}; + +static int rt711_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + + switch (level) { + case SND_SOC_BIAS_PREPARE: + if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { + regmap_write(rt711->regmap, + RT711_SET_AUDIO_POWER_STATE, + AC_PWRST_D0); + } + break; + + case SND_SOC_BIAS_STANDBY: + regmap_write(rt711->regmap, + RT711_SET_AUDIO_POWER_STATE, + AC_PWRST_D3); + break; + + default: + break; + } + + return 0; +} + +static int rt711_probe(struct snd_soc_component *component) +{ + struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + + rt711->component = component; + + return 0; +} + +static const struct snd_soc_component_driver soc_codec_dev_rt711 = { + .probe = rt711_probe, + .set_bias_level = rt711_set_bias_level, + .controls = rt711_snd_controls, + .num_controls = ARRAY_SIZE(rt711_snd_controls), + .dapm_widgets = rt711_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt711_dapm_widgets), + .dapm_routes = rt711_audio_map, + .num_dapm_routes = ARRAY_SIZE(rt711_audio_map), + .set_jack = rt711_set_jack_detect, +}; + +static int rt711_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, + int direction) +{ + struct sdw_stream_data *stream; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; + + stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream; + + /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + dai->playback_dma_data = stream; + else + dai->capture_dma_data = stream; + + return 0; +} + +static void rt711_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sdw_stream_data *stream; + + stream = snd_soc_dai_get_dma_data(dai, substream); + snd_soc_dai_set_dma_data(dai, substream, NULL); + kfree(stream); +} + +static int rt711_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; + enum sdw_data_direction direction; + struct sdw_stream_data *stream; + int retval, port, num_channels; + unsigned int val = 0; + + dev_dbg(dai->dev, "%s %s", __func__, dai->name); + stream = snd_soc_dai_get_dma_data(dai, substream); + + if (!stream) + return -EINVAL; + + if (!rt711->slave) + return -EINVAL; + + /* SoundWire specific configuration */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + direction = SDW_DATA_DIR_RX; + port = 3; + } else { + direction = SDW_DATA_DIR_TX; + if (dai->id == RT711_AIF1) + port = 4; + else if (dai->id == RT711_AIF2) + port = 2; + else + return -EINVAL; + } + + stream_config.frame_rate = params_rate(params); + stream_config.ch_count = params_channels(params); + stream_config.bps = snd_pcm_format_width(params_format(params)); + stream_config.direction = direction; + + num_channels = params_channels(params); + port_config.ch_mask = (1 << (num_channels)) - 1; + port_config.num = port; + + retval = sdw_stream_add_slave(rt711->slave, &stream_config, + &port_config, 1, stream->sdw_stream); + if (retval) { + dev_err(dai->dev, "Unable to configure port\n"); + return retval; + } + + if (params_channels(params) <= 16) { + /* bit 3:0 Number of Channel */ + val |= (params_channels(params) - 1); + } else { + dev_err(component->dev, "Unsupported channels %d\n", + params_channels(params)); + return -EINVAL; + } + + switch (params_width(params)) { + /* bit 6:4 Bits per Sample */ + case 8: + break; + case 16: + val |= (0x1 << 4); + break; + case 20: + val |= (0x2 << 4); + break; + case 24: + val |= (0x3 << 4); + break; + case 32: + val |= (0x4 << 4); + break; + default: + return -EINVAL; + } + + /* 48Khz */ + regmap_write(rt711->regmap, RT711_DAC_FORMAT_H, val); + regmap_write(rt711->regmap, RT711_ADC1_FORMAT_H, val); + regmap_write(rt711->regmap, RT711_ADC2_FORMAT_H, val); + + return retval; +} + +static int rt711_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + struct sdw_stream_data *stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt711->slave) + return -EINVAL; + + sdw_stream_remove_slave(rt711->slave, stream->sdw_stream); + return 0; +} + +#define RT711_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define RT711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static struct snd_soc_dai_ops rt711_ops = { + .hw_params = rt711_pcm_hw_params, + .hw_free = rt711_pcm_hw_free, + .set_sdw_stream = rt711_set_sdw_stream, + .shutdown = rt711_shutdown, +}; + +static struct snd_soc_dai_driver rt711_dai[] = { + { + .name = "rt711-aif1", + .id = RT711_AIF1, + .playback = { + .stream_name = "DP3 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT711_STEREO_RATES, + .formats = RT711_FORMATS, + }, + .capture = { + .stream_name = "DP4 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT711_STEREO_RATES, + .formats = RT711_FORMATS, + }, + .ops = &rt711_ops, + }, + { + .name = "rt711-aif2", + .id = RT711_AIF2, + .capture = { + .stream_name = "DP2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT711_STEREO_RATES, + .formats = RT711_FORMATS, + }, + .ops = &rt711_ops, + } +}; + +/* Bus clock frequency */ +#define RT711_CLK_FREQ_9600000HZ 9600000 +#define RT711_CLK_FREQ_12000000HZ 12000000 +#define RT711_CLK_FREQ_6000000HZ 6000000 +#define RT711_CLK_FREQ_4800000HZ 4800000 +#define RT711_CLK_FREQ_2400000HZ 2400000 +#define RT711_CLK_FREQ_12288000HZ 12288000 + +int rt711_clock_config(struct device *dev) +{ + struct rt711_priv *rt711 = dev_get_drvdata(dev); + unsigned int clk_freq, value; + + clk_freq = (rt711->params.curr_dr_freq >> 1); + + switch (clk_freq) { + case RT711_CLK_FREQ_12000000HZ: + value = 0x0; + break; + case RT711_CLK_FREQ_6000000HZ: + value = 0x1; + break; + case RT711_CLK_FREQ_9600000HZ: + value = 0x2; + break; + case RT711_CLK_FREQ_4800000HZ: + value = 0x3; + break; + case RT711_CLK_FREQ_2400000HZ: + value = 0x4; + break; + case RT711_CLK_FREQ_12288000HZ: + value = 0x5; + break; + default: + return -EINVAL; + } + + regmap_write(rt711->regmap, 0xe0, value); + regmap_write(rt711->regmap, 0xf0, value); + + dev_dbg(dev, "%s complete, clk_freq=%d\n", __func__, clk_freq); + + return 0; +} + +static void rt711_calibration_work(struct work_struct *work) +{ + struct rt711_priv *rt711 = + container_of(work, struct rt711_priv, calibration_work); + + rt711_calibration(rt711); +} + +int rt711_init(struct device *dev, struct regmap *sdw_regmap, + struct regmap *regmap, struct sdw_slave *slave) +{ + struct rt711_priv *rt711; + int ret; + + rt711 = devm_kzalloc(dev, sizeof(*rt711), GFP_KERNEL); + if (!rt711) + return -ENOMEM; + + dev_set_drvdata(dev, rt711); + rt711->slave = slave; + rt711->sdw_regmap = sdw_regmap; + rt711->regmap = regmap; + + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt711->hw_init = false; + rt711->first_init = false; + + ret = devm_snd_soc_register_component(dev, + &soc_codec_dev_rt711, + rt711_dai, + ARRAY_SIZE(rt711_dai)); + + dev_dbg(&slave->dev, "%s\n", __func__); + + return ret; +} + +int rt711_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt711_priv *rt711 = dev_get_drvdata(dev); + + if (rt711->hw_init) + return 0; + + /* + * PM runtime is only enabled when a Slave reports as Attached + */ + if (!rt711->first_init) { + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(&slave->dev, 3000); + pm_runtime_use_autosuspend(&slave->dev); + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(&slave->dev); + + pm_runtime_enable(&slave->dev); + + rt711->first_init = true; + } + + pm_runtime_get_noresume(&slave->dev); + + rt711_reset(rt711->regmap); + + /* power on */ + regmap_write(rt711->regmap, RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); + + /* Set Pin Widget */ + regmap_write(rt711->regmap, RT711_SET_PIN_MIC2, 0x25); + regmap_write(rt711->regmap, RT711_SET_PIN_HP, 0xc0); + regmap_write(rt711->regmap, RT711_SET_PIN_DMIC1, 0x20); + regmap_write(rt711->regmap, RT711_SET_PIN_DMIC2, 0x20); + regmap_write(rt711->regmap, RT711_SET_PIN_LINE1, 0x20); + regmap_write(rt711->regmap, RT711_SET_PIN_LINE2, 0x20); + + /* Mute HP/ADC1/ADC2 */ + regmap_write(rt711->regmap, RT711_SET_GAIN_HP_H, 0xa080); + regmap_write(rt711->regmap, RT711_SET_GAIN_HP_H, 0x9080); + regmap_write(rt711->regmap, RT711_SET_GAIN_ADC2_H, 0x6080); + regmap_write(rt711->regmap, RT711_SET_GAIN_ADC2_H, 0x5080); + regmap_write(rt711->regmap, RT711_SET_GAIN_ADC1_H, 0x6080); + regmap_write(rt711->regmap, RT711_SET_GAIN_ADC1_H, 0x5080); + + /* Set Configuration Default */ + regmap_write(rt711->regmap, 0x4f12, 0x91); + regmap_write(rt711->regmap, 0x4e12, 0xd6); + regmap_write(rt711->regmap, 0x4d12, 0x11); + regmap_write(rt711->regmap, 0x4c12, 0x20); + regmap_write(rt711->regmap, 0x4f13, 0x91); + regmap_write(rt711->regmap, 0x4e13, 0xd6); + regmap_write(rt711->regmap, 0x4d13, 0x11); + regmap_write(rt711->regmap, 0x4c13, 0x21); + regmap_write(rt711->regmap, 0x4c21, 0xf0); + regmap_write(rt711->regmap, 0x4d21, 0x11); + regmap_write(rt711->regmap, 0x4e21, 0x11); + regmap_write(rt711->regmap, 0x4f21, 0x01); + + /* Data port arrangement */ + rt711_index_write(rt711->regmap, RT711_VENDOR_REG, + RT711_TX_RX_MUX_CTL, 0x0154); + + /* Set index */ + rt711_index_write(rt711->regmap, RT711_VENDOR_REG, + RT711_DIGITAL_MISC_CTRL4, 0x201b); + rt711_index_write(rt711->regmap, RT711_VENDOR_REG, + RT711_COMBO_JACK_AUTO_CTL1, 0x5089); + rt711_index_write(rt711->regmap, RT711_VENDOR_REG, + RT711_VREFOUT_CTL, 0x5064); + rt711_index_write(rt711->regmap, RT711_VENDOR_REG, + RT711_INLINE_CMD_CTL, 0xd249); + + /* Finish Initial Settings, set power to D3 */ + regmap_write(rt711->regmap, RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); + + INIT_DELAYED_WORK(&rt711->jack_detect_work, + rt711_jack_detect_handler); + INIT_DELAYED_WORK(&rt711->jack_btn_check_work, + rt711_btn_check_handler); + mutex_init(&rt711->calibrate_mutex); + INIT_WORK(&rt711->calibration_work, rt711_calibration_work); + schedule_work(&rt711->calibration_work); + + /* + * if set_jack callback occurred early than io_init, + * we set up the jack detection function now + */ + if (rt711->hs_jack) + rt711_jack_init(rt711); + + /* Mark Slave initialization complete */ + rt711->hw_init = true; + + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + + dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); + return 0; +} + +MODULE_DESCRIPTION("ASoC RT711 SDW driver"); +MODULE_AUTHOR("Shuming Fan "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt711.h b/sound/soc/codecs/rt711.h new file mode 100644 index 00000000000000..795803db7acd13 --- /dev/null +++ b/sound/soc/codecs/rt711.h @@ -0,0 +1,212 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * rt711.h -- RT711 ALSA SoC audio driver header + * + * Copyright(c) 2019 Realtek Semiconductor Corp. + */ + +#ifndef __RT711_H__ +#define __RT711_H__ + +#include + +extern const struct dev_pm_ops rt711_runtime_pm; + +struct rt711_priv { + struct regmap *regmap; + struct regmap *sdw_regmap; + struct snd_soc_component *component; + struct sdw_slave *slave; + enum sdw_slave_status status; + struct sdw_bus_params params; + bool hw_init; + bool first_init; + struct snd_soc_jack *hs_jack; + struct delayed_work jack_detect_work; + struct delayed_work jack_btn_check_work; + struct work_struct calibration_work; + struct mutex calibrate_mutex; /* for headset calibration */ + int jack_type; +}; + +struct sdw_stream_data { + struct sdw_stream_runtime *sdw_stream; +}; + +/* NID */ +#define RT711_AUDIO_FUNCTION_GROUP 0x01 +#define RT711_DAC_OUT2 0x03 +#define RT711_ADC_IN1 0x09 +#define RT711_ADC_IN2 0x08 +#define RT711_DMIC1 0x12 +#define RT711_DMIC2 0x13 +#define RT711_MIC2 0x19 +#define RT711_LINE1 0x1a +#define RT711_LINE2 0x1b +#define RT711_BEEP 0x1d +#define RT711_VENDOR_REG 0x20 +#define RT711_HP_OUT 0x21 +#define RT711_MIXER_IN1 0x22 +#define RT711_MIXER_IN2 0x23 +#define RT711_INLINE_CMD 0x55 +#define RT711_VENDOR_CALI 0x58 +#define RT711_VENDOR_IMS_DRE 0x5b + +/* Index (NID:20h) */ +#define RT711_DAC_DC_CALI_CTL1 0x00 +#define RT711_PARA_VERB_CTL 0x1a +#define RT711_COMBO_JACK_AUTO_CTL1 0x45 +#define RT711_COMBO_JACK_AUTO_CTL2 0x46 +#define RT711_INLINE_CMD_CTL 0x48 +#define RT711_DIGITAL_MISC_CTRL4 0x4a +#define RT711_VREFOUT_CTL 0x6b +#define RT711_FSM_CTL 0x6f +#define RT711_IRQ_FLAG_TABLE1 0x80 +#define RT711_IRQ_FLAG_TABLE2 0x81 +#define RT711_IRQ_FLAG_TABLE3 0x82 +#define RT711_TX_RX_MUX_CTL 0x91 + +/* Index (NID:5bh) */ +#define RT711_IMS_DIGITAL_CTL1 0x00 +#define RT711_HP_IMS_RESULT_L 0x20 +#define RT711_HP_IMS_RESULT_R 0x21 + +/* Verb */ +#define RT711_VERB_SET_CONNECT_SEL 0x3100 +#define RT711_VERB_SET_EAPD_BTLENABLE 0x3c00 +#define RT711_VERB_GET_CONNECT_SEL 0xb100 +#define RT711_VERB_SET_POWER_STATE 0x3500 +#define RT711_VERB_SET_CHANNEL_STREAMID 0x3600 +#define RT711_VERB_SET_PIN_WIDGET_CONTROL 0x3700 +#define RT711_VERB_SET_UNSOLICITED_ENABLE 0x3800 +#define RT711_SET_AMP_GAIN_MUTE_H 0x7300 +#define RT711_SET_AMP_GAIN_MUTE_L 0x8380 +#define RT711_VERB_GET_POWER_STATE 0xb500 +#define RT711_VERB_GET_CHANNEL_STREAMID 0xb600 +#define RT711_VERB_GET_PIN_SENSE 0xb900 +#define RT711_FUNC_RESET 0xff01 + +#define RT711_READ_HDA_3 0x2012 +#define RT711_READ_HDA_2 0x2013 +#define RT711_READ_HDA_1 0x2014 +#define RT711_READ_HDA_0 0x2015 +#define RT711_PRIV_INDEX_W_H 0x7500 +#define RT711_PRIV_INDEX_W_L 0x8580 +#define RT711_PRIV_DATA_W_H 0x7400 +#define RT711_PRIV_DATA_W_L 0x8480 +#define RT711_PRIV_INDEX_R_H 0x9d00 +#define RT711_PRIV_INDEX_R_L 0xad80 +#define RT711_PRIV_DATA_R_H 0x9c00 +#define RT711_PRIV_DATA_R_L 0xac80 +#define RT711_DAC_FORMAT_H 0x7203 +#define RT711_DAC_FORMAT_L 0x8283 +#define RT711_ADC1_FORMAT_H 0x7209 +#define RT711_ADC1_FORMAT_L 0x8289 +#define RT711_ADC2_FORMAT_H 0x7208 +#define RT711_ADC2_FORMAT_L 0x8288 + +#define RT711_SET_AUDIO_POWER_STATE\ + (RT711_VERB_SET_POWER_STATE | RT711_AUDIO_FUNCTION_GROUP) +#define RT711_GET_AUDIO_POWER_STATE\ + (RT711_VERB_GET_POWER_STATE | RT711_AUDIO_FUNCTION_GROUP) +#define RT711_SET_PIN_DMIC1\ + (RT711_VERB_SET_PIN_WIDGET_CONTROL | RT711_DMIC1) +#define RT711_SET_PIN_DMIC2\ + (RT711_VERB_SET_PIN_WIDGET_CONTROL | RT711_DMIC2) +#define RT711_SET_PIN_HP\ + (RT711_VERB_SET_PIN_WIDGET_CONTROL | RT711_HP_OUT) +#define RT711_SET_PIN_MIC2\ + (RT711_VERB_SET_PIN_WIDGET_CONTROL | RT711_MIC2) +#define RT711_SET_PIN_LINE1\ + (RT711_VERB_SET_PIN_WIDGET_CONTROL | RT711_LINE1) +#define RT711_SET_PIN_LINE2\ + (RT711_VERB_SET_PIN_WIDGET_CONTROL | RT711_LINE2) +#define RT711_SET_MIC2_UNSOLICITED_ENABLE\ + (RT711_VERB_SET_UNSOLICITED_ENABLE | RT711_MIC2) +#define RT711_SET_HP_UNSOLICITED_ENABLE\ + (RT711_VERB_SET_UNSOLICITED_ENABLE | RT711_HP_OUT) +#define RT711_SET_INLINE_UNSOLICITED_ENABLE\ + (RT711_VERB_SET_UNSOLICITED_ENABLE | RT711_INLINE_CMD) +#define RT711_SET_STREAMID_DAC2\ + (RT711_VERB_SET_CHANNEL_STREAMID | RT711_DAC_OUT2) +#define RT711_SET_STREAMID_ADC1\ + (RT711_VERB_SET_CHANNEL_STREAMID | RT711_ADC_IN1) +#define RT711_SET_STREAMID_ADC2\ + (RT711_VERB_SET_CHANNEL_STREAMID | RT711_ADC_IN2) +#define RT711_GET_STREAMID_DAC2\ + (RT711_VERB_GET_CHANNEL_STREAMID | RT711_DAC_OUT2) +#define RT711_GET_STREAMID_ADC1\ + (RT711_VERB_GET_CHANNEL_STREAMID | RT711_ADC_IN1) +#define RT711_GET_STREAMID_ADC2\ + (RT711_VERB_GET_CHANNEL_STREAMID | RT711_ADC_IN2) +#define RT711_SET_GAIN_DAC2_L\ + (RT711_SET_AMP_GAIN_MUTE_L | RT711_DAC_OUT2) +#define RT711_SET_GAIN_DAC2_H\ + (RT711_SET_AMP_GAIN_MUTE_H | RT711_DAC_OUT2) +#define RT711_SET_GAIN_ADC1_L\ + (RT711_SET_AMP_GAIN_MUTE_L | RT711_ADC_IN1) +#define RT711_SET_GAIN_ADC1_H\ + (RT711_SET_AMP_GAIN_MUTE_H | RT711_ADC_IN1) +#define RT711_SET_GAIN_ADC2_L\ + (RT711_SET_AMP_GAIN_MUTE_L | RT711_ADC_IN2) +#define RT711_SET_GAIN_ADC2_H\ + (RT711_SET_AMP_GAIN_MUTE_H | RT711_ADC_IN2) +#define RT711_SET_GAIN_AMIC_L\ + (RT711_SET_AMP_GAIN_MUTE_L | RT711_MIC2) +#define RT711_SET_GAIN_AMIC_H\ + (RT711_SET_AMP_GAIN_MUTE_H | RT711_MIC2) +#define RT711_SET_GAIN_DMIC1_L\ + (RT711_SET_AMP_GAIN_MUTE_L | RT711_DMIC1) +#define RT711_SET_GAIN_DMIC1_H\ + (RT711_SET_AMP_GAIN_MUTE_H | RT711_DMIC1) +#define RT711_SET_GAIN_DMIC2_L\ + (RT711_SET_AMP_GAIN_MUTE_L | RT711_DMIC2) +#define RT711_SET_GAIN_DMIC2_H\ + (RT711_SET_AMP_GAIN_MUTE_H | RT711_DMIC2) +#define RT711_SET_GAIN_HP_L\ + (RT711_SET_AMP_GAIN_MUTE_L | RT711_HP_OUT) +#define RT711_SET_GAIN_HP_H\ + (RT711_SET_AMP_GAIN_MUTE_H | RT711_HP_OUT) + +/* DAC DC offset calibration control-1 (0x00)(NID:20h) */ +#define RT711_DAC_DC_CALI_TRIGGER (0x1 << 15) + +/* Parameter & Verb control (0x1a)(NID:20h) */ +#define RT711_HIDDEN_REG_SW_RESET (0x1 << 14) + +/* combo jack auto switch control 2 (0x46)(NID:20h) */ +#define RT711_COMBOJACK_AUTO_DET_STATUS (0x1 << 11) +#define RT711_COMBOJACK_AUTO_DET_TRS (0x1 << 10) +#define RT711_COMBOJACK_AUTO_DET_CTIA (0x1 << 9) +#define RT711_COMBOJACK_AUTO_DET_OMTP (0x1 << 8) + +/* FSM control (0x6f)(NID:20h) */ +#define RT711_CALI_CTL (0x0 << 0) +#define RT711_COMBOJACK_CTL (0x1 << 0) +#define RT711_IMS_CTL (0x2 << 0) +#define RT711_DEPOP_CTL (0x3 << 0) + +/* Impedance Sense Digital Control 1 (0x00)(NID:5bh) */ +#define RT711_TRIGGER_IMS (0x1 << 15) +#define RT711_IMS_EN (0x1 << 6) + +#define RT711_EAPD_HIGH 0x2 +#define RT711_EAPD_LOW 0x0 +#define RT711_MUTE_SFT 7 +/* set input/output mapping to payload[14][15] separately */ +#define RT711_DIR_IN_SFT 6 +#define RT711_DIR_OUT_SFT 7 + +enum { + RT711_AIF1, + RT711_AIF2, + RT711_AIFS, +}; + +int rt711_io_init(struct device *dev, struct sdw_slave *slave); +int rt711_init(struct device *dev, struct regmap *sdw_regmap, + struct regmap *regmap, struct sdw_slave *slave); + +int rt711_jack_detect(struct rt711_priv *rt711, bool *hp, bool *mic); +int rt711_clock_config(struct device *dev); +#endif /* __RT711_H__ */ From aa9e66e2e8bc9a6c848793960f78ac3733e5fc8d Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 21 Aug 2019 17:40:49 +0800 Subject: [PATCH 1837/1995] ASoC: codecs: rt715: add SoundWire support The driver for this capture device was tested by Realtek and Intel using the Realtek 3-in-1 add-on boards connected to CometLake and IceLake platforms Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Jack Yu --- sound/soc/codecs/Kconfig | 9 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt715-sdw.c | 530 +++++++++++++++++++++ sound/soc/codecs/rt715-sdw.h | 276 +++++++++++ sound/soc/codecs/rt715.c | 864 +++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt715.h | 205 +++++++++ 6 files changed, 1886 insertions(+) create mode 100644 sound/soc/codecs/rt715-sdw.c create mode 100644 sound/soc/codecs/rt715-sdw.h create mode 100644 sound/soc/codecs/rt715.c create mode 100644 sound/soc/codecs/rt715.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c2dd6eb7c7f3ab..543f5efe89a6fd 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1082,6 +1082,15 @@ config SND_SOC_RT711_SDW select SND_SOC_RT711 select REGMAP_SOUNDWIRE +config SND_SOC_RT715 + tristate + +config SND_SOC_RT715_SDW + tristate "Realtek RT715 Codec - SDW" + depends on SOUNDWIRE + select SND_SOC_RT715 + select REGMAP_SOUNDWIRE + #Freescale sgtl5000 codec config SND_SOC_SGTL5000 tristate "Freescale SGTL5000 CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index b64a387a14d641..a70ed120ae6f02 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -282,6 +282,7 @@ snd-soc-zx-aud96p22-objs := zx_aud96p22.o snd-soc-rt700-objs := rt700.o rt700-sdw.o snd-soc-rt1308-sdw-objs := rt1308-sdw.o snd-soc-rt711-objs := rt711.o rt711-sdw.o +snd-soc-rt715-objs := rt715.o rt715-sdw.o # Amp snd-soc-max9877-objs := max9877.o @@ -576,6 +577,7 @@ obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.o obj-$(CONFIG_SND_SOC_RT700) += snd-soc-rt700.o obj-$(CONFIG_SND_SOC_RT1308_SDW) += snd-soc-rt1308-sdw.o obj-$(CONFIG_SND_SOC_RT711) += snd-soc-rt711.o +obj-$(CONFIG_SND_SOC_RT715) += snd-soc-rt715.o # Amp obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c new file mode 100644 index 00000000000000..cd1ab562fd64c5 --- /dev/null +++ b/sound/soc/codecs/rt715-sdw.c @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rt715-sdw.c -- rt715 ALSA SoC audio driver + * + * Copyright(c) 2019 Realtek Semiconductor Corp. + * + * ALC715 ASoC Codec Driver based Intel Dummy SdW codec driver + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rt715.h" +#include "rt715-sdw.h" + +static bool rt715_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x02e0: + case 0x02f0: + case 0x04e0: + case 0x04f0: + case 0x06e0: + case 0x06f0: + case 0x00e0 ... 0x00e5: + case 0x00ee ... 0x00ef: + case 0x00f0 ... 0x00f5: + case 0x00fe ... 0x00ff: + case 0x2000 ... 0x2027: + case 0x2029 ... 0x202a: + case 0x202d ... 0x2034: + case 0x2200 ... 0x2204: + case 0x2206 ... 0x2212: + case 0x2220 ... 0x2223: + case 0x2230 ... 0x2239: + case 0x22f0 ... 0x22f3: + case 0x3000 ... 0x3fff: + case 0x7000 ... 0x7fff: + case 0x8300 ... 0x83ff: + case 0x9c00 ... 0x9cff: + case 0xb900 ... 0xb9ff: + case 0x75200039: + return true; + default: + return false; + } +} + +static bool rt715_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x00e5: + case 0x00f0: + case 0x00f3: + case 0x00f5: + case 0x2009: + case 0x2016: + case 0x201b: + case 0x201c: + case 0x201d: + case 0x201f: + case 0x2023: + case 0x2230: + case 0x200b ... 0x200e: /* i2c read */ + case 0x2012 ... 0x2015: /* HD-A read */ + case 0x202d ... 0x202f: /* BRA */ + case 0x2201 ... 0x2212: /* i2c debug */ + case 0x2220 ... 0x2223: /* decoded HD-A */ + case 0x9c00 ... 0x9cff: + case 0xb900 ... 0xb9ff: + case 0x75200039: + return true; + default: + return false; + } +} + +static int rt715_sdw_read(void *context, unsigned int reg, unsigned int *val) +{ + struct device *dev = context; + struct rt715_priv *rt715 = dev_get_drvdata(dev); + unsigned int sdw_data_3, sdw_data_2, sdw_data_1, sdw_data_0; + unsigned int reg2 = 0, reg3 = 0, reg4 = 0, mask, nid, val2; + unsigned int is_hda_reg = 1, is_index_reg = 0; + int ret; + + if (reg > 0xffff) + is_index_reg = 1; + + mask = reg & 0xf000; + + if (is_index_reg) { /* index registers */ + val2 = reg & 0xffff; + reg = reg >> 16; + nid = reg & 0xff; + ret = regmap_write(rt715->sdw_regmap, reg, ((val2 >> 8) & 0xff)); + if (ret < 0) + return ret; + reg2 = reg + 0x1000; + reg2 |= 0x80; + ret = regmap_write(rt715->sdw_regmap, reg2, (val2 & 0xff)); + if (ret < 0) + return ret; + + reg3 = RT715_PRIV_DATA_R_H | nid; + ret = regmap_write(rt715->sdw_regmap, reg3, ((*val >> 8) & 0xff)); + if (ret < 0) + return ret; + reg4 = reg3 + 0x1000; + reg4 |= 0x80; + ret = regmap_write(rt715->sdw_regmap, reg4, (*val & 0xff)); + if (ret < 0) + return ret; + } else if (mask == 0x3000) { + reg += 0x8000; + ret = regmap_write(rt715->sdw_regmap, reg, *val); + if (ret < 0) + return ret; + } else if (mask == 0x7000) { + reg += 0x2000; + reg |= 0x800; + ret = regmap_write(rt715->sdw_regmap, reg, ((*val >> 8) & 0xff)); + if (ret < 0) + return ret; + reg2 = reg + 0x1000; + reg2 |= 0x80; + ret = regmap_write(rt715->sdw_regmap, reg2, (*val & 0xff)); + if (ret < 0) + return ret; + } else if ((reg & 0xff00) == 0x8300) { /* for R channel */ + reg2 = reg - 0x1000; + reg2 &= ~0x80; + ret = regmap_write(rt715->sdw_regmap, reg2, ((*val >> 8) & 0xff)); + if (ret < 0) + return ret; + ret = regmap_write(rt715->sdw_regmap, reg, (*val & 0xff)); + if (ret < 0) + return ret; + } else if (mask == 0x9000) { + ret = regmap_write(rt715->sdw_regmap, reg, ((*val >> 8) & 0xff)); + if (ret < 0) + return ret; + reg2 = reg + 0x1000; + reg2 |= 0x80; + ret = regmap_write(rt715->sdw_regmap, reg2, (*val & 0xff)); + if (ret < 0) + return ret; + } else if (mask == 0xb000) { + ret = regmap_write(rt715->sdw_regmap, reg, *val); + if (ret < 0) + return ret; + } else { + ret = regmap_read(rt715->sdw_regmap, reg, val); + if (ret < 0) + return ret; + is_hda_reg = 0; + } + + if (is_hda_reg || is_index_reg) { + sdw_data_3 = 0; + sdw_data_2 = 0; + sdw_data_1 = 0; + sdw_data_0 = 0; + ret = regmap_read(rt715->sdw_regmap, RT715_READ_HDA_3, &sdw_data_3); + if (ret < 0) + return ret; + ret = regmap_read(rt715->sdw_regmap, RT715_READ_HDA_2, &sdw_data_2); + if (ret < 0) + return ret; + ret = regmap_read(rt715->sdw_regmap, RT715_READ_HDA_1, &sdw_data_1); + if (ret < 0) + return ret; + ret = regmap_read(rt715->sdw_regmap, RT715_READ_HDA_0, &sdw_data_0); + if (ret < 0) + return ret; + *val = ((sdw_data_3 & 0xff) << 24) | ((sdw_data_2 & 0xff) << 16) | + ((sdw_data_1 & 0xff) << 8) | (sdw_data_0 & 0xff); + } + + if (is_hda_reg == 0) + dev_dbg(dev, "[%s] %04x => %08x\n", __func__, reg, *val); + else if (is_index_reg) + dev_dbg(dev, "[%s] %04x %04x %04x %04x => %08x\n", __func__, + reg, reg2, reg3, reg4, *val); + else + dev_dbg(dev, "[%s] %04x %04x => %08x\n", __func__, reg, reg2, *val); + + return 0; +} + +static int rt715_sdw_write(void *context, unsigned int reg, unsigned int val) +{ + struct device *dev = context; + struct rt715_priv *rt715 = dev_get_drvdata(dev); + unsigned int reg2 = 0, reg3, reg4, nid, mask, val2; + unsigned int is_index_reg = 0; + int ret; + + if (reg > 0xffff) + is_index_reg = 1; + + mask = reg & 0xf000; + + if (is_index_reg) { /* index registers */ + val2 = reg & 0xffff; + reg = reg >> 16; + nid = reg & 0xff; + ret = regmap_write(rt715->sdw_regmap, reg, ((val2 >> 8) & 0xff)); + if (ret < 0) + return ret; + reg2 = reg + 0x1000; + reg2 |= 0x80; + ret = regmap_write(rt715->sdw_regmap, reg2, (val2 & 0xff)); + if (ret < 0) + return ret; + + reg3 = RT715_PRIV_DATA_W_H | nid; + ret = regmap_write(rt715->sdw_regmap, reg3, ((val >> 8) & 0xff)); + if (ret < 0) + return ret; + reg4 = reg3 + 0x1000; + reg4 |= 0x80; + ret = regmap_write(rt715->sdw_regmap, reg4, (val & 0xff)); + if (ret < 0) + return ret; + is_index_reg = 1; + } else if (reg < 0x4fff) { + ret = regmap_write(rt715->sdw_regmap, reg, val); + if (ret < 0) + return ret; + } else if (reg == RT715_FUNC_RESET) { + ret = regmap_write(rt715->sdw_regmap, reg, val); + if (ret < 0) + return ret; + } else if (mask == 0x7000) { + ret = regmap_write(rt715->sdw_regmap, reg, ((val >> 8) & 0xff)); + if (ret < 0) + return ret; + reg2 = reg + 0x1000; + reg2 |= 0x80; + ret = regmap_write(rt715->sdw_regmap, reg2, (val & 0xff)); + if (ret < 0) + return ret; + } else if ((reg & 0xff00) == 0x8300) { /* for R channel */ + reg2 = reg - 0x1000; + reg2 &= ~0x80; + ret = regmap_write(rt715->sdw_regmap, reg2, ((val >> 8) & 0xff)); + if (ret < 0) + return ret; + ret = regmap_write(rt715->sdw_regmap, reg, (val & 0xff)); + if (ret < 0) + return ret; + } + + if (reg2 == 0) + dev_dbg(dev, "[%s] %04x <= %04x\n", __func__, reg, val); + else if (is_index_reg) + dev_dbg(dev, "[%s] %04x %04x %04x %04x <= %04x %04x\n", __func__, + reg, reg2, reg3, reg4, val2, val); + else + dev_dbg(dev, "[%s] %04x %04x <= %04x\n", __func__, reg, reg2, val); + + return 0; +} + +static const struct regmap_config rt715_regmap = { + .reg_bits = 32, + .val_bits = 32, + .readable_reg = rt715_readable_register, /* Readable registers */ + .volatile_reg = rt715_volatile_register, /* volatile register */ + .max_register = 0x75200039, /* Maximum number of register */ + .reg_defaults = rt715_reg_defaults, /* Defaults */ + .num_reg_defaults = ARRAY_SIZE(rt715_reg_defaults), + .cache_type = REGCACHE_RBTREE, + .use_single_read = true, + .use_single_write = true, + .reg_read = rt715_sdw_read, + .reg_write = rt715_sdw_write, +}; + +const struct regmap_config rt715_sdw_regmap = { + .name = "sdw", + .reg_bits = 32, /* Total register space for SDW */ + .val_bits = 8, /* Total number of bits in register */ + .readable_reg = rt715_readable_register, /* Readable registers */ + .max_register = 0xff01, /* Maximum number of register */ + .cache_type = REGCACHE_NONE, + .use_single_read = true, + .use_single_write = true, +}; + +int hda_to_sdw(unsigned int nid, unsigned int verb, unsigned int payload, + unsigned int *sdw_addr_h, unsigned int *sdw_data_h, + unsigned int *sdw_addr_l, unsigned int *sdw_data_l) +{ + unsigned int offset_h, offset_l, e_verb; + + if (((verb & 0xff) != 0) || verb == 0xf00) { /* 12 bits command */ + if (verb == 0x7ff) /* special case */ + offset_h = 0; + else + offset_h = 0x3000; + + if (verb & 0x800) /* get command */ + e_verb = (verb - 0xf00) | 0x80; + else /* set command */ + e_verb = (verb - 0x700); + + *sdw_data_h = payload; /* 7 bits payload */ + *sdw_addr_l = *sdw_data_l = 0; + } else { /* 4 bits command */ + if ((verb & 0x800) == 0x800) { /* read */ + offset_h = 0x9000; + offset_l = 0xa000; + } else { /* write */ + offset_h = 0x7000; + offset_l = 0x8000; + } + e_verb = verb >> 8; + *sdw_data_h = (payload >> 8); /* 16 bits payload [15:8] */ + *sdw_addr_l = (e_verb << 8) | nid | 0x80; /* 0x80: valid bit */ + *sdw_addr_l += offset_l; + *sdw_data_l = payload & 0xff; + } + + *sdw_addr_h = (e_verb << 8) | nid; + *sdw_addr_h += offset_h; + + return 0; +} +EXPORT_SYMBOL(hda_to_sdw); + +static int rt715_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt715_priv *rt715 = dev_get_drvdata(&slave->dev); + + /* Update the status */ + rt715->status = status; + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt715->hw_init || rt715->status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt715_io_init(&slave->dev, slave); +} + +static int rt715_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int nval, i, num_of_ports = 1; + u32 bit; + unsigned long addr; + struct sdw_dpn_prop *dpn; + + prop->paging_support = false; + + /* first we need to allocate memory for set bits in port lists */ + prop->source_ports = 0x50; /* BITMAP: 01010000 */ + prop->sink_ports = 0x0; /* BITMAP: 00000000 */ + + nval = hweight32(prop->source_ports); + num_of_ports += nval; + prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->src_dpn_prop), + GFP_KERNEL); + if (!prop->src_dpn_prop) + return -ENOMEM; + + dpn = prop->src_dpn_prop; + i = 0; + addr = prop->source_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* do this again for sink now */ + nval = hweight32(prop->sink_ports); + num_of_ports += nval; + prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->sink_dpn_prop), + GFP_KERNEL); + if (!prop->sink_dpn_prop) + return -ENOMEM; + + dpn = prop->sink_dpn_prop; + i = 0; + addr = prop->sink_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* Allocate port_ready based on num_of_ports */ + slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports, + sizeof(*slave->port_ready), + GFP_KERNEL); + if (!slave->port_ready) + return -ENOMEM; + + /* Initialize completion */ + for (i = 0; i < num_of_ports; i++) + init_completion(&slave->port_ready[i]); + + /* set the timeout values */ + prop->clk_stop_timeout = 20; + + return 0; +} + +static int rt715_bus_config(struct sdw_slave *slave, + struct sdw_bus_params *params) +{ + struct rt715_priv *rt715 = dev_get_drvdata(&slave->dev); + int ret; + + memcpy(&rt715->params, params, sizeof(*params)); + + ret = rt715_clock_config(&slave->dev); + if (ret < 0) + dev_err(&slave->dev, "Invalid clk config"); + + return 0; +} + +static struct sdw_slave_ops rt715_slave_ops = { + .read_prop = rt715_read_prop, + .update_status = rt715_update_status, + .bus_config = rt715_bus_config, +}; + +static int rt715_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *sdw_regmap, *regmap; + + /* Assign ops */ + slave->ops = &rt715_slave_ops; + + /* Regmap Initialization */ + sdw_regmap = devm_regmap_init_sdw(slave, &rt715_sdw_regmap); + if (!sdw_regmap) + return -EINVAL; + + regmap = devm_regmap_init(&slave->dev, NULL, &slave->dev, &rt715_regmap); + if (!regmap) + return -EINVAL; + + rt715_init(&slave->dev, sdw_regmap, regmap, slave); + + return 0; +} + +static const struct sdw_device_id rt715_id[] = { + SDW_SLAVE_ENTRY(0x025d, 0x715, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt715_id); + +static int rt715_dev_suspend(struct device *dev) +{ + struct rt715_priv *rt715 = dev_get_drvdata(dev); + + if (!rt715->hw_init) + return 0; + + regcache_cache_only(rt715->regmap, true); + + return 0; +} + +#define RT715_PROBE_TIMEOUT 2000 + +static int rt715_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = to_sdw_slave_device(dev); + struct rt715_priv *rt715 = dev_get_drvdata(dev); + unsigned long time; + + if (!rt715->hw_init) + return 0; + + time = wait_for_completion_timeout(&slave->enumeration_complete, + msecs_to_jiffies(RT715_PROBE_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "Enumeration not complete, timed out\n"); + return -ETIMEDOUT; + } + + regcache_cache_only(rt715->regmap, false); + regcache_sync_region(rt715->regmap, 0x3000, 0x8fff); + regcache_sync_region(rt715->regmap, 0x75200039, 0x75200039); + + return 0; +} + +static const struct dev_pm_ops rt715_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt715_dev_suspend, rt715_dev_resume) + SET_RUNTIME_PM_OPS(rt715_dev_suspend, rt715_dev_resume, NULL) +}; + +static struct sdw_driver rt715_sdw_driver = { + .driver = { + .name = "rt715", + .owner = THIS_MODULE, + .pm = &rt715_pm, + }, + .probe = rt715_sdw_probe, + .ops = &rt715_slave_ops, + .id_table = rt715_id, +}; +module_sdw_driver(rt715_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT715 driver SDW"); +MODULE_AUTHOR("Jack Yu "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt715-sdw.h b/sound/soc/codecs/rt715-sdw.h new file mode 100644 index 00000000000000..1834127ecfcaab --- /dev/null +++ b/sound/soc/codecs/rt715-sdw.h @@ -0,0 +1,276 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * rt715-sdw.h -- RT715 ALSA SoC audio driver header + * + * Copyright(c) 2019 Realtek Semiconductor Corp. + */ + +#ifndef __RT715_SDW_H__ +#define __RT715_SDW_H__ + +static const struct reg_default rt715_reg_defaults[] = { + { 0x0000, 0x00 }, + { 0x0001, 0x00 }, + { 0x0002, 0x00 }, + { 0x0003, 0x00 }, + { 0x0004, 0x00 }, + { 0x0005, 0x01 }, + { 0x0020, 0x00 }, + { 0x0022, 0x00 }, + { 0x0023, 0x00 }, + { 0x0024, 0x00 }, + { 0x0025, 0x00 }, + { 0x0026, 0x00 }, + { 0x0030, 0x00 }, + { 0x0032, 0x00 }, + { 0x0033, 0x00 }, + { 0x0034, 0x00 }, + { 0x0035, 0x00 }, + { 0x0036, 0x00 }, + { 0x0040, 0x00 }, + { 0x0041, 0x00 }, + { 0x0042, 0x00 }, + { 0x0043, 0x00 }, + { 0x0044, 0x20 }, + { 0x0045, 0x01 }, + { 0x0046, 0x00 }, + { 0x0050, 0x20 }, + { 0x0051, 0x02 }, + { 0x0052, 0x5d }, + { 0x0053, 0x07 }, + { 0x0054, 0x15 }, + { 0x0055, 0x00 }, + { 0x0060, 0x00 }, + { 0x0070, 0x00 }, + { 0x0080, 0x00 }, + { 0x00e0, 0x00 }, + { 0x00e1, 0x00 }, + { 0x00e2, 0x00 }, + { 0x00e3, 0x00 }, + { 0x00e4, 0x00 }, + { 0x00e5, 0x00 }, + { 0x00ee, 0x00 }, + { 0x00ef, 0x00 }, + { 0x00f0, 0x00 }, + { 0x00f1, 0x00 }, + { 0x00f2, 0x00 }, + { 0x00f3, 0x00 }, + { 0x00f4, 0x00 }, + { 0x00f5, 0x00 }, + { 0x00fe, 0x00 }, + { 0x00ff, 0x00 }, + { 0x0200, 0x00 }, + { 0x0201, 0x00 }, + { 0x0202, 0x20 }, + { 0x0203, 0x00 }, + { 0x0204, 0x00 }, + { 0x0205, 0x00 }, + { 0x0220, 0x00 }, + { 0x0221, 0x00 }, + { 0x0222, 0x00 }, + { 0x0223, 0x00 }, + { 0x0224, 0x00 }, + { 0x0225, 0x00 }, + { 0x0226, 0x00 }, + { 0x0227, 0x00 }, + { 0x0230, 0x00 }, + { 0x0231, 0x00 }, + { 0x0232, 0x00 }, + { 0x0233, 0x00 }, + { 0x0234, 0x00 }, + { 0x0235, 0x00 }, + { 0x0236, 0x00 }, + { 0x0237, 0x00 }, + { 0x02e0, 0x00 }, + { 0x02f0, 0x00 }, + { 0x0400, 0x00 }, + { 0x0401, 0x00 }, + { 0x0402, 0x20 }, + { 0x0403, 0x00 }, + { 0x0404, 0x00 }, + { 0x0405, 0x00 }, + { 0x0420, 0x00 }, + { 0x0421, 0x00 }, + { 0x0422, 0x00 }, + { 0x0423, 0x00 }, + { 0x0424, 0x00 }, + { 0x0425, 0x00 }, + { 0x0426, 0x00 }, + { 0x0427, 0x00 }, + { 0x0430, 0x00 }, + { 0x0431, 0x00 }, + { 0x0432, 0x00 }, + { 0x0433, 0x00 }, + { 0x0434, 0x00 }, + { 0x0435, 0x00 }, + { 0x0436, 0x00 }, + { 0x0437, 0x00 }, + { 0x04e0, 0x00 }, + { 0x04f0, 0x00 }, + { 0x0600, 0x00 }, + { 0x0601, 0x00 }, + { 0x0602, 0x20 }, + { 0x0603, 0x00 }, + { 0x0604, 0x00 }, + { 0x0605, 0x00 }, + { 0x0620, 0x00 }, + { 0x0621, 0x00 }, + { 0x0622, 0x00 }, + { 0x0623, 0x00 }, + { 0x0624, 0x00 }, + { 0x0625, 0x00 }, + { 0x0626, 0x00 }, + { 0x0627, 0x00 }, + { 0x0630, 0x00 }, + { 0x0631, 0x00 }, + { 0x0632, 0x00 }, + { 0x0633, 0x00 }, + { 0x0634, 0x00 }, + { 0x0635, 0x00 }, + { 0x0636, 0x00 }, + { 0x0637, 0x00 }, + { 0x06e0, 0x00 }, + { 0x06f0, 0x00 }, + { 0x0f00, 0x00 }, + { 0x0f01, 0x00 }, + { 0x0f02, 0x00 }, + { 0x0f03, 0x00 }, + { 0x0f04, 0x00 }, + { 0x0f05, 0xff }, + { 0x0f06, 0x00 }, + { 0x0f07, 0x00 }, + { 0x0f08, 0x00 }, + { 0x0f09, 0x00 }, + { 0x0f0a, 0x00 }, + { 0x0f0b, 0x00 }, + { 0x0f0c, 0x00 }, + { 0x0f0d, 0x00 }, + { 0x0f0e, 0x00 }, + { 0x0f0f, 0x00 }, + { 0x0f10, 0x00 }, + { 0x0f11, 0x00 }, + { 0x0f12, 0x00 }, + { 0x0f13, 0x00 }, + { 0x0f14, 0x00 }, + { 0x0f15, 0xff }, + { 0x0f16, 0x00 }, + { 0x0f17, 0x00 }, + { 0x0f18, 0x00 }, + { 0x0f19, 0x00 }, + { 0x0f1a, 0x00 }, + { 0x0f1b, 0x00 }, + { 0x0f1c, 0x00 }, + { 0x0f1d, 0x00 }, + { 0x0f1e, 0x00 }, + { 0x0f1f, 0x00 }, + { 0x0f20, 0x00 }, + { 0x0f21, 0x00 }, + { 0x0f22, 0x00 }, + { 0x0f23, 0x00 }, + { 0x0f24, 0x00 }, + { 0x0f25, 0x00 }, + { 0x0f26, 0x00 }, + { 0x0f27, 0x00 }, + { 0x0f30, 0x00 }, + { 0x0f31, 0x00 }, + { 0x0f32, 0x00 }, + { 0x0f33, 0x00 }, + { 0x0f34, 0x00 }, + { 0x0f35, 0x00 }, + { 0x0f36, 0x00 }, + { 0x0f37, 0x00 }, + { 0x2000, 0x00 }, + { 0x2001, 0x00 }, + { 0x2002, 0x00 }, + { 0x2003, 0x00 }, + { 0x2004, 0x00 }, + { 0x2005, 0x00 }, + { 0x2006, 0x00 }, + { 0x2007, 0x00 }, + { 0x2008, 0x00 }, + { 0x2009, 0x03 }, + { 0x200a, 0x00 }, + { 0x200b, 0x00 }, + { 0x200c, 0x00 }, + { 0x200d, 0x00 }, + { 0x200e, 0x00 }, + { 0x200f, 0x00 }, + { 0x2010, 0x00 }, + { 0x2011, 0x00 }, + { 0x2012, 0x00 }, + { 0x2013, 0x00 }, + { 0x2014, 0x00 }, + { 0x2015, 0x00 }, + { 0x2016, 0x00 }, + { 0x201a, 0x00 }, + { 0x201b, 0x00 }, + { 0x201c, 0x00 }, + { 0x201d, 0x00 }, + { 0x201e, 0x00 }, + { 0x201f, 0x00 }, + { 0x2020, 0x00 }, + { 0x2021, 0x00 }, + { 0x2022, 0x00 }, + { 0x2023, 0x00 }, + { 0x2024, 0x00 }, + { 0x2025, 0x01 }, + { 0x2026, 0x00 }, + { 0x2027, 0x00 }, + { 0x2029, 0x00 }, + { 0x202a, 0x00 }, + { 0x202d, 0x00 }, + { 0x202e, 0x00 }, + { 0x202f, 0x00 }, + { 0x2030, 0x00 }, + { 0x2031, 0x00 }, + { 0x2032, 0x00 }, + { 0x2033, 0x00 }, + { 0x2034, 0x00 }, + { 0x2200, 0x00 }, + { 0x2201, 0x00 }, + { 0x2202, 0x00 }, + { 0x2203, 0x00 }, + { 0x2204, 0x00 }, + { 0x2206, 0x00 }, + { 0x2207, 0x00 }, + { 0x2208, 0x00 }, + { 0x2209, 0x00 }, + { 0x220a, 0x00 }, + { 0x220b, 0x00 }, + { 0x220c, 0x00 }, + { 0x220d, 0x00 }, + { 0x220e, 0x00 }, + { 0x220f, 0x00 }, + { 0x2210, 0x00 }, + { 0x2211, 0x00 }, + { 0x2212, 0x00 }, + { 0x2220, 0x00 }, + { 0x2221, 0x00 }, + { 0x2222, 0x00 }, + { 0x2223, 0x00 }, + { 0x2230, 0x00 }, + { 0x2231, 0x0f }, + { 0x2232, 0x00 }, + { 0x2233, 0x00 }, + { 0x2234, 0x00 }, + { 0x2235, 0x00 }, + { 0x2236, 0x00 }, + { 0x2237, 0x00 }, + { 0x2238, 0x00 }, + { 0x2239, 0x00 }, + { 0x22f0, 0x00 }, + { 0x22f1, 0x00 }, + { 0x22f2, 0x00 }, + { 0x22f3, 0x00 }, + { 0x7307, 0x97 }, + { 0x8387, 0x97 }, + { 0x7308, 0x97 }, + { 0x8388, 0x97 }, + { 0x7309, 0x97 }, + { 0x8389, 0x97 }, + { 0x7327, 0x97 }, + { 0x83a7, 0x97 }, + { 0x75200039, 0xa500 }, +}; + +#endif /* __RT715_H__ */ diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c new file mode 100644 index 00000000000000..0ac8868012d83d --- /dev/null +++ b/sound/soc/codecs/rt715.c @@ -0,0 +1,864 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rt715.c -- rt715 ALSA SoC audio driver + * + * Copyright(c) 2019 Realtek Semiconductor Corp. + * + * ALC715 ASoC Codec Driver based Intel Dummy SdW codec driver + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt715.h" + +static int rt715_index_write(struct regmap *regmap, unsigned int reg, + unsigned int value) +{ + int ret; + unsigned int addr = ((RT715_PRIV_INDEX_W_H) << 16) | reg; + + ret = regmap_write(regmap, addr, value); + if (ret < 0) { + pr_err("Failed to set private value: %08x <= %04x %d\n", ret, + addr, value); + } + + return ret; +} + +static unsigned int rt715_index_read(struct regmap *regmap, unsigned int reg, + unsigned int *value) +{ + int ret; + unsigned int addr = ((RT715_PRIV_INDEX_W_H) << 16) | reg; + + *value = 0; + ret = regmap_read(regmap, addr, value); + if (ret < 0) { + pr_err("Failed to get private value: %08x => %04x %d\n", ret, + addr, *value); + } + + return ret; +} + +static void rt715_get_gain(struct rt715_priv *rt715, unsigned int addr_h, + unsigned int addr_l, unsigned int val_h, + unsigned int *r_val, unsigned int *l_val) +{ + /* R Channel */ + *r_val = (val_h << 8); + regmap_read(rt715->regmap, addr_l, r_val); + + /* L Channel */ + val_h |= 0x20; + *l_val = (val_h << 8); + regmap_read(rt715->regmap, addr_h, l_val); +} + +/* For Verb-Set Amplifier Gain (Verb ID = 3h) */ +static int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); + unsigned int addr_h, addr_l, val_h, val_ll, val_lr; + unsigned int read_ll, read_rl; + int i; + + /* Can't use update bit function, so read the original value first */ + addr_h = mc->reg; + addr_l = mc->rreg; + if (mc->shift == RT715_DIR_OUT_SFT) /* output */ + val_h = 0x80; + else /* input */ + val_h = 0x0; + + rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll); + + /* L Channel */ + if (mc->invert) { + /* for mute */ + val_ll = (mc->max - ucontrol->value.integer.value[0]) << 7; + /* keep gain */ + read_ll = read_ll & 0x7f; + val_ll |= read_ll; + } else { + /* for gain */ + val_ll = ((ucontrol->value.integer.value[0]) & 0x7f); + if (val_ll > mc->max) + val_ll = mc->max; + /* keep mute status */ + read_ll = read_ll & 0x80; + val_ll |= read_ll; + } + + /* R Channel */ + if (mc->invert) { + regmap_write(rt715->regmap, + RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D0); + /* for mute */ + val_lr = (mc->max - ucontrol->value.integer.value[1]) << 7; + /* keep gain */ + read_rl = read_rl & 0x7f; + val_lr |= read_rl; + } else { + /* for gain */ + val_lr = ((ucontrol->value.integer.value[1]) & 0x7f); + if (val_lr > mc->max) + val_lr = mc->max; + /* keep mute status */ + read_rl = read_rl & 0x80; + val_lr |= read_rl; + } + + for (i = 0; i < 3; i++) { /* retry 3 times at most */ + + if (val_ll == val_lr) { + /* Set both L/R channels at the same time */ + val_h = (1 << mc->shift) | (3 << 4); + regmap_write(rt715->regmap, addr_h, (val_h << 8 | val_ll)); + regmap_write(rt715->regmap, addr_l, (val_h << 8 | val_ll)); + } else { + /* Lch*/ + val_h = (1 << mc->shift) | (1 << 5); + regmap_write(rt715->regmap, addr_h, (val_h << 8 | val_ll)); + + /* Rch */ + val_h = (1 << mc->shift) | (1 << 4); + regmap_write(rt715->regmap, addr_l, (val_h << 8 | val_lr)); + } + /* check result */ + if (mc->shift == RT715_DIR_OUT_SFT) /* output */ + val_h = 0x80; + else /* input */ + val_h = 0x0; + + rt715_get_gain(rt715, addr_h, addr_l, val_h, + &read_rl, &read_ll); + if (read_rl == val_lr && read_ll == val_ll) + break; + } + /* D0:power on state, D3: power saving mode */ + if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) + regmap_write(rt715->regmap, + RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3); + return 0; +} + +static int rt715_set_amp_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int addr_h, addr_l, val_h; + unsigned int read_ll, read_rl; + + addr_h = mc->reg; + addr_l = mc->rreg; + if (mc->shift == RT715_DIR_OUT_SFT) /* output */ + val_h = 0x80; + else /* input */ + val_h = 0x0; + + rt715_get_gain(rt715, addr_h, addr_l, val_h, &read_rl, &read_ll); + + if (mc->invert) { + /* for mute status */ + read_ll = !((read_ll & 0x80) >> RT715_MUTE_SFT); + read_rl = !((read_rl & 0x80) >> RT715_MUTE_SFT); + } else { + /* for gain */ + read_ll = read_ll & 0x7f; + read_rl = read_rl & 0x7f; + } + ucontrol->value.integer.value[0] = read_ll; + ucontrol->value.integer.value[1] = read_rl; + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); +static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); + +#define SOC_DOUBLE_R_EXT(xname, reg_left, reg_right, xshift, xmax, xinvert,\ + xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .info = snd_soc_info_volsw, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \ + xmax, xinvert) } + +static const struct snd_kcontrol_new rt715_snd_controls[] = { + /* Capture switch */ + SOC_DOUBLE_R_EXT("ADC 07 Capture Switch", RT715_SET_GAIN_MIC_ADC_H, + RT715_SET_GAIN_MIC_ADC_L, RT715_DIR_IN_SFT, 1, 1, + rt715_set_amp_gain_get, rt715_set_amp_gain_put), + SOC_DOUBLE_R_EXT("ADC 08 Capture Switch", RT715_SET_GAIN_LINE_ADC_H, + RT715_SET_GAIN_LINE_ADC_L, RT715_DIR_IN_SFT, 1, 1, + rt715_set_amp_gain_get, rt715_set_amp_gain_put), + SOC_DOUBLE_R_EXT("ADC 09 Capture Switch", RT715_SET_GAIN_MIX_ADC_H, + RT715_SET_GAIN_MIX_ADC_L, RT715_DIR_IN_SFT, 1, 1, + rt715_set_amp_gain_get, rt715_set_amp_gain_put), + SOC_DOUBLE_R_EXT("ADC 27 Capture Switch", RT715_SET_GAIN_MIX_ADC2_H, + RT715_SET_GAIN_MIX_ADC2_L, RT715_DIR_IN_SFT, 1, 1, + rt715_set_amp_gain_get, rt715_set_amp_gain_put), + /* Volume Control */ + SOC_DOUBLE_R_EXT_TLV("ADC 07 Capture Volume", RT715_SET_GAIN_MIC_ADC_H, + RT715_SET_GAIN_MIC_ADC_L, RT715_DIR_IN_SFT, 0x3f, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + in_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("ADC 08 Capture Volume", RT715_SET_GAIN_LINE_ADC_H, + RT715_SET_GAIN_LINE_ADC_L, RT715_DIR_IN_SFT, 0x3f, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + in_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("ADC 09 Capture Volume", RT715_SET_GAIN_MIX_ADC_H, + RT715_SET_GAIN_MIX_ADC_L, RT715_DIR_IN_SFT, 0x3f, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + in_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("ADC 27 Capture Volume", RT715_SET_GAIN_MIX_ADC2_H, + RT715_SET_GAIN_MIX_ADC2_L, RT715_DIR_IN_SFT, 0x3f, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + in_vol_tlv), + /* MIC Boost Control */ + SOC_DOUBLE_R_EXT_TLV("DMIC1 Boost", RT715_SET_GAIN_DMIC1_H, + RT715_SET_GAIN_DMIC1_L, RT715_DIR_IN_SFT, 3, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("DMIC2 Boost", RT715_SET_GAIN_DMIC2_H, + RT715_SET_GAIN_DMIC2_L, RT715_DIR_IN_SFT, 3, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("DMIC3 Boost", RT715_SET_GAIN_DMIC3_H, + RT715_SET_GAIN_DMIC3_L, RT715_DIR_IN_SFT, 3, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("DMIC4 Boost", RT715_SET_GAIN_DMIC4_H, + RT715_SET_GAIN_DMIC4_L, RT715_DIR_IN_SFT, 3, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("MIC1 Boost", RT715_SET_GAIN_MIC1_H, + RT715_SET_GAIN_MIC1_L, RT715_DIR_IN_SFT, 3, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("MIC2 Boost", RT715_SET_GAIN_MIC2_H, + RT715_SET_GAIN_MIC2_L, RT715_DIR_IN_SFT, 3, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("LINE1 Boost", RT715_SET_GAIN_LINE1_H, + RT715_SET_GAIN_LINE1_L, RT715_DIR_IN_SFT, 3, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("LINE2 Boost", RT715_SET_GAIN_LINE2_H, + RT715_SET_GAIN_LINE2_L, RT715_DIR_IN_SFT, 3, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + mic_vol_tlv), +}; + +static int rt715_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int reg, val, ret; + + /* nid = e->reg, vid = 0xf01 */ + reg = RT715_VERB_SET_CONNECT_SEL | e->reg; + ret = regmap_read(rt715->regmap, reg, &val); + if (ret < 0) { + dev_err(component->dev, "%s: sdw read failed: %d\n", __func__, ret); + return ret; + } + + /* + * The first two indices of ADC Mux 24/25 are routed to the same + * hardware source. ie, ADC Mux 24 0/1 will both connect to MIC2. + * To have a unique set of inputs, we skip the index1 of the muxes. + */ + if ((e->reg == RT715_MUX_IN3 || e->reg == RT715_MUX_IN4) && (val > 0)) + val -= 1; + ucontrol->value.enumerated.item[0] = val; + + return 0; +} + +static int rt715_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + unsigned int val, val2 = 0, change, reg, ret; + + if (item[0] >= e->items) + return -EINVAL; + + /* Verb ID = 0x701h, nid = e->reg */ + val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; + + reg = RT715_VERB_SET_CONNECT_SEL | e->reg; + ret = regmap_read(rt715->regmap, reg, &val2); + if (ret < 0) { + dev_err(component->dev, "%s: sdw read failed: %d\n", __func__, ret); + return ret; + } + + if (val == val2) + change = 0; + else + change = 1; + + if (change) { + reg = RT715_VERB_SET_CONNECT_SEL | e->reg; + regmap_write(rt715->regmap, reg, val); + } + + snd_soc_dapm_mux_update_power(dapm, kcontrol, + item[0], e, NULL); + + return change; +} + +static const char * const adc_22_23_mux_text[] = { + "MIC1", + "MIC2", + "LINE1", + "LINE2", + "DMIC1", + "DMIC2", + "DMIC3", + "DMIC4", +}; + +/** + * Due to mux design for nid 24 (MUX_IN3)/25 (MUX_IN4), connection index 0 and + * 1 will be connected to the same dmic source, therefore we skip index 1 to + * avoid misunderstanding on usage of dapm routing. + */ +static const unsigned int rt715_adc_24_25_values[] = { + 0, + 2, + 3, + 4, + 5, +}; + +static const char * const adc_24_mux_text[] = { + "MIC2", + "DMIC1", + "DMIC2", + "DMIC3", + "DMIC4", +}; + +static const char * const adc_25_mux_text[] = { + "MIC1", + "DMIC1", + "DMIC2", + "DMIC3", + "DMIC4", +}; + +static SOC_ENUM_SINGLE_DECL( + rt715_adc22_enum, RT715_MUX_IN1, 0, adc_22_23_mux_text); + +static SOC_ENUM_SINGLE_DECL( + rt715_adc23_enum, RT715_MUX_IN2, 0, adc_22_23_mux_text); + +static SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc24_enum, + RT715_MUX_IN3, 0, 0xf, + adc_24_mux_text, rt715_adc_24_25_values); +static SOC_VALUE_ENUM_SINGLE_DECL(rt715_adc25_enum, + RT715_MUX_IN4, 0, 0xf, + adc_25_mux_text, rt715_adc_24_25_values); + +static const struct snd_kcontrol_new rt715_adc22_mux = + SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt715_adc22_enum, + rt715_mux_get, rt715_mux_put); + +static const struct snd_kcontrol_new rt715_adc23_mux = + SOC_DAPM_ENUM_EXT("ADC 23 Mux", rt715_adc23_enum, + rt715_mux_get, rt715_mux_put); + +static const struct snd_kcontrol_new rt715_adc24_mux = + SOC_DAPM_ENUM_EXT("ADC 24 Mux", rt715_adc24_enum, + rt715_mux_get, rt715_mux_put); + +static const struct snd_kcontrol_new rt715_adc25_mux = + SOC_DAPM_ENUM_EXT("ADC 25 Mux", rt715_adc25_enum, + rt715_mux_get, rt715_mux_put); + +static const struct snd_soc_dapm_widget rt715_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("DMIC1"), + SND_SOC_DAPM_INPUT("DMIC2"), + SND_SOC_DAPM_INPUT("DMIC3"), + SND_SOC_DAPM_INPUT("DMIC4"), + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("LINE1"), + SND_SOC_DAPM_INPUT("LINE2"), + SND_SOC_DAPM_ADC("ADC 07", NULL, RT715_SET_STREAMID_MIC_ADC, 4, 0), + SND_SOC_DAPM_ADC("ADC 08", NULL, RT715_SET_STREAMID_LINE_ADC, 4, 0), + SND_SOC_DAPM_ADC("ADC 09", NULL, RT715_SET_STREAMID_MIX_ADC, 4, 0), + SND_SOC_DAPM_ADC("ADC 27", NULL, RT715_SET_STREAMID_MIX_ADC2, 4, 0), + SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0, + &rt715_adc22_mux), + SND_SOC_DAPM_MUX("ADC 23 Mux", SND_SOC_NOPM, 0, 0, + &rt715_adc23_mux), + SND_SOC_DAPM_MUX("ADC 24 Mux", SND_SOC_NOPM, 0, 0, + &rt715_adc24_mux), + SND_SOC_DAPM_MUX("ADC 25 Mux", SND_SOC_NOPM, 0, 0, + &rt715_adc25_mux), + SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("DP6TX", "DP6 Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route rt715_audio_map[] = { + {"DP6TX", NULL, "ADC 09"}, + {"DP6TX", NULL, "ADC 08"}, + {"DP4TX", NULL, "ADC 07"}, + {"DP4TX", NULL, "ADC 27"}, + {"ADC 09", NULL, "ADC 22 Mux"}, + {"ADC 08", NULL, "ADC 23 Mux"}, + {"ADC 07", NULL, "ADC 24 Mux"}, + {"ADC 27", NULL, "ADC 25 Mux"}, + {"ADC 22 Mux", "MIC1", "MIC1"}, + {"ADC 22 Mux", "MIC2", "MIC2"}, + {"ADC 22 Mux", "LINE1", "LINE1"}, + {"ADC 22 Mux", "LINE2", "LINE2"}, + {"ADC 22 Mux", "DMIC1", "DMIC1"}, + {"ADC 22 Mux", "DMIC2", "DMIC2"}, + {"ADC 22 Mux", "DMIC3", "DMIC3"}, + {"ADC 22 Mux", "DMIC4", "DMIC4"}, + {"ADC 23 Mux", "MIC1", "MIC1"}, + {"ADC 23 Mux", "MIC2", "MIC2"}, + {"ADC 23 Mux", "LINE1", "LINE1"}, + {"ADC 23 Mux", "LINE2", "LINE2"}, + {"ADC 23 Mux", "DMIC1", "DMIC1"}, + {"ADC 23 Mux", "DMIC2", "DMIC2"}, + {"ADC 23 Mux", "DMIC3", "DMIC3"}, + {"ADC 23 Mux", "DMIC4", "DMIC4"}, + {"ADC 24 Mux", "MIC2", "MIC2"}, + {"ADC 24 Mux", "DMIC1", "DMIC1"}, + {"ADC 24 Mux", "DMIC2", "DMIC2"}, + {"ADC 24 Mux", "DMIC3", "DMIC3"}, + {"ADC 24 Mux", "DMIC4", "DMIC4"}, + {"ADC 25 Mux", "MIC1", "MIC1"}, + {"ADC 25 Mux", "DMIC1", "DMIC1"}, + {"ADC 25 Mux", "DMIC2", "DMIC2"}, + {"ADC 25 Mux", "DMIC3", "DMIC3"}, + {"ADC 25 Mux", "DMIC4", "DMIC4"}, +}; + +static int rt715_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); + + switch (level) { + case SND_SOC_BIAS_PREPARE: + if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { + regmap_write(rt715->regmap, + RT715_SET_AUDIO_POWER_STATE, + AC_PWRST_D0); + } + break; + + case SND_SOC_BIAS_STANDBY: + regmap_write(rt715->regmap, + RT715_SET_AUDIO_POWER_STATE, + AC_PWRST_D3); + break; + + default: + break; + } + dapm->bias_level = level; + return 0; +} + +static const struct snd_soc_component_driver soc_codec_dev_rt715 = { + .set_bias_level = rt715_set_bias_level, + .controls = rt715_snd_controls, + .num_controls = ARRAY_SIZE(rt715_snd_controls), + .dapm_widgets = rt715_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt715_dapm_widgets), + .dapm_routes = rt715_audio_map, + .num_dapm_routes = ARRAY_SIZE(rt715_audio_map), +}; + +static int rt715_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, + int direction) +{ + + struct sdw_stream_data *stream; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; + + stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream; + + /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + dai->playback_dma_data = stream; + else + dai->capture_dma_data = stream; + + return 0; +} + +static void rt715_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) + +{ + struct sdw_stream_data *stream; + + stream = snd_soc_dai_get_dma_data(dai, substream); + snd_soc_dai_set_dma_data(dai, substream, NULL); + kfree(stream); +} + +static int rt715_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; + enum sdw_data_direction direction; + struct sdw_stream_data *stream; + int retval, port, num_channels; + unsigned int val = 0; + + stream = snd_soc_dai_get_dma_data(dai, substream); + + if (!stream) + return -EINVAL; + + if (!rt715->slave) + return -EINVAL; + + switch (dai->id) { + case RT715_AIF1: + direction = SDW_DATA_DIR_TX; + port = 6; + rt715_index_write(rt715->regmap, RT715_SDW_INPUT_SEL, 0xa500); + break; + case RT715_AIF2: + direction = SDW_DATA_DIR_TX; + port = 4; + rt715_index_write(rt715->regmap, RT715_SDW_INPUT_SEL, 0xa000); + break; + default: + dev_err(component->dev, "Invalid DAI id %d\n", dai->id); + return -EINVAL; + } + + stream_config.frame_rate = params_rate(params); + stream_config.ch_count = params_channels(params); + stream_config.bps = snd_pcm_format_width(params_format(params)); + stream_config.direction = direction; + + num_channels = params_channels(params); + port_config.ch_mask = (1 << (num_channels)) - 1; + port_config.num = port; + + retval = sdw_stream_add_slave(rt715->slave, &stream_config, + &port_config, 1, stream->sdw_stream); + if (retval) { + dev_err(dai->dev, "Unable to configure port\n"); + return retval; + } + + switch (params_rate(params)) { + /* bit 14 0:48K 1:44.1K */ + /* bit 15 Stream Type 0:PCM 1:Non-PCM, should always be PCM */ + case 44100: + val |= 0x40 << 8; + break; + case 48000: + val |= 0x0 << 8; + break; + default: + dev_err(component->dev, "Unsupported sample rate %d\n", + params_rate(params)); + return -EINVAL; + } + + if (params_channels(params) <= 16) { + /* bit 3:0 Number of Channel */ + val |= (params_channels(params) - 1); + } else { + dev_err(component->dev, "Unsupported channels %d\n", + params_channels(params)); + return -EINVAL; + } + + switch (params_width(params)) { + /* bit 6:4 Bits per Sample */ + case 8: + break; + case 16: + val |= (0x1 << 4); + break; + case 20: + val |= (0x2 << 4); + break; + case 24: + val |= (0x3 << 4); + break; + case 32: + val |= (0x4 << 4); + break; + default: + return -EINVAL; + } + + regmap_write(rt715->regmap, RT715_MIC_ADC_FORMAT_H, val); + regmap_write(rt715->regmap, RT715_MIC_LINE_FORMAT_H, val); + regmap_write(rt715->regmap, RT715_MIX_ADC_FORMAT_H, val); + regmap_write(rt715->regmap, RT715_MIX_ADC2_FORMAT_H, val); + + return retval; +} + +static int rt715_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); + struct sdw_stream_data *stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt715->slave) + return -EINVAL; + + sdw_stream_remove_slave(rt715->slave, stream->sdw_stream); + return 0; +} + +#define RT715_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define RT715_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static struct snd_soc_dai_ops rt715_ops = { + .hw_params = rt715_pcm_hw_params, + .hw_free = rt715_pcm_hw_free, + .set_sdw_stream = rt715_set_sdw_stream, + .shutdown = rt715_shutdown, +}; + +static struct snd_soc_dai_driver rt715_dai[] = { + { + .name = "rt715-aif1", + .id = RT715_AIF1, + .capture = { + .stream_name = "DP6 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT715_STEREO_RATES, + .formats = RT715_FORMATS, + }, + .ops = &rt715_ops, + }, + { + .name = "rt715-aif2", + .id = RT715_AIF2, + .capture = { + .stream_name = "DP4 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT715_STEREO_RATES, + .formats = RT715_FORMATS, + }, + .ops = &rt715_ops, + }, +}; + +/* Bus clock frequency */ +#define RT715_CLK_FREQ_9600000HZ 9600000 +#define RT715_CLK_FREQ_12000000HZ 12000000 +#define RT715_CLK_FREQ_6000000HZ 6000000 +#define RT715_CLK_FREQ_4800000HZ 4800000 +#define RT715_CLK_FREQ_2400000HZ 2400000 +#define RT715_CLK_FREQ_12288000HZ 12288000 + +int rt715_clock_config(struct device *dev) +{ + struct rt715_priv *rt715 = dev_get_drvdata(dev); + unsigned int clk_freq, value; + + clk_freq = (rt715->params.curr_dr_freq >> 1); + + switch (clk_freq) { + case RT715_CLK_FREQ_12000000HZ: + value = 0x0; + break; + case RT715_CLK_FREQ_6000000HZ: + value = 0x1; + break; + case RT715_CLK_FREQ_9600000HZ: + value = 0x2; + break; + case RT715_CLK_FREQ_4800000HZ: + value = 0x3; + break; + case RT715_CLK_FREQ_2400000HZ: + value = 0x4; + break; + case RT715_CLK_FREQ_12288000HZ: + value = 0x5; + break; + default: + return -EINVAL; + } + + regmap_write(rt715->regmap, 0xe0, value); + regmap_write(rt715->regmap, 0xf0, value); + + return 0; +} + +int rt715_init(struct device *dev, struct regmap *sdw_regmap, + struct regmap *regmap, struct sdw_slave *slave) +{ + struct rt715_priv *rt715; + int ret; + + rt715 = devm_kzalloc(dev, sizeof(*rt715), GFP_KERNEL); + if (!rt715) + return -ENOMEM; + + dev_set_drvdata(dev, rt715); + rt715->slave = slave; + rt715->regmap = regmap; + rt715->sdw_regmap = sdw_regmap; + + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt715->hw_init = false; + rt715->first_init = false; + + ret = devm_snd_soc_register_component(dev, + &soc_codec_dev_rt715, + rt715_dai, + ARRAY_SIZE(rt715_dai)); + + return ret; +} + +int rt715_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt715_priv *rt715 = dev_get_drvdata(dev); + + if (rt715->hw_init) + return 0; + + /* + * PM runtime is only enabled when a Slave reports as Attached + */ + if (!rt715->first_init) { + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(&slave->dev, 3000); + pm_runtime_use_autosuspend(&slave->dev); + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(&slave->dev); + + pm_runtime_enable(&slave->dev); + + rt715->first_init = true; + } + + pm_runtime_get_noresume(&slave->dev); + + /* Mute nid=08h/09h */ + regmap_write(rt715->regmap, RT715_SET_GAIN_LINE_ADC_H, 0xb080); + regmap_write(rt715->regmap, RT715_SET_GAIN_MIX_ADC_H, 0xb080); + /* Mute nid=07h/27h */ + regmap_write(rt715->regmap, RT715_SET_GAIN_MIC_ADC_H, 0xb080); + regmap_write(rt715->regmap, RT715_SET_GAIN_MIX_ADC2_H, 0xb080); + + /* Set Pin Widget */ + regmap_write(rt715->regmap, RT715_SET_PIN_DMIC1, 0x20); + regmap_write(rt715->regmap, RT715_SET_PIN_DMIC2, 0x20); + /* Set Converter Stream */ + regmap_write(rt715->regmap, RT715_SET_STREAMID_LINE_ADC, 0x10); + regmap_write(rt715->regmap, RT715_SET_STREAMID_MIX_ADC, 0x10); + regmap_write(rt715->regmap, RT715_SET_STREAMID_MIC_ADC, 0x10); + regmap_write(rt715->regmap, RT715_SET_STREAMID_MIX_ADC2, 0x10); + /* Set Configuration Default */ + regmap_write(rt715->regmap, RT715_SET_DMIC1_CONFIG_DEFAULT1, 0xd0); + regmap_write(rt715->regmap, RT715_SET_DMIC1_CONFIG_DEFAULT2, 0x11); + regmap_write(rt715->regmap, RT715_SET_DMIC1_CONFIG_DEFAULT3, 0xa1); + regmap_write(rt715->regmap, RT715_SET_DMIC1_CONFIG_DEFAULT4, 0x81); + regmap_write(rt715->regmap, RT715_SET_DMIC2_CONFIG_DEFAULT1, 0xd1); + regmap_write(rt715->regmap, RT715_SET_DMIC2_CONFIG_DEFAULT2, 0x11); + regmap_write(rt715->regmap, RT715_SET_DMIC2_CONFIG_DEFAULT3, 0xa1); + regmap_write(rt715->regmap, RT715_SET_DMIC2_CONFIG_DEFAULT4, 0x81); + + /* Finish Initial Settings, set power to D3 */ + regmap_write(rt715->regmap, RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3); + + /* Mark Slave initialization complete */ + rt715->hw_init = true; + + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + + return 0; +} + +MODULE_DESCRIPTION("ASoC rt715 driver"); +MODULE_DESCRIPTION("ASoC rt715 driver SDW"); +MODULE_AUTHOR("Jack Yu "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt715.h b/sound/soc/codecs/rt715.h new file mode 100644 index 00000000000000..846d6a0116d9d0 --- /dev/null +++ b/sound/soc/codecs/rt715.h @@ -0,0 +1,205 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * rt715.h -- RT715 ALSA SoC audio driver header + * + * Copyright(c) 2019 Realtek Semiconductor Corp. + */ + +#ifndef __RT715_H__ +#define __RT715_H__ + +#include + +struct rt715_priv { + struct regmap *regmap; + struct regmap *sdw_regmap; + struct snd_soc_codec *codec; + struct sdw_slave *slave; + int dbg_nid; + int dbg_vid; + int dbg_payload; + enum sdw_slave_status status; + struct sdw_bus_params params; + bool hw_init; + bool first_init; +}; + +struct sdw_stream_data { + struct sdw_stream_runtime *sdw_stream; +}; + +/* NID */ +#define RT715_AUDIO_FUNCTION_GROUP 0x01 +#define RT715_MIC_ADC 0x07 +#define RT715_LINE_ADC 0x08 +#define RT715_MIX_ADC 0x09 +#define RT715_DMIC1 0x12 +#define RT715_DMIC2 0x13 +#define RT715_MIC1 0x18 +#define RT715_MIC2 0x19 +#define RT715_LINE1 0x1a +#define RT715_LINE2 0x1b +#define RT715_DMIC3 0x1d +#define RT715_DMIC4 0x29 +#define RT715_VENDOR_REGISTERS 0x20 +#define RT715_MUX_IN1 0x22 +#define RT715_MUX_IN2 0x23 +#define RT715_MUX_IN3 0x24 +#define RT715_MUX_IN4 0x25 +#define RT715_MIX_ADC2 0x27 +#define RT715_INLINE_CMD 0x55 + +/* Index (NID:20h) */ +#define RT715_SDW_INPUT_SEL 0x39 +#define RT715_EXT_DMIC_CLK_CTRL2 0x54 + +/* Verb */ +#define RT715_VERB_SET_CONNECT_SEL 0x3100 +#define RT715_VERB_GET_CONNECT_SEL 0xb100 +#define RT715_VERB_SET_EAPD_BTLENABLE 0x3c00 +#define RT715_VERB_SET_POWER_STATE 0x3500 +#define RT715_VERB_SET_CHANNEL_STREAMID 0x3600 +#define RT715_VERB_SET_PIN_WIDGET_CONTROL 0x3700 +#define RT715_VERB_SET_CONFIG_DEFAULT1 0x4c00 +#define RT715_VERB_SET_CONFIG_DEFAULT2 0x4d00 +#define RT715_VERB_SET_CONFIG_DEFAULT3 0x4e00 +#define RT715_VERB_SET_CONFIG_DEFAULT4 0x4f00 +#define RT715_VERB_SET_UNSOLICITED_ENABLE 0x3800 +#define RT715_SET_AMP_GAIN_MUTE_H 0x7300 +#define RT715_SET_AMP_GAIN_MUTE_L 0x8380 +#define RT715_READ_HDA_3 0x2012 +#define RT715_READ_HDA_2 0x2013 +#define RT715_READ_HDA_1 0x2014 +#define RT715_READ_HDA_0 0x2015 +#define RT715_PRIV_INDEX_W_H 0x7520 +#define RT715_PRIV_INDEX_W_L 0x85a0 +#define RT715_PRIV_DATA_W_H 0x7420 +#define RT715_PRIV_DATA_W_L 0x84a0 +#define RT715_PRIV_INDEX_R_H 0x9d20 +#define RT715_PRIV_INDEX_R_L 0xada0 +#define RT715_PRIV_DATA_R_H 0x9c20 +#define RT715_PRIV_DATA_R_L 0xaca0 +#define RT715_MIC_ADC_FORMAT_H 0x7207 +#define RT715_MIC_ADC_FORMAT_L 0x8287 +#define RT715_MIC_LINE_FORMAT_H 0x7208 +#define RT715_MIC_LINE_FORMAT_L 0x8288 +#define RT715_MIX_ADC_FORMAT_H 0x7209 +#define RT715_MIX_ADC_FORMAT_L 0x8289 +#define RT715_MIX_ADC2_FORMAT_H 0x7227 +#define RT715_MIX_ADC2_FORMAT_L 0x82a7 +#define RT715_FUNC_RESET 0xff01 + +#define RT715_SET_AUDIO_POWER_STATE\ + (RT715_VERB_SET_POWER_STATE | RT715_AUDIO_FUNCTION_GROUP) +#define RT715_SET_PIN_DMIC1\ + (RT715_VERB_SET_PIN_WIDGET_CONTROL | RT715_DMIC1) +#define RT715_SET_PIN_DMIC2\ + (RT715_VERB_SET_PIN_WIDGET_CONTROL | RT715_DMIC2) +#define RT715_SET_PIN_DMIC3\ + (RT715_VERB_SET_PIN_WIDGET_CONTROL | RT715_DMIC3) +#define RT715_SET_PIN_DMIC4\ + (RT715_VERB_SET_PIN_WIDGET_CONTROL | RT715_DMIC4) +#define RT715_SET_PIN_MIC1\ + (RT715_VERB_SET_PIN_WIDGET_CONTROL | RT715_MIC1) +#define RT715_SET_PIN_MIC2\ + (RT715_VERB_SET_PIN_WIDGET_CONTROL | RT715_MIC2) +#define RT715_SET_PIN_LINE1\ + (RT715_VERB_SET_PIN_WIDGET_CONTROL | RT715_LINE1) +#define RT715_SET_PIN_LINE2\ + (RT715_VERB_SET_PIN_WIDGET_CONTROL | RT715_LINE2) +#define RT715_SET_MIC1_UNSOLICITED_ENABLE\ + (RT715_VERB_SET_UNSOLICITED_ENABLE | RT715_MIC1) +#define RT715_SET_MIC2_UNSOLICITED_ENABLE\ + (RT715_VERB_SET_UNSOLICITED_ENABLE | RT715_MIC2) +#define RT715_SET_STREAMID_MIC_ADC\ + (RT715_VERB_SET_CHANNEL_STREAMID | RT715_MIC_ADC) +#define RT715_SET_STREAMID_LINE_ADC\ + (RT715_VERB_SET_CHANNEL_STREAMID | RT715_LINE_ADC) +#define RT715_SET_STREAMID_MIX_ADC\ + (RT715_VERB_SET_CHANNEL_STREAMID | RT715_MIX_ADC) +#define RT715_SET_STREAMID_MIX_ADC2\ + (RT715_VERB_SET_CHANNEL_STREAMID | RT715_MIX_ADC2) +#define RT715_SET_GAIN_MIC_ADC_L\ + (RT715_SET_AMP_GAIN_MUTE_L | RT715_MIC_ADC) +#define RT715_SET_GAIN_MIC_ADC_H\ + (RT715_SET_AMP_GAIN_MUTE_H | RT715_MIC_ADC) +#define RT715_SET_GAIN_LINE_ADC_L\ + (RT715_SET_AMP_GAIN_MUTE_L | RT715_LINE_ADC) +#define RT715_SET_GAIN_LINE_ADC_H\ + (RT715_SET_AMP_GAIN_MUTE_H | RT715_LINE_ADC) +#define RT715_SET_GAIN_MIX_ADC_L\ + (RT715_SET_AMP_GAIN_MUTE_L | RT715_MIX_ADC) +#define RT715_SET_GAIN_MIX_ADC_H\ + (RT715_SET_AMP_GAIN_MUTE_H | RT715_MIX_ADC) +#define RT715_SET_GAIN_MIX_ADC2_L\ + (RT715_SET_AMP_GAIN_MUTE_L | RT715_MIX_ADC2) +#define RT715_SET_GAIN_MIX_ADC2_H\ + (RT715_SET_AMP_GAIN_MUTE_H | RT715_MIX_ADC2) +#define RT715_SET_GAIN_DMIC1_L\ + (RT715_SET_AMP_GAIN_MUTE_L | RT715_DMIC1) +#define RT715_SET_GAIN_DMIC1_H\ + (RT715_SET_AMP_GAIN_MUTE_H | RT715_DMIC1) +#define RT715_SET_GAIN_DMIC2_L\ + (RT715_SET_AMP_GAIN_MUTE_L | RT715_DMIC2) +#define RT715_SET_GAIN_DMIC2_H\ + (RT715_SET_AMP_GAIN_MUTE_H | RT715_DMIC2) +#define RT715_SET_GAIN_DMIC3_L\ + (RT715_SET_AMP_GAIN_MUTE_L | RT715_DMIC3) +#define RT715_SET_GAIN_DMIC3_H\ + (RT715_SET_AMP_GAIN_MUTE_H | RT715_DMIC3) +#define RT715_SET_GAIN_DMIC4_L\ + (RT715_SET_AMP_GAIN_MUTE_L | RT715_DMIC4) +#define RT715_SET_GAIN_DMIC4_H\ + (RT715_SET_AMP_GAIN_MUTE_H | RT715_DMIC4) +#define RT715_SET_GAIN_MIC1_L\ + (RT715_SET_AMP_GAIN_MUTE_L | RT715_MIC1) +#define RT715_SET_GAIN_MIC1_H\ + (RT715_SET_AMP_GAIN_MUTE_H | RT715_MIC1) +#define RT715_SET_GAIN_MIC2_L\ + (RT715_SET_AMP_GAIN_MUTE_L | RT715_MIC2) +#define RT715_SET_GAIN_MIC2_H\ + (RT715_SET_AMP_GAIN_MUTE_H | RT715_MIC2) +#define RT715_SET_GAIN_LINE1_L\ + (RT715_SET_AMP_GAIN_MUTE_L | RT715_LINE1) +#define RT715_SET_GAIN_LINE1_H\ + (RT715_SET_AMP_GAIN_MUTE_H | RT715_LINE1) +#define RT715_SET_GAIN_LINE2_L\ + (RT715_SET_AMP_GAIN_MUTE_L | RT715_LINE2) +#define RT715_SET_GAIN_LINE2_H\ + (RT715_SET_AMP_GAIN_MUTE_H | RT715_LINE2) +#define RT715_SET_DMIC1_CONFIG_DEFAULT1\ + (RT715_VERB_SET_CONFIG_DEFAULT1 | RT715_DMIC1) +#define RT715_SET_DMIC2_CONFIG_DEFAULT1\ + (RT715_VERB_SET_CONFIG_DEFAULT1 | RT715_DMIC2) +#define RT715_SET_DMIC1_CONFIG_DEFAULT2\ + (RT715_VERB_SET_CONFIG_DEFAULT2 | RT715_DMIC1) +#define RT715_SET_DMIC2_CONFIG_DEFAULT2\ + (RT715_VERB_SET_CONFIG_DEFAULT2 | RT715_DMIC2) +#define RT715_SET_DMIC1_CONFIG_DEFAULT3\ + (RT715_VERB_SET_CONFIG_DEFAULT3 | RT715_DMIC1) +#define RT715_SET_DMIC2_CONFIG_DEFAULT3\ + (RT715_VERB_SET_CONFIG_DEFAULT3 | RT715_DMIC2) +#define RT715_SET_DMIC1_CONFIG_DEFAULT4\ + (RT715_VERB_SET_CONFIG_DEFAULT4 | RT715_DMIC1) +#define RT715_SET_DMIC2_CONFIG_DEFAULT4\ + (RT715_VERB_SET_CONFIG_DEFAULT4 | RT715_DMIC2) + +#define RT715_MUTE_SFT 7 +#define RT715_DIR_IN_SFT 6 +#define RT715_DIR_OUT_SFT 7 + +enum { + RT715_AIF1, + RT715_AIF2, + RT715_AIFS, +}; + +int rt715_io_init(struct device *dev, struct sdw_slave *slave); +int rt715_init(struct device *dev, struct regmap *sdw_regmap, + struct regmap *regmap, struct sdw_slave *slave); + +int hda_to_sdw(unsigned int nid, unsigned int verb, unsigned int payload, + unsigned int *sdw_addr_h, unsigned int *sdw_data_h, + unsigned int *sdw_addr_l, unsigned int *sdw_data_l); +int rt715_clock_config(struct device *dev); +#endif /* __RT715_H__ */ From edbdbec10386ee2717b946ed3e0fb6a64965f4d7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 18 Apr 2019 16:20:05 -0500 Subject: [PATCH 1838/1995] ASoC: codecs: Add DEBUG to Makefile Don't push upstream Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index a70ed120ae6f02..2cdb67dbff198e 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -1,3 +1,5 @@ +ccflags-y += -DDEBUG + # SPDX-License-Identifier: GPL-2.0 snd-soc-88pm860x-objs := 88pm860x-codec.o snd-soc-ab8500-codec-objs := ab8500-codec.o From 08c5b0414371b2c9f7f2fe1ac9a63fd6d1caed15 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Fri, 18 Oct 2019 17:02:29 +0800 Subject: [PATCH 1839/1995] ASoC: codecs: rt715: rt715_sdw_regmap can be static Fixes: 340dea861e4c ("ASoC: codecs: rt715: add SoundWire support") Signed-off-by: kbuild test robot --- sound/soc/codecs/rt715-sdw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index cd1ab562fd64c5..58f5e31131385d 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -284,7 +284,7 @@ static const struct regmap_config rt715_regmap = { .reg_write = rt715_sdw_write, }; -const struct regmap_config rt715_sdw_regmap = { +static const struct regmap_config rt715_sdw_regmap = { .name = "sdw", .reg_bits = 32, /* Total register space for SDW */ .val_bits = 8, /* Total number of bits in register */ From c5336d6312be5d9f9246e467a412d3db635acbb7 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 23 Oct 2019 13:43:46 +0800 Subject: [PATCH 1840/1995] ASoC: rt711: changes 32bits address mapping of index defined registers to 24bits It takes too many times to dump the registers when using 32 bits mapping. We change it to 24 bits to map the Realtek index defined registers. And this patch fixes some coding style. Signed-off-by: Shuming Fan --- sound/soc/codecs/rt711-sdw.c | 135 +++++++++++++++++++---------------- sound/soc/codecs/rt711-sdw.h | 14 ++-- sound/soc/codecs/rt711.c | 132 ++++++++++++++++++---------------- 3 files changed, 153 insertions(+), 128 deletions(-) diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index b044d12a515dd2..404a4b6ad4a904 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -37,17 +37,17 @@ static bool rt711_readable_register(struct device *dev, unsigned int reg) case 0x8300 ... 0x83ff: case 0x9c00 ... 0x9cff: case 0xb900 ... 0xb9ff: - case 0x7520001a: - case 0x75200045: - case 0x75200046: - case 0x75200048: - case 0x7520004a: - case 0x7520006b: - case 0x7520006f: - case 0x75200080: - case 0x75200081: - case 0x75200091: - case 0x75580000: + case 0x75201a: + case 0x752045: + case 0x752046: + case 0x752048: + case 0x75204a: + case 0x75206b: + case 0x75206f: + case 0x752080: + case 0x752081: + case 0x752091: + case 0x755800: return true; default: return false; @@ -72,11 +72,11 @@ static bool rt711_volatile_register(struct device *dev, unsigned int reg) case 0x9c00 ... 0x9cff: case 0xb900 ... 0xb9ff: case 0xff01: - case 0x7520001a: - case 0x75200046: - case 0x75200080: - case 0x75200081: - case 0x75580000: + case 0x75201a: + case 0x752046: + case 0x752080: + case 0x752081: + case 0x755800: return true; default: return false; @@ -98,20 +98,21 @@ static int rt711_sdw_read(void *context, unsigned int reg, unsigned int *val) mask = reg & 0xf000; if (is_index_reg) { /* index registers */ - val2 = reg & 0xffff; - reg = reg >> 16; + val2 = reg & 0xff; + reg = reg >> 8; nid = reg & 0xff; - ret = regmap_write(rt711->sdw_regmap, reg, ((val2 >> 8) & 0xff)); + ret = regmap_write(rt711->sdw_regmap, reg, 0); if (ret < 0) return ret; reg2 = reg + 0x1000; reg2 |= 0x80; - ret = regmap_write(rt711->sdw_regmap, reg2, (val2 & 0xff)); + ret = regmap_write(rt711->sdw_regmap, reg2, val2); if (ret < 0) return ret; reg3 = RT711_PRIV_DATA_R_H | nid; - ret = regmap_write(rt711->sdw_regmap, reg3, ((*val >> 8) & 0xff)); + ret = regmap_write(rt711->sdw_regmap, + reg3, ((*val >> 8) & 0xff)); if (ret < 0) return ret; reg4 = reg3 + 0x1000; @@ -127,7 +128,8 @@ static int rt711_sdw_read(void *context, unsigned int reg, unsigned int *val) } else if (mask == 0x7000) { reg += 0x2000; reg |= 0x800; - ret = regmap_write(rt711->sdw_regmap, reg, ((*val >> 8) & 0xff)); + ret = regmap_write(rt711->sdw_regmap, + reg, ((*val >> 8) & 0xff)); if (ret < 0) return ret; reg2 = reg + 0x1000; @@ -138,14 +140,16 @@ static int rt711_sdw_read(void *context, unsigned int reg, unsigned int *val) } else if ((reg & 0xff00) == 0x8300) { /* for R channel */ reg2 = reg - 0x1000; reg2 &= ~0x80; - ret = regmap_write(rt711->sdw_regmap, reg2, ((*val >> 8) & 0xff)); + ret = regmap_write(rt711->sdw_regmap, + reg2, ((*val >> 8) & 0xff)); if (ret < 0) return ret; ret = regmap_write(rt711->sdw_regmap, reg, (*val & 0xff)); if (ret < 0) return ret; } else if (mask == 0x9000) { - ret = regmap_write(rt711->sdw_regmap, reg, ((*val >> 8) & 0xff)); + ret = regmap_write(rt711->sdw_regmap, + reg, ((*val >> 8) & 0xff)); if (ret < 0) return ret; reg2 = reg + 0x1000; @@ -169,29 +173,35 @@ static int rt711_sdw_read(void *context, unsigned int reg, unsigned int *val) sdw_data_2 = 0; sdw_data_1 = 0; sdw_data_0 = 0; - ret = regmap_read(rt711->sdw_regmap, RT711_READ_HDA_3, &sdw_data_3); + ret = regmap_read(rt711->sdw_regmap, + RT711_READ_HDA_3, &sdw_data_3); if (ret < 0) return ret; - ret = regmap_read(rt711->sdw_regmap, RT711_READ_HDA_2, &sdw_data_2); + ret = regmap_read(rt711->sdw_regmap, + RT711_READ_HDA_2, &sdw_data_2); if (ret < 0) return ret; - ret = regmap_read(rt711->sdw_regmap, RT711_READ_HDA_1, &sdw_data_1); + ret = regmap_read(rt711->sdw_regmap, + RT711_READ_HDA_1, &sdw_data_1); if (ret < 0) return ret; - ret = regmap_read(rt711->sdw_regmap, RT711_READ_HDA_0, &sdw_data_0); + ret = regmap_read(rt711->sdw_regmap, + RT711_READ_HDA_0, &sdw_data_0); if (ret < 0) return ret; - *val = ((sdw_data_3 & 0xff) << 24) | ((sdw_data_2 & 0xff) << 16) | - ((sdw_data_1 & 0xff) << 8) | (sdw_data_0 & 0xff); + *val = ((sdw_data_3 & 0xff) << 24) | + ((sdw_data_2 & 0xff) << 16) | + ((sdw_data_1 & 0xff) << 8) | (sdw_data_0 & 0xff); } if (is_hda_reg == 0) dev_dbg(dev, "[%s] %04x => %08x\n", __func__, reg, *val); else if (is_index_reg) - dev_dbg(dev, "[%s] %04x %04x %04x %04x => %08x\n", __func__, - reg, reg2, reg3, reg4, *val); + dev_dbg(dev, "[%s] %04x %04x %04x %04x => %08x\n", + __func__, reg, reg2, reg3, reg4, *val); else - dev_dbg(dev, "[%s] %04x %04x => %08x\n", __func__, reg, reg2, *val); + dev_dbg(dev, "[%s] %04x %04x => %08x\n", + __func__, reg, reg2, *val); return 0; } @@ -210,20 +220,21 @@ static int rt711_sdw_write(void *context, unsigned int reg, unsigned int val) mask = reg & 0xf000; if (is_index_reg) { /* index registers */ - val2 = reg & 0xffff; - reg = reg >> 16; + val2 = reg & 0xff; + reg = reg >> 8; nid = reg & 0xff; - ret = regmap_write(rt711->sdw_regmap, reg, ((val2 >> 8) & 0xff)); + ret = regmap_write(rt711->sdw_regmap, reg, 0); if (ret < 0) return ret; reg2 = reg + 0x1000; reg2 |= 0x80; - ret = regmap_write(rt711->sdw_regmap, reg2, (val2 & 0xff)); + ret = regmap_write(rt711->sdw_regmap, reg2, val2); if (ret < 0) return ret; reg3 = RT711_PRIV_DATA_W_H | nid; - ret = regmap_write(rt711->sdw_regmap, reg3, ((val >> 8) & 0xff)); + ret = regmap_write(rt711->sdw_regmap, + reg3, ((val >> 8) & 0xff)); if (ret < 0) return ret; reg4 = reg3 + 0x1000; @@ -241,7 +252,8 @@ static int rt711_sdw_write(void *context, unsigned int reg, unsigned int val) if (ret < 0) return ret; } else if (mask == 0x7000) { - ret = regmap_write(rt711->sdw_regmap, reg, ((val >> 8) & 0xff)); + ret = regmap_write(rt711->sdw_regmap, + reg, ((val >> 8) & 0xff)); if (ret < 0) return ret; reg2 = reg + 0x1000; @@ -252,7 +264,8 @@ static int rt711_sdw_write(void *context, unsigned int reg, unsigned int val) } else if ((reg & 0xff00) == 0x8300) { /* for R channel */ reg2 = reg - 0x1000; reg2 &= ~0x80; - ret = regmap_write(rt711->sdw_regmap, reg2, ((val >> 8) & 0xff)); + ret = regmap_write(rt711->sdw_regmap, + reg2, ((val >> 8) & 0xff)); if (ret < 0) return ret; ret = regmap_write(rt711->sdw_regmap, reg, (val & 0xff)); @@ -263,20 +276,21 @@ static int rt711_sdw_write(void *context, unsigned int reg, unsigned int val) if (reg2 == 0) dev_dbg(dev, "[%s] %04x <= %04x\n", __func__, reg, val); else if (is_index_reg) - dev_dbg(dev, "[%s] %04x %04x %04x %04x <= %04x %04x\n", __func__, - reg, reg2, reg3, reg4, val2, val); + dev_dbg(dev, "[%s] %04x %04x %04x %04x <= %04x %04x\n", + __func__, reg, reg2, reg3, reg4, val2, val); else - dev_dbg(dev, "[%s] %04x %04x <= %04x\n", __func__, reg, reg2, val); + dev_dbg(dev, "[%s] %04x %04x <= %04x\n", + __func__, reg, reg2, val); return 0; } static const struct regmap_config rt711_regmap = { - .reg_bits = 32, + .reg_bits = 24, .val_bits = 32, .readable_reg = rt711_readable_register, /* Readable registers */ .volatile_reg = rt711_volatile_register, /* volatile register */ - .max_register = 0x75580000, /* Maximum number of register */ + .max_register = 0x755800, /* Maximum number of register */ .reg_defaults = rt711_reg_defaults, /* Defaults */ .num_reg_defaults = ARRAY_SIZE(rt711_reg_defaults), .cache_type = REGCACHE_RBTREE, @@ -298,7 +312,7 @@ static const struct regmap_config rt711_sdw_regmap = { }; static int rt711_update_status(struct sdw_slave *slave, - enum sdw_slave_status status) + enum sdw_slave_status status) { struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev); @@ -330,14 +344,14 @@ static int rt711_read_prop(struct sdw_slave *slave) prop->paging_support = false; /* first we need to allocate memory for set bits in port lists */ - prop->source_ports = 0x14; /* BITMAP: 00010100 */ - prop->sink_ports = 0x8; /* BITMAP: 00001000 */ + prop->source_ports = 0x14; /* BITMAP: 00010100 */ + prop->sink_ports = 0x8; /* BITMAP: 00001000 */ nval = hweight32(prop->source_ports); num_of_ports += nval; prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, - sizeof(*prop->src_dpn_prop), - GFP_KERNEL); + sizeof(*prop->src_dpn_prop), + GFP_KERNEL); if (!prop->src_dpn_prop) return -ENOMEM; @@ -356,8 +370,8 @@ static int rt711_read_prop(struct sdw_slave *slave) nval = hweight32(prop->sink_ports); num_of_ports += nval; prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, - sizeof(*prop->sink_dpn_prop), - GFP_KERNEL); + sizeof(*prop->sink_dpn_prop), + GFP_KERNEL); if (!prop->sink_dpn_prop) return -ENOMEM; @@ -374,8 +388,8 @@ static int rt711_read_prop(struct sdw_slave *slave) /* Allocate port_ready based on num_of_ports */ slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports, - sizeof(*slave->port_ready), - GFP_KERNEL); + sizeof(*slave->port_ready), + GFP_KERNEL); if (!slave->port_ready) return -ENOMEM; @@ -390,7 +404,7 @@ static int rt711_read_prop(struct sdw_slave *slave) } static int rt711_bus_config(struct sdw_slave *slave, - struct sdw_bus_params *params) + struct sdw_bus_params *params) { struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev); int ret; @@ -405,7 +419,7 @@ static int rt711_bus_config(struct sdw_slave *slave, } static int rt711_interrupt_callback(struct sdw_slave *slave, - struct sdw_slave_intr_status *status) + struct sdw_slave_intr_status *status) { struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev); @@ -428,7 +442,7 @@ static struct sdw_slave_ops rt711_slave_ops = { }; static int rt711_sdw_probe(struct sdw_slave *slave, - const struct sdw_device_id *id) + const struct sdw_device_id *id) { struct regmap *sdw_regmap, *regmap; @@ -440,7 +454,8 @@ static int rt711_sdw_probe(struct sdw_slave *slave, if (!sdw_regmap) return -EINVAL; - regmap = devm_regmap_init(&slave->dev, NULL, &slave->dev, &rt711_regmap); + regmap = devm_regmap_init(&slave->dev, NULL, + &slave->dev, &rt711_regmap); if (!regmap) return -EINVAL; @@ -492,7 +507,7 @@ static int rt711_dev_resume(struct device *dev) return 0; time = wait_for_completion_timeout(&slave->enumeration_complete, - msecs_to_jiffies(RT711_PROBE_TIMEOUT)); + msecs_to_jiffies(RT711_PROBE_TIMEOUT)); if (!time) { dev_err(&slave->dev, "Enumeration not complete, timed out\n"); return -ETIMEDOUT; @@ -500,7 +515,7 @@ static int rt711_dev_resume(struct device *dev) regcache_cache_only(rt711->regmap, false); regcache_sync_region(rt711->regmap, 0x3000, 0x8fff); - regcache_sync_region(rt711->regmap, 0x75200010, 0x75200091); + regcache_sync_region(rt711->regmap, 0x752010, 0x752091); return 0; } diff --git a/sound/soc/codecs/rt711-sdw.h b/sound/soc/codecs/rt711-sdw.h index 7d0a2a3c699470..10cd6e2cc063a1 100644 --- a/sound/soc/codecs/rt711-sdw.h +++ b/sound/soc/codecs/rt711-sdw.h @@ -267,13 +267,13 @@ static const struct reg_default rt711_reg_defaults[] = { { 0x8393, 0x00 }, { 0x7319, 0x00 }, { 0x8399, 0x00 }, - { 0x7520001a, 0x8003 }, - { 0x75200045, 0x5289 }, - { 0x75200048, 0xd049 }, - { 0x7520004a, 0xa83b }, - { 0x7520006b, 0x5064 }, - { 0x7520006f, 0x058b }, - { 0x75200091, 0x0000 }, + { 0x75201a, 0x8003 }, + { 0x752045, 0x5289 }, + { 0x752048, 0xd049 }, + { 0x75204a, 0xa83b }, + { 0x75206b, 0x5064 }, + { 0x75206f, 0x058b }, + { 0x752091, 0x0000 }, }; #endif /* __RT711_SDW_H__ */ diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 183201f7212f52..11fab034e9735c 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -41,11 +41,12 @@ static int rt711_index_write(struct regmap *regmap, unsigned int nid, unsigned int reg, unsigned int value) { int ret; - unsigned int addr = ((RT711_PRIV_INDEX_W_H | nid) << 16) | reg; + unsigned int addr = ((RT711_PRIV_INDEX_W_H | nid) << 8) | reg; ret = regmap_write(regmap, addr, value); if (ret < 0) - pr_err("Failed to set private value: %08x <= %04x %d\n", ret, addr, value); + pr_err("Failed to set private value: %06x <= %04x ret=%d\n", + addr, value, ret); return ret; } @@ -54,12 +55,13 @@ static unsigned int rt711_index_read(struct regmap *regmap, unsigned int nid, unsigned int reg, unsigned int *value) { int ret; - unsigned int addr = ((RT711_PRIV_INDEX_W_H | nid) << 16) | reg; + unsigned int addr = ((RT711_PRIV_INDEX_W_H | nid) << 8) | reg; *value = 0; ret = regmap_read(regmap, addr, value); if (ret < 0) - pr_err("Failed to get private value: %08x => %04x %d\n", ret, addr, *value); + pr_err("Failed to get private value: %06x => %04x ret=%d\n", + addr, *value, ret); return ret; } @@ -71,7 +73,7 @@ static void rt711_reset(struct regmap *regmap) regmap_write(regmap, RT711_FUNC_RESET, 0); rt711_index_read(regmap, RT711_VENDOR_REG, RT711_PARA_VERB_CTL, &val); rt711_index_write(regmap, RT711_VENDOR_REG, - RT711_PARA_VERB_CTL, (val | RT711_HIDDEN_REG_SW_RESET)); + RT711_PARA_VERB_CTL, (val | RT711_HIDDEN_REG_SW_RESET)); } static int rt711_calibration(struct rt711_priv *rt711) @@ -184,7 +186,7 @@ static int rt711_headset_detect(struct rt711_priv *rt711) int ret; ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG, - RT711_COMBO_JACK_AUTO_CTL2, &buf); + RT711_COMBO_JACK_AUTO_CTL2, &buf); if (ret < 0) goto io_error; @@ -402,8 +404,8 @@ static int rt711_set_jack_detect(struct snd_soc_component *component, } static void rt711_get_gain(struct rt711_priv *rt711, unsigned int addr_h, - unsigned int addr_l, unsigned int val_h, - unsigned int *r_val, unsigned int *l_val) + unsigned int addr_l, unsigned int val_h, + unsigned int *r_val, unsigned int *l_val) { /* R Channel */ *r_val = (val_h << 8); @@ -417,7 +419,7 @@ static void rt711_get_gain(struct rt711_priv *rt711, unsigned int addr_h, /* For Verb-Set Amplifier Gain (Verb ID = 3h) */ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct snd_soc_dapm_context *dapm = @@ -459,7 +461,7 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol, if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) regmap_write(rt711->regmap, - RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); + RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); /* R Channel */ if (mc->invert) { @@ -484,16 +486,20 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol, if (val_ll == val_lr) { /* Set both L/R channels at the same time */ val_h = (1 << mc->shift) | (3 << 4); - regmap_write(rt711->regmap, addr_h, (val_h << 8 | val_ll)); - regmap_write(rt711->regmap, addr_l, (val_h << 8 | val_ll)); + regmap_write(rt711->regmap, + addr_h, (val_h << 8 | val_ll)); + regmap_write(rt711->regmap, + addr_l, (val_h << 8 | val_ll)); } else { /* Lch*/ val_h = (1 << mc->shift) | (1 << 5); - regmap_write(rt711->regmap, addr_h, (val_h << 8 | val_ll)); + regmap_write(rt711->regmap, + addr_h, (val_h << 8 | val_ll)); /* Rch */ val_h = (1 << mc->shift) | (1 << 4); - regmap_write(rt711->regmap, addr_l, (val_h << 8 | val_lr)); + regmap_write(rt711->regmap, + addr_l, (val_h << 8 | val_lr)); } /* check result */ if (mc->shift == RT711_DIR_OUT_SFT) /* output */ @@ -502,19 +508,19 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol, val_h = 0x0; rt711_get_gain(rt711, addr_h, addr_l, val_h, - &read_rl, &read_ll); + &read_rl, &read_ll); if (read_rl == val_lr && read_ll == val_ll) break; } if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) regmap_write(rt711->regmap, - RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); + RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); return 0; } static int rt711_set_amp_gain_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); @@ -553,40 +559,42 @@ static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); static const struct snd_kcontrol_new rt711_snd_controls[] = { - SOC_DOUBLE_R_EXT_TLV("DAC Surr Playback Volume", RT711_SET_GAIN_DAC2_H, - RT711_SET_GAIN_DAC2_L, RT711_DIR_OUT_SFT, 0x57, 0, - rt711_set_amp_gain_get, rt711_set_amp_gain_put, - out_vol_tlv), - SOC_DOUBLE_R_EXT("ADC 08 Capture Switch", RT711_SET_GAIN_ADC2_H, - RT711_SET_GAIN_ADC2_L, RT711_DIR_IN_SFT, 1, 1, - rt711_set_amp_gain_get, rt711_set_amp_gain_put), - SOC_DOUBLE_R_EXT("ADC 09 Capture Switch", RT711_SET_GAIN_ADC1_H, - RT711_SET_GAIN_ADC1_L, RT711_DIR_IN_SFT, 1, 1, - rt711_set_amp_gain_get, rt711_set_amp_gain_put), - SOC_DOUBLE_R_EXT_TLV("ADC 08 Capture Volume", RT711_SET_GAIN_ADC2_H, - RT711_SET_GAIN_ADC2_L, RT711_DIR_IN_SFT, 0x3f, 0, - rt711_set_amp_gain_get, rt711_set_amp_gain_put, - in_vol_tlv), - SOC_DOUBLE_R_EXT_TLV("ADC 09 Capture Volume", RT711_SET_GAIN_ADC1_H, - RT711_SET_GAIN_ADC1_L, RT711_DIR_IN_SFT, 0x3f, 0, - rt711_set_amp_gain_get, rt711_set_amp_gain_put, - in_vol_tlv), - SOC_DOUBLE_R_EXT_TLV("AMIC Volume", RT711_SET_GAIN_AMIC_H, - RT711_SET_GAIN_AMIC_L, RT711_DIR_IN_SFT, 3, 0, - rt711_set_amp_gain_get, rt711_set_amp_gain_put, - mic_vol_tlv), - SOC_DOUBLE_R_EXT_TLV("DMIC1 Volume", RT711_SET_GAIN_DMIC1_H, - RT711_SET_GAIN_DMIC1_L, RT711_DIR_IN_SFT, 3, 0, - rt711_set_amp_gain_get, rt711_set_amp_gain_put, - mic_vol_tlv), - SOC_DOUBLE_R_EXT_TLV("DMIC2 Volume", RT711_SET_GAIN_DMIC2_H, - RT711_SET_GAIN_DMIC2_L, RT711_DIR_IN_SFT, 3, 0, - rt711_set_amp_gain_get, rt711_set_amp_gain_put, - mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("DAC Surr Playback Volume", + RT711_SET_GAIN_DAC2_H, RT711_SET_GAIN_DAC2_L, + RT711_DIR_OUT_SFT, 0x57, 0, + rt711_set_amp_gain_get, rt711_set_amp_gain_put, out_vol_tlv), + SOC_DOUBLE_R_EXT("ADC 08 Capture Switch", + RT711_SET_GAIN_ADC2_H, RT711_SET_GAIN_ADC2_L, + RT711_DIR_IN_SFT, 1, 1, + rt711_set_amp_gain_get, rt711_set_amp_gain_put), + SOC_DOUBLE_R_EXT("ADC 09 Capture Switch", + RT711_SET_GAIN_ADC1_H, RT711_SET_GAIN_ADC1_L, + RT711_DIR_IN_SFT, 1, 1, + rt711_set_amp_gain_get, rt711_set_amp_gain_put), + SOC_DOUBLE_R_EXT_TLV("ADC 08 Capture Volume", + RT711_SET_GAIN_ADC2_H, RT711_SET_GAIN_ADC2_L, + RT711_DIR_IN_SFT, 0x3f, 0, + rt711_set_amp_gain_get, rt711_set_amp_gain_put, in_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("ADC 09 Capture Volume", + RT711_SET_GAIN_ADC1_H, RT711_SET_GAIN_ADC1_L, + RT711_DIR_IN_SFT, 0x3f, 0, + rt711_set_amp_gain_get, rt711_set_amp_gain_put, in_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("AMIC Volume", + RT711_SET_GAIN_AMIC_H, RT711_SET_GAIN_AMIC_L, + RT711_DIR_IN_SFT, 3, 0, + rt711_set_amp_gain_get, rt711_set_amp_gain_put, mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("DMIC1 Volume", + RT711_SET_GAIN_DMIC1_H, RT711_SET_GAIN_DMIC1_L, + RT711_DIR_IN_SFT, 3, 0, + rt711_set_amp_gain_get, rt711_set_amp_gain_put, mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("DMIC2 Volume", + RT711_SET_GAIN_DMIC2_H, RT711_SET_GAIN_DMIC2_L, + RT711_DIR_IN_SFT, 3, 0, + rt711_set_amp_gain_get, rt711_set_amp_gain_put, mic_vol_tlv), }; static int rt711_mux_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); @@ -605,7 +613,8 @@ static int rt711_mux_get(struct snd_kcontrol *kcontrol, reg = RT711_VERB_SET_CONNECT_SEL | nid; ret = regmap_read(rt711->regmap, reg, &val); if (ret < 0) { - dev_err(component->dev, "%s: sdw read failed: %d\n", __func__, ret); + dev_err(component->dev, "%s: sdw read failed: %d\n", + __func__, ret); return ret; } @@ -615,7 +624,7 @@ static int rt711_mux_get(struct snd_kcontrol *kcontrol, } static int rt711_mux_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); @@ -643,7 +652,8 @@ static int rt711_mux_put(struct snd_kcontrol *kcontrol, reg = RT711_VERB_SET_CONNECT_SEL | nid; ret = regmap_read(rt711->regmap, reg, &val2); if (ret < 0) { - dev_err(component->dev, "%s: sdw read failed: %d\n", __func__, ret); + dev_err(component->dev, "%s: sdw read failed: %d\n", + __func__, ret); return ret; } @@ -658,7 +668,7 @@ static int rt711_mux_put(struct snd_kcontrol *kcontrol, } snd_soc_dapm_mux_update_power(dapm, kcontrol, - item[0], e, NULL); + item[0], e, NULL); return change; } @@ -871,7 +881,7 @@ static int rt711_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, } static void rt711_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) + struct snd_soc_dai *dai) { struct sdw_stream_data *stream; @@ -881,8 +891,8 @@ static void rt711_shutdown(struct snd_pcm_substream *substream, } static int rt711_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); @@ -926,7 +936,7 @@ static int rt711_pcm_hw_params(struct snd_pcm_substream *substream, port_config.num = port; retval = sdw_stream_add_slave(rt711->slave, &stream_config, - &port_config, 1, stream->sdw_stream); + &port_config, 1, stream->sdw_stream); if (retval) { dev_err(dai->dev, "Unable to configure port\n"); return retval; @@ -970,7 +980,7 @@ static int rt711_pcm_hw_params(struct snd_pcm_substream *substream, } static int rt711_pcm_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) + struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); @@ -1084,7 +1094,7 @@ static void rt711_calibration_work(struct work_struct *work) } int rt711_init(struct device *dev, struct regmap *sdw_regmap, - struct regmap *regmap, struct sdw_slave *slave) + struct regmap *regmap, struct sdw_slave *slave) { struct rt711_priv *rt711; int ret; @@ -1106,9 +1116,9 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap, rt711->first_init = false; ret = devm_snd_soc_register_component(dev, - &soc_codec_dev_rt711, - rt711_dai, - ARRAY_SIZE(rt711_dai)); + &soc_codec_dev_rt711, + rt711_dai, + ARRAY_SIZE(rt711_dai)); dev_dbg(&slave->dev, "%s\n", __func__); From a639fd756d8839e146f01885782ff67a892a84db Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 23 Oct 2019 13:44:08 +0800 Subject: [PATCH 1841/1995] ASoC: rt700: changes 32bits address mapping of index defined registers to 24bits It takes too many times to dump the registers when using 32 bits mapping. We change it to 24 bits to map the Realtek index defined registers. And this patch fixes some coding style. Signed-off-by: Shuming Fan --- sound/soc/codecs/rt700-sdw.c | 127 ++++++++++++++++++++--------------- sound/soc/codecs/rt700-sdw.h | 10 +-- sound/soc/codecs/rt700.c | 114 ++++++++++++++++--------------- 3 files changed, 137 insertions(+), 114 deletions(-) diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index 2ec16a5b9015aa..30977b9c3c08d1 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -38,14 +38,14 @@ static bool rt700_readable_register(struct device *dev, unsigned int reg) case 0x8300 ... 0x83ff: case 0x9c00 ... 0x9cff: case 0xb900 ... 0xb9ff: - case 0x7520001a: - case 0x75200045: - case 0x75200046: - case 0x75200048: - case 0x7520004a: - case 0x7520006b: - case 0x75200080: - case 0x75200081: + case 0x75201a: + case 0x752045: + case 0x752046: + case 0x752048: + case 0x75204a: + case 0x75206b: + case 0x752080: + case 0x752081: return true; default: return false; @@ -72,10 +72,10 @@ static bool rt700_volatile_register(struct device *dev, unsigned int reg) case 0x9c00 ... 0x9cff: case 0xb900 ... 0xb9ff: case 0xff01: - case 0x7520001a: - case 0x75200046: - case 0x75200080: - case 0x75200081: + case 0x75201a: + case 0x752046: + case 0x752080: + case 0x752081: return true; default: return false; @@ -97,20 +97,21 @@ static int rt700_sdw_read(void *context, unsigned int reg, unsigned int *val) mask = reg & 0xf000; if (is_index_reg) { /* index registers */ - val2 = reg & 0xffff; - reg = reg >> 16; + val2 = reg & 0xff; + reg = reg >> 8; nid = reg & 0xff; - ret = regmap_write(rt700->sdw_regmap, reg, ((val2 >> 8) & 0xff)); + ret = regmap_write(rt700->sdw_regmap, reg, 0); if (ret < 0) return ret; reg2 = reg + 0x1000; reg2 |= 0x80; - ret = regmap_write(rt700->sdw_regmap, reg2, (val2 & 0xff)); + ret = regmap_write(rt700->sdw_regmap, reg2, val2); if (ret < 0) return ret; reg3 = RT700_PRIV_DATA_R_H | nid; - ret = regmap_write(rt700->sdw_regmap, reg3, ((*val >> 8) & 0xff)); + ret = regmap_write(rt700->sdw_regmap, + reg3, ((*val >> 8) & 0xff)); if (ret < 0) return ret; reg4 = reg3 + 0x1000; @@ -126,7 +127,8 @@ static int rt700_sdw_read(void *context, unsigned int reg, unsigned int *val) } else if (mask == 0x7000) { reg += 0x2000; reg |= 0x800; - ret = regmap_write(rt700->sdw_regmap, reg, ((*val >> 8) & 0xff)); + ret = regmap_write(rt700->sdw_regmap, + reg, ((*val >> 8) & 0xff)); if (ret < 0) return ret; reg2 = reg + 0x1000; @@ -137,14 +139,16 @@ static int rt700_sdw_read(void *context, unsigned int reg, unsigned int *val) } else if ((reg & 0xff00) == 0x8300) { /* for R channel */ reg2 = reg - 0x1000; reg2 &= ~0x80; - ret = regmap_write(rt700->sdw_regmap, reg2, ((*val >> 8) & 0xff)); + ret = regmap_write(rt700->sdw_regmap, + reg2, ((*val >> 8) & 0xff)); if (ret < 0) return ret; ret = regmap_write(rt700->sdw_regmap, reg, (*val & 0xff)); if (ret < 0) return ret; } else if (mask == 0x9000) { - ret = regmap_write(rt700->sdw_regmap, reg, ((*val >> 8) & 0xff)); + ret = regmap_write(rt700->sdw_regmap, + reg, ((*val >> 8) & 0xff)); if (ret < 0) return ret; reg2 = reg + 0x1000; @@ -168,29 +172,35 @@ static int rt700_sdw_read(void *context, unsigned int reg, unsigned int *val) sdw_data_2 = 0; sdw_data_1 = 0; sdw_data_0 = 0; - ret = regmap_read(rt700->sdw_regmap, RT700_READ_HDA_3, &sdw_data_3); + ret = regmap_read(rt700->sdw_regmap, + RT700_READ_HDA_3, &sdw_data_3); if (ret < 0) return ret; - ret = regmap_read(rt700->sdw_regmap, RT700_READ_HDA_2, &sdw_data_2); + ret = regmap_read(rt700->sdw_regmap, + RT700_READ_HDA_2, &sdw_data_2); if (ret < 0) return ret; - ret = regmap_read(rt700->sdw_regmap, RT700_READ_HDA_1, &sdw_data_1); + ret = regmap_read(rt700->sdw_regmap, + RT700_READ_HDA_1, &sdw_data_1); if (ret < 0) return ret; - ret = regmap_read(rt700->sdw_regmap, RT700_READ_HDA_0, &sdw_data_0); + ret = regmap_read(rt700->sdw_regmap, + RT700_READ_HDA_0, &sdw_data_0); if (ret < 0) return ret; - *val = ((sdw_data_3 & 0xff) << 24) | ((sdw_data_2 & 0xff) << 16) | - ((sdw_data_1 & 0xff) << 8) | (sdw_data_0 & 0xff); + *val = ((sdw_data_3 & 0xff) << 24) | + ((sdw_data_2 & 0xff) << 16) | + ((sdw_data_1 & 0xff) << 8) | (sdw_data_0 & 0xff); } if (is_hda_reg == 0) dev_dbg(dev, "[%s] %04x => %08x\n", __func__, reg, *val); else if (is_index_reg) - dev_dbg(dev, "[%s] %04x %04x %04x %04x => %08x\n", __func__, - reg, reg2, reg3, reg4, *val); + dev_dbg(dev, "[%s] %04x %04x %04x %04x => %08x\n", + __func__, reg, reg2, reg3, reg4, *val); else - dev_dbg(dev, "[%s] %04x %04x => %08x\n", __func__, reg, reg2, *val); + dev_dbg(dev, "[%s] %04x %04x => %08x\n", + __func__, reg, reg2, *val); return 0; } @@ -209,20 +219,21 @@ static int rt700_sdw_write(void *context, unsigned int reg, unsigned int val) mask = reg & 0xf000; if (is_index_reg) { /* index registers */ - val2 = reg & 0xffff; - reg = reg >> 16; + val2 = reg & 0xff; + reg = reg >> 8; nid = reg & 0xff; - ret = regmap_write(rt700->sdw_regmap, reg, ((val2 >> 8) & 0xff)); + ret = regmap_write(rt700->sdw_regmap, reg, 0); if (ret < 0) return ret; reg2 = reg + 0x1000; reg2 |= 0x80; - ret = regmap_write(rt700->sdw_regmap, reg2, (val2 & 0xff)); + ret = regmap_write(rt700->sdw_regmap, reg2, val2); if (ret < 0) return ret; reg3 = RT700_PRIV_DATA_W_H | nid; - ret = regmap_write(rt700->sdw_regmap, reg3, ((val >> 8) & 0xff)); + ret = regmap_write(rt700->sdw_regmap, + reg3, ((val >> 8) & 0xff)); if (ret < 0) return ret; reg4 = reg3 + 0x1000; @@ -240,7 +251,8 @@ static int rt700_sdw_write(void *context, unsigned int reg, unsigned int val) if (ret < 0) return ret; } else if (mask == 0x7000) { - ret = regmap_write(rt700->sdw_regmap, reg, ((val >> 8) & 0xff)); + ret = regmap_write(rt700->sdw_regmap, + reg, ((val >> 8) & 0xff)); if (ret < 0) return ret; reg2 = reg + 0x1000; @@ -251,7 +263,8 @@ static int rt700_sdw_write(void *context, unsigned int reg, unsigned int val) } else if ((reg & 0xff00) == 0x8300) { /* for R channel */ reg2 = reg - 0x1000; reg2 &= ~0x80; - ret = regmap_write(rt700->sdw_regmap, reg2, ((val >> 8) & 0xff)); + ret = regmap_write(rt700->sdw_regmap, + reg2, ((val >> 8) & 0xff)); if (ret < 0) return ret; ret = regmap_write(rt700->sdw_regmap, reg, (val & 0xff)); @@ -262,20 +275,21 @@ static int rt700_sdw_write(void *context, unsigned int reg, unsigned int val) if (reg2 == 0) dev_dbg(dev, "[%s] %04x <= %04x\n", __func__, reg, val); else if (is_index_reg) - dev_dbg(dev, "[%s] %04x %04x %04x %04x <= %04x %04x\n", __func__, - reg, reg2, reg3, reg4, val2, val); + dev_dbg(dev, "[%s] %04x %04x %04x %04x <= %04x %04x\n", + __func__, reg, reg2, reg3, reg4, val2, val); else - dev_dbg(dev, "[%s] %04x %04x <= %04x\n", __func__, reg, reg2, val); + dev_dbg(dev, "[%s] %04x %04x <= %04x\n", + __func__, reg, reg2, val); return 0; } static const struct regmap_config rt700_regmap = { - .reg_bits = 32, + .reg_bits = 24, .val_bits = 32, .readable_reg = rt700_readable_register, /* Readable registers */ .volatile_reg = rt700_volatile_register, /* volatile register */ - .max_register = 0x75580000, /* Maximum number of register */ + .max_register = 0x755800, /* Maximum number of register */ .reg_defaults = rt700_reg_defaults, /* Defaults */ .num_reg_defaults = ARRAY_SIZE(rt700_reg_defaults), .cache_type = REGCACHE_RBTREE, @@ -297,7 +311,7 @@ static const struct regmap_config rt700_sdw_regmap = { }; static int rt700_update_status(struct sdw_slave *slave, - enum sdw_slave_status status) + enum sdw_slave_status status) { struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev); @@ -329,14 +343,14 @@ static int rt700_read_prop(struct sdw_slave *slave) prop->paging_support = false; /* first we need to allocate memory for set bits in port lists */ - prop->source_ports = 0x14; /* BITMAP: 00010100 */ - prop->sink_ports = 0xA; /* BITMAP: 00001010 */ + prop->source_ports = 0x14; /* BITMAP: 00010100 */ + prop->sink_ports = 0xA; /* BITMAP: 00001010 */ nval = hweight32(prop->source_ports); num_of_ports += nval; prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, - sizeof(*prop->src_dpn_prop), - GFP_KERNEL); + sizeof(*prop->src_dpn_prop), + GFP_KERNEL); if (!prop->src_dpn_prop) return -ENOMEM; @@ -355,8 +369,8 @@ static int rt700_read_prop(struct sdw_slave *slave) nval = hweight32(prop->sink_ports); num_of_ports += nval; prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, - sizeof(*prop->sink_dpn_prop), - GFP_KERNEL); + sizeof(*prop->sink_dpn_prop), + GFP_KERNEL); if (!prop->sink_dpn_prop) return -ENOMEM; @@ -373,8 +387,8 @@ static int rt700_read_prop(struct sdw_slave *slave) /* Allocate port_ready based on num_of_ports */ slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports, - sizeof(*slave->port_ready), - GFP_KERNEL); + sizeof(*slave->port_ready), + GFP_KERNEL); if (!slave->port_ready) return -ENOMEM; @@ -389,7 +403,7 @@ static int rt700_read_prop(struct sdw_slave *slave) } static int rt700_bus_config(struct sdw_slave *slave, - struct sdw_bus_params *params) + struct sdw_bus_params *params) { struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev); int ret; @@ -404,7 +418,7 @@ static int rt700_bus_config(struct sdw_slave *slave, } static int rt700_interrupt_callback(struct sdw_slave *slave, - struct sdw_slave_intr_status *status) + struct sdw_slave_intr_status *status) { struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev); @@ -431,7 +445,7 @@ static struct sdw_slave_ops rt700_slave_ops = { }; static int rt700_sdw_probe(struct sdw_slave *slave, - const struct sdw_device_id *id) + const struct sdw_device_id *id) { struct regmap *sdw_regmap, *regmap; @@ -443,7 +457,8 @@ static int rt700_sdw_probe(struct sdw_slave *slave, if (!sdw_regmap) return -EINVAL; - regmap = devm_regmap_init(&slave->dev, NULL, &slave->dev, &rt700_regmap); + regmap = devm_regmap_init(&slave->dev, NULL, + &slave->dev, &rt700_regmap); if (!regmap) return -EINVAL; @@ -494,7 +509,7 @@ static int rt700_dev_resume(struct device *dev) return 0; time = wait_for_completion_timeout(&slave->enumeration_complete, - msecs_to_jiffies(RT700_PROBE_TIMEOUT)); + msecs_to_jiffies(RT700_PROBE_TIMEOUT)); if (!time) { dev_err(&slave->dev, "Enumeration not complete, timed out\n"); return -ETIMEDOUT; @@ -502,7 +517,7 @@ static int rt700_dev_resume(struct device *dev) regcache_cache_only(rt700->regmap, false); regcache_sync_region(rt700->regmap, 0x3000, 0x8fff); - regcache_sync_region(rt700->regmap, 0x75200010, 0x7520006b); + regcache_sync_region(rt700->regmap, 0x752010, 0x75206b); return 0; } diff --git a/sound/soc/codecs/rt700-sdw.h b/sound/soc/codecs/rt700-sdw.h index 2f5301b0bd8dff..4ad0dcfd16fdb7 100644 --- a/sound/soc/codecs/rt700-sdw.h +++ b/sound/soc/codecs/rt700-sdw.h @@ -325,11 +325,11 @@ static const struct reg_default rt700_reg_defaults[] = { { 0x8393, 0x0000 }, { 0x7319, 0x0000 }, { 0x8399, 0x0000 }, - { 0x7520001a, 0x8003 }, - { 0x75200045, 0x5289 }, - { 0x75200048, 0xd049 }, - { 0x7520004a, 0xa83b }, - { 0x7520006b, 0x5064 }, + { 0x75201a, 0x8003 }, + { 0x752045, 0x5289 }, + { 0x752048, 0xd049 }, + { 0x75204a, 0xa83b }, + { 0x75206b, 0x5064 }, }; #endif /* __RT700_H__ */ diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index 2bfa9b180e431d..d110e4526409a9 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -38,28 +38,30 @@ #include "rt700.h" static int rt700_index_write(struct regmap *regmap, - unsigned int reg, unsigned int value) + unsigned int reg, unsigned int value) { int ret; - unsigned int addr = (RT700_PRIV_INDEX_W_H << 16) | reg; + unsigned int addr = (RT700_PRIV_INDEX_W_H << 8) | reg; ret = regmap_write(regmap, addr, value); if (ret < 0) - pr_err("Failed to set private value: %08x <= %04x %d\n", ret, addr, value); + pr_err("Failed to set private value: %06x <= %04x ret=%d\n", + addr, value, ret); return ret; } static int rt700_index_read(struct regmap *regmap, - unsigned int reg, unsigned int *value) + unsigned int reg, unsigned int *value) { int ret; - unsigned int addr = (RT700_PRIV_INDEX_W_H << 16) | reg; + unsigned int addr = (RT700_PRIV_INDEX_W_H << 8) | reg; *value = 0; ret = regmap_read(regmap, addr, value); if (ret < 0) - pr_err("Failed to get private value: %08x => %04x %d\n", ret, addr, *value); + pr_err("Failed to get private value: %06x => %04x ret=%d\n", + addr, *value, ret); return ret; } @@ -115,7 +117,7 @@ static int rt700_headset_detect(struct rt700_priv *rt700) int ret; ret = rt700_index_read(rt700->regmap, - RT700_COMBO_JACK_AUTO_CTL2, &buf); + RT700_COMBO_JACK_AUTO_CTL2, &buf); if (ret < 0) goto io_error; @@ -328,8 +330,8 @@ static int rt700_set_jack_detect(struct snd_soc_component *component, } static void rt700_get_gain(struct rt700_priv *rt700, unsigned int addr_h, - unsigned int addr_l, unsigned int val_h, - unsigned int *r_val, unsigned int *l_val) + unsigned int addr_l, unsigned int val_h, + unsigned int *r_val, unsigned int *l_val) { /* R Channel */ *r_val = (val_h << 8); @@ -343,7 +345,7 @@ static void rt700_get_gain(struct rt700_priv *rt700, unsigned int addr_h, /* For Verb-Set Amplifier Gain (Verb ID = 3h) */ static int rt700_set_amp_gain_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct snd_soc_dapm_context *dapm = @@ -384,7 +386,7 @@ static int rt700_set_amp_gain_put(struct snd_kcontrol *kcontrol, if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) regmap_write(rt700->regmap, - RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D0); + RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D0); /* R Channel */ if (mc->invert) { @@ -407,16 +409,20 @@ static int rt700_set_amp_gain_put(struct snd_kcontrol *kcontrol, if (val_ll == val_lr) { /* Set both L/R channels at the same time */ val_h = (1 << mc->shift) | (3 << 4); - regmap_write(rt700->regmap, addr_h, (val_h << 8 | val_ll)); - regmap_write(rt700->regmap, addr_l, (val_h << 8 | val_ll)); + regmap_write(rt700->regmap, + addr_h, (val_h << 8 | val_ll)); + regmap_write(rt700->regmap, + addr_l, (val_h << 8 | val_ll)); } else { /* Lch*/ val_h = (1 << mc->shift) | (1 << 5); - regmap_write(rt700->regmap, addr_h, (val_h << 8 | val_ll)); + regmap_write(rt700->regmap, + addr_h, (val_h << 8 | val_ll)); /* Rch */ val_h = (1 << mc->shift) | (1 << 4); - regmap_write(rt700->regmap, addr_l, (val_h << 8 | val_lr)); + regmap_write(rt700->regmap, + addr_l, (val_h << 8 | val_lr)); } /* check result */ if (mc->shift == RT700_DIR_OUT_SFT) /* output */ @@ -425,19 +431,19 @@ static int rt700_set_amp_gain_put(struct snd_kcontrol *kcontrol, val_h = 0x0; rt700_get_gain(rt700, addr_h, addr_l, val_h, - &read_rl, &read_ll); + &read_rl, &read_ll); if (read_rl == val_lr && read_ll == val_ll) break; } if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) regmap_write(rt700->regmap, - RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3); + RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3); return 0; } static int rt700_set_amp_gain_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); @@ -475,32 +481,34 @@ static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); static const struct snd_kcontrol_new rt700_snd_controls[] = { - SOC_DOUBLE_R_EXT_TLV("DAC Front Playback Volume", RT700_SET_GAIN_DAC1_H, - RT700_SET_GAIN_DAC1_L, RT700_DIR_OUT_SFT, 0x57, 0, - rt700_set_amp_gain_get, rt700_set_amp_gain_put, - out_vol_tlv), - SOC_DOUBLE_R_EXT("ADC 08 Capture Switch", RT700_SET_GAIN_ADC2_H, - RT700_SET_GAIN_ADC2_L, RT700_DIR_IN_SFT, 1, 1, - rt700_set_amp_gain_get, rt700_set_amp_gain_put), - SOC_DOUBLE_R_EXT("ADC 09 Capture Switch", RT700_SET_GAIN_ADC1_H, - RT700_SET_GAIN_ADC1_L, RT700_DIR_IN_SFT, 1, 1, - rt700_set_amp_gain_get, rt700_set_amp_gain_put), - SOC_DOUBLE_R_EXT_TLV("ADC 08 Capture Volume", RT700_SET_GAIN_ADC2_H, - RT700_SET_GAIN_ADC2_L, RT700_DIR_IN_SFT, 0x3f, 0, - rt700_set_amp_gain_get, rt700_set_amp_gain_put, - in_vol_tlv), - SOC_DOUBLE_R_EXT_TLV("ADC 09 Capture Volume", RT700_SET_GAIN_ADC1_H, - RT700_SET_GAIN_ADC1_L, RT700_DIR_IN_SFT, 0x3f, 0, - rt700_set_amp_gain_get, rt700_set_amp_gain_put, - in_vol_tlv), - SOC_DOUBLE_R_EXT_TLV("AMIC Volume", RT700_SET_GAIN_AMIC_H, - RT700_SET_GAIN_AMIC_L, RT700_DIR_IN_SFT, 3, 0, - rt700_set_amp_gain_get, rt700_set_amp_gain_put, - mic_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("DAC Front Playback Volume", + RT700_SET_GAIN_DAC1_H, RT700_SET_GAIN_DAC1_L, + RT700_DIR_OUT_SFT, 0x57, 0, + rt700_set_amp_gain_get, rt700_set_amp_gain_put, out_vol_tlv), + SOC_DOUBLE_R_EXT("ADC 08 Capture Switch", + RT700_SET_GAIN_ADC2_H, RT700_SET_GAIN_ADC2_L, + RT700_DIR_IN_SFT, 1, 1, + rt700_set_amp_gain_get, rt700_set_amp_gain_put), + SOC_DOUBLE_R_EXT("ADC 09 Capture Switch", + RT700_SET_GAIN_ADC1_H, RT700_SET_GAIN_ADC1_L, + RT700_DIR_IN_SFT, 1, 1, + rt700_set_amp_gain_get, rt700_set_amp_gain_put), + SOC_DOUBLE_R_EXT_TLV("ADC 08 Capture Volume", + RT700_SET_GAIN_ADC2_H, RT700_SET_GAIN_ADC2_L, + RT700_DIR_IN_SFT, 0x3f, 0, + rt700_set_amp_gain_get, rt700_set_amp_gain_put, in_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("ADC 09 Capture Volume", + RT700_SET_GAIN_ADC1_H, RT700_SET_GAIN_ADC1_L, + RT700_DIR_IN_SFT, 0x3f, 0, + rt700_set_amp_gain_get, rt700_set_amp_gain_put, in_vol_tlv), + SOC_DOUBLE_R_EXT_TLV("AMIC Volume", + RT700_SET_GAIN_AMIC_H, RT700_SET_GAIN_AMIC_L, + RT700_DIR_IN_SFT, 3, 0, + rt700_set_amp_gain_get, rt700_set_amp_gain_put, mic_vol_tlv), }; static int rt700_mux_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); @@ -529,7 +537,7 @@ static int rt700_mux_get(struct snd_kcontrol *kcontrol, } static int rt700_mux_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); @@ -572,7 +580,7 @@ static int rt700_mux_put(struct snd_kcontrol *kcontrol, } snd_soc_dapm_mux_update_power(dapm, kcontrol, - item[0], e, NULL); + item[0], e, NULL); return change; } @@ -608,7 +616,7 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new rt700_hp_mux = SOC_DAPM_ENUM_EXT("HP Mux", rt700_hp_enum, - rt700_mux_get, rt700_mux_put); + rt700_mux_get, rt700_mux_put); static int rt700_dac_front_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) @@ -867,7 +875,7 @@ static int rt700_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, } static void rt700_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) + struct snd_soc_dai *dai) { struct sdw_stream_data *stream; @@ -877,8 +885,8 @@ static void rt700_shutdown(struct snd_pcm_substream *substream, } static int rt700_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); @@ -929,7 +937,7 @@ static int rt700_pcm_hw_params(struct snd_pcm_substream *substream, port_config.num = port; retval = sdw_stream_add_slave(rt700->slave, &stream_config, - &port_config, 1, stream->sdw_stream); + &port_config, 1, stream->sdw_stream); if (retval) { dev_err(dai->dev, "Unable to configure port\n"); return retval; @@ -972,7 +980,7 @@ static int rt700_pcm_hw_params(struct snd_pcm_substream *substream, } static int rt700_pcm_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) + struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); @@ -1085,7 +1093,7 @@ int rt700_clock_config(struct device *dev) } int rt700_init(struct device *dev, struct regmap *sdw_regmap, - struct regmap *regmap, struct sdw_slave *slave) + struct regmap *regmap, struct sdw_slave *slave) { struct rt700_priv *rt700; @@ -1108,9 +1116,9 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap, rt700->first_init = false; ret = devm_snd_soc_register_component(dev, - &soc_codec_dev_rt700, - rt700_dai, - ARRAY_SIZE(rt700_dai)); + &soc_codec_dev_rt700, + rt700_dai, + ARRAY_SIZE(rt700_dai)); dev_dbg(&slave->dev, "%s\n", __func__); From 98a1631b339adb47c32cecac968dd9757994b6ec Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 23 Oct 2019 13:44:23 +0800 Subject: [PATCH 1842/1995] ASoC: rt1308-sdw: fix some coding style Signed-off-by: Shuming Fan --- sound/soc/codecs/rt1308-sdw.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index 5730f59ae08022..fac0fa20843eac 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -129,15 +129,15 @@ static int rt1308_read_prop(struct sdw_slave *slave) prop->paging_support = true; /* first we need to allocate memory for set bits in port lists */ - prop->source_ports = 0x00; /* BITMAP: 00010100 (not enable yet) */ - prop->sink_ports = 0x2; /* BITMAP: 00000010 */ + prop->source_ports = 0x00; /* BITMAP: 00010100 (not enable yet) */ + prop->sink_ports = 0x2; /* BITMAP: 00000010 */ /* for sink */ nval = hweight32(prop->sink_ports); num_of_ports += nval; prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, - sizeof(*prop->sink_dpn_prop), - GFP_KERNEL); + sizeof(*prop->sink_dpn_prop), + GFP_KERNEL); if (!prop->sink_dpn_prop) return -ENOMEM; @@ -154,8 +154,8 @@ static int rt1308_read_prop(struct sdw_slave *slave) /* Allocate port_ready based on num_of_ports */ slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports, - sizeof(*slave->port_ready), - GFP_KERNEL); + sizeof(*slave->port_ready), + GFP_KERNEL); if (!slave->port_ready) return -ENOMEM; @@ -258,7 +258,7 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) } static int rt1308_update_status(struct sdw_slave *slave, - enum sdw_slave_status status) + enum sdw_slave_status status) { struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev); @@ -280,7 +280,7 @@ static int rt1308_update_status(struct sdw_slave *slave, } static int rt1308_bus_config(struct sdw_slave *slave, - struct sdw_bus_params *params) + struct sdw_bus_params *params) { struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev); int ret; @@ -295,7 +295,7 @@ static int rt1308_bus_config(struct sdw_slave *slave, } static int rt1308_interrupt_callback(struct sdw_slave *slave, - struct sdw_slave_intr_status *status) + struct sdw_slave_intr_status *status) { dev_dbg(&slave->dev, "%s control_port_stat=%x", __func__, status->control_port); @@ -469,7 +469,7 @@ static int rt1308_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, } static void rt1308_sdw_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) + struct snd_soc_dai *dai) { struct sdw_stream_data *stream; @@ -528,7 +528,7 @@ static int rt1308_sdw_hw_params(struct snd_pcm_substream *substream, } static int rt1308_sdw_pcm_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) + struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; struct rt1308_sdw_priv *rt1308 = @@ -590,7 +590,7 @@ static struct snd_soc_dai_driver rt1308_sdw_dai[] = { }; static int rt1308_sdw_init(struct device *dev, struct regmap *regmap, - struct sdw_slave *slave) + struct sdw_slave *slave) { struct rt1308_sdw_priv *rt1308; int ret; @@ -611,9 +611,9 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap, rt1308->first_init = false; ret = devm_snd_soc_register_component(dev, - &soc_component_sdw_rt1308, - rt1308_sdw_dai, - ARRAY_SIZE(rt1308_sdw_dai)); + &soc_component_sdw_rt1308, + rt1308_sdw_dai, + ARRAY_SIZE(rt1308_sdw_dai)); dev_dbg(&slave->dev, "%s\n", __func__); @@ -621,7 +621,7 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap, } static int rt1308_sdw_probe(struct sdw_slave *slave, - const struct sdw_device_id *id) + const struct sdw_device_id *id) { struct regmap *regmap; @@ -668,7 +668,7 @@ static int rt1308_dev_resume(struct device *dev) return 0; time = wait_for_completion_timeout(&slave->enumeration_complete, - msecs_to_jiffies(RT1308_PROBE_TIMEOUT)); + msecs_to_jiffies(RT1308_PROBE_TIMEOUT)); if (!time) { dev_err(&slave->dev, "Enumeration not complete, timed out\n"); return -ETIMEDOUT; From 91b79e98eb2adc500f1a33d6e9356623e2046414 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 24 Oct 2019 13:29:54 +0800 Subject: [PATCH 1843/1995] Resume correct register setting for dmic recording after suspend. Signed-off-by: Jack Yu --- sound/soc/codecs/rt715-sdw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index 58f5e31131385d..66e7d09ef263c7 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -74,7 +74,6 @@ static bool rt715_volatile_register(struct device *dev, unsigned int reg) case 0x2220 ... 0x2223: /* decoded HD-A */ case 0x9c00 ... 0x9cff: case 0xb900 ... 0xb9ff: - case 0x75200039: return true; default: return false; From 21e7a4d4d5e70c1f83f44942dcf20ed650af50d9 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 24 Oct 2019 20:50:50 +0800 Subject: [PATCH 1844/1995] ASoC: rt711: add JD2 configuration In dell project, the JD source changes to JD2. Therefore, the codec driver add the JD2 configuration in default. The application circuit also changes to JD2 as JD source. Signed-off-by: Shuming Fan --- sound/soc/codecs/rt711-sdw.c | 2 + sound/soc/codecs/rt711-sdw.h | 2 + sound/soc/codecs/rt711.c | 76 +++++++++++++++++++++++++++--------- sound/soc/codecs/rt711.h | 19 ++++++++- 4 files changed, 80 insertions(+), 19 deletions(-) diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 404a4b6ad4a904..5223bc17d00ca4 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -37,6 +37,8 @@ static bool rt711_readable_register(struct device *dev, unsigned int reg) case 0x8300 ... 0x83ff: case 0x9c00 ... 0x9cff: case 0xb900 ... 0xb9ff: + case 0x752009: + case 0x752011: case 0x75201a: case 0x752045: case 0x752046: diff --git a/sound/soc/codecs/rt711-sdw.h b/sound/soc/codecs/rt711-sdw.h index 10cd6e2cc063a1..43b2b984b29cb9 100644 --- a/sound/soc/codecs/rt711-sdw.h +++ b/sound/soc/codecs/rt711-sdw.h @@ -267,6 +267,8 @@ static const struct reg_default rt711_reg_defaults[] = { { 0x8393, 0x00 }, { 0x7319, 0x00 }, { 0x8399, 0x00 }, + { 0x752009, 0x1029 }, + { 0x752011, 0x007a }, { 0x75201a, 0x8003 }, { 0x752045, 0x5289 }, { 0x752048, 0xd049 }, diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 11fab034e9735c..96f9fe21d9a469 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -51,7 +51,7 @@ static int rt711_index_write(struct regmap *regmap, return ret; } -static unsigned int rt711_index_read(struct regmap *regmap, +static int rt711_index_read(struct regmap *regmap, unsigned int nid, unsigned int reg, unsigned int *value) { int ret; @@ -66,14 +66,28 @@ static unsigned int rt711_index_read(struct regmap *regmap, return ret; } -static void rt711_reset(struct regmap *regmap) +static int rt711_index_update_bits(struct regmap *regmap, unsigned int nid, + unsigned int reg, unsigned int mask, unsigned int val) { - unsigned int val; + unsigned int tmp, orig; + int ret; + + ret = rt711_index_read(regmap, nid, reg, &orig); + if (ret < 0) + return ret; + + tmp = orig & ~mask; + tmp |= val & mask; + return rt711_index_write(regmap, nid, reg, tmp); +} + +static void rt711_reset(struct regmap *regmap) +{ regmap_write(regmap, RT711_FUNC_RESET, 0); - rt711_index_read(regmap, RT711_VENDOR_REG, RT711_PARA_VERB_CTL, &val); - rt711_index_write(regmap, RT711_VENDOR_REG, - RT711_PARA_VERB_CTL, (val | RT711_HIDDEN_REG_SW_RESET)); + rt711_index_update_bits(regmap, RT711_VENDOR_REG, + RT711_PARA_VERB_CTL, RT711_HIDDEN_REG_SW_RESET, + RT711_HIDDEN_REG_SW_RESET); } static int rt711_calibration(struct rt711_priv *rt711) @@ -90,16 +104,13 @@ static int rt711_calibration(struct rt711_priv *rt711) dev = regmap_get_device(regmap); /* Calibration manual mode */ - rt711_index_read(regmap, RT711_VENDOR_REG, RT711_FSM_CTL, &val); - val &= 0xfffffff0; - rt711_index_write(regmap, RT711_VENDOR_REG, RT711_FSM_CTL, val); + rt711_index_update_bits(regmap, RT711_VENDOR_REG, RT711_FSM_CTL, + 0xf, 0x0); /* trigger */ - rt711_index_read(regmap, RT711_VENDOR_CALI, - RT711_DAC_DC_CALI_CTL1, &val); - val |= RT711_DAC_DC_CALI_TRIGGER; - rt711_index_write(regmap, RT711_VENDOR_CALI, - RT711_DAC_DC_CALI_CTL1, val); + rt711_index_update_bits(regmap, RT711_VENDOR_CALI, + RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_TRIGGER, + RT711_DAC_DC_CALI_TRIGGER); /* wait for calibration process */ rt711_index_read(regmap, RT711_VENDOR_CALI, @@ -120,10 +131,8 @@ static int rt711_calibration(struct rt711_priv *rt711) } /* depop mode */ - rt711_index_read(regmap, RT711_VENDOR_REG, RT711_FSM_CTL, &val); - val &= 0xfffffff0; - val |= RT711_DEPOP_CTL; - rt711_index_write(regmap, RT711_VENDOR_REG, RT711_FSM_CTL, val); + rt711_index_update_bits(regmap, RT711_VENDOR_REG, + RT711_FSM_CTL, 0xf, RT711_DEPOP_CTL); regmap_write(rt711->regmap, RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); @@ -363,6 +372,25 @@ static void rt711_jack_init(struct rt711_priv *rt711) rt711_index_write(rt711->regmap, RT711_VENDOR_REG, 0x19, 0x2e11); + switch (rt711->jd_src) { + case RT711_JD1: + /* default settings was already for JD1 */ + break; + case RT711_JD2: + rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, + RT711_JD_CTL2, RT711_JD2_2PORT_200K_DECODE_HP | + RT711_HP_JD_SEL_JD2, + RT711_JD2_2PORT_200K_DECODE_HP | + RT711_HP_JD_SEL_JD2); + rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, + RT711_CC_DET1, RT711_HP_JD_FINAL_RESULT_CTL_JD12, + RT711_HP_JD_FINAL_RESULT_CTL_JD12); + break; + default: + dev_warn(rt711->component->dev, "Wrong JD source\n"); + break; + } + dev_dbg(&rt711->slave->dev, "in %s enable\n", __func__); mod_delayed_work(system_power_efficient_wq, @@ -1093,6 +1121,14 @@ static void rt711_calibration_work(struct work_struct *work) rt711_calibration(rt711); } +static int rt711_parse_dt(struct rt711_priv *rt711, struct device *dev) +{ + device_property_read_u32(dev, "realtek,jd-src", + &rt711->jd_src); + + return 0; +} + int rt711_init(struct device *dev, struct regmap *sdw_regmap, struct regmap *regmap, struct sdw_slave *slave) { @@ -1115,6 +1151,10 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap, rt711->hw_init = false; rt711->first_init = false; + /* JD source uses JD2 in default */ + rt711->jd_src = RT711_JD2; + rt711_parse_dt(rt711, &slave->dev); + ret = devm_snd_soc_register_component(dev, &soc_codec_dev_rt711, rt711_dai, diff --git a/sound/soc/codecs/rt711.h b/sound/soc/codecs/rt711.h index 795803db7acd13..ac7509bfa32d8b 100644 --- a/sound/soc/codecs/rt711.h +++ b/sound/soc/codecs/rt711.h @@ -26,7 +26,7 @@ struct rt711_priv { struct delayed_work jack_btn_check_work; struct work_struct calibration_work; struct mutex calibrate_mutex; /* for headset calibration */ - int jack_type; + int jack_type, jd_src; }; struct sdw_stream_data { @@ -54,6 +54,8 @@ struct sdw_stream_data { /* Index (NID:20h) */ #define RT711_DAC_DC_CALI_CTL1 0x00 +#define RT711_JD_CTL2 0x09 +#define RT711_CC_DET1 0x11 #define RT711_PARA_VERB_CTL 0x1a #define RT711_COMBO_JACK_AUTO_CTL1 0x45 #define RT711_COMBO_JACK_AUTO_CTL2 0x46 @@ -171,6 +173,15 @@ struct sdw_stream_data { /* DAC DC offset calibration control-1 (0x00)(NID:20h) */ #define RT711_DAC_DC_CALI_TRIGGER (0x1 << 15) +/* jack detect control 2 (0x09)(NID:20h) */ +#define RT711_JD2_2PORT_200K_DECODE_HP (0x1 << 13) +#define RT711_HP_JD_SEL_JD1 (0x0 << 1) +#define RT711_HP_JD_SEL_JD2 (0x1 << 1) + +/* CC DET1 (0x11)(NID:20h) */ +#define RT711_HP_JD_FINAL_RESULT_CTL_JD12 (0x1 << 10) +#define RT711_HP_JD_FINAL_RESULT_CTL_CCDET (0x0 << 10) + /* Parameter & Verb control (0x1a)(NID:20h) */ #define RT711_HIDDEN_REG_SW_RESET (0x1 << 14) @@ -203,6 +214,12 @@ enum { RT711_AIFS, }; +enum rt711_jd_src { + RT711_JD_NULL, + RT711_JD1, + RT711_JD2 +}; + int rt711_io_init(struct device *dev, struct sdw_slave *slave); int rt711_init(struct device *dev, struct regmap *sdw_regmap, struct regmap *regmap, struct sdw_slave *slave); From 4b51bb34fc70e4390c8f3df4646a6e2990d7a258 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 25 Oct 2019 10:16:19 +0800 Subject: [PATCH 1845/1995] ASoC: codec:rt715-sdw:Modify register mapping of index from 32bits to 24bits. Signed-off-by: Jack Yu --- sound/soc/codecs/rt715-sdw.c | 94 ++++++++++++---------- sound/soc/codecs/rt715-sdw.h | 2 +- sound/soc/codecs/rt715.c | 151 +++++++++++++++++++---------------- sound/soc/codecs/rt715.h | 16 ++++ 4 files changed, 154 insertions(+), 109 deletions(-) diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index 66e7d09ef263c7..c9b1328365abe0 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -45,7 +45,7 @@ static bool rt715_readable_register(struct device *dev, unsigned int reg) case 0x8300 ... 0x83ff: case 0x9c00 ... 0x9cff: case 0xb900 ... 0xb9ff: - case 0x75200039: + case 0x752039: return true; default: return false; @@ -95,20 +95,21 @@ static int rt715_sdw_read(void *context, unsigned int reg, unsigned int *val) mask = reg & 0xf000; if (is_index_reg) { /* index registers */ - val2 = reg & 0xffff; - reg = reg >> 16; + val2 = reg & 0xff; + reg = reg >> 8; nid = reg & 0xff; - ret = regmap_write(rt715->sdw_regmap, reg, ((val2 >> 8) & 0xff)); + ret = regmap_write(rt715->sdw_regmap, reg, 0); if (ret < 0) return ret; reg2 = reg + 0x1000; reg2 |= 0x80; - ret = regmap_write(rt715->sdw_regmap, reg2, (val2 & 0xff)); + ret = regmap_write(rt715->sdw_regmap, reg2, val2); if (ret < 0) return ret; reg3 = RT715_PRIV_DATA_R_H | nid; - ret = regmap_write(rt715->sdw_regmap, reg3, ((*val >> 8) & 0xff)); + ret = regmap_write(rt715->sdw_regmap, reg3, + ((*val >> 8) & 0xff)); if (ret < 0) return ret; reg4 = reg3 + 0x1000; @@ -124,7 +125,8 @@ static int rt715_sdw_read(void *context, unsigned int reg, unsigned int *val) } else if (mask == 0x7000) { reg += 0x2000; reg |= 0x800; - ret = regmap_write(rt715->sdw_regmap, reg, ((*val >> 8) & 0xff)); + ret = regmap_write(rt715->sdw_regmap, reg, + ((*val >> 8) & 0xff)); if (ret < 0) return ret; reg2 = reg + 0x1000; @@ -135,14 +137,16 @@ static int rt715_sdw_read(void *context, unsigned int reg, unsigned int *val) } else if ((reg & 0xff00) == 0x8300) { /* for R channel */ reg2 = reg - 0x1000; reg2 &= ~0x80; - ret = regmap_write(rt715->sdw_regmap, reg2, ((*val >> 8) & 0xff)); + ret = regmap_write(rt715->sdw_regmap, reg2, + ((*val >> 8) & 0xff)); if (ret < 0) return ret; ret = regmap_write(rt715->sdw_regmap, reg, (*val & 0xff)); if (ret < 0) return ret; } else if (mask == 0x9000) { - ret = regmap_write(rt715->sdw_regmap, reg, ((*val >> 8) & 0xff)); + ret = regmap_write(rt715->sdw_regmap, reg, + ((*val >> 8) & 0xff)); if (ret < 0) return ret; reg2 = reg + 0x1000; @@ -166,20 +170,25 @@ static int rt715_sdw_read(void *context, unsigned int reg, unsigned int *val) sdw_data_2 = 0; sdw_data_1 = 0; sdw_data_0 = 0; - ret = regmap_read(rt715->sdw_regmap, RT715_READ_HDA_3, &sdw_data_3); + ret = regmap_read(rt715->sdw_regmap, RT715_READ_HDA_3, + &sdw_data_3); if (ret < 0) return ret; - ret = regmap_read(rt715->sdw_regmap, RT715_READ_HDA_2, &sdw_data_2); + ret = regmap_read(rt715->sdw_regmap, RT715_READ_HDA_2, + &sdw_data_2); if (ret < 0) return ret; - ret = regmap_read(rt715->sdw_regmap, RT715_READ_HDA_1, &sdw_data_1); + ret = regmap_read(rt715->sdw_regmap, RT715_READ_HDA_1, + &sdw_data_1); if (ret < 0) return ret; - ret = regmap_read(rt715->sdw_regmap, RT715_READ_HDA_0, &sdw_data_0); + ret = regmap_read(rt715->sdw_regmap, RT715_READ_HDA_0, + &sdw_data_0); if (ret < 0) return ret; - *val = ((sdw_data_3 & 0xff) << 24) | ((sdw_data_2 & 0xff) << 16) | - ((sdw_data_1 & 0xff) << 8) | (sdw_data_0 & 0xff); + *val = ((sdw_data_3 & 0xff) << 24) | + ((sdw_data_2 & 0xff) << 16) | + ((sdw_data_1 & 0xff) << 8) | (sdw_data_0 & 0xff); } if (is_hda_reg == 0) @@ -188,7 +197,8 @@ static int rt715_sdw_read(void *context, unsigned int reg, unsigned int *val) dev_dbg(dev, "[%s] %04x %04x %04x %04x => %08x\n", __func__, reg, reg2, reg3, reg4, *val); else - dev_dbg(dev, "[%s] %04x %04x => %08x\n", __func__, reg, reg2, *val); + dev_dbg(dev, "[%s] %04x %04x => %08x\n", + __func__, reg, reg2, *val); return 0; } @@ -207,20 +217,21 @@ static int rt715_sdw_write(void *context, unsigned int reg, unsigned int val) mask = reg & 0xf000; if (is_index_reg) { /* index registers */ - val2 = reg & 0xffff; - reg = reg >> 16; + val2 = reg & 0xff; + reg = reg >> 8; nid = reg & 0xff; - ret = regmap_write(rt715->sdw_regmap, reg, ((val2 >> 8) & 0xff)); + ret = regmap_write(rt715->sdw_regmap, reg, 0); if (ret < 0) return ret; reg2 = reg + 0x1000; reg2 |= 0x80; - ret = regmap_write(rt715->sdw_regmap, reg2, (val2 & 0xff)); + ret = regmap_write(rt715->sdw_regmap, reg2, val2); if (ret < 0) return ret; reg3 = RT715_PRIV_DATA_W_H | nid; - ret = regmap_write(rt715->sdw_regmap, reg3, ((val >> 8) & 0xff)); + ret = regmap_write(rt715->sdw_regmap, reg3, + ((val >> 8) & 0xff)); if (ret < 0) return ret; reg4 = reg3 + 0x1000; @@ -238,7 +249,8 @@ static int rt715_sdw_write(void *context, unsigned int reg, unsigned int val) if (ret < 0) return ret; } else if (mask == 0x7000) { - ret = regmap_write(rt715->sdw_regmap, reg, ((val >> 8) & 0xff)); + ret = regmap_write(rt715->sdw_regmap, reg, + ((val >> 8) & 0xff)); if (ret < 0) return ret; reg2 = reg + 0x1000; @@ -249,7 +261,8 @@ static int rt715_sdw_write(void *context, unsigned int reg, unsigned int val) } else if ((reg & 0xff00) == 0x8300) { /* for R channel */ reg2 = reg - 0x1000; reg2 &= ~0x80; - ret = regmap_write(rt715->sdw_regmap, reg2, ((val >> 8) & 0xff)); + ret = regmap_write(rt715->sdw_regmap, reg2, + ((val >> 8) & 0xff)); if (ret < 0) return ret; ret = regmap_write(rt715->sdw_regmap, reg, (val & 0xff)); @@ -260,20 +273,21 @@ static int rt715_sdw_write(void *context, unsigned int reg, unsigned int val) if (reg2 == 0) dev_dbg(dev, "[%s] %04x <= %04x\n", __func__, reg, val); else if (is_index_reg) - dev_dbg(dev, "[%s] %04x %04x %04x %04x <= %04x %04x\n", __func__, - reg, reg2, reg3, reg4, val2, val); + dev_dbg(dev, "[%s] %04x %04x %04x %04x <= %04x %04x\n", + __func__, reg, reg2, reg3, reg4, val2, val); else - dev_dbg(dev, "[%s] %04x %04x <= %04x\n", __func__, reg, reg2, val); + dev_dbg(dev, "[%s] %04x %04x <= %04x\n", + __func__, reg, reg2, val); return 0; } static const struct regmap_config rt715_regmap = { - .reg_bits = 32, + .reg_bits = 24, .val_bits = 32, .readable_reg = rt715_readable_register, /* Readable registers */ .volatile_reg = rt715_volatile_register, /* volatile register */ - .max_register = 0x75200039, /* Maximum number of register */ + .max_register = 0x752039, /* Maximum number of register */ .reg_defaults = rt715_reg_defaults, /* Defaults */ .num_reg_defaults = ARRAY_SIZE(rt715_reg_defaults), .cache_type = REGCACHE_RBTREE, @@ -287,7 +301,6 @@ static const struct regmap_config rt715_sdw_regmap = { .name = "sdw", .reg_bits = 32, /* Total register space for SDW */ .val_bits = 8, /* Total number of bits in register */ - .readable_reg = rt715_readable_register, /* Readable registers */ .max_register = 0xff01, /* Maximum number of register */ .cache_type = REGCACHE_NONE, .use_single_read = true, @@ -336,7 +349,7 @@ int hda_to_sdw(unsigned int nid, unsigned int verb, unsigned int payload, EXPORT_SYMBOL(hda_to_sdw); static int rt715_update_status(struct sdw_slave *slave, - enum sdw_slave_status status) + enum sdw_slave_status status) { struct rt715_priv *rt715 = dev_get_drvdata(&slave->dev); @@ -364,14 +377,14 @@ static int rt715_read_prop(struct sdw_slave *slave) prop->paging_support = false; /* first we need to allocate memory for set bits in port lists */ - prop->source_ports = 0x50; /* BITMAP: 01010000 */ + prop->source_ports = 0x50;/* BITMAP: 01010000 */ prop->sink_ports = 0x0; /* BITMAP: 00000000 */ nval = hweight32(prop->source_ports); num_of_ports += nval; prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, - sizeof(*prop->src_dpn_prop), - GFP_KERNEL); + sizeof(*prop->src_dpn_prop), + GFP_KERNEL); if (!prop->src_dpn_prop) return -ENOMEM; @@ -389,8 +402,8 @@ static int rt715_read_prop(struct sdw_slave *slave) nval = hweight32(prop->sink_ports); num_of_ports += nval; prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, - sizeof(*prop->sink_dpn_prop), - GFP_KERNEL); + sizeof(*prop->sink_dpn_prop), + GFP_KERNEL); if (!prop->sink_dpn_prop) return -ENOMEM; @@ -406,8 +419,8 @@ static int rt715_read_prop(struct sdw_slave *slave) /* Allocate port_ready based on num_of_ports */ slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports, - sizeof(*slave->port_ready), - GFP_KERNEL); + sizeof(*slave->port_ready), + GFP_KERNEL); if (!slave->port_ready) return -ENOMEM; @@ -422,7 +435,7 @@ static int rt715_read_prop(struct sdw_slave *slave) } static int rt715_bus_config(struct sdw_slave *slave, - struct sdw_bus_params *params) + struct sdw_bus_params *params) { struct rt715_priv *rt715 = dev_get_drvdata(&slave->dev); int ret; @@ -455,7 +468,8 @@ static int rt715_sdw_probe(struct sdw_slave *slave, if (!sdw_regmap) return -EINVAL; - regmap = devm_regmap_init(&slave->dev, NULL, &slave->dev, &rt715_regmap); + regmap = devm_regmap_init(&slave->dev, NULL, &slave->dev, + &rt715_regmap); if (!regmap) return -EINVAL; @@ -502,7 +516,7 @@ static int rt715_dev_resume(struct device *dev) regcache_cache_only(rt715->regmap, false); regcache_sync_region(rt715->regmap, 0x3000, 0x8fff); - regcache_sync_region(rt715->regmap, 0x75200039, 0x75200039); + regcache_sync_region(rt715->regmap, 0x752039, 0x752039); return 0; } diff --git a/sound/soc/codecs/rt715-sdw.h b/sound/soc/codecs/rt715-sdw.h index 1834127ecfcaab..0bc0efada86296 100644 --- a/sound/soc/codecs/rt715-sdw.h +++ b/sound/soc/codecs/rt715-sdw.h @@ -270,7 +270,7 @@ static const struct reg_default rt715_reg_defaults[] = { { 0x8389, 0x97 }, { 0x7327, 0x97 }, { 0x83a7, 0x97 }, - { 0x75200039, 0xa500 }, + { 0x752039, 0xa500 }, }; #endif /* __RT715_H__ */ diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 0ac8868012d83d..63e9465a0e9a52 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -42,7 +42,7 @@ static int rt715_index_write(struct regmap *regmap, unsigned int reg, unsigned int value) { int ret; - unsigned int addr = ((RT715_PRIV_INDEX_W_H) << 16) | reg; + unsigned int addr = ((RT715_PRIV_INDEX_W_H) << 8) | reg; ret = regmap_write(regmap, addr, value); if (ret < 0) { @@ -57,7 +57,7 @@ static unsigned int rt715_index_read(struct regmap *regmap, unsigned int reg, unsigned int *value) { int ret; - unsigned int addr = ((RT715_PRIV_INDEX_W_H) << 16) | reg; + unsigned int addr = ((RT715_PRIV_INDEX_W_H) << 8) | reg; *value = 0; ret = regmap_read(regmap, addr, value); @@ -70,8 +70,8 @@ static unsigned int rt715_index_read(struct regmap *regmap, unsigned int reg, } static void rt715_get_gain(struct rt715_priv *rt715, unsigned int addr_h, - unsigned int addr_l, unsigned int val_h, - unsigned int *r_val, unsigned int *l_val) + unsigned int addr_l, unsigned int val_h, + unsigned int *r_val, unsigned int *l_val) { /* R Channel */ *r_val = (val_h << 8); @@ -85,7 +85,7 @@ static void rt715_get_gain(struct rt715_priv *rt715, unsigned int addr_h, /* For Verb-Set Amplifier Gain (Verb ID = 3h) */ static int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct snd_soc_dapm_context *dapm = @@ -148,16 +148,19 @@ static int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol, if (val_ll == val_lr) { /* Set both L/R channels at the same time */ val_h = (1 << mc->shift) | (3 << 4); - regmap_write(rt715->regmap, addr_h, (val_h << 8 | val_ll)); - regmap_write(rt715->regmap, addr_l, (val_h << 8 | val_ll)); + regmap_write(rt715->regmap, addr_h, + (val_h << 8 | val_ll)); + regmap_write(rt715->regmap, addr_l, + (val_h << 8 | val_ll)); } else { /* Lch*/ val_h = (1 << mc->shift) | (1 << 5); - regmap_write(rt715->regmap, addr_h, (val_h << 8 | val_ll)); - + regmap_write(rt715->regmap, addr_h, + (val_h << 8 | val_ll)); /* Rch */ val_h = (1 << mc->shift) | (1 << 4); - regmap_write(rt715->regmap, addr_l, (val_h << 8 | val_lr)); + regmap_write(rt715->regmap, addr_l, + (val_h << 8 | val_lr)); } /* check result */ if (mc->shift == RT715_DIR_OUT_SFT) /* output */ @@ -173,7 +176,7 @@ static int rt715_set_amp_gain_put(struct snd_kcontrol *kcontrol, /* D0:power on state, D3: power saving mode */ if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) regmap_write(rt715->regmap, - RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3); + RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3); return 0; } @@ -226,71 +229,71 @@ static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); static const struct snd_kcontrol_new rt715_snd_controls[] = { /* Capture switch */ SOC_DOUBLE_R_EXT("ADC 07 Capture Switch", RT715_SET_GAIN_MIC_ADC_H, - RT715_SET_GAIN_MIC_ADC_L, RT715_DIR_IN_SFT, 1, 1, - rt715_set_amp_gain_get, rt715_set_amp_gain_put), + RT715_SET_GAIN_MIC_ADC_L, RT715_DIR_IN_SFT, 1, 1, + rt715_set_amp_gain_get, rt715_set_amp_gain_put), SOC_DOUBLE_R_EXT("ADC 08 Capture Switch", RT715_SET_GAIN_LINE_ADC_H, - RT715_SET_GAIN_LINE_ADC_L, RT715_DIR_IN_SFT, 1, 1, - rt715_set_amp_gain_get, rt715_set_amp_gain_put), + RT715_SET_GAIN_LINE_ADC_L, RT715_DIR_IN_SFT, 1, 1, + rt715_set_amp_gain_get, rt715_set_amp_gain_put), SOC_DOUBLE_R_EXT("ADC 09 Capture Switch", RT715_SET_GAIN_MIX_ADC_H, - RT715_SET_GAIN_MIX_ADC_L, RT715_DIR_IN_SFT, 1, 1, - rt715_set_amp_gain_get, rt715_set_amp_gain_put), + RT715_SET_GAIN_MIX_ADC_L, RT715_DIR_IN_SFT, 1, 1, + rt715_set_amp_gain_get, rt715_set_amp_gain_put), SOC_DOUBLE_R_EXT("ADC 27 Capture Switch", RT715_SET_GAIN_MIX_ADC2_H, - RT715_SET_GAIN_MIX_ADC2_L, RT715_DIR_IN_SFT, 1, 1, - rt715_set_amp_gain_get, rt715_set_amp_gain_put), + RT715_SET_GAIN_MIX_ADC2_L, RT715_DIR_IN_SFT, 1, 1, + rt715_set_amp_gain_get, rt715_set_amp_gain_put), /* Volume Control */ SOC_DOUBLE_R_EXT_TLV("ADC 07 Capture Volume", RT715_SET_GAIN_MIC_ADC_H, - RT715_SET_GAIN_MIC_ADC_L, RT715_DIR_IN_SFT, 0x3f, 0, - rt715_set_amp_gain_get, rt715_set_amp_gain_put, - in_vol_tlv), + RT715_SET_GAIN_MIC_ADC_L, RT715_DIR_IN_SFT, 0x3f, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + in_vol_tlv), SOC_DOUBLE_R_EXT_TLV("ADC 08 Capture Volume", RT715_SET_GAIN_LINE_ADC_H, - RT715_SET_GAIN_LINE_ADC_L, RT715_DIR_IN_SFT, 0x3f, 0, - rt715_set_amp_gain_get, rt715_set_amp_gain_put, - in_vol_tlv), + RT715_SET_GAIN_LINE_ADC_L, RT715_DIR_IN_SFT, 0x3f, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + in_vol_tlv), SOC_DOUBLE_R_EXT_TLV("ADC 09 Capture Volume", RT715_SET_GAIN_MIX_ADC_H, - RT715_SET_GAIN_MIX_ADC_L, RT715_DIR_IN_SFT, 0x3f, 0, - rt715_set_amp_gain_get, rt715_set_amp_gain_put, - in_vol_tlv), + RT715_SET_GAIN_MIX_ADC_L, RT715_DIR_IN_SFT, 0x3f, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + in_vol_tlv), SOC_DOUBLE_R_EXT_TLV("ADC 27 Capture Volume", RT715_SET_GAIN_MIX_ADC2_H, - RT715_SET_GAIN_MIX_ADC2_L, RT715_DIR_IN_SFT, 0x3f, 0, - rt715_set_amp_gain_get, rt715_set_amp_gain_put, - in_vol_tlv), + RT715_SET_GAIN_MIX_ADC2_L, RT715_DIR_IN_SFT, 0x3f, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + in_vol_tlv), /* MIC Boost Control */ SOC_DOUBLE_R_EXT_TLV("DMIC1 Boost", RT715_SET_GAIN_DMIC1_H, - RT715_SET_GAIN_DMIC1_L, RT715_DIR_IN_SFT, 3, 0, - rt715_set_amp_gain_get, rt715_set_amp_gain_put, - mic_vol_tlv), + RT715_SET_GAIN_DMIC1_L, RT715_DIR_IN_SFT, 3, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + mic_vol_tlv), SOC_DOUBLE_R_EXT_TLV("DMIC2 Boost", RT715_SET_GAIN_DMIC2_H, - RT715_SET_GAIN_DMIC2_L, RT715_DIR_IN_SFT, 3, 0, - rt715_set_amp_gain_get, rt715_set_amp_gain_put, - mic_vol_tlv), + RT715_SET_GAIN_DMIC2_L, RT715_DIR_IN_SFT, 3, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + mic_vol_tlv), SOC_DOUBLE_R_EXT_TLV("DMIC3 Boost", RT715_SET_GAIN_DMIC3_H, - RT715_SET_GAIN_DMIC3_L, RT715_DIR_IN_SFT, 3, 0, - rt715_set_amp_gain_get, rt715_set_amp_gain_put, - mic_vol_tlv), + RT715_SET_GAIN_DMIC3_L, RT715_DIR_IN_SFT, 3, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + mic_vol_tlv), SOC_DOUBLE_R_EXT_TLV("DMIC4 Boost", RT715_SET_GAIN_DMIC4_H, - RT715_SET_GAIN_DMIC4_L, RT715_DIR_IN_SFT, 3, 0, - rt715_set_amp_gain_get, rt715_set_amp_gain_put, - mic_vol_tlv), + RT715_SET_GAIN_DMIC4_L, RT715_DIR_IN_SFT, 3, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + mic_vol_tlv), SOC_DOUBLE_R_EXT_TLV("MIC1 Boost", RT715_SET_GAIN_MIC1_H, - RT715_SET_GAIN_MIC1_L, RT715_DIR_IN_SFT, 3, 0, - rt715_set_amp_gain_get, rt715_set_amp_gain_put, - mic_vol_tlv), + RT715_SET_GAIN_MIC1_L, RT715_DIR_IN_SFT, 3, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + mic_vol_tlv), SOC_DOUBLE_R_EXT_TLV("MIC2 Boost", RT715_SET_GAIN_MIC2_H, - RT715_SET_GAIN_MIC2_L, RT715_DIR_IN_SFT, 3, 0, - rt715_set_amp_gain_get, rt715_set_amp_gain_put, - mic_vol_tlv), + RT715_SET_GAIN_MIC2_L, RT715_DIR_IN_SFT, 3, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + mic_vol_tlv), SOC_DOUBLE_R_EXT_TLV("LINE1 Boost", RT715_SET_GAIN_LINE1_H, - RT715_SET_GAIN_LINE1_L, RT715_DIR_IN_SFT, 3, 0, - rt715_set_amp_gain_get, rt715_set_amp_gain_put, - mic_vol_tlv), + RT715_SET_GAIN_LINE1_L, RT715_DIR_IN_SFT, 3, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + mic_vol_tlv), SOC_DOUBLE_R_EXT_TLV("LINE2 Boost", RT715_SET_GAIN_LINE2_H, - RT715_SET_GAIN_LINE2_L, RT715_DIR_IN_SFT, 3, 0, - rt715_set_amp_gain_get, rt715_set_amp_gain_put, - mic_vol_tlv), + RT715_SET_GAIN_LINE2_L, RT715_DIR_IN_SFT, 3, 0, + rt715_set_amp_gain_get, rt715_set_amp_gain_put, + mic_vol_tlv), }; static int rt715_mux_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); @@ -302,7 +305,8 @@ static int rt715_mux_get(struct snd_kcontrol *kcontrol, reg = RT715_VERB_SET_CONNECT_SEL | e->reg; ret = regmap_read(rt715->regmap, reg, &val); if (ret < 0) { - dev_err(component->dev, "%s: sdw read failed: %d\n", __func__, ret); + dev_err(component->dev, "%s: sdw read failed: %d\n", + __func__, ret); return ret; } @@ -319,7 +323,7 @@ static int rt715_mux_get(struct snd_kcontrol *kcontrol, } static int rt715_mux_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); @@ -339,7 +343,8 @@ static int rt715_mux_put(struct snd_kcontrol *kcontrol, reg = RT715_VERB_SET_CONNECT_SEL | e->reg; ret = regmap_read(rt715->regmap, reg, &val2); if (ret < 0) { - dev_err(component->dev, "%s: sdw read failed: %d\n", __func__, ret); + dev_err(component->dev, "%s: sdw read failed: %d\n", + __func__, ret); return ret; } @@ -354,7 +359,7 @@ static int rt715_mux_put(struct snd_kcontrol *kcontrol, } snd_soc_dapm_mux_update_power(dapm, kcontrol, - item[0], e, NULL); + item[0], e, NULL); return change; } @@ -551,7 +556,7 @@ static int rt715_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, } static void rt715_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) + struct snd_soc_dai *dai) { struct sdw_stream_data *stream; @@ -562,8 +567,8 @@ static void rt715_shutdown(struct snd_pcm_substream *substream, } static int rt715_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); @@ -608,7 +613,7 @@ static int rt715_pcm_hw_params(struct snd_pcm_substream *substream, port_config.num = port; retval = sdw_stream_add_slave(rt715->slave, &stream_config, - &port_config, 1, stream->sdw_stream); + &port_config, 1, stream->sdw_stream); if (retval) { dev_err(dai->dev, "Unable to configure port\n"); return retval; @@ -667,7 +672,7 @@ static int rt715_pcm_hw_params(struct snd_pcm_substream *substream, } static int rt715_pcm_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) + struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); @@ -786,9 +791,9 @@ int rt715_init(struct device *dev, struct regmap *sdw_regmap, rt715->first_init = false; ret = devm_snd_soc_register_component(dev, - &soc_codec_dev_rt715, - rt715_dai, - ARRAY_SIZE(rt715_dai)); + &soc_codec_dev_rt715, + rt715_dai, + ARRAY_SIZE(rt715_dai)); return ret; } @@ -831,6 +836,8 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave) /* Set Pin Widget */ regmap_write(rt715->regmap, RT715_SET_PIN_DMIC1, 0x20); regmap_write(rt715->regmap, RT715_SET_PIN_DMIC2, 0x20); + regmap_write(rt715->regmap, RT715_SET_PIN_DMIC3, 0x20); + regmap_write(rt715->regmap, RT715_SET_PIN_DMIC4, 0x20); /* Set Converter Stream */ regmap_write(rt715->regmap, RT715_SET_STREAMID_LINE_ADC, 0x10); regmap_write(rt715->regmap, RT715_SET_STREAMID_MIX_ADC, 0x10); @@ -845,6 +852,14 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave) regmap_write(rt715->regmap, RT715_SET_DMIC2_CONFIG_DEFAULT2, 0x11); regmap_write(rt715->regmap, RT715_SET_DMIC2_CONFIG_DEFAULT3, 0xa1); regmap_write(rt715->regmap, RT715_SET_DMIC2_CONFIG_DEFAULT4, 0x81); + regmap_write(rt715->regmap, RT715_SET_DMIC3_CONFIG_DEFAULT1, 0xd0); + regmap_write(rt715->regmap, RT715_SET_DMIC3_CONFIG_DEFAULT2, 0x11); + regmap_write(rt715->regmap, RT715_SET_DMIC3_CONFIG_DEFAULT3, 0xa1); + regmap_write(rt715->regmap, RT715_SET_DMIC3_CONFIG_DEFAULT4, 0x81); + regmap_write(rt715->regmap, RT715_SET_DMIC4_CONFIG_DEFAULT1, 0xd1); + regmap_write(rt715->regmap, RT715_SET_DMIC4_CONFIG_DEFAULT2, 0x11); + regmap_write(rt715->regmap, RT715_SET_DMIC4_CONFIG_DEFAULT3, 0xa1); + regmap_write(rt715->regmap, RT715_SET_DMIC4_CONFIG_DEFAULT4, 0x81); /* Finish Initial Settings, set power to D3 */ regmap_write(rt715->regmap, RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3); diff --git a/sound/soc/codecs/rt715.h b/sound/soc/codecs/rt715.h index 846d6a0116d9d0..52d24cfb581d1b 100644 --- a/sound/soc/codecs/rt715.h +++ b/sound/soc/codecs/rt715.h @@ -183,6 +183,22 @@ struct sdw_stream_data { (RT715_VERB_SET_CONFIG_DEFAULT4 | RT715_DMIC1) #define RT715_SET_DMIC2_CONFIG_DEFAULT4\ (RT715_VERB_SET_CONFIG_DEFAULT4 | RT715_DMIC2) +#define RT715_SET_DMIC3_CONFIG_DEFAULT1\ + (RT715_VERB_SET_CONFIG_DEFAULT1 | RT715_DMIC3) +#define RT715_SET_DMIC4_CONFIG_DEFAULT1\ + (RT715_VERB_SET_CONFIG_DEFAULT1 | RT715_DMIC4) +#define RT715_SET_DMIC3_CONFIG_DEFAULT2\ + (RT715_VERB_SET_CONFIG_DEFAULT2 | RT715_DMIC3) +#define RT715_SET_DMIC4_CONFIG_DEFAULT2\ + (RT715_VERB_SET_CONFIG_DEFAULT2 | RT715_DMIC4) +#define RT715_SET_DMIC3_CONFIG_DEFAULT3\ + (RT715_VERB_SET_CONFIG_DEFAULT3 | RT715_DMIC3) +#define RT715_SET_DMIC4_CONFIG_DEFAULT3\ + (RT715_VERB_SET_CONFIG_DEFAULT3 | RT715_DMIC4) +#define RT715_SET_DMIC3_CONFIG_DEFAULT4\ + (RT715_VERB_SET_CONFIG_DEFAULT4 | RT715_DMIC3) +#define RT715_SET_DMIC4_CONFIG_DEFAULT4\ + (RT715_VERB_SET_CONFIG_DEFAULT4 | RT715_DMIC4) #define RT715_MUTE_SFT 7 #define RT715_DIR_IN_SFT 6 From d1b15704c980e851ddf8864f0492edec35cd3577 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 28 Oct 2019 17:26:53 +0800 Subject: [PATCH 1846/1995] ASoC: rt700: fix pop noise while stopping playback Signed-off-by: Shuming Fan --- sound/soc/codecs/rt700.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index d110e4526409a9..73911494711f14 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -717,6 +717,7 @@ static int rt700_hpo_mux_event(struct snd_soc_dapm_widget *w, val_l = (1 << RT700_MUTE_SFT); regmap_write(rt700->regmap, RT700_SET_GAIN_HP_H, (val_h << 8 | val_l)); + usleep_range(50000, 55000); break; } return 0; From 26ecc12ea101d487142099fe985b6674fb70a0f4 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 28 Oct 2019 17:27:06 +0800 Subject: [PATCH 1847/1995] ASoC: rt711: fix pop noise while stopping playback Signed-off-by: Shuming Fan --- sound/soc/codecs/rt711.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 96f9fe21d9a469..19bd118ae6964d 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -383,7 +383,8 @@ static void rt711_jack_init(struct rt711_priv *rt711) RT711_JD2_2PORT_200K_DECODE_HP | RT711_HP_JD_SEL_JD2); rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, - RT711_CC_DET1, RT711_HP_JD_FINAL_RESULT_CTL_JD12, + RT711_CC_DET1, + RT711_HP_JD_FINAL_RESULT_CTL_JD12, RT711_HP_JD_FINAL_RESULT_CTL_JD12); break; default: @@ -741,12 +742,13 @@ static int rt711_dac_surround_event(struct snd_soc_dapm_widget *w, RT711_SET_GAIN_HP_H, (val_h << 8 | val_l)); break; case SND_SOC_DAPM_PRE_PMD: - regmap_write(rt711->regmap, - RT711_SET_STREAMID_DAC2, 0x00); - val_l = (1 << RT711_MUTE_SFT); regmap_write(rt711->regmap, RT711_SET_GAIN_HP_H, (val_h << 8 | val_l)); + usleep_range(50000, 55000); + + regmap_write(rt711->regmap, + RT711_SET_STREAMID_DAC2, 0x00); break; } return 0; From 770bcdd0c752b0a475a266aa70e114dfece2d3e1 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 28 Oct 2019 17:27:21 +0800 Subject: [PATCH 1848/1995] ASoC: rt1308-sdw: fix DC offset loading from EFUSE and increase DAC volume Fix the PVDD DC calibration parameters doesn't be loaded correctly. The DAC volume gain adjusts to the 0xe7 value which HW AE suggests. Signed-off-by: Shuming Fan --- sound/soc/codecs/rt1308-sdw.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index fac0fa20843eac..96afc7aa8291d9 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -175,6 +175,8 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) { struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev); int ret = 0; + unsigned int efuse_m_btl_l, efuse_m_btl_r, tmp; + unsigned int efuse_c_btl_l, efuse_c_btl_r; if (rt1308->hw_init) return 0; @@ -209,7 +211,7 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) /* read efuse */ regmap_write(rt1308->regmap, 0xc360, 0x01); - regmap_write(rt1308->regmap, 0xc360, 0x80); + regmap_write(rt1308->regmap, 0xc361, 0x80); regmap_write(rt1308->regmap, 0xc7f0, 0x04); regmap_write(rt1308->regmap, 0xc7f1, 0xfe); msleep(100); @@ -217,6 +219,27 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) msleep(20); regmap_write(rt1308->regmap, 0xc240, 0x10); + regmap_read(rt1308->regmap, 0xc861, &tmp); + efuse_m_btl_l = tmp; + regmap_read(rt1308->regmap, 0xc860, &tmp); + efuse_m_btl_l = efuse_m_btl_l | (tmp << 8); + regmap_read(rt1308->regmap, 0xc863, &tmp); + efuse_c_btl_l = tmp; + regmap_read(rt1308->regmap, 0xc862, &tmp); + efuse_c_btl_l = efuse_c_btl_l | (tmp << 8); + regmap_read(rt1308->regmap, 0xc871, &tmp); + efuse_m_btl_r = tmp; + regmap_read(rt1308->regmap, 0xc870, &tmp); + efuse_m_btl_r = efuse_m_btl_r | (tmp << 8); + regmap_read(rt1308->regmap, 0xc873, &tmp); + efuse_c_btl_r = tmp; + regmap_read(rt1308->regmap, 0xc872, &tmp); + efuse_c_btl_r = efuse_c_btl_r | (tmp << 8); + dev_info(&slave->dev, "%s m_btl_l=0x%x, m_btl_r=0x%x\n", __func__, + efuse_m_btl_l, efuse_m_btl_r); + dev_info(&slave->dev, "%s c_btl_l=0x%x, c_btl_r=0x%x\n", __func__, + efuse_c_btl_l, efuse_c_btl_r); + /* initial settings */ regmap_write(rt1308->regmap, 0xc103, 0xc0); regmap_write(rt1308->regmap, 0xc030, 0x17); @@ -241,8 +264,8 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) regmap_write(rt1308->regmap, 0xc0a1, 0x71); regmap_write(rt1308->regmap, 0xc210, 0x00); regmap_write(rt1308->regmap, 0xc070, 0x00); - regmap_write(rt1308->regmap, 0xc100, 0xaf); - regmap_write(rt1308->regmap, 0xc101, 0xaf); + regmap_write(rt1308->regmap, 0xc100, 0xe7); + regmap_write(rt1308->regmap, 0xc101, 0xe7); regmap_write(rt1308->regmap, 0xc310, 0x24); /* Mark Slave initialization complete */ From 7761a101bfd9356ac9c5f7ae28730b9dcc55522e Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 29 Oct 2019 11:28:03 +0800 Subject: [PATCH 1849/1995] ASoC: codec:rt715-sdw: Modify some ret values regarding to warning and add return handle for regmap_read. Signed-off-by: Jack Yu --- sound/soc/codecs/rt715.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 63e9465a0e9a52..40e006b0fc6138 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -73,14 +73,19 @@ static void rt715_get_gain(struct rt715_priv *rt715, unsigned int addr_h, unsigned int addr_l, unsigned int val_h, unsigned int *r_val, unsigned int *l_val) { + int ret; /* R Channel */ *r_val = (val_h << 8); - regmap_read(rt715->regmap, addr_l, r_val); + ret = regmap_read(rt715->regmap, addr_l, r_val); + if (ret < 0) + pr_err("Failed to get R channel gain.\n"); /* L Channel */ val_h |= 0x20; *l_val = (val_h << 8); - regmap_read(rt715->regmap, addr_h, l_val); + ret = regmap_read(rt715->regmap, addr_h, l_val); + if (ret < 0) + pr_err("Failed to get L channel gain.\n"); } /* For Verb-Set Amplifier Gain (Verb ID = 3h) */ @@ -299,7 +304,8 @@ static int rt715_mux_get(struct snd_kcontrol *kcontrol, snd_soc_dapm_kcontrol_component(kcontrol); struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned int reg, val, ret; + unsigned int reg, val; + int ret; /* nid = e->reg, vid = 0xf01 */ reg = RT715_VERB_SET_CONNECT_SEL | e->reg; @@ -332,7 +338,8 @@ static int rt715_mux_put(struct snd_kcontrol *kcontrol, struct rt715_priv *rt715 = snd_soc_component_get_drvdata(component); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; unsigned int *item = ucontrol->value.enumerated.item; - unsigned int val, val2 = 0, change, reg, ret; + unsigned int val, val2 = 0, change, reg; + int ret; if (item[0] >= e->items) return -EINVAL; From d038109794468178cae04262103de55d610e19dd Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 30 Oct 2019 18:34:28 +0800 Subject: [PATCH 1850/1995] ASoC: rt1308-sdw: output gain enhancement The HW engineer changes HV_Gain voltage setting to enhance the output gain. And he also adjusts the DAC volume gain. Signed-off-by: Shuming Fan --- sound/soc/codecs/rt1308-sdw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index 96afc7aa8291d9..266a3d1076547a 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -264,9 +264,9 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) regmap_write(rt1308->regmap, 0xc0a1, 0x71); regmap_write(rt1308->regmap, 0xc210, 0x00); regmap_write(rt1308->regmap, 0xc070, 0x00); - regmap_write(rt1308->regmap, 0xc100, 0xe7); - regmap_write(rt1308->regmap, 0xc101, 0xe7); - regmap_write(rt1308->regmap, 0xc310, 0x24); + regmap_write(rt1308->regmap, 0xc100, 0xd7); + regmap_write(rt1308->regmap, 0xc101, 0xd7); + regmap_write(rt1308->regmap, 0xc300, 0x09); /* Mark Slave initialization complete */ rt1308->hw_init = true; From da3553b4bf2e1c853d67957be03a1f415ccb0480 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 4 Nov 2019 14:10:01 +0800 Subject: [PATCH 1851/1995] ASoC: rt711: move rt711_parse_dt to rt711_probe Intel add device property on machine driver. So we can't parse device before machine driver is probed. Signed-off-by: Bard Liao --- sound/soc/codecs/rt711.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 19bd118ae6964d..7190642534397d 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -869,10 +869,19 @@ static int rt711_set_bias_level(struct snd_soc_component *component, return 0; } +static int rt711_parse_dt(struct rt711_priv *rt711, struct device *dev) +{ + device_property_read_u32(dev, "realtek,jd-src", + &rt711->jd_src); + + return 0; +} + static int rt711_probe(struct snd_soc_component *component) { struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); + rt711_parse_dt(rt711, &rt711->slave->dev); rt711->component = component; return 0; @@ -1123,14 +1132,6 @@ static void rt711_calibration_work(struct work_struct *work) rt711_calibration(rt711); } -static int rt711_parse_dt(struct rt711_priv *rt711, struct device *dev) -{ - device_property_read_u32(dev, "realtek,jd-src", - &rt711->jd_src); - - return 0; -} - int rt711_init(struct device *dev, struct regmap *sdw_regmap, struct regmap *regmap, struct sdw_slave *slave) { @@ -1155,7 +1156,6 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap, /* JD source uses JD2 in default */ rt711->jd_src = RT711_JD2; - rt711_parse_dt(rt711, &slave->dev); ret = devm_snd_soc_register_component(dev, &soc_codec_dev_rt711, From 1e6f398b89f3ee229975410e029977de36e4096b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 4 Nov 2019 12:56:51 -0600 Subject: [PATCH 1852/1995] ASoC: codecs: rt1308-sdw.c: wait for initialization_complete Make sure the resume steps are delayed until all settings have been restored after the device becomes enumerated and .update_status is called. Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/rt1308-sdw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index 266a3d1076547a..ba6350366b24b4 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -690,10 +690,10 @@ static int rt1308_dev_resume(struct device *dev) if (!rt1308->hw_init) return 0; - time = wait_for_completion_timeout(&slave->enumeration_complete, + time = wait_for_completion_timeout(&slave->initialization_complete, msecs_to_jiffies(RT1308_PROBE_TIMEOUT)); if (!time) { - dev_err(&slave->dev, "Enumeration not complete, timed out\n"); + dev_err(&slave->dev, "Initialization not complete, timed out\n"); return -ETIMEDOUT; } From 684fcd2854f13aeceae340cdbccdaec1dd8e3386 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 4 Nov 2019 12:56:52 -0600 Subject: [PATCH 1853/1995] ASoC: codecs: rt700-sdw.c: wait for initialization_complete Make sure the resume steps are delayed until all settings have been restored after the device becomes enumerated and .update_status is called. Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/rt700-sdw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index 30977b9c3c08d1..5388b14be5f050 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -508,10 +508,10 @@ static int rt700_dev_resume(struct device *dev) if (!rt700->hw_init) return 0; - time = wait_for_completion_timeout(&slave->enumeration_complete, + time = wait_for_completion_timeout(&slave->initialization_complete, msecs_to_jiffies(RT700_PROBE_TIMEOUT)); if (!time) { - dev_err(&slave->dev, "Enumeration not complete, timed out\n"); + dev_err(&slave->dev, "Initialization not complete, timed out\n"); return -ETIMEDOUT; } From ea17db7b0d4c61316c405d7fcfe807e7a5d20201 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 4 Nov 2019 12:56:52 -0600 Subject: [PATCH 1854/1995] ASoC: codecs: rt711-sdw.c: wait for initialization_complete Make sure the resume steps are delayed until all settings have been restored after the device becomes enumerated and .update_status is called. Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/rt711-sdw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 5223bc17d00ca4..7121fe720654fd 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -508,10 +508,10 @@ static int rt711_dev_resume(struct device *dev) if (!rt711->hw_init) return 0; - time = wait_for_completion_timeout(&slave->enumeration_complete, + time = wait_for_completion_timeout(&slave->initialization_complete, msecs_to_jiffies(RT711_PROBE_TIMEOUT)); if (!time) { - dev_err(&slave->dev, "Enumeration not complete, timed out\n"); + dev_err(&slave->dev, "Initialization not complete, timed out\n"); return -ETIMEDOUT; } From 62fd75d3c373d0384b05f87922014482a3805d59 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 4 Nov 2019 12:56:53 -0600 Subject: [PATCH 1855/1995] ASoC: codecs: rt715-sdw.c: wait for initialization_complete Make sure the resume steps are delayed until all settings have been restored after the device becomes enumerated and .update_status is called Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/rt715-sdw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index c9b1328365abe0..8ec9ef09f6c679 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -507,10 +507,10 @@ static int rt715_dev_resume(struct device *dev) if (!rt715->hw_init) return 0; - time = wait_for_completion_timeout(&slave->enumeration_complete, + time = wait_for_completion_timeout(&slave->initialization_complete, msecs_to_jiffies(RT715_PROBE_TIMEOUT)); if (!time) { - dev_err(&slave->dev, "Enumeration not complete, timed out\n"); + dev_err(&slave->dev, "Initialization not complete, timed out\n"); return -ETIMEDOUT; } From c60f3d98b1dbc2da7dfa0dd98ff2dd082ecaf570 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 7 Nov 2019 14:40:08 +0800 Subject: [PATCH 1856/1995] ASoC: rt700: enable wake_capable Signed-off-by: Shuming Fan --- sound/soc/codecs/rt700-sdw.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index 5388b14be5f050..9e7a0bf9b5c634 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -399,6 +399,9 @@ static int rt700_read_prop(struct sdw_slave *slave) /* set the timeout values */ prop->clk_stop_timeout = 20; + /* wake-up event */ + prop->wake_capable = 1; + return 0; } From d39d9eb70ba2c442c2d6cccbbe79f719a8614897 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 7 Nov 2019 14:40:22 +0800 Subject: [PATCH 1857/1995] ASoC: rt711: enable wake_capable Signed-off-by: Shuming Fan --- sound/soc/codecs/rt711-sdw.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 7121fe720654fd..c8a6dfceae1e4f 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -402,6 +402,9 @@ static int rt711_read_prop(struct sdw_slave *slave) /* set the timeout values */ prop->clk_stop_timeout = 20; + /* wake-up event */ + prop->wake_capable = 1; + return 0; } From 3178f63a5b20a52d24d09c01e405065a86c85ff5 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 7 Nov 2019 14:40:34 +0800 Subject: [PATCH 1858/1995] ASoC: rt715: enable wake_capable Signed-off-by: Shuming Fan --- sound/soc/codecs/rt715-sdw.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index 8ec9ef09f6c679..aa6b22236290fd 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -431,6 +431,9 @@ static int rt715_read_prop(struct sdw_slave *slave) /* set the timeout values */ prop->clk_stop_timeout = 20; + /* wake-up event */ + prop->wake_capable = 1; + return 0; } From 7eb0378fe777bf7e8f1d80887a03b489cd64d36e Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 7 Nov 2019 14:45:10 +0800 Subject: [PATCH 1859/1995] ASoC: rt700: re-do io_init in cache_bypass mode when system resume Signed-off-by: Shuming Fan --- sound/soc/codecs/rt700.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index 73911494711f14..44a8cafbad5bfa 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -1133,6 +1133,11 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave) if (rt700->hw_init) return 0; + if (rt700->first_init) { + regcache_cache_only(rt700->regmap, false); + regcache_cache_bypass(rt700->regmap, true); + } + /* * PM runtime is only enabled when a Slave reports as Attached */ @@ -1148,8 +1153,6 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave) pm_runtime_mark_last_busy(&slave->dev); pm_runtime_enable(&slave->dev); - - rt700->first_init = true; } pm_runtime_get_noresume(&slave->dev); @@ -1198,10 +1201,12 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave) /* Finish Initial Settings, set power to D3 */ regmap_write(rt700->regmap, RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3); - INIT_DELAYED_WORK(&rt700->jack_detect_work, + if (!rt700->first_init) { + INIT_DELAYED_WORK(&rt700->jack_detect_work, rt700_jack_detect_handler); - INIT_DELAYED_WORK(&rt700->jack_btn_check_work, + INIT_DELAYED_WORK(&rt700->jack_btn_check_work, rt700_btn_check_handler); + } /* * if set_jack callback occurred early than io_init, @@ -1210,6 +1215,11 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave) if (rt700->hs_jack) rt700_jack_init(rt700); + if (rt700->first_init) + regcache_cache_bypass(rt700->regmap, false); + else + rt700->first_init = true; + /* Mark Slave initialization complete */ rt700->hw_init = true; From 7ca46e6b49726cc73612970bf1baf0be36f0a9af Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 7 Nov 2019 14:45:23 +0800 Subject: [PATCH 1860/1995] ASoC: rt711: re-do io_init in cache_bypass mode when system resume Signed-off-by: Shuming Fan --- sound/soc/codecs/rt711.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 7190642534397d..4090dc09694d0b 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -1174,6 +1174,11 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave) if (rt711->hw_init) return 0; + if (rt711->first_init) { + regcache_cache_only(rt711->regmap, false); + regcache_cache_bypass(rt711->regmap, true); + } + /* * PM runtime is only enabled when a Slave reports as Attached */ @@ -1189,8 +1194,6 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave) pm_runtime_mark_last_busy(&slave->dev); pm_runtime_enable(&slave->dev); - - rt711->first_init = true; } pm_runtime_get_noresume(&slave->dev); @@ -1247,13 +1250,17 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave) /* Finish Initial Settings, set power to D3 */ regmap_write(rt711->regmap, RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); - INIT_DELAYED_WORK(&rt711->jack_detect_work, + if (rt711->first_init) + rt711_calibration(rt711); + else { + INIT_DELAYED_WORK(&rt711->jack_detect_work, rt711_jack_detect_handler); - INIT_DELAYED_WORK(&rt711->jack_btn_check_work, + INIT_DELAYED_WORK(&rt711->jack_btn_check_work, rt711_btn_check_handler); - mutex_init(&rt711->calibrate_mutex); - INIT_WORK(&rt711->calibration_work, rt711_calibration_work); - schedule_work(&rt711->calibration_work); + mutex_init(&rt711->calibrate_mutex); + INIT_WORK(&rt711->calibration_work, rt711_calibration_work); + schedule_work(&rt711->calibration_work); + } /* * if set_jack callback occurred early than io_init, @@ -1262,6 +1269,11 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave) if (rt711->hs_jack) rt711_jack_init(rt711); + if (rt711->first_init) + regcache_cache_bypass(rt711->regmap, false); + else + rt711->first_init = true; + /* Mark Slave initialization complete */ rt711->hw_init = true; From 006f076e9c0125be86026149c175c0cad9eae76f Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 7 Nov 2019 14:45:41 +0800 Subject: [PATCH 1861/1995] ASoC: rt1308-sdw: re-do io_init in cache_bypass mode when system resume Signed-off-by: Shuming Fan --- sound/soc/codecs/rt1308-sdw.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index ba6350366b24b4..98bf6417f4c4ca 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -185,6 +185,11 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) if (ret < 0) goto _io_init_err_; + if (rt1308->first_init) { + regcache_cache_only(rt1308->regmap, false); + regcache_cache_bypass(rt1308->regmap, true); + } + /* * PM runtime is only enabled when a Slave reports as Attached */ @@ -200,8 +205,6 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) pm_runtime_mark_last_busy(&slave->dev); pm_runtime_enable(&slave->dev); - - rt1308->first_init = true; } pm_runtime_get_noresume(&slave->dev); @@ -268,6 +271,11 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) regmap_write(rt1308->regmap, 0xc101, 0xd7); regmap_write(rt1308->regmap, 0xc300, 0x09); + if (rt1308->first_init) + regcache_cache_bypass(rt1308->regmap, false); + else + rt1308->first_init = true; + /* Mark Slave initialization complete */ rt1308->hw_init = true; From 4e5f0eab43401c41d18841319d248accd0b941aa Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 11 Nov 2019 10:19:52 +0800 Subject: [PATCH 1862/1995] ASoC: codec: rt715: Remove unused rt715_index_read function. Signed-off-by: Jack Yu --- sound/soc/codecs/rt715.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 40e006b0fc6138..fce9c6939eda0c 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -53,22 +53,6 @@ static int rt715_index_write(struct regmap *regmap, unsigned int reg, return ret; } -static unsigned int rt715_index_read(struct regmap *regmap, unsigned int reg, - unsigned int *value) -{ - int ret; - unsigned int addr = ((RT715_PRIV_INDEX_W_H) << 8) | reg; - - *value = 0; - ret = regmap_read(regmap, addr, value); - if (ret < 0) { - pr_err("Failed to get private value: %08x => %04x %d\n", ret, - addr, *value); - } - - return ret; -} - static void rt715_get_gain(struct rt715_priv *rt715, unsigned int addr_h, unsigned int addr_l, unsigned int val_h, unsigned int *r_val, unsigned int *l_val) From 05626e14e083e77dc44b5c22481f5cff176d2168 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Nov 2019 17:42:00 -0600 Subject: [PATCH 1863/1995] ASoC: codecs: rt1308-sdw: check unattach request before wait_for_completion() Only start the wait_for_completion() if the Master device requested the Slave device status to become unattached, e.g with a bus reset. For normal pm_runtime resume just sync the regmap Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/rt1308-sdw.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index 98bf6417f4c4ca..c60db67e33eb22 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -698,6 +698,9 @@ static int rt1308_dev_resume(struct device *dev) if (!rt1308->hw_init) return 0; + if (!slave->unattach_request) + goto regmap_sync; + time = wait_for_completion_timeout(&slave->initialization_complete, msecs_to_jiffies(RT1308_PROBE_TIMEOUT)); if (!time) { @@ -705,6 +708,8 @@ static int rt1308_dev_resume(struct device *dev) return -ETIMEDOUT; } +regmap_sync: + slave->unattach_request = 0; regcache_cache_only(rt1308->regmap, false); regcache_sync_region(rt1308->regmap, 0xc000, 0xcfff); From 61fed9ca37ee378337a14a1f2841106d350da0f5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Nov 2019 17:42:00 -0600 Subject: [PATCH 1864/1995] ASoC: codecs: rt700-sdw: check unattach request before wait_for_completion() Only start the wait_for_completion() if the Master device requested the Slave device status to become unattached, e.g with a bus reset. For normal pm_runtime resume just sync the regmap Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/rt700-sdw.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index 9e7a0bf9b5c634..40954f18ddae7c 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -511,6 +511,9 @@ static int rt700_dev_resume(struct device *dev) if (!rt700->hw_init) return 0; + if (!slave->unattach_request) + goto regmap_sync; + time = wait_for_completion_timeout(&slave->initialization_complete, msecs_to_jiffies(RT700_PROBE_TIMEOUT)); if (!time) { @@ -518,6 +521,8 @@ static int rt700_dev_resume(struct device *dev) return -ETIMEDOUT; } +regmap_sync: + slave->unattach_request = 0; regcache_cache_only(rt700->regmap, false); regcache_sync_region(rt700->regmap, 0x3000, 0x8fff); regcache_sync_region(rt700->regmap, 0x752010, 0x75206b); From 8342529f544694fdc57456fac561115b899da9ca Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Nov 2019 17:42:01 -0600 Subject: [PATCH 1865/1995] ASoC: codecs: rt711-sdw: check unattach request before wait_for_completion() Only start the wait_for_completion() if the Master device requested the Slave device status to become unattached, e.g with a bus reset. For normal pm_runtime resume just sync the regmap Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/rt711-sdw.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index c8a6dfceae1e4f..ee7fa574d3298d 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -511,6 +511,9 @@ static int rt711_dev_resume(struct device *dev) if (!rt711->hw_init) return 0; + if (!slave->unattach_request) + goto regmap_sync; + time = wait_for_completion_timeout(&slave->initialization_complete, msecs_to_jiffies(RT711_PROBE_TIMEOUT)); if (!time) { @@ -518,6 +521,8 @@ static int rt711_dev_resume(struct device *dev) return -ETIMEDOUT; } +regmap_sync: + slave->unattach_request = 0; regcache_cache_only(rt711->regmap, false); regcache_sync_region(rt711->regmap, 0x3000, 0x8fff); regcache_sync_region(rt711->regmap, 0x752010, 0x752091); From ca8ee52668cb9a088f5ba9c7aa3b8be3ffe21ff4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Nov 2019 17:42:01 -0600 Subject: [PATCH 1866/1995] ASoC: codecs: rt715-sdw: check unattach request before wait_for_completion() Only start the wait_for_completion() if the Master device requested the Slave device status to become unattached, e.g with a bus reset. For normal pm_runtime resume just sync the regmap Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/rt715-sdw.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index aa6b22236290fd..096c9f3bcf1dc4 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -510,6 +510,9 @@ static int rt715_dev_resume(struct device *dev) if (!rt715->hw_init) return 0; + if (!slave->unattach_request) + goto regmap_sync; + time = wait_for_completion_timeout(&slave->initialization_complete, msecs_to_jiffies(RT715_PROBE_TIMEOUT)); if (!time) { @@ -517,6 +520,8 @@ static int rt715_dev_resume(struct device *dev) return -ETIMEDOUT; } +regmap_sync: + slave->unattach_request = 0; regcache_cache_only(rt715->regmap, false); regcache_sync_region(rt715->regmap, 0x3000, 0x8fff); regcache_sync_region(rt715->regmap, 0x752039, 0x752039); From 7b29cf366b48d9ac1bba92f63a79ee465d258ce2 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Wed, 13 Nov 2019 17:21:42 +0800 Subject: [PATCH 1867/1995] ASoC: rt711: fix no sound output after waking up from deep s3 The resume function needs to cache sync JD2 settings. Signed-off-by: Shuming Fan --- sound/soc/codecs/rt711-sdw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index ee7fa574d3298d..4174d175925c33 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -525,7 +525,7 @@ static int rt711_dev_resume(struct device *dev) slave->unattach_request = 0; regcache_cache_only(rt711->regmap, false); regcache_sync_region(rt711->regmap, 0x3000, 0x8fff); - regcache_sync_region(rt711->regmap, 0x752010, 0x752091); + regcache_sync_region(rt711->regmap, 0x752009, 0x752091); return 0; } From 44999cac6e86df37df86a517c87e00288aa42e14 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 22 Nov 2019 13:51:27 +0800 Subject: [PATCH 1868/1995] Correct some sdw default registers and add missing registers in rt715_reg_defaults[] Signed-off-by: Jack Yu --- sound/soc/codecs/rt715-sdw.c | 62 +++++++++++++++++++++++++++++------- sound/soc/codecs/rt715-sdw.h | 47 ++++++++++++++++++++++++--- 2 files changed, 92 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index 096c9f3bcf1dc4..d1fe32a9397df4 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -22,17 +22,18 @@ static bool rt715_readable_register(struct device *dev, unsigned int reg) { switch (reg) { + case 0x00e0 ... 0x00e5: + case 0x00ee ... 0x00ef: + case 0x00f0 ... 0x00f5: + case 0x00fe ... 0x00ff: case 0x02e0: case 0x02f0: case 0x04e0: case 0x04f0: case 0x06e0: case 0x06f0: - case 0x00e0 ... 0x00e5: - case 0x00ee ... 0x00ef: - case 0x00f0 ... 0x00f5: - case 0x00fe ... 0x00ff: - case 0x2000 ... 0x2027: + case 0x2000 ... 0x2016: + case 0x201a ... 0x2027: case 0x2029 ... 0x202a: case 0x202d ... 0x2034: case 0x2200 ... 0x2204: @@ -40,11 +41,50 @@ static bool rt715_readable_register(struct device *dev, unsigned int reg) case 0x2220 ... 0x2223: case 0x2230 ... 0x2239: case 0x22f0 ... 0x22f3: - case 0x3000 ... 0x3fff: - case 0x7000 ... 0x7fff: - case 0x8300 ... 0x83ff: - case 0x9c00 ... 0x9cff: - case 0xb900 ... 0xb9ff: + case 0x3122: + case 0x3123: + case 0x3124: + case 0x3125: + case 0x3607: + case 0x3608: + case 0x3609: + case 0x3610: + case 0x3611: + case 0x3627: + case 0x3712: + case 0x3713: + case 0x3718: + case 0x3719: + case 0x371a: + case 0x371b: + case 0x371d: + case 0x3729: + case 0x385e: + case 0x3859: + case 0x4c12: + case 0x4c13: + case 0x4c1d: + case 0x4c29: + case 0x4d12: + case 0x4d13: + case 0x4d1d: + case 0x4d29: + case 0x4e12: + case 0x4e13: + case 0x4e1d: + case 0x4e29: + case 0x4f12: + case 0x4f13: + case 0x4f1d: + case 0x4f29: + case 0x7307: + case 0x7308: + case 0x7309: + case 0x7327: + case 0x8387: + case 0x8388: + case 0x8389: + case 0x83a7: case 0x752039: return true; default: @@ -72,8 +112,6 @@ static bool rt715_volatile_register(struct device *dev, unsigned int reg) case 0x202d ... 0x202f: /* BRA */ case 0x2201 ... 0x2212: /* i2c debug */ case 0x2220 ... 0x2223: /* decoded HD-A */ - case 0x9c00 ... 0x9cff: - case 0xb900 ... 0xb9ff: return true; default: return false; diff --git a/sound/soc/codecs/rt715-sdw.h b/sound/soc/codecs/rt715-sdw.h index 0bc0efada86296..0a74a6497c2089 100644 --- a/sound/soc/codecs/rt715-sdw.h +++ b/sound/soc/codecs/rt715-sdw.h @@ -43,6 +43,7 @@ static const struct reg_default rt715_reg_defaults[] = { { 0x0060, 0x00 }, { 0x0070, 0x00 }, { 0x0080, 0x00 }, + { 0x0088, 0x10 }, { 0x00e0, 0x00 }, { 0x00e1, 0x00 }, { 0x00e2, 0x00 }, @@ -64,7 +65,7 @@ static const struct reg_default rt715_reg_defaults[] = { { 0x0202, 0x20 }, { 0x0203, 0x00 }, { 0x0204, 0x00 }, - { 0x0205, 0x00 }, + { 0x0205, 0x03 }, { 0x0220, 0x00 }, { 0x0221, 0x00 }, { 0x0222, 0x00 }, @@ -88,7 +89,7 @@ static const struct reg_default rt715_reg_defaults[] = { { 0x0402, 0x20 }, { 0x0403, 0x00 }, { 0x0404, 0x00 }, - { 0x0405, 0x00 }, + { 0x0405, 0x0f }, { 0x0420, 0x00 }, { 0x0421, 0x00 }, { 0x0422, 0x00 }, @@ -112,7 +113,7 @@ static const struct reg_default rt715_reg_defaults[] = { { 0x0602, 0x20 }, { 0x0603, 0x00 }, { 0x0604, 0x00 }, - { 0x0605, 0x00 }, + { 0x0605, 0xff }, { 0x0620, 0x00 }, { 0x0621, 0x00 }, { 0x0622, 0x00 }, @@ -152,7 +153,7 @@ static const struct reg_default rt715_reg_defaults[] = { { 0x0f12, 0x00 }, { 0x0f13, 0x00 }, { 0x0f14, 0x00 }, - { 0x0f15, 0xff }, + { 0x0f15, 0x00 }, { 0x0f16, 0x00 }, { 0x0f17, 0x00 }, { 0x0f18, 0x00 }, @@ -194,7 +195,7 @@ static const struct reg_default rt715_reg_defaults[] = { { 0x200c, 0x00 }, { 0x200d, 0x00 }, { 0x200e, 0x00 }, - { 0x200f, 0x00 }, + { 0x200f, 0x10 }, { 0x2010, 0x00 }, { 0x2011, 0x00 }, { 0x2012, 0x00 }, @@ -262,6 +263,42 @@ static const struct reg_default rt715_reg_defaults[] = { { 0x22f1, 0x00 }, { 0x22f2, 0x00 }, { 0x22f3, 0x00 }, + { 0x3122, 0x02 }, + { 0x3123, 0x03 }, + { 0x3124, 0x00 }, + { 0x3125, 0x01 }, + { 0x3607, 0x00 }, + { 0x3608, 0x00 }, + { 0x3609, 0x00 }, + { 0x3610, 0x00 }, + { 0x3611, 0x00 }, + { 0x3627, 0x00 }, + { 0x3712, 0x00 }, + { 0x3713, 0x00 }, + { 0x3718, 0x00 }, + { 0x3719, 0x00 }, + { 0x371a, 0x00 }, + { 0x371b, 0x00 }, + { 0x371d, 0x00 }, + { 0x3729, 0x00 }, + { 0x385e, 0x00 }, + { 0x3859, 0x00 }, + { 0x4c12, 0x411111f0 }, + { 0x4c13, 0x411111f0 }, + { 0x4c1d, 0x411111f0 }, + { 0x4c29, 0x411111f0 }, + { 0x4d12, 0x411111f0 }, + { 0x4d13, 0x411111f0 }, + { 0x4d1d, 0x411111f0 }, + { 0x4d29, 0x411111f0 }, + { 0x4e12, 0x411111f0 }, + { 0x4e13, 0x411111f0 }, + { 0x4e1d, 0x411111f0 }, + { 0x4e29, 0x411111f0 }, + { 0x4f12, 0x411111f0 }, + { 0x4f13, 0x411111f0 }, + { 0x4f1d, 0x411111f0 }, + { 0x4f29, 0x411111f0 }, { 0x7307, 0x97 }, { 0x8387, 0x97 }, { 0x7308, 0x97 }, From c17a9b70eb9d7297ee5ce3b32e6f371f97a244e1 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Fri, 22 Nov 2019 13:22:11 +0800 Subject: [PATCH 1869/1995] ASoC: rt5682: Add the field "is_sdw" of private data The field "is_sdw" is used for distinguishing the driver whether is run in soundwire mode or not. That will run the separated setting in runtime to make sure the driver can be run with the same build between i2s mode and soundwire mode. Signed-off-by: Oder Chiou --- sound/soc/codecs/rt5682.c | 154 ++++++++++++++++++++++---------------- sound/soc/codecs/rt5682.h | 3 + 2 files changed, 92 insertions(+), 65 deletions(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index ae6f6121bc1b0f..6a65d1efee41dc 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -56,6 +56,7 @@ struct rt5682_priv { struct delayed_work jack_detect_work; struct delayed_work jd_check_work; struct mutex calibrate_mutex; + bool is_sdw; int sysclk; int sysclk_src; @@ -805,10 +806,13 @@ static const struct snd_kcontrol_new rt5682_if1_45_adc_swap_mux = static const struct snd_kcontrol_new rt5682_if1_67_adc_swap_mux = SOC_DAPM_ENUM("IF1 67 ADC Swap Mux", rt5682_if1_67_adc_enum); -static void rt5682_reset(struct regmap *regmap) +static void rt5682_reset(struct rt5682_priv *rt5682) { - regmap_write(regmap, RT5682_RESET, 0); - regmap_write(regmap, RT5682_I2C_MODE, 1); + regmap_write(rt5682->regmap, RT5682_RESET, 0); + if (!rt5682->is_sdw) { + regmap_write(rt5682->regmap, RT5682_I2C_CTRL, 0x000f); + regmap_write(rt5682->regmap, RT5682_I2C_MODE, 1); + } } /** * rt5682_sel_asrc_clk_src - select ASRC clock source for a set of filters @@ -871,6 +875,8 @@ static int rt5682_button_detect(struct snd_soc_component *component) static void rt5682_enable_push_button_irq(struct snd_soc_component *component, bool enable) { + struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); + if (enable) { snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1, RT5682_SAR_BUTT_DET_MASK, RT5682_SAR_BUTT_DET_EN); @@ -880,8 +886,15 @@ static void rt5682_enable_push_button_irq(struct snd_soc_component *component, snd_soc_component_update_bits(component, RT5682_4BTN_IL_CMD_2, RT5682_4BTN_IL_MASK | RT5682_4BTN_IL_RST_MASK, RT5682_4BTN_IL_EN | RT5682_4BTN_IL_NOR); - snd_soc_component_update_bits(component, RT5682_IRQ_CTRL_3, - RT5682_IL_IRQ_MASK, RT5682_IL_IRQ_EN); + if (rt5682->is_sdw) + snd_soc_component_update_bits(component, + RT5682_IRQ_CTRL_3, + RT5682_IL_IRQ_MASK | RT5682_IL_IRQ_TYPE_MASK, + RT5682_IL_IRQ_EN | RT5682_IL_IRQ_PUL); + else + snd_soc_component_update_bits(component, + RT5682_IRQ_CTRL_3, RT5682_IL_IRQ_MASK, + RT5682_IL_IRQ_EN); } else { snd_soc_component_update_bits(component, RT5682_IRQ_CTRL_3, RT5682_IL_IRQ_MASK, RT5682_IL_IRQ_DIS); @@ -999,62 +1012,69 @@ static int rt5682_set_jack_detect(struct snd_soc_component *component, rt5682->hs_jack = hs_jack; - if (!hs_jack) { - regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2, - RT5682_JD1_EN_MASK, RT5682_JD1_DIS); - regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL, - RT5682_POW_JDH | RT5682_POW_JDL, 0); - cancel_delayed_work_sync(&rt5682->jack_detect_work); - return 0; - } + if (!rt5682->is_sdw) { + if (!hs_jack) { + regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2, + RT5682_JD1_EN_MASK, RT5682_JD1_DIS); + regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL, + RT5682_POW_JDH | RT5682_POW_JDL, 0); + cancel_delayed_work_sync(&rt5682->jack_detect_work); + return 0; + } - switch (rt5682->pdata.jd_src) { - case RT5682_JD1: - snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_2, - RT5682_EXT_JD_SRC, RT5682_EXT_JD_SRC_MANUAL); - snd_soc_component_write(component, RT5682_CBJ_CTRL_1, 0xd042); - snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_3, - RT5682_CBJ_IN_BUF_EN, RT5682_CBJ_IN_BUF_EN); - snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1, - RT5682_SAR_POW_MASK, RT5682_SAR_POW_EN); - regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1, - RT5682_GP1_PIN_MASK, RT5682_GP1_PIN_IRQ); - regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL, + switch (rt5682->pdata.jd_src) { + case RT5682_JD1: + snd_soc_component_update_bits(component, + RT5682_CBJ_CTRL_2, RT5682_EXT_JD_SRC, + RT5682_EXT_JD_SRC_MANUAL); + snd_soc_component_write(component, RT5682_CBJ_CTRL_1, + 0xd042); + snd_soc_component_update_bits(component, + RT5682_CBJ_CTRL_3, RT5682_CBJ_IN_BUF_EN, + RT5682_CBJ_IN_BUF_EN); + snd_soc_component_update_bits(component, + RT5682_SAR_IL_CMD_1, RT5682_SAR_POW_MASK, + RT5682_SAR_POW_EN); + regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1, + RT5682_GP1_PIN_MASK, RT5682_GP1_PIN_IRQ); + regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL, RT5682_POW_IRQ | RT5682_POW_JDH | RT5682_POW_ANA, RT5682_POW_IRQ | RT5682_POW_JDH | RT5682_POW_ANA); - regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_2, - RT5682_PWR_JDH | RT5682_PWR_JDL, - RT5682_PWR_JDH | RT5682_PWR_JDL); - regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2, - RT5682_JD1_EN_MASK | RT5682_JD1_POL_MASK, - RT5682_JD1_EN | RT5682_JD1_POL_NOR); - regmap_update_bits(rt5682->regmap, RT5682_4BTN_IL_CMD_4, - 0x7f7f, (rt5682->pdata.btndet_delay << 8 | - rt5682->pdata.btndet_delay)); - regmap_update_bits(rt5682->regmap, RT5682_4BTN_IL_CMD_5, - 0x7f7f, (rt5682->pdata.btndet_delay << 8 | - rt5682->pdata.btndet_delay)); - regmap_update_bits(rt5682->regmap, RT5682_4BTN_IL_CMD_6, - 0x7f7f, (rt5682->pdata.btndet_delay << 8 | - rt5682->pdata.btndet_delay)); - regmap_update_bits(rt5682->regmap, RT5682_4BTN_IL_CMD_7, - 0x7f7f, (rt5682->pdata.btndet_delay << 8 | - rt5682->pdata.btndet_delay)); - mod_delayed_work(system_power_efficient_wq, - &rt5682->jack_detect_work, msecs_to_jiffies(250)); - break; + regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_2, + RT5682_PWR_JDH | RT5682_PWR_JDL, + RT5682_PWR_JDH | RT5682_PWR_JDL); + regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2, + RT5682_JD1_EN_MASK | RT5682_JD1_POL_MASK, + RT5682_JD1_EN | RT5682_JD1_POL_NOR); + regmap_update_bits(rt5682->regmap, RT5682_4BTN_IL_CMD_4, + 0x7f7f, (rt5682->pdata.btndet_delay << 8 | + rt5682->pdata.btndet_delay)); + regmap_update_bits(rt5682->regmap, RT5682_4BTN_IL_CMD_5, + 0x7f7f, (rt5682->pdata.btndet_delay << 8 | + rt5682->pdata.btndet_delay)); + regmap_update_bits(rt5682->regmap, RT5682_4BTN_IL_CMD_6, + 0x7f7f, (rt5682->pdata.btndet_delay << 8 | + rt5682->pdata.btndet_delay)); + regmap_update_bits(rt5682->regmap, RT5682_4BTN_IL_CMD_7, + 0x7f7f, (rt5682->pdata.btndet_delay << 8 | + rt5682->pdata.btndet_delay)); + mod_delayed_work(system_power_efficient_wq, + &rt5682->jack_detect_work, + msecs_to_jiffies(250)); + break; - case RT5682_JD_NULL: - regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2, - RT5682_JD1_EN_MASK, RT5682_JD1_DIS); - regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL, - RT5682_POW_JDH | RT5682_POW_JDL, 0); - break; + case RT5682_JD_NULL: + regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2, + RT5682_JD1_EN_MASK, RT5682_JD1_DIS); + regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL, + RT5682_POW_JDH | RT5682_POW_JDL, 0); + break; - default: - dev_warn(component->dev, "Wrong JD source\n"); - break; + default: + dev_warn(component->dev, "Wrong JD source\n"); + break; + } } return 0; @@ -1134,11 +1154,13 @@ static void rt5682_jack_detect_handler(struct work_struct *work) SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3); - if (rt5682->jack_type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3)) - schedule_delayed_work(&rt5682->jd_check_work, 0); - else - cancel_delayed_work_sync(&rt5682->jd_check_work); + if (!rt5682->is_sdw) { + if (rt5682->jack_type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3)) + schedule_delayed_work(&rt5682->jd_check_work, 0); + else + cancel_delayed_work_sync(&rt5682->jd_check_work); + } mutex_unlock(&rt5682->calibrate_mutex); } @@ -1232,6 +1254,9 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w, static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48}; static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48}; + if (rt5682->is_sdw) + return 0; + val = snd_soc_component_read32(component, RT5682_GPIO_CTRL_1) & RT5682_GP4_PIN_MASK; if (w->shift == RT5682_PWR_ADC_S1F_BIT && @@ -2332,7 +2357,7 @@ static void rt5682_remove(struct snd_soc_component *component) { struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); - rt5682_reset(rt5682->regmap); + rt5682_reset(rt5682); } #ifdef CONFIG_PM @@ -2474,8 +2499,7 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682) mutex_lock(&rt5682->calibrate_mutex); - rt5682_reset(rt5682->regmap); - regmap_write(rt5682->regmap, RT5682_I2C_CTRL, 0x000f); + rt5682_reset(rt5682); regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2af); usleep_range(15000, 20000); regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2af); @@ -2586,7 +2610,7 @@ static int rt5682_i2c_probe(struct i2c_client *i2c, return -ENODEV; } - rt5682_reset(rt5682->regmap); + rt5682_reset(rt5682); mutex_init(&rt5682->calibrate_mutex); rt5682_calibrate(rt5682); @@ -2676,7 +2700,7 @@ static void rt5682_i2c_shutdown(struct i2c_client *client) { struct rt5682_priv *rt5682 = i2c_get_clientdata(client); - rt5682_reset(rt5682->regmap); + rt5682_reset(rt5682); } #ifdef CONFIG_OF diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h index 18faaa2a49a0ce..61a577dacdaa3d 100644 --- a/sound/soc/codecs/rt5682.h +++ b/sound/soc/codecs/rt5682.h @@ -1096,6 +1096,9 @@ #define RT5682_IL_IRQ_MASK (0x1 << 7) #define RT5682_IL_IRQ_DIS (0x0 << 7) #define RT5682_IL_IRQ_EN (0x1 << 7) +#define RT5682_IL_IRQ_TYPE_MASK (0x1 << 4) +#define RT5682_IL_IRQ_LEV (0x0 << 4) +#define RT5682_IL_IRQ_PUL (0x1 << 4) /* GPIO Control 1 (0x00c0) */ #define RT5682_GP1_PIN_MASK (0x3 << 14) From c2335ac00a0117b79091921d6bdf4095949580bc Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Tue, 26 Nov 2019 16:32:18 +0800 Subject: [PATCH 1870/1995] ASoC: rt5682: Add the soundwire support This patch adds the soundwire support for ALC5682. Signed-off-by: Oder Chiou --- sound/soc/codecs/Kconfig | 6 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt5682-sdw.c | 335 +++++++++++++++++++++++ sound/soc/codecs/rt5682-sdw.h | 18 ++ sound/soc/codecs/rt5682.c | 497 ++++++++++++++++++++++++++++++++-- sound/soc/codecs/rt5682.h | 45 ++- 6 files changed, 871 insertions(+), 32 deletions(-) create mode 100644 sound/soc/codecs/rt5682-sdw.c create mode 100644 sound/soc/codecs/rt5682-sdw.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 543f5efe89a6fd..89421d817007cb 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1058,6 +1058,12 @@ config SND_SOC_RT5677_SPI config SND_SOC_RT5682 tristate +config SND_SOC_RT5682_SDW + tristate "Realtek RT5682 Codec - SDW" + depends on SOUNDWIRE + select SND_SOC_RT5682 + select REGMAP_SOUNDWIRE + config SND_SOC_RT700 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 2cdb67dbff198e..663a5431706084 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -175,6 +175,7 @@ snd-soc-rt5670-objs := rt5670.o snd-soc-rt5677-objs := rt5677.o snd-soc-rt5677-spi-objs := rt5677-spi.o snd-soc-rt5682-objs := rt5682.o +snd-soc-rt5682-sdw-objs := rt5682-sdw.o snd-soc-sgtl5000-objs := sgtl5000.o snd-soc-alc5623-objs := alc5623.o snd-soc-alc5632-objs := alc5632.o @@ -471,6 +472,7 @@ obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o obj-$(CONFIG_SND_SOC_RT5682) += snd-soc-rt5682.o +obj-$(CONFIG_SND_SOC_RT5682_SDW) += snd-soc-rt5682-sdw.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c new file mode 100644 index 00000000000000..1e47fa85a1ff7f --- /dev/null +++ b/sound/soc/codecs/rt5682-sdw.c @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * rt5682-sdw.c -- RT5682 ALSA SoC audio component driver + * + * Copyright 2019 Realtek Semiconductor Corp. + * Author: Oder Chiou + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rt5682.h" +#include "rt5682-sdw.h" + +static bool rt5682_sdw_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x00e0: + case 0x00f0: + case 0x3000: + case 0x3001: + case 0x3004: + case 0x3005: + case 0x3008: + return true; + default: + return false; + } +} + +const struct regmap_config rt5682_sdw_regmap = { + .name = "sdw", + .reg_bits = 32, + .val_bits = 8, + .max_register = RT5682_I2C_MODE, + .readable_reg = rt5682_sdw_readable_register, + .cache_type = REGCACHE_NONE, + .use_single_read = true, + .use_single_write = true, +}; + +static int rt5682_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev); + + /* Update the status */ + rt5682->status = status; + + if (status == SDW_SLAVE_UNATTACHED) + rt5682->hw_init = false; + + /* + * Perform initialization only if slave status is present and + * hw_init flag is false + */ + if (rt5682->hw_init || rt5682->status != SDW_SLAVE_ATTACHED) + return 0; + + /* perform I/O transfers required for Slave initialization */ + return rt5682_io_init(&slave->dev, slave); +} + +static int rt5682_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int nval, i, num_of_ports = 1; + u32 bit; + unsigned long addr; + struct sdw_dpn_prop *dpn; + + prop->paging_support = false; + + /* first we need to allocate memory for set bits in port lists */ + prop->source_ports = 0x4; /* BITMAP: 00000100 */ + prop->sink_ports = 0x2; /* BITMAP: 00000010 */ + + nval = hweight32(prop->source_ports); + num_of_ports += nval; + prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->src_dpn_prop), + GFP_KERNEL); + if (!prop->src_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->src_dpn_prop; + addr = prop->source_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].type = SDW_DPN_FULL; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* do this again for sink now */ + nval = hweight32(prop->sink_ports); + num_of_ports += nval; + prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->sink_dpn_prop), + GFP_KERNEL); + if (!prop->sink_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->sink_dpn_prop; + addr = prop->sink_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].type = SDW_DPN_FULL; + dpn[i].simple_ch_prep_sm = true; + dpn[i].ch_prep_timeout = 10; + i++; + } + + /* Allocate port_ready based on num_of_ports */ + slave->port_ready = devm_kcalloc(&slave->dev, num_of_ports, + sizeof(*slave->port_ready), + GFP_KERNEL); + if (!slave->port_ready) + return -ENOMEM; + + /* Initialize completion */ + for (i = 0; i < num_of_ports; i++) + init_completion(&slave->port_ready[i]); + + /* set the timeout values */ + prop->clk_stop_timeout = 20; + + /* wake-up event */ + prop->wake_capable = 1; + + return 0; +} + +/* Bus clock frequency */ +#define RT5682_CLK_FREQ_9600000HZ 9600000 +#define RT5682_CLK_FREQ_12000000HZ 12000000 +#define RT5682_CLK_FREQ_6000000HZ 6000000 +#define RT5682_CLK_FREQ_4800000HZ 4800000 +#define RT5682_CLK_FREQ_2400000HZ 2400000 +#define RT5682_CLK_FREQ_12288000HZ 12288000 + +int rt5682_clock_config(struct device *dev) +{ + struct rt5682_priv *rt5682 = dev_get_drvdata(dev); + unsigned int clk_freq, value; + + clk_freq = (rt5682->params.curr_dr_freq >> 1); + + switch (clk_freq) { + case RT5682_CLK_FREQ_12000000HZ: + value = 0x0; + break; + case RT5682_CLK_FREQ_6000000HZ: + value = 0x1; + break; + case RT5682_CLK_FREQ_9600000HZ: + value = 0x2; + break; + case RT5682_CLK_FREQ_4800000HZ: + value = 0x3; + break; + case RT5682_CLK_FREQ_2400000HZ: + value = 0x4; + break; + case RT5682_CLK_FREQ_12288000HZ: + value = 0x5; + break; + default: + return -EINVAL; + } + + regmap_write(rt5682->sdw_regmap, 0xe0, value); + regmap_write(rt5682->sdw_regmap, 0xf0, value); + + dev_dbg(dev, "%s complete, clk_freq=%d\n", __func__, clk_freq); + + return 0; +} + +static int rt5682_bus_config(struct sdw_slave *slave, + struct sdw_bus_params *params) +{ + struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev); + int ret; + + memcpy(&rt5682->params, params, sizeof(*params)); + + ret = rt5682_clock_config(&slave->dev); + if (ret < 0) + dev_err(&slave->dev, "Invalid clk config"); + + return ret; +} + +static int rt5682_interrupt_callback(struct sdw_slave *slave, + struct sdw_slave_intr_status *status) +{ + struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev); + + dev_dbg(&slave->dev, + "%s control_port_stat=%x", __func__, status->control_port); + + if (status->control_port & 0x4) { + mod_delayed_work(system_power_efficient_wq, + &rt5682->jack_detect_work, msecs_to_jiffies(250)); + } + + return 0; +} + +static struct sdw_slave_ops rt5682_slave_ops = { + .read_prop = rt5682_read_prop, + .interrupt_callback = rt5682_interrupt_callback, + .update_status = rt5682_update_status, + .bus_config = rt5682_bus_config, +}; + +static int rt5682_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct regmap *regmap; + + /* Assign ops */ + slave->ops = &rt5682_slave_ops; + + /* Regmap Initialization */ + regmap = devm_regmap_init_sdw(slave, &rt5682_sdw_regmap); + if (!regmap) + return -EINVAL; + + rt5682_sdw_init(&slave->dev, regmap, slave); + + return 0; +} + +static int rt5682_sdw_remove(struct sdw_slave *slave) +{ + struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev); + + if (rt5682 && rt5682->hw_init) + cancel_delayed_work(&rt5682->jack_detect_work); + + return 0; +} + +static const struct sdw_device_id rt5682_id[] = { + SDW_SLAVE_ENTRY(0x025d, 0x5682, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, rt5682_id); + +static int rt5682_dev_suspend(struct device *dev) +{ + struct rt5682_priv *rt5682 = dev_get_drvdata(dev); + + if (!rt5682->hw_init) + return 0; + + regcache_cache_only(rt5682->regmap, true); + regcache_mark_dirty(rt5682->regmap); + + return 0; +} + +#define rt5682_PROBE_TIMEOUT 2000 + +static int rt5682_dev_resume(struct device *dev) +{ + struct sdw_slave *slave = to_sdw_slave_device(dev); + struct rt5682_priv *rt5682 = dev_get_drvdata(dev); + unsigned long time; + + if (!rt5682->hw_init) + return 0; + + if (!slave->unattach_request) + goto regmap_sync; + + time = wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(rt5682_PROBE_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "Initialization not complete, timed out\n"); + return -ETIMEDOUT; + } + +regmap_sync: + slave->unattach_request = 0; + regcache_cache_only(rt5682->regmap, false); + regcache_sync(rt5682->regmap); + + return 0; +} + +static const struct dev_pm_ops rt5682_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rt5682_dev_suspend, rt5682_dev_resume) + SET_RUNTIME_PM_OPS(rt5682_dev_suspend, rt5682_dev_resume, NULL) +}; + +static struct sdw_driver rt5682_sdw_driver = { + .driver = { + .name = "rt5682", + .owner = THIS_MODULE, + .pm = &rt5682_pm, + }, + .probe = rt5682_sdw_probe, + .remove = rt5682_sdw_remove, + .ops = &rt5682_slave_ops, + .id_table = rt5682_id, +}; +module_sdw_driver(rt5682_sdw_driver); + +MODULE_DESCRIPTION("ASoC RT5682 driver SDW"); +MODULE_AUTHOR("Oder Chiou "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5682-sdw.h b/sound/soc/codecs/rt5682-sdw.h new file mode 100644 index 00000000000000..688a172ad74570 --- /dev/null +++ b/sound/soc/codecs/rt5682-sdw.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * rt5682-sdw.h -- RT5682 SDW ALSA SoC audio driver + * + * Copyright 2019 Realtek Semiconductor Corp. + * Author: Oder Chiou + */ + +#ifndef __RT5682_SDW_H__ +#define __RT5682_SDW_H__ + +#define RT5682_SDW_ADDR_L 0x3000 +#define RT5682_SDW_ADDR_H 0x3001 +#define RT5682_SDW_DATA_L 0x3004 +#define RT5682_SDW_DATA_H 0x3005 +#define RT5682_SDW_CMD 0x3008 + +#endif /* __RT5682_SDW_H__ */ diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 6a65d1efee41dc..8c477426956189 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -11,13 +11,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include #include #include #include @@ -31,8 +31,7 @@ #include "rl6231.h" #include "rt5682.h" - -#define RT5682_NUM_SUPPLIES 3 +#include "rt5682-sdw.h" static const char *rt5682_supply_names[RT5682_NUM_SUPPLIES] = { "AVDD", @@ -47,30 +46,6 @@ static const struct rt5682_platform_data i2s_default_platform_data = { .btndet_delay = 16, }; -struct rt5682_priv { - struct snd_soc_component *component; - struct rt5682_platform_data pdata; - struct regmap *regmap; - struct snd_soc_jack *hs_jack; - struct regulator_bulk_data supplies[RT5682_NUM_SUPPLIES]; - struct delayed_work jack_detect_work; - struct delayed_work jd_check_work; - struct mutex calibrate_mutex; - bool is_sdw; - - int sysclk; - int sysclk_src; - int lrck[RT5682_AIFS]; - int bclk[RT5682_AIFS]; - int master[RT5682_AIFS]; - - int pll_src; - int pll_in; - int pll_out; - - int jack_type; -}; - static const struct reg_sequence patch_list[] = { {RT5682_HP_IMP_SENS_CTRL_19, 0x1000}, {RT5682_DAC_ADC_DIG_VOL1, 0xa020}, @@ -806,6 +781,21 @@ static const struct snd_kcontrol_new rt5682_if1_45_adc_swap_mux = static const struct snd_kcontrol_new rt5682_if1_67_adc_swap_mux = SOC_DAPM_ENUM("IF1 67 ADC Swap Mux", rt5682_if1_67_adc_enum); +static const char * const rt5682_dac_select[] = { + "IF1", "SOUND" +}; +static SOC_ENUM_SINGLE_DECL(rt5682_dacl_enum, + RT5682_AD_DA_MIXER, RT5682_DAC1_L_SEL_SFT, rt5682_dac_select); + +static const struct snd_kcontrol_new rt5682_dac_l_mux = + SOC_DAPM_ENUM("DAC L Mux", rt5682_dacl_enum); + +static SOC_ENUM_SINGLE_DECL(rt5682_dacr_enum, + RT5682_AD_DA_MIXER, RT5682_DAC1_R_SEL_SFT, rt5682_dac_select); + +static const struct snd_kcontrol_new rt5682_dac_r_mux = + SOC_DAPM_ENUM("DAC R Mux", rt5682_dacr_enum); + static void rt5682_reset(struct rt5682_priv *rt5682) { regmap_write(rt5682->regmap, RT5682_RESET, 0); @@ -1711,6 +1701,8 @@ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = { SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("SOUND DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("SOUND DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), /* Digital Interface Select */ SND_SOC_DAPM_MUX("IF1 01 ADC Swap Mux", SND_SOC_NOPM, 0, 0, @@ -1727,12 +1719,19 @@ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = { SND_SOC_DAPM_MUX("ADCDAT Mux", SND_SOC_NOPM, 0, 0, &rt5682_adcdat_pin_ctrl), + SND_SOC_DAPM_MUX("DAC L Mux", SND_SOC_NOPM, 0, 0, + &rt5682_dac_l_mux), + SND_SOC_DAPM_MUX("DAC R Mux", SND_SOC_NOPM, 0, 0, + &rt5682_dac_r_mux), + /* Audio Interface */ SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, RT5682_I2S1_SDP, RT5682_SEL_ADCDAT_SFT, 1), SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, RT5682_I2S2_SDP, RT5682_I2S2_PIN_CFG_SFT, 1), SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("SDWRX", "SDW Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("SDWTX", "SDW Capture", 0, SND_SOC_NOPM, 0, 0), /* Output Side */ /* DAC mixer before sound effect */ @@ -1885,8 +1884,8 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = { {"IF1_ADC Mux", "Slot 2", "IF1 23 ADC Swap Mux"}, {"IF1_ADC Mux", "Slot 4", "IF1 45 ADC Swap Mux"}, {"IF1_ADC Mux", "Slot 6", "IF1 67 ADC Swap Mux"}, - {"IF1_ADC Mux", NULL, "I2S1"}, {"ADCDAT Mux", "ADCDAT1", "IF1_ADC Mux"}, + {"AIF1TX", NULL, "I2S1"}, {"AIF1TX", NULL, "ADCDAT Mux"}, {"IF2 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"}, {"IF2 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"}, @@ -1895,6 +1894,10 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = { {"ADCDAT Mux", "ADCDAT2", "IF2 ADC Swap Mux"}, {"AIF2TX", NULL, "ADCDAT Mux"}, + {"SDWTX", NULL, "PLL2B"}, + {"SDWTX", NULL, "PLL2F"}, + {"SDWTX", NULL, "ADCDAT Mux"}, + {"IF1 DAC1 L", NULL, "AIF1RX"}, {"IF1 DAC1 L", NULL, "I2S1"}, {"IF1 DAC1 L", NULL, "DAC Stereo1 Filter"}, @@ -1902,10 +1905,24 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = { {"IF1 DAC1 R", NULL, "I2S1"}, {"IF1 DAC1 R", NULL, "DAC Stereo1 Filter"}, + {"SOUND DAC L", NULL, "SDWRX"}, + {"SOUND DAC L", NULL, "DAC Stereo1 Filter"}, + {"SOUND DAC L", NULL, "PLL2B"}, + {"SOUND DAC L", NULL, "PLL2F"}, + {"SOUND DAC R", NULL, "SDWRX"}, + {"SOUND DAC R", NULL, "DAC Stereo1 Filter"}, + {"SOUND DAC R", NULL, "PLL2B"}, + {"SOUND DAC R", NULL, "PLL2F"}, + + {"DAC L Mux", "IF1", "IF1 DAC1 L"}, + {"DAC L Mux", "SOUND", "SOUND DAC L"}, + {"DAC R Mux", "IF1", "IF1 DAC1 R"}, + {"DAC R Mux", "SOUND", "SOUND DAC R"}, + {"DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"}, - {"DAC1 MIXL", "DAC1 Switch", "IF1 DAC1 L"}, + {"DAC1 MIXL", "DAC1 Switch", "DAC L Mux"}, {"DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"}, - {"DAC1 MIXR", "DAC1 Switch", "IF1 DAC1 R"}, + {"DAC1 MIXR", "DAC1 Switch", "DAC R Mux"}, {"Stereo1 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"}, {"Stereo1 DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"}, @@ -2402,6 +2419,194 @@ static const struct snd_soc_dai_ops rt5682_aif2_dai_ops = { .set_bclk_ratio = rt5682_set_bclk_ratio, }; +#if IS_ENABLED(CONFIG_SND_SOC_RT5682_SDW) +struct sdw_stream_data { + struct sdw_stream_runtime *sdw_stream; +}; + +static int rt5682_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, + int direction) +{ + struct sdw_stream_data *stream; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; + + stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream; + + /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + dai->playback_dma_data = stream; + else + dai->capture_dma_data = stream; + + return 0; +} + +static void rt5682_sdw_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sdw_stream_data *stream; + + stream = snd_soc_dai_get_dma_data(dai, substream); + snd_soc_dai_set_dma_data(dai, substream, NULL); + kfree(stream); +} + +static int rt5682_sdw_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; + enum sdw_data_direction direction; + struct sdw_stream_data *stream; + int retval, port, num_channels; + unsigned int val_p = 0, val_c = 0, osr_p = 0, osr_c = 0; + + dev_dbg(dai->dev, "%s %s", __func__, dai->name); + stream = snd_soc_dai_get_dma_data(dai, substream); + + if (!stream) + return -ENOMEM; + + if (!rt5682->slave) + return -EINVAL; + + /* SoundWire specific configuration */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + direction = SDW_DATA_DIR_RX; + port = 1; + } else { + direction = SDW_DATA_DIR_TX; + port = 2; + } + + stream_config.frame_rate = params_rate(params); + stream_config.ch_count = params_channels(params); + stream_config.bps = snd_pcm_format_width(params_format(params)); + stream_config.direction = direction; + + num_channels = params_channels(params); + port_config.ch_mask = (1 << (num_channels)) - 1; + port_config.num = port; + + retval = sdw_stream_add_slave(rt5682->slave, &stream_config, + &port_config, 1, stream->sdw_stream); + if (retval) { + dev_err(dai->dev, "Unable to configure port\n"); + return retval; + } + + switch (params_rate(params)) { + case 48000: + val_p = RT5682_SDW_REF_1_48K; + val_c = RT5682_SDW_REF_2_48K; + break; + case 96000: + val_p = RT5682_SDW_REF_1_96K; + val_c = RT5682_SDW_REF_2_96K; + break; + case 192000: + val_p = RT5682_SDW_REF_1_192K; + val_c = RT5682_SDW_REF_2_192K; + break; + case 32000: + val_p = RT5682_SDW_REF_1_32K; + val_c = RT5682_SDW_REF_2_32K; + break; + case 24000: + val_p = RT5682_SDW_REF_1_24K; + val_c = RT5682_SDW_REF_2_24K; + break; + case 16000: + val_p = RT5682_SDW_REF_1_16K; + val_c = RT5682_SDW_REF_2_16K; + break; + case 12000: + val_p = RT5682_SDW_REF_1_12K; + val_c = RT5682_SDW_REF_2_12K; + break; + case 8000: + val_p = RT5682_SDW_REF_1_8K; + val_c = RT5682_SDW_REF_2_8K; + break; + case 44100: + val_p = RT5682_SDW_REF_1_44K; + val_c = RT5682_SDW_REF_2_44K; + break; + case 88200: + val_p = RT5682_SDW_REF_1_88K; + val_c = RT5682_SDW_REF_2_88K; + break; + case 176400: + val_p = RT5682_SDW_REF_1_176K; + val_c = RT5682_SDW_REF_2_176K; + break; + case 22050: + val_p = RT5682_SDW_REF_1_22K; + val_c = RT5682_SDW_REF_2_22K; + break; + case 11025: + val_p = RT5682_SDW_REF_1_11K; + val_c = RT5682_SDW_REF_2_11K; + break; + default: + return -EINVAL; + } + + if (params_rate(params) <= 48000) { + osr_p = RT5682_DAC_OSR_D_8; + osr_c = RT5682_ADC_OSR_D_8; + } else if (params_rate(params) <= 96000) { + osr_p = RT5682_DAC_OSR_D_4; + osr_c = RT5682_ADC_OSR_D_4; + } else { + osr_p = RT5682_DAC_OSR_D_2; + osr_c = RT5682_ADC_OSR_D_2; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_update_bits(rt5682->regmap, RT5682_SDW_REF_CLK, + RT5682_SDW_REF_1_MASK, val_p); + regmap_update_bits(rt5682->regmap, RT5682_ADDA_CLK_1, + RT5682_DAC_OSR_MASK, osr_p); + } else { + regmap_update_bits(rt5682->regmap, RT5682_SDW_REF_CLK, + RT5682_SDW_REF_2_MASK, val_c); + regmap_update_bits(rt5682->regmap, RT5682_ADDA_CLK_1, + RT5682_ADC_OSR_MASK, osr_c); + } + + return retval; +} + +static int rt5682_sdw_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); + struct sdw_stream_data *stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!rt5682->slave) + return -EINVAL; + + sdw_stream_remove_slave(rt5682->slave, stream->sdw_stream); + return 0; +} + +static struct snd_soc_dai_ops rt5682_sdw_ops = { + .hw_params = rt5682_sdw_hw_params, + .hw_free = rt5682_sdw_hw_free, + .set_sdw_stream = rt5682_set_sdw_stream, + .shutdown = rt5682_sdw_shutdown, +}; +#endif + static struct snd_soc_dai_driver rt5682_dai[] = { { .name = "rt5682-aif1", @@ -2434,6 +2639,27 @@ static struct snd_soc_dai_driver rt5682_dai[] = { }, .ops = &rt5682_aif2_dai_ops, }, +#if IS_ENABLED(CONFIG_SND_SOC_RT5682_SDW) + { + .name = "rt5682-sdw", + .id = RT5682_SDW, + .playback = { + .stream_name = "SDW Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5682_STEREO_RATES, + .formats = RT5682_FORMATS, + }, + .capture = { + .stream_name = "SDW Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5682_STEREO_RATES, + .formats = RT5682_FORMATS, + }, + .ops = &rt5682_sdw_ops, + }, +#endif }; static const struct snd_soc_component_driver soc_component_dev_rt5682 = { @@ -2544,6 +2770,217 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682) } +#if IS_ENABLED(CONFIG_SND_SOC_RT5682_SDW) +static int rt5682_sdw_read(void *context, unsigned int reg, unsigned int *val) +{ + struct device *dev = context; + struct rt5682_priv *rt5682 = dev_get_drvdata(dev); + unsigned int data_l, data_h; + + regmap_write(rt5682->sdw_regmap, RT5682_SDW_CMD, 0); + regmap_write(rt5682->sdw_regmap, RT5682_SDW_ADDR_H, (reg >> 8) & 0xff); + regmap_write(rt5682->sdw_regmap, RT5682_SDW_ADDR_L, (reg & 0xff)); + regmap_read(rt5682->sdw_regmap, RT5682_SDW_DATA_H, &data_h); + regmap_read(rt5682->sdw_regmap, RT5682_SDW_DATA_L, &data_l); + + *val = (data_h << 8) | data_l; + + dev_vdbg(dev, "[%s] %04x => %04x\n", __func__, reg, *val); + + return 0; +} + +static int rt5682_sdw_write(void *context, unsigned int reg, unsigned int val) +{ + struct device *dev = context; + struct rt5682_priv *rt5682 = dev_get_drvdata(dev); + + regmap_write(rt5682->sdw_regmap, RT5682_SDW_CMD, 1); + regmap_write(rt5682->sdw_regmap, RT5682_SDW_ADDR_H, (reg >> 8) & 0xff); + regmap_write(rt5682->sdw_regmap, RT5682_SDW_ADDR_L, (reg & 0xff)); + regmap_write(rt5682->sdw_regmap, RT5682_SDW_DATA_H, (val >> 8) & 0xff); + regmap_write(rt5682->sdw_regmap, RT5682_SDW_DATA_L, (val & 0xff)); + + dev_vdbg(dev, "[%s] %04x <= %04x\n", __func__, reg, val); + + return 0; +} + +static const struct regmap_config rt5682_sdw_regmap = { + .reg_bits = 16, + .val_bits = 16, + .max_register = RT5682_I2C_MODE, + .volatile_reg = rt5682_volatile_register, + .readable_reg = rt5682_readable_register, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5682_reg, + .num_reg_defaults = ARRAY_SIZE(rt5682_reg), + .use_single_read = true, + .use_single_write = true, + .reg_read = rt5682_sdw_read, + .reg_write = rt5682_sdw_write, +}; + +int rt5682_sdw_init(struct device *dev, struct regmap *regmap, + struct sdw_slave *slave) +{ + struct rt5682_priv *rt5682; + int ret; + + rt5682 = devm_kzalloc(dev, sizeof(*rt5682), GFP_KERNEL); + if (!rt5682) + return -ENOMEM; + + dev_set_drvdata(dev, rt5682); + rt5682->slave = slave; + rt5682->sdw_regmap = regmap; + rt5682->is_sdw = true; + + rt5682->regmap = devm_regmap_init(dev, NULL, dev, &rt5682_sdw_regmap); + if (IS_ERR(rt5682->regmap)) { + ret = PTR_ERR(rt5682->regmap); + dev_err(dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + /* + * Mark hw_init to false + * HW init will be performed when device reports present + */ + rt5682->hw_init = false; + rt5682->first_init = false; + + mutex_init(&rt5682->calibrate_mutex); + INIT_DELAYED_WORK(&rt5682->jack_detect_work, + rt5682_jack_detect_handler); + + ret = devm_snd_soc_register_component(dev, &soc_component_dev_rt5682, + rt5682_dai, ARRAY_SIZE(rt5682_dai)); + + dev_dbg(&slave->dev, "%s\n", __func__); + + return ret; +} +EXPORT_SYMBOL_GPL(rt5682_sdw_init); + +int rt5682_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt5682_priv *rt5682 = dev_get_drvdata(dev); + int ret = 0; + unsigned int val; + + if (rt5682->hw_init) + return 0; + + regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val); + if (val != DEVICE_ID) { + pr_err("Device with ID register %x is not rt5682\n", val); + return -ENODEV; + } + + /* + * PM runtime is only enabled when a Slave reports as Attached + */ + if (!rt5682->first_init) { + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(&slave->dev, 3000); + pm_runtime_use_autosuspend(&slave->dev); + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(&slave->dev); + + pm_runtime_enable(&slave->dev); + } + + pm_runtime_get_noresume(&slave->dev); + + rt5682_reset(rt5682); + + if (rt5682->first_init) + regcache_cache_bypass(rt5682->regmap, true); + + rt5682_calibrate(rt5682); + + if (rt5682->first_init) { + regcache_cache_bypass(rt5682->regmap, false); + regcache_mark_dirty(rt5682->regmap); + regcache_sync(rt5682->regmap); + + /* volatile registers */ + regmap_update_bits(rt5682->regmap, RT5682_CBJ_CTRL_2, + RT5682_EXT_JD_SRC, RT5682_EXT_JD_SRC_MANUAL); + + goto reinit; + } + + ret = regmap_multi_reg_write(rt5682->regmap, patch_list, + ARRAY_SIZE(patch_list)); + if (ret != 0) + dev_warn(dev, "Failed to apply regmap patch: %d\n", ret); + + regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0000); + + regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1, + RT5682_LDO1_DVO_MASK | RT5682_HP_DRIVER_MASK, + RT5682_LDO1_DVO_12 | RT5682_HP_DRIVER_5X); + regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380); + regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000); + regmap_update_bits(rt5682->regmap, RT5682_BIAS_CUR_CTRL_8, + RT5682_HPA_CP_BIAS_CTRL_MASK, RT5682_HPA_CP_BIAS_3UA); + regmap_update_bits(rt5682->regmap, RT5682_CHARGE_PUMP_1, + RT5682_CP_CLK_HP_MASK, RT5682_CP_CLK_HP_300KHZ); + + /* Soundwire */ + regmap_write(rt5682->regmap, RT5682_PLL2_INTERNAL, 0xa266); + regmap_write(rt5682->regmap, RT5682_PLL2_CTRL_1, 0x1700); + regmap_write(rt5682->regmap, RT5682_PLL2_CTRL_2, 0x0006); + regmap_write(rt5682->regmap, RT5682_PLL2_CTRL_3, 0x2600); + regmap_write(rt5682->regmap, RT5682_PLL2_CTRL_4, 0x0c8f); + regmap_write(rt5682->regmap, RT5682_PLL_TRACK_2, 0x3000); + regmap_write(rt5682->regmap, RT5682_PLL_TRACK_3, 0x4000); + regmap_update_bits(rt5682->regmap, RT5682_GLB_CLK, + RT5682_SCLK_SRC_MASK | RT5682_PLL2_SRC_MASK, + RT5682_SCLK_SRC_PLL2 | RT5682_PLL2_SRC_SDW); + + regmap_update_bits(rt5682->regmap, RT5682_CBJ_CTRL_2, + RT5682_EXT_JD_SRC, RT5682_EXT_JD_SRC_MANUAL); + regmap_write(rt5682->regmap, RT5682_CBJ_CTRL_1, 0xd042); + regmap_update_bits(rt5682->regmap, RT5682_CBJ_CTRL_3, + RT5682_CBJ_IN_BUF_EN, RT5682_CBJ_IN_BUF_EN); + regmap_update_bits(rt5682->regmap, RT5682_SAR_IL_CMD_1, + RT5682_SAR_POW_MASK, RT5682_SAR_POW_EN); + regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL, + RT5682_POW_IRQ | RT5682_POW_JDH | + RT5682_POW_ANA, RT5682_POW_IRQ | + RT5682_POW_JDH | RT5682_POW_ANA); + regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_2, + RT5682_PWR_JDH, RT5682_PWR_JDH); + regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2, + RT5682_JD1_EN_MASK | RT5682_JD1_IRQ_MASK, + RT5682_JD1_EN | RT5682_JD1_IRQ_PUL); + +reinit: + mod_delayed_work(system_power_efficient_wq, + &rt5682->jack_detect_work, msecs_to_jiffies(250)); + + /* Mark Slave initialization complete */ + rt5682->hw_init = true; + rt5682->first_init = true; + + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + + dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); + + return ret; +} +EXPORT_SYMBOL_GPL(rt5682_io_init); +#endif + static int rt5682_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h index 61a577dacdaa3d..a5c8429cebcae0 100644 --- a/sound/soc/codecs/rt5682.h +++ b/sound/soc/codecs/rt5682.h @@ -10,6 +10,9 @@ #define __RT5682_H__ #include +#include +#include +#include #define DEVICE_ID 0x6530 @@ -177,7 +180,7 @@ #define RT5682_TEST_MODE_CTRL_4 0x0148 #define RT5682_TEST_MODE_CTRL_5 0x0149 #define RT5682_PLL1_INTERNAL 0x0150 -#define RT5682_PLL2_INTERNAL 0x0151 +#define RT5682_PLL2_INTERNAL 0x0156 #define RT5682_STO_NG2_CTRL_1 0x0160 #define RT5682_STO_NG2_CTRL_2 0x0161 #define RT5682_STO_NG2_CTRL_3 0x0162 @@ -354,7 +357,6 @@ #define RT5682_R_EQ_POST_VOL 0x03f3 #define RT5682_I2C_MODE 0xffff - /* global definition */ #define RT5682_L_MUTE (0x1 << 15) #define RT5682_L_MUTE_SFT 15 @@ -1091,6 +1093,9 @@ #define RT5682_JD1_POL_MASK (0x1 << 13) #define RT5682_JD1_POL_NOR (0x0 << 13) #define RT5682_JD1_POL_INV (0x1 << 13) +#define RT5682_JD1_IRQ_MASK (0x1 << 10) +#define RT5682_JD1_IRQ_LEV (0x0 << 10) +#define RT5682_JD1_IRQ_PUL (0x1 << 10) /* IRQ Control 3 (0x00b8) */ #define RT5682_IL_IRQ_MASK (0x1 << 7) @@ -1317,6 +1322,7 @@ enum { enum { RT5682_AIF1, RT5682_AIF2, + RT5682_SDW, RT5682_AIFS }; @@ -1332,7 +1338,42 @@ enum { RT5682_CLK_SEL_I2S2_ASRC, }; +#define RT5682_NUM_SUPPLIES 3 + +struct rt5682_priv { + struct snd_soc_component *component; + struct rt5682_platform_data pdata; + struct regmap *regmap; + struct regmap *sdw_regmap; + struct snd_soc_jack *hs_jack; + struct regulator_bulk_data supplies[RT5682_NUM_SUPPLIES]; + struct delayed_work jack_detect_work; + struct delayed_work jd_check_work; + struct mutex calibrate_mutex; + struct sdw_slave *slave; + enum sdw_slave_status status; + struct sdw_bus_params params; + bool hw_init; + bool first_init; + bool is_sdw; + + int sysclk; + int sysclk_src; + int lrck[RT5682_AIFS]; + int bclk[RT5682_AIFS]; + int master[RT5682_AIFS]; + + int pll_src; + int pll_in; + int pll_out; + + int jack_type; +}; + int rt5682_sel_asrc_clk_src(struct snd_soc_component *component, unsigned int filter_mask, unsigned int clk_src); +int rt5682_sdw_init(struct device *dev, struct regmap *regmap, + struct sdw_slave *slave); +int rt5682_io_init(struct device *dev, struct sdw_slave *slave); #endif /* __RT5682_H__ */ From 111ffd5668f84da451990bc19a6accd45dc2fc1e Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 2 Dec 2019 19:03:11 +0800 Subject: [PATCH 1871/1995] Add missing rt715_reg_defaults values. Signed-off-by: Jack Yu --- sound/soc/codecs/rt715-sdw.c | 24 ++++++++++++++++++++++++ sound/soc/codecs/rt715-sdw.h | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index d1fe32a9397df4..c35591fd281b3e 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -77,14 +77,38 @@ static bool rt715_readable_register(struct device *dev, unsigned int reg) case 0x4f13: case 0x4f1d: case 0x4f29: + case 0x7207: + case 0x7208: + case 0x7209: + case 0x7227: case 0x7307: case 0x7308: case 0x7309: + case 0x7312: + case 0x7313: + case 0x7318: + case 0x7319: + case 0x731a: + case 0x731b: + case 0x731d: case 0x7327: + case 0x7329: + case 0x8287: + case 0x8288: + case 0x8289: + case 0x82a7: case 0x8387: case 0x8388: case 0x8389: + case 0x8392: + case 0x8393: + case 0x8398: + case 0x8399: + case 0x839a: + case 0x839b: + case 0x839d: case 0x83a7: + case 0x83a9: case 0x752039: return true; default: diff --git a/sound/soc/codecs/rt715-sdw.h b/sound/soc/codecs/rt715-sdw.h index 0a74a6497c2089..5d7661e335ae55 100644 --- a/sound/soc/codecs/rt715-sdw.h +++ b/sound/soc/codecs/rt715-sdw.h @@ -299,14 +299,38 @@ static const struct reg_default rt715_reg_defaults[] = { { 0x4f13, 0x411111f0 }, { 0x4f1d, 0x411111f0 }, { 0x4f29, 0x411111f0 }, + { 0x7207, 0x00 }, + { 0x8287, 0x00 }, + { 0x7208, 0x00 }, + { 0x8288, 0x00 }, + { 0x7209, 0x00 }, + { 0x8289, 0x00 }, + { 0x7227, 0x00 }, + { 0x82a7, 0x00 }, { 0x7307, 0x97 }, { 0x8387, 0x97 }, { 0x7308, 0x97 }, { 0x8388, 0x97 }, { 0x7309, 0x97 }, { 0x8389, 0x97 }, + { 0x7312, 0x00 }, + { 0x8392, 0x00 }, + { 0x7313, 0x00 }, + { 0x8393, 0x00 }, + { 0x7318, 0x00 }, + { 0x8398, 0x00 }, + { 0x7319, 0x00 }, + { 0x8399, 0x00 }, + { 0x731a, 0x00 }, + { 0x839a, 0x00 }, + { 0x731b, 0x00 }, + { 0x839b, 0x00 }, + { 0x731d, 0x00 }, + { 0x839d, 0x00 }, { 0x7327, 0x97 }, { 0x83a7, 0x97 }, + { 0x7329, 0x00 }, + { 0x83a9, 0x00 }, { 0x752039, 0xa500 }, }; From 08f949d9d89da0e8049ebd2c80daebe6c9a16b2b Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Wed, 4 Dec 2019 16:56:10 +0800 Subject: [PATCH 1872/1995] ASoC: rt5682: Fix the merging conflict This patch fixes the patch "ASoC: rt5682: fix i2c arbitration lost issue" that is conflicted during the merging. Signed-off-by: Oder Chiou --- sound/soc/codecs/rt5682.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 8c477426956189..975984006a1b5e 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -800,7 +800,6 @@ static void rt5682_reset(struct rt5682_priv *rt5682) { regmap_write(rt5682->regmap, RT5682_RESET, 0); if (!rt5682->is_sdw) { - regmap_write(rt5682->regmap, RT5682_I2C_CTRL, 0x000f); regmap_write(rt5682->regmap, RT5682_I2C_MODE, 1); } } @@ -2726,6 +2725,7 @@ static void rt5682_calibrate(struct rt5682_priv *rt5682) mutex_lock(&rt5682->calibrate_mutex); rt5682_reset(rt5682); + regmap_write(rt5682->regmap, RT5682_I2C_CTRL, 0x000f); regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2af); usleep_range(15000, 20000); regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2af); From 3f593dbffd1fd05970c886d97381de3dd86ef4d2 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 5 Dec 2019 17:20:40 +0800 Subject: [PATCH 1873/1995] ASoC: rt700: mark cache_dirty if redo the io_init funciton If the resume process redo the io_init function, I want to make sure the cache value will be synced again. And the first_init variable changes name to first_hw_init. Signed-off-by: Shuming Fan --- sound/soc/codecs/rt700.c | 15 ++++++++------- sound/soc/codecs/rt700.h | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index 44a8cafbad5bfa..fbb3f5b3b29b0c 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -1114,7 +1114,7 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap, * HW init will be performed when device reports present */ rt700->hw_init = false; - rt700->first_init = false; + rt700->first_hw_init = false; ret = devm_snd_soc_register_component(dev, &soc_codec_dev_rt700, @@ -1133,7 +1133,7 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave) if (rt700->hw_init) return 0; - if (rt700->first_init) { + if (rt700->first_hw_init) { regcache_cache_only(rt700->regmap, false); regcache_cache_bypass(rt700->regmap, true); } @@ -1141,7 +1141,7 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave) /* * PM runtime is only enabled when a Slave reports as Attached */ - if (!rt700->first_init) { + if (!rt700->first_hw_init) { /* set autosuspend parameters */ pm_runtime_set_autosuspend_delay(&slave->dev, 3000); pm_runtime_use_autosuspend(&slave->dev); @@ -1201,7 +1201,7 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave) /* Finish Initial Settings, set power to D3 */ regmap_write(rt700->regmap, RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3); - if (!rt700->first_init) { + if (!rt700->first_hw_init) { INIT_DELAYED_WORK(&rt700->jack_detect_work, rt700_jack_detect_handler); INIT_DELAYED_WORK(&rt700->jack_btn_check_work, @@ -1215,10 +1215,11 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave) if (rt700->hs_jack) rt700_jack_init(rt700); - if (rt700->first_init) + if (rt700->first_hw_init) { regcache_cache_bypass(rt700->regmap, false); - else - rt700->first_init = true; + regcache_mark_dirty(rt700->regmap); + } else + rt700->first_hw_init = true; /* Mark Slave initialization complete */ rt700->hw_init = true; diff --git a/sound/soc/codecs/rt700.h b/sound/soc/codecs/rt700.h index 11f046e6255e29..8e6e233ce3aad9 100644 --- a/sound/soc/codecs/rt700.h +++ b/sound/soc/codecs/rt700.h @@ -20,7 +20,7 @@ struct rt700_priv { enum sdw_slave_status status; struct sdw_bus_params params; bool hw_init; - bool first_init; + bool first_hw_init; struct snd_soc_jack *hs_jack; struct delayed_work jack_detect_work; struct delayed_work jack_btn_check_work; From ce45b4c4edd59f0485738d1d1ee01802d37dc9c8 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 5 Dec 2019 17:21:15 +0800 Subject: [PATCH 1874/1995] ASoC: rt711: mark cache_dirty if redo the io_init funciton If the resume process redo the io_init function, I want to make sure the cache value will be synced again. And the first_init variable changes name to first_hw_init. Signed-off-by: Shuming Fan --- sound/soc/codecs/rt711.c | 15 ++++++++------- sound/soc/codecs/rt711.h | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 4090dc09694d0b..688fe05b0ee961 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -1152,7 +1152,7 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap, * HW init will be performed when device reports present */ rt711->hw_init = false; - rt711->first_init = false; + rt711->first_hw_init = false; /* JD source uses JD2 in default */ rt711->jd_src = RT711_JD2; @@ -1174,7 +1174,7 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave) if (rt711->hw_init) return 0; - if (rt711->first_init) { + if (rt711->first_hw_init) { regcache_cache_only(rt711->regmap, false); regcache_cache_bypass(rt711->regmap, true); } @@ -1182,7 +1182,7 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave) /* * PM runtime is only enabled when a Slave reports as Attached */ - if (!rt711->first_init) { + if (!rt711->first_hw_init) { /* set autosuspend parameters */ pm_runtime_set_autosuspend_delay(&slave->dev, 3000); pm_runtime_use_autosuspend(&slave->dev); @@ -1250,7 +1250,7 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave) /* Finish Initial Settings, set power to D3 */ regmap_write(rt711->regmap, RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); - if (rt711->first_init) + if (rt711->first_hw_init) rt711_calibration(rt711); else { INIT_DELAYED_WORK(&rt711->jack_detect_work, @@ -1269,10 +1269,11 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave) if (rt711->hs_jack) rt711_jack_init(rt711); - if (rt711->first_init) + if (rt711->first_hw_init) { regcache_cache_bypass(rt711->regmap, false); - else - rt711->first_init = true; + regcache_mark_dirty(rt711->regmap); + } else + rt711->first_hw_init = true; /* Mark Slave initialization complete */ rt711->hw_init = true; diff --git a/sound/soc/codecs/rt711.h b/sound/soc/codecs/rt711.h index ac7509bfa32d8b..c4b0572a5f9d44 100644 --- a/sound/soc/codecs/rt711.h +++ b/sound/soc/codecs/rt711.h @@ -20,7 +20,7 @@ struct rt711_priv { enum sdw_slave_status status; struct sdw_bus_params params; bool hw_init; - bool first_init; + bool first_hw_init; struct snd_soc_jack *hs_jack; struct delayed_work jack_detect_work; struct delayed_work jack_btn_check_work; From 9e07acf2875aae09600544da344a5b3fd8c4d3c9 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 5 Dec 2019 17:21:44 +0800 Subject: [PATCH 1875/1995] ASoC: rt715: mark cache_dirty if redo the io_init funciton If the resume process redo the io_init function, I want to make sure the cache value will be synced again. And the first_init variable changes name to first_hw_init. Signed-off-by: Shuming Fan --- sound/soc/codecs/rt715.c | 11 +++++++---- sound/soc/codecs/rt715.h | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index fce9c6939eda0c..5c6f05b8d8ab3c 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -779,7 +779,7 @@ int rt715_init(struct device *dev, struct regmap *sdw_regmap, * HW init will be performed when device reports present */ rt715->hw_init = false; - rt715->first_init = false; + rt715->first_hw_init = false; ret = devm_snd_soc_register_component(dev, &soc_codec_dev_rt715, @@ -799,7 +799,7 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave) /* * PM runtime is only enabled when a Slave reports as Attached */ - if (!rt715->first_init) { + if (!rt715->first_hw_init) { /* set autosuspend parameters */ pm_runtime_set_autosuspend_delay(&slave->dev, 3000); pm_runtime_use_autosuspend(&slave->dev); @@ -811,8 +811,6 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave) pm_runtime_mark_last_busy(&slave->dev); pm_runtime_enable(&slave->dev); - - rt715->first_init = true; } pm_runtime_get_noresume(&slave->dev); @@ -855,6 +853,11 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave) /* Finish Initial Settings, set power to D3 */ regmap_write(rt715->regmap, RT715_SET_AUDIO_POWER_STATE, AC_PWRST_D3); + if (rt715->first_hw_init) + regcache_mark_dirty(rt715->regmap); + else + rt715->first_hw_init = true; + /* Mark Slave initialization complete */ rt715->hw_init = true; diff --git a/sound/soc/codecs/rt715.h b/sound/soc/codecs/rt715.h index 52d24cfb581d1b..df0f24f9bc0c77 100644 --- a/sound/soc/codecs/rt715.h +++ b/sound/soc/codecs/rt715.h @@ -21,7 +21,7 @@ struct rt715_priv { enum sdw_slave_status status; struct sdw_bus_params params; bool hw_init; - bool first_init; + bool first_hw_init; }; struct sdw_stream_data { From 2c5faa8ebd5d2b2fc6d2c5f4f06e0759cf9e27a8 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Thu, 5 Dec 2019 17:22:07 +0800 Subject: [PATCH 1876/1995] ASoC: rt1308-sdw: mark cache_dirty if redo the io_init funciton If the resume process redo the io_init function, I want to make sure the cache value will be synced again. And the first_init variable changes name to first_hw_init. Signed-off-by: Shuming Fan --- sound/soc/codecs/rt1308-sdw.c | 13 +++++++------ sound/soc/codecs/rt1308-sdw.h | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index c60db67e33eb22..8df824af6e6e74 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -185,7 +185,7 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) if (ret < 0) goto _io_init_err_; - if (rt1308->first_init) { + if (rt1308->first_hw_init) { regcache_cache_only(rt1308->regmap, false); regcache_cache_bypass(rt1308->regmap, true); } @@ -193,7 +193,7 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) /* * PM runtime is only enabled when a Slave reports as Attached */ - if (!rt1308->first_init) { + if (!rt1308->first_hw_init) { /* set autosuspend parameters */ pm_runtime_set_autosuspend_delay(&slave->dev, 3000); pm_runtime_use_autosuspend(&slave->dev); @@ -271,10 +271,11 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) regmap_write(rt1308->regmap, 0xc101, 0xd7); regmap_write(rt1308->regmap, 0xc300, 0x09); - if (rt1308->first_init) + if (rt1308->first_hw_init) { regcache_cache_bypass(rt1308->regmap, false); - else - rt1308->first_init = true; + regcache_mark_dirty(rt1308->regmap); + } else + rt1308->first_hw_init = true; /* Mark Slave initialization complete */ rt1308->hw_init = true; @@ -639,7 +640,7 @@ static int rt1308_sdw_init(struct device *dev, struct regmap *regmap, * HW init will be performed when device reports present */ rt1308->hw_init = false; - rt1308->first_init = false; + rt1308->first_hw_init = false; ret = devm_snd_soc_register_component(dev, &soc_component_sdw_rt1308, diff --git a/sound/soc/codecs/rt1308-sdw.h b/sound/soc/codecs/rt1308-sdw.h index e83440be32f240..c9341e70d6cf56 100644 --- a/sound/soc/codecs/rt1308-sdw.h +++ b/sound/soc/codecs/rt1308-sdw.h @@ -159,7 +159,7 @@ struct rt1308_sdw_priv { enum sdw_slave_status status; struct sdw_bus_params params; bool hw_init; - bool first_init; + bool first_hw_init; }; struct sdw_stream_data { From 05dadaba2d3e3db697e1eff6469d53c14465bb94 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 9 Dec 2019 14:45:27 +0800 Subject: [PATCH 1877/1995] ASoC: rt700: Add pin sense check during jack type detection To avoid IO error, the codec driver needs to check the pin sense during jack type detection. Due to the jack type detection will take some times in the loop, in case the jack is removed during this time, then the driver goes into suspend mode. The IO error will occur in the rest of process. Signed-off-by: Shuming Fan --- sound/soc/codecs/rt700.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/codecs/rt700.c b/sound/soc/codecs/rt700.c index fbb3f5b3b29b0c..257686c936cfff 100644 --- a/sound/soc/codecs/rt700.c +++ b/sound/soc/codecs/rt700.c @@ -115,6 +115,7 @@ static int rt700_headset_detect(struct rt700_priv *rt700) { unsigned int buf, loop = 0; int ret; + unsigned int jack_status = 0, reg; ret = rt700_index_read(rt700->regmap, RT700_COMBO_JACK_AUTO_CTL2, &buf); @@ -130,6 +131,11 @@ static int rt700_headset_detect(struct rt700_priv *rt700) RT700_COMBO_JACK_AUTO_CTL2, &buf); if (ret < 0) goto io_error; + + reg = RT700_VERB_GET_PIN_SENSE | RT700_HP_OUT; + ret = regmap_read(rt700->regmap, reg, &jack_status); + if ((jack_status & (1 << 31)) == 0) + goto remove_error; } if (loop >= 500) @@ -150,6 +156,9 @@ static int rt700_headset_detect(struct rt700_priv *rt700) io_error: pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); return ret; +remove_error: + pr_err_ratelimited("Jack removal in %s\n", __func__); + return -ENODEV; } static void rt700_jack_detect_handler(struct work_struct *work) From 7bbf71f4b01f70fb4f685a7c5ba651b6d55f0ee0 Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 9 Dec 2019 14:45:46 +0800 Subject: [PATCH 1878/1995] ASoC: rt711: Add pin sense check during jack type detection To avoid IO error, the codec driver needs to check the pin sense during jack type detection. Due to the jack type detection will take some times in the loop, in case the jack is removed during this time, then the driver goes into suspend mode. The IO error will occur in the rest of process. Signed-off-by: Shuming Fan --- sound/soc/codecs/rt711.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c index 688fe05b0ee961..0d05f331c18315 100644 --- a/sound/soc/codecs/rt711.c +++ b/sound/soc/codecs/rt711.c @@ -193,6 +193,7 @@ static int rt711_headset_detect(struct rt711_priv *rt711) { unsigned int buf, loop = 0; int ret; + unsigned int jack_status = 0, reg; ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG, RT711_COMBO_JACK_AUTO_CTL2, &buf); @@ -208,6 +209,13 @@ static int rt711_headset_detect(struct rt711_priv *rt711) RT711_COMBO_JACK_AUTO_CTL2, &buf); if (ret < 0) goto io_error; + + reg = RT711_VERB_GET_PIN_SENSE | RT711_HP_OUT; + ret = regmap_read(rt711->regmap, reg, &jack_status); + if (ret < 0) + goto io_error; + if ((jack_status & (1 << 31)) == 0) + goto remove_error; } if (loop >= 500) @@ -228,6 +236,9 @@ static int rt711_headset_detect(struct rt711_priv *rt711) io_error: pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); return ret; +remove_error: + pr_err_ratelimited("Jack removal in %s\n", __func__); + return -ENODEV; } static void rt711_jack_detect_handler(struct work_struct *work) From a6aaadd77f49b46ba9781fcaf805aa64fd95aab1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 6 Dec 2019 12:54:01 -0600 Subject: [PATCH 1879/1995] ASoC: codecs: rt711-sdw: add traces for suspend-resume These traces show the suspend can happen before jack detection is complete [ 184.045885] rt711 sdw:0:25d:711:0: [rt711_sdw_read] 7520 85a0 9c20 aca0 => 00000404 [ 184.056884] rt711 sdw:0:25d:711:0: [rt711_sdw_read] 7520 85a0 9c20 aca0 => 00000404 [ 184.067823] rt711 sdw:0:25d:711:0: [rt711_sdw_read] 7520 85a0 9c20 aca0 => 00000404 [ 184.078824] rt711 sdw:0:25d:711:0: [rt711_sdw_read] 7520 85a0 9c20 aca0 => 00000404 [ 184.089928] rt711 sdw:0:25d:711:0: [rt711_sdw_read] 7520 85a0 9c20 aca0 => 00000404 [ 184.100949] rt711 sdw:0:25d:711:0: [rt711_sdw_read] 7520 85a0 9c20 aca0 => 00000404 [ 184.111990] rt711 sdw:0:25d:711:0: [rt711_sdw_read] 7520 85a0 9c20 aca0 => 00000404 [ 184.121175] rt711 sdw:0:25d:711:0: rt711_dev_suspend start [ 184.121183] rt711 sdw:0:25d:711:0: rt711_dev_suspend end [ 184.121205] Failed to get private value: 752046 => 0000 ret=-16 [ 184.121214] IO error in rt711_headset_detect, ret -16 [ 184.121221] IO error in rt711_jack_detect_handler, ret -16 Signed-off-by: Pierre-Louis Bossart --- sound/soc/codecs/rt711-sdw.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index 4174d175925c33..435da5b121dde4 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -492,11 +492,15 @@ static int rt711_dev_suspend(struct device *dev) { struct rt711_priv *rt711 = dev_get_drvdata(dev); + dev_dbg(dev, "%s start\n", __func__); + if (!rt711->hw_init) return 0; regcache_cache_only(rt711->regmap, true); + dev_dbg(dev, "%s end\n", __func__); + return 0; } @@ -508,6 +512,8 @@ static int rt711_dev_resume(struct device *dev) struct rt711_priv *rt711 = dev_get_drvdata(dev); unsigned long time; + dev_dbg(dev, "%s start\n", __func__); + if (!rt711->hw_init) return 0; @@ -527,6 +533,8 @@ static int rt711_dev_resume(struct device *dev) regcache_sync_region(rt711->regmap, 0x3000, 0x8fff); regcache_sync_region(rt711->regmap, 0x752009, 0x752091); + dev_dbg(dev, "%s end\n", __func__); + return 0; } From f1d5a9118b7ea4a4626c9bdf97ee2dbce6abb159 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 24 Aug 2019 15:52:40 -0500 Subject: [PATCH 1880/1995] ASoC: Intel: common: soc-acpi: declare new tables for SoundWire We cannot really lump SoundWire-based configurations into the same tables since the mechanisms to identify boards is based on link configurations and _ADR instead of _HID for I2S, so define new tables Signed-off-by: Pierre-Louis Bossart --- include/sound/soc-acpi-intel-match.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/sound/soc-acpi-intel-match.h b/include/sound/soc-acpi-intel-match.h index 20c0bee3b959db..ab6f75a86611dc 100644 --- a/include/sound/soc-acpi-intel-match.h +++ b/include/sound/soc-acpi-intel-match.h @@ -31,6 +31,12 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_sdw_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_sdw_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_sdw_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[]; + /* * generic table used for HDA codec-based platforms, possibly with * additional ACPI-enumerated codecs From 12ac9729477ce2cd008951ebf9926207813d9aa5 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 20 Jun 2019 17:47:01 +0800 Subject: [PATCH 1881/1995] ASoC: Intel: common: add match tables for ICL w/ SoundWire The two configurations are with the Realtek 3-in-1 board requiring all 4 links to be enabled, or basic configuration with the on-board RT700 using link0. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- .../soc/intel/common/soc-acpi-intel-icl-match.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c index 38977669b57653..63b6197a605606 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -33,5 +33,22 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_icl_machines); +struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_sdw_machines[] = { + { + .link_mask = 0xF, /* 4 active links required */ + .drv_name = "sdw_rt711_rt1308_rt715", + .sof_fw_filename = "sof-icl.ri", + .sof_tplg_filename = "sof-icl-rt711-rt1308-rt715.tplg", + }, + { + .link_mask = 0x1, /* rt700 connected on link0 */ + .drv_name = "sdw_rt700", + .sof_fw_filename = "sof-icl.ri", + .sof_tplg_filename = "sof-icl-rt700.tplg", + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_icl_sdw_machines); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel Common ACPI Match module"); From 568ec88c550c4a1705171cf8184c3ef13ad0d0aa Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 22 Jul 2019 17:20:53 +0800 Subject: [PATCH 1882/1995] ASoC: Intel: common: add match tables for CNL/CFL/CML w/ SoundWire The two configurations are with the Realtek 3-in-1 board requiring all 4 links to be enabled, or basic configuration with the on-board RT700 using link1. For now we only have definitions for CML, CNL and CFL are just placeholders. Signed-off-by: Rander Wang Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- .../intel/common/soc-acpi-intel-cfl-match.c | 5 ++++ .../intel/common/soc-acpi-intel-cml-match.c | 23 +++++++++++++++++++ .../intel/common/soc-acpi-intel-cnl-match.c | 5 ++++ 3 files changed, 33 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-cfl-match.c b/sound/soc/intel/common/soc-acpi-intel-cfl-match.c index d6fd2026d0b863..ff9d6938b9f668 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cfl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cfl-match.c @@ -14,5 +14,10 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_machines[] = { }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cfl_machines); +struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_sdw_machines[] = { + {} +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cfl_sdw_machines); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel Common ACPI Match module"); diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c index fb9ba881970604..70d53cafbc4474 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c @@ -59,5 +59,28 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = { }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cml_machines); +struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_sdw_machines[] = { + { + .link_mask = 0xF, /* 4 active links required */ + .drv_name = "sdw_rt711_rt1308_rt715", + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-rt711-rt1308-rt715.tplg", + }, + { + .link_mask = 0xB, /* 3 active links required */ + .drv_name = "sdw_rt711_rt1308_rt715", + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-rt711-rt1308-mono-rt715.tplg", + }, + { + .link_mask = 0x2, /* RT700 connected on Link1 */ + .drv_name = "sdw_rt700", + .sof_fw_filename = "sof-cml.ri", + .sof_tplg_filename = "sof-cml-rt700.tplg", + }, + {} +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cml_sdw_machines); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel Common ACPI Match module"); diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index 27588841c8b005..828980d5630d46 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -27,5 +27,10 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_machines); +struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[] = { + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_sdw_machines); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel Common ACPI Match module"); From ffd4391c8b00ca631d90d8839389d14ab22d07c7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 4 Sep 2019 10:01:58 -0500 Subject: [PATCH 1883/1995] ASoC: Intel: common: add match tables for TGL w/ SoundWire RT711 is in SoundWire mode on link0 and RT1308 on SSP2. Signed-off-by: Pierre-Louis Bossart --- .../soc/intel/common/soc-acpi-intel-tgl-match.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c index b4687a5d1962e6..3d8daacfb334d4 100644 --- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -17,9 +17,10 @@ static struct snd_soc_acpi_codecs tgl_codecs = { struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { { .id = "10EC1308", - .drv_name = "tgl_rt1308", + .drv_name = "rt711_rt1308", + .link_mask = 0x1, /* RT711 on SoundWire link0 */ .sof_fw_filename = "sof-tgl.ri", - .sof_tplg_filename = "sof-tgl-rt1308.tplg", + .sof_tplg_filename = "sof-tgl-rt711-rt1308.tplg", }, { .id = "10EC5682", @@ -33,5 +34,16 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_machines); +struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = { + { + .link_mask = 0x1, /* this will only enable rt711 for now */ + .drv_name = "sdw_rt711_rt1308_rt715", + .sof_fw_filename = "sof-tgl.ri", + .sof_tplg_filename = "sof-tgl-rt711-rt1308-rt715.tplg", + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_sdw_machines); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel Common ACPI Match module"); From b1972e4902371397796277528483eb9614f9e5a6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 4 Sep 2019 10:05:06 -0500 Subject: [PATCH 1884/1995] ASoC: SOF: Intel: reference SoundWire machine lists Use static tables to automatically select the relevant configurations. Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/sof-pci-dev.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 9d09131a6a56cd..1ee58e45063187 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -118,6 +118,7 @@ static const struct sof_dev_desc tng_desc = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) static const struct sof_dev_desc cnl_desc = { .machines = snd_soc_acpi_intel_cnl_machines, + .alt_machines = snd_soc_acpi_intel_cnl_sdw_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, @@ -135,6 +136,7 @@ static const struct sof_dev_desc cnl_desc = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) static const struct sof_dev_desc cfl_desc = { .machines = snd_soc_acpi_intel_cfl_machines, + .alt_machines = snd_soc_acpi_intel_cfl_sdw_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, @@ -154,6 +156,7 @@ static const struct sof_dev_desc cfl_desc = { static const struct sof_dev_desc cml_desc = { .machines = snd_soc_acpi_intel_cml_machines, + .alt_machines = snd_soc_acpi_intel_cml_sdw_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, @@ -171,6 +174,7 @@ static const struct sof_dev_desc cml_desc = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) static const struct sof_dev_desc icl_desc = { .machines = snd_soc_acpi_intel_icl_machines, + .alt_machines = snd_soc_acpi_intel_icl_sdw_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, @@ -188,6 +192,7 @@ static const struct sof_dev_desc icl_desc = { #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) static const struct sof_dev_desc tgl_desc = { .machines = snd_soc_acpi_intel_tgl_machines, + .alt_machines = snd_soc_acpi_intel_tgl_sdw_machines, .resindex_lpe_base = 0, .resindex_pcicfg_base = -1, .resindex_imr_base = -1, From 81cbfc323a01ed19cb2632a6607e776caf12f16f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 10 Apr 2019 20:58:52 -0500 Subject: [PATCH 1885/1995] ASoC: Intel: boards: add sdw_rt700 machine driver This machine driver supports CML and ICL RVP boards in SoundWire mode only. These boards need to be reworked to support the SoundWire link and the BIOS advanced config menu also needs to select SoundWire for links 0 (ICL) or 1 (CML). Unlike a lot of machine drivers, we use different DAI links for capture and playback since SoundWire PDIs can do capture OR playback, not both simultaneously. Signed-off-by: Rander Wang Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 16 ++ sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/sdw_rt700.c | 319 +++++++++++++++++++++++++++++ 3 files changed, 337 insertions(+) create mode 100644 sound/soc/intel/boards/sdw_rt700.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 1e9701d9a56088..6a635f4eba56d1 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -551,4 +551,20 @@ config SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH endif ## SND_SOC_SOF_JASPERLAKE +if SND_SOC_SOF_INTEL_SOUNDWIRE + +config SND_SOC_INTEL_SOUNDWIRE_RT700_MACH + tristate "SoundWire with RT700 codec" + depends on SOUNDWIRE && ACPI + select SND_SOC_RT700_SDW + select SND_SOC_DMIC + select SND_SOC_HDAC_HDMI if SND_SOC_SOF_HDA_LINK + help + Add support for Intel SoundWire-based platforms connected to RT700 + on link 0 or 1 + If unsure select "N" + +endif + + endif ## SND_SOC_INTEL_MACH diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 7b97f9527befb9..f8a59d67351311 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -33,6 +33,7 @@ snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o snd-soc-tgl-rt1308-objs := tgl_rt1308.o hda_dsp_common.o snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o hda_dsp_common.o +snd-soc-sdw-rt700-objs := sdw_rt700.o hda_dsp_common.o obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o @@ -68,3 +69,4 @@ obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ss obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o obj-$(CONFIG_SND_SOC_INTEL_TGL_RT1308_MACH) += snd-soc-tgl-rt1308.o obj-$(CONFIG_SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH) += snd-soc-sof_da7219_max98373.o +obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_RT700_MACH) += snd-soc-sdw-rt700.o diff --git a/sound/soc/intel/boards/sdw_rt700.c b/sound/soc/intel/boards/sdw_rt700.c new file mode 100644 index 00000000000000..fd46f0b18b149e --- /dev/null +++ b/sound/soc/intel/boards/sdw_rt700.c @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2016-19 Intel Corporation + +/* + * sdw_rt700 - ASOC Machine driver for Intel SoundWire platforms + * connected to ALC700 device + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/hdac_hdmi.h" +#include "hda_dsp_common.h" + +struct mc_private { + struct list_head hdmi_pcm_list; + bool common_hdmi_codec_drv; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) +static struct snd_soc_jack hdmi[3]; + +struct hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +static int hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + /* dai_link id is 1:1 mapped to the PCM device */ + pcm->device = rtd->dai_link->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +#define NAME_SIZE 32 +static int card_late_probe(struct snd_soc_card *card) +{ + struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct hdmi_pcm *pcm; + struct snd_soc_component *component = NULL; + int err, i = 0; + char jack_name[NAME_SIZE]; + + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm, + head); + component = pcm->codec_dai->component; + + if (ctx->common_hdmi_codec_drv) + return hda_dsp_hdmi_build_controls(card, component); + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &hdmi[i]); + if (err < 0) + return err; + + i++; + } + + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); +} +#else +static int card_late_probe(struct snd_soc_card *card) +{ + return 0; +} +#endif + +static const struct snd_soc_dapm_widget widgets[] = { + SND_SOC_DAPM_HP("Headphones", NULL), + SND_SOC_DAPM_MIC("AMIC", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_soc_dapm_route map[] = { + /*Headphones*/ + { "Headphones", NULL, "HP" }, + { "Speaker", NULL, "SPK" }, + { "MIC2", NULL, "AMIC" }, +}; + +static const struct snd_kcontrol_new controls[] = { + SOC_DAPM_PIN_SWITCH("Headphones"), + SOC_DAPM_PIN_SWITCH("AMIC"), + SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +SND_SOC_DAILINK_DEF(sdw0_pin2, + DAILINK_COMP_ARRAY(COMP_CPU("SDW0 Pin2"))); +SND_SOC_DAILINK_DEF(sdw0_pin3, + DAILINK_COMP_ARRAY(COMP_CPU("SDW0 Pin3"))); +SND_SOC_DAILINK_DEF(sdw0_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("sdw:0:25d:700:0", "rt700-aif1"))); + +SND_SOC_DAILINK_DEF(sdw1_pin2, + DAILINK_COMP_ARRAY(COMP_CPU("SDW1 Pin2"))); +SND_SOC_DAILINK_DEF(sdw1_pin3, + DAILINK_COMP_ARRAY(COMP_CPU("SDW1 Pin3"))); +SND_SOC_DAILINK_DEF(sdw1_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("sdw:1:25d:700:0", "rt700-aif1"))); + +SND_SOC_DAILINK_DEF(dmic_pin, + DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); + +SND_SOC_DAILINK_DEF(dmic16k_pin, + DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); + +SND_SOC_DAILINK_DEF(dmic_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); + +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) +SND_SOC_DAILINK_DEF(idisp1_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); +SND_SOC_DAILINK_DEF(idisp1_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); + +SND_SOC_DAILINK_DEF(idisp2_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); +SND_SOC_DAILINK_DEF(idisp2_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); + +SND_SOC_DAILINK_DEF(idisp3_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); +SND_SOC_DAILINK_DEF(idisp3_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); +#endif + +SND_SOC_DAILINK_DEF(platform, + DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); + +struct snd_soc_dai_link dailink[] = { + { + .name = "SDW0-Playback", + .id = 0, + .no_pcm = 1, + .dpcm_playback = 1, + .nonatomic = true, + SND_SOC_DAILINK_REG(sdw0_pin2, sdw0_codec, platform), + }, + { + .name = "SDW0-Capture", + .id = 1, + .no_pcm = 1, + .dpcm_capture = 1, + .nonatomic = true, + SND_SOC_DAILINK_REG(sdw0_pin3, sdw0_codec, platform), + }, + { + .name = "dmic01", + .id = 2, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), + }, + { + .name = "dmic16k", + .id = 3, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform), + }, +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) + { + .name = "iDisp1", + .id = 4, + .init = hdmi_init, + .no_pcm = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), + }, + { + .name = "iDisp2", + .id = 5, + .init = hdmi_init, + .no_pcm = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), + }, + { + .name = "iDisp3", + .id = 6, + .init = hdmi_init, + .no_pcm = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), + }, +#endif +}; + +/* SoC card */ +static struct snd_soc_card card_sdw_rt700 = { + .name = "sdw-rt700", + .dai_link = dailink, + .num_links = ARRAY_SIZE(dailink), + .controls = controls, + .num_controls = ARRAY_SIZE(controls), + .dapm_widgets = widgets, + .num_dapm_widgets = ARRAY_SIZE(widgets), + .dapm_routes = map, + .num_dapm_routes = ARRAY_SIZE(map), + .late_probe = card_late_probe, +}; + +static int mc_probe(struct platform_device *pdev) +{ + struct mc_private *ctx; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + struct snd_soc_card *card = &card_sdw_rt700; + const char *board; + int ret; + + dev_dbg(&pdev->dev, "Entry %s\n", __func__); + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); +#endif + + board = dmi_get_system_info(DMI_BOARD_NAME); + if (strstr(board, "CometLake U DDR4 HR")) { + dailink[0].name = "SDW1-Playback"; + dailink[0].codecs = sdw1_codec; + dailink[0].num_codecs = ARRAY_SIZE(sdw1_codec); + dailink[0].cpus = sdw1_pin2; + dailink[0].num_cpus = ARRAY_SIZE(sdw1_pin2); + + dailink[1].name = "SDW1-Capture"; + dailink[1].codecs = sdw1_codec; + dailink[1].num_codecs = ARRAY_SIZE(sdw1_codec); + dailink[1].cpus = sdw1_pin3; + dailink[1].num_cpus = ARRAY_SIZE(sdw1_pin3); + } + + card->dev = &pdev->dev; + + /* override platform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(card, platform_name); + if (ret) + return ret; + + ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; + + snd_soc_card_set_drvdata(card, ctx); + + /* Register the card */ + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) { + dev_err(card->dev, "snd_soc_register_card failed %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, card); + + return ret; +} + +static struct platform_driver sdw_rt700_driver = { + .driver = { + .name = "sdw_rt700", + .pm = &snd_soc_pm_ops, + }, + .probe = mc_probe, +}; + +module_platform_driver(sdw_rt700_driver); + +MODULE_DESCRIPTION("ASoC SoundWire RT700 Machine driver"); +MODULE_AUTHOR("Bard Liao "); +MODULE_AUTHOR("Pierre-Louis Bossart "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:sdw_rt700"); From 0d63b2b3f765f7969d82189cc52554d18d039887 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 26 Aug 2019 15:07:50 -0500 Subject: [PATCH 1886/1995] ASoC: Intel: boards: add sdw_rt711_rt1308_rt715 3-in-1 config support Add configuration with 4 SoundWire links connected to RT711, RT1308 (2x) and RT715, using the '3-in-1' test card. This topology will also be used on actual form-factors. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 12 + sound/soc/intel/boards/Makefile | 2 + .../soc/intel/boards/sdw_rt711_rt1308_rt715.c | 461 ++++++++++++++++++ 3 files changed, 475 insertions(+) create mode 100644 sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 6a635f4eba56d1..514368de7a7f54 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -564,6 +564,18 @@ config SND_SOC_INTEL_SOUNDWIRE_RT700_MACH on link 0 or 1 If unsure select "N" +config SND_SOC_INTEL_SOUNDWIRE_RT711_RT1308_RT715_MACH + tristate "SoundWire with RT711, RT1308 and RT715" + depends on SOUNDWIRE && ACPI + select SND_SOC_RT711_SDW + select SND_SOC_RT1308_SDW + select SND_SOC_RT715_SDW + select SND_SOC_HDAC_HDMI if SND_SOC_SOF_HDA_LINK + help + Add support for Intel SoundWire-based platforms connected to RT711, + RT1308 and RT715 + If unsure select "N". + endif diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index f8a59d67351311..6f734adbeec654 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -34,6 +34,7 @@ snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o snd-soc-tgl-rt1308-objs := tgl_rt1308.o hda_dsp_common.o snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o hda_dsp_common.o snd-soc-sdw-rt700-objs := sdw_rt700.o hda_dsp_common.o +snd-soc-sdw-rt711-rt1308-rt715-objs := sdw_rt711_rt1308_rt715.o hda_dsp_common.o obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o @@ -70,3 +71,4 @@ obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o obj-$(CONFIG_SND_SOC_INTEL_TGL_RT1308_MACH) += snd-soc-tgl-rt1308.o obj-$(CONFIG_SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH) += snd-soc-sof_da7219_max98373.o obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_RT700_MACH) += snd-soc-sdw-rt700.o +obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_RT711_RT1308_RT715_MACH) += snd-soc-sdw-rt711-rt1308-rt715.o diff --git a/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c b/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c new file mode 100644 index 00000000000000..b594e0a9effc46 --- /dev/null +++ b/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c @@ -0,0 +1,461 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019 Intel Corporation + +/* + * sdw_rt711_rt1308_rt715 - ASOC Machine driver for Intel SoundWire platforms + * connected to 3 Realtek devices + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/hdac_hdmi.h" +#include "hda_dsp_common.h" + +/* comment out this define for mono configurations */ +#define ENABLE_RT1308_SDW2 + +#define MAX_NO_PROPS 2 + +extern struct bus_type sdw_bus_type; + +enum { + SOF_RT711_JD_SRC_JD1 = 1, + SOF_RT711_JD_SRC_JD2 = 2, +}; + +#define SOF_RT711_JDSRC(quirk) ((quirk) & GENMASK(1, 0)) + +static unsigned long sof_rt711_rt1308_rt715_quirk = SOF_RT711_JD_SRC_JD1; + +struct mc_private { + struct list_head hdmi_pcm_list; + bool common_hdmi_codec_drv; + struct snd_soc_jack sdw_headset; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) +static struct snd_soc_jack hdmi[3]; + +struct hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +static int hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + /* dai_link id is 1:1 mapped to the PCM device */ + pcm->device = rtd->dai_link->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +#define NAME_SIZE 32 +static int card_late_probe(struct snd_soc_card *card) +{ + struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct hdmi_pcm *pcm; + struct snd_soc_component *component = NULL; + int err, i = 0; + char jack_name[NAME_SIZE]; + + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm, + head); + component = pcm->codec_dai->component; + + if (ctx->common_hdmi_codec_drv) + return hda_dsp_hdmi_build_controls(card, component); + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &hdmi[i], + NULL, 0); + + if (err) + return err; + + err = snd_jack_add_new_kctl(hdmi[i].jack, + jack_name, SND_JACK_AVOUT); + if (err) + dev_warn(component->dev, "failed creating Jack kctl\n"); + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &hdmi[i]); + if (err < 0) + return err; + + i++; + } + + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); +} +#else +static int card_late_probe(struct snd_soc_card *card) +{ + return 0; +} +#endif + +static struct snd_soc_jack_pin sdw_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int headset_init(struct snd_soc_pcm_runtime *rtd) +{ + struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_component *component = rtd->codec_dai->component; + struct snd_soc_jack *jack; + int ret; + + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->sdw_headset, + sdw_jack_pins, + ARRAY_SIZE(sdw_jack_pins)); + if (ret) { + dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", + ret); + return ret; + } + + jack = &ctx->sdw_headset; + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + + ret = snd_soc_component_set_jack(component, jack, NULL); + + if (ret) + dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", + ret); + + return ret; +} + +static int sof_rt711_rt1308_rt715_quirk_cb(const struct dmi_system_id *id) +{ + sof_rt711_rt1308_rt715_quirk = (unsigned long)id->driver_data; + return 1; +} + +static const struct dmi_system_id sof_sdw_rt711_rt1308_rt715_quirk_table[] = { + { + .callback = sof_rt711_rt1308_rt715_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + }, + .driver_data = (void *)(SOF_RT711_JD_SRC_JD2), + }, + {} +}; + +/* + * Note this MUST be called before snd_soc_register_card(), so that the props + * are in place before the codec component driver's probe function parses them. + */ +static int sof_rt711_add_codec_device_props(const char *sdw_dev_name) +{ + struct property_entry props[MAX_NO_PROPS] = {}; + struct device *sdw_dev; + int ret, cnt = 0; + + sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_dev_name); + if (!sdw_dev) + return -EPROBE_DEFER; + + if (SOF_RT711_JDSRC(sof_rt711_rt1308_rt715_quirk)) { + props[cnt++] = PROPERTY_ENTRY_U32( + "realtek,jd-src", + SOF_RT711_JDSRC(sof_rt711_rt1308_rt715_quirk)); + } + + ret = device_add_properties(sdw_dev, props); + put_device(sdw_dev); + + return ret; +} + +static const struct snd_soc_dapm_widget widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_soc_dapm_route map[] = { + /* Headphones */ + { "Headphone", NULL, "rt711 HP" }, + { "rt711 MIC2", NULL, "Headset Mic" }, + /* Speakers */ + { "Speaker", NULL, "rt1308-1 SPOL" }, + { "Speaker", NULL, "rt1308-1 SPOR" }, +#ifdef ENABLE_RT1308_SDW2 + { "Speaker", NULL, "rt1308-2 SPOL" }, + { "Speaker", NULL, "rt1308-2 SPOR" }, +#endif +}; + +static const struct snd_kcontrol_new controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +SND_SOC_DAILINK_DEF(sdw0_pin2, + DAILINK_COMP_ARRAY(COMP_CPU("SDW0 Pin2"))); +SND_SOC_DAILINK_DEF(sdw0_pin3, + DAILINK_COMP_ARRAY(COMP_CPU("SDW0 Pin3"))); +SND_SOC_DAILINK_DEF(sdw0_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("sdw:0:25d:711:0", "rt711-aif1"))); + +SND_SOC_DAILINK_DEF(sdw1_pin2, + DAILINK_COMP_ARRAY(COMP_CPU("SDW1 Pin2"))); +SND_SOC_DAILINK_DEF(sdw1_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("sdw:1:25d:1308:0", "rt1308-aif"))); + +#ifdef ENABLE_RT1308_SDW2 +SND_SOC_DAILINK_DEF(sdw2_pin2, + DAILINK_COMP_ARRAY(COMP_CPU("SDW2 Pin2"))); +SND_SOC_DAILINK_DEF(sdw2_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("sdw:2:25d:1308:0", "rt1308-aif"))); +#endif + +SND_SOC_DAILINK_DEF(sdw3_pin2, + DAILINK_COMP_ARRAY(COMP_CPU("SDW3 Pin2"))); +SND_SOC_DAILINK_DEF(sdw3_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("sdw:3:25d:715:0", "rt715-aif2"))); + +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) +SND_SOC_DAILINK_DEF(idisp1_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); +SND_SOC_DAILINK_DEF(idisp1_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); + +SND_SOC_DAILINK_DEF(idisp2_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); +SND_SOC_DAILINK_DEF(idisp2_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); + +SND_SOC_DAILINK_DEF(idisp3_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); +SND_SOC_DAILINK_DEF(idisp3_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); +#endif + +SND_SOC_DAILINK_DEF(platform, + DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); + +static struct snd_soc_codec_conf codec_conf[] = { + { + .dev_name = "sdw:0:25d:711:0", + .name_prefix = "rt711", + }, + { + .dev_name = "sdw:1:25d:1308:0", + .name_prefix = "rt1308-1", + }, +#ifdef ENABLE_RT1308_SDW2 + { + .dev_name = "sdw:2:25d:1308:0", + .name_prefix = "rt1308-2", + }, +#endif + { + .dev_name = "sdw:3:25d:715:0", + .name_prefix = "rt715", + }, + +}; + +struct snd_soc_dai_link dailink[] = { + { + .name = "SDW0-Playback", + .id = 0, + .init = headset_init, + .no_pcm = 1, + .dpcm_playback = 1, + .nonatomic = true, + SND_SOC_DAILINK_REG(sdw0_pin2, sdw0_codec, platform), + }, + { + .name = "SDW0-Capture", + .id = 1, + .no_pcm = 1, + .dpcm_capture = 1, + .nonatomic = true, + SND_SOC_DAILINK_REG(sdw0_pin3, sdw0_codec, platform), + }, + { + .name = "SDW1-Playback", + .id = 2, + .no_pcm = 1, + .dpcm_playback = 1, + .nonatomic = true, + SND_SOC_DAILINK_REG(sdw1_pin2, sdw1_codec, platform), + }, +#ifdef ENABLE_RT1308_SDW2 + { + .name = "SDW2-Playback", + .id = 3, + .no_pcm = 1, + .dpcm_playback = 1, + .nonatomic = true, + SND_SOC_DAILINK_REG(sdw2_pin2, sdw2_codec, platform), + }, +#endif + { + .name = "SDW3-Capture", + .id = 4, + .no_pcm = 1, + .dpcm_capture = 1, + .nonatomic = true, + SND_SOC_DAILINK_REG(sdw3_pin2, sdw3_codec, platform), + }, + +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) + { + .name = "iDisp1", + .id = 5, + .init = hdmi_init, + .no_pcm = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), + }, + { + .name = "iDisp2", + .id = 6, + .init = hdmi_init, + .no_pcm = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), + }, + { + .name = "iDisp3", + .id = 7, + .init = hdmi_init, + .no_pcm = 1, + .dpcm_playback = 1, + SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), + }, +#endif +}; + +/* SoC card */ +static struct snd_soc_card card_rt700_rt1308_rt715 = { + .name = "sdw-rt711-1308-715", + .dai_link = dailink, + .num_links = ARRAY_SIZE(dailink), + .controls = controls, + .num_controls = ARRAY_SIZE(controls), + .dapm_widgets = widgets, + .num_dapm_widgets = ARRAY_SIZE(widgets), + .dapm_routes = map, + .num_dapm_routes = ARRAY_SIZE(map), + .late_probe = card_late_probe, + .codec_conf = codec_conf, + .num_configs = ARRAY_SIZE(codec_conf), +}; + +static int mc_probe(struct platform_device *pdev) +{ + struct mc_private *ctx; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + struct snd_soc_card *card = &card_rt700_rt1308_rt715; + int ret; + + dev_dbg(&pdev->dev, "Entry %s\n", __func__); + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + dmi_check_system(sof_sdw_rt711_rt1308_rt715_quirk_table); + +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); +#endif + + card->dev = &pdev->dev; + + /* override platform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(card, platform_name); + if (ret) + return ret; + + ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; + + snd_soc_card_set_drvdata(card, ctx); + + sof_rt711_add_codec_device_props("sdw:0:25d:711:0"); + /* Register the card */ + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) { + dev_err(card->dev, "snd_soc_register_card failed %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, card); + + return ret; +} + +static struct platform_driver sdw_rt711_rt1308_rt715_driver = { + .driver = { + .name = "sdw_rt711_rt1308_rt715", + .pm = &snd_soc_pm_ops, + }, + .probe = mc_probe, +}; + +module_platform_driver(sdw_rt711_rt1308_rt715_driver); + +MODULE_DESCRIPTION("ASoC SoundWire RT711/1308/715 Machine driver"); +MODULE_AUTHOR("Bard Liao "); +MODULE_AUTHOR("Pierre-Louis Bossart "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:sdw_rt711_rt1308_rt715"); From b0dd468598211810dc2b83cd6b20c6583a8a72a1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 17 Sep 2019 18:29:27 -0500 Subject: [PATCH 1887/1995] ASoC: Intel: boards: sdw_rt711: add machine driver Simpler subset of rt711_rt1308_rt715. The RT711 is assumed to be located on Link0. Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 9 + sound/soc/intel/boards/Makefile | 2 + sound/soc/intel/boards/sdw_rt711.c | 276 +++++++++++++++++++++++++++++ 3 files changed, 287 insertions(+) create mode 100644 sound/soc/intel/boards/sdw_rt711.c diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 514368de7a7f54..cfaf741d090eb3 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -564,6 +564,15 @@ config SND_SOC_INTEL_SOUNDWIRE_RT700_MACH on link 0 or 1 If unsure select "N" +config SND_SOC_INTEL_SOUNDWIRE_RT711_MACH + tristate "SoundWire with RT711 codec" + depends on SOUNDWIRE && ACPI + select SND_SOC_RT711_SDW + help + Add support for Intel SoundWire-based platforms connected to RT711 + on link 0 or 1 + If unsure select "N" + config SND_SOC_INTEL_SOUNDWIRE_RT711_RT1308_RT715_MACH tristate "SoundWire with RT711, RT1308 and RT715" depends on SOUNDWIRE && ACPI diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 6f734adbeec654..1abcfdf1417463 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -34,6 +34,7 @@ snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o snd-soc-tgl-rt1308-objs := tgl_rt1308.o hda_dsp_common.o snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o hda_dsp_common.o snd-soc-sdw-rt700-objs := sdw_rt700.o hda_dsp_common.o +snd-soc-sdw-rt711-objs := sdw_rt711.o hda_dsp_common.o snd-soc-sdw-rt711-rt1308-rt715-objs := sdw_rt711_rt1308_rt715.o hda_dsp_common.o obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o @@ -71,4 +72,5 @@ obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o obj-$(CONFIG_SND_SOC_INTEL_TGL_RT1308_MACH) += snd-soc-tgl-rt1308.o obj-$(CONFIG_SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH) += snd-soc-sof_da7219_max98373.o obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_RT700_MACH) += snd-soc-sdw-rt700.o +obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_RT711_MACH) += snd-soc-sdw-rt711.o obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_RT711_RT1308_RT715_MACH) += snd-soc-sdw-rt711-rt1308-rt715.o diff --git a/sound/soc/intel/boards/sdw_rt711.c b/sound/soc/intel/boards/sdw_rt711.c new file mode 100644 index 00000000000000..09da46b150992f --- /dev/null +++ b/sound/soc/intel/boards/sdw_rt711.c @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019 Intel Corporation + +/* + * sdw_rt711 - ASOC Machine driver for Intel SoundWire platforms + * connected to ALC711 device + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../codecs/hdac_hdmi.h" +#include "hda_dsp_common.h" + +struct mc_private { + struct list_head hdmi_pcm_list; + bool common_hdmi_codec_drv; + struct snd_soc_jack sdw_headset; +}; + +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) +static struct snd_soc_jack hdmi[3]; + +struct hdmi_pcm { + struct list_head head; + struct snd_soc_dai *codec_dai; + int device; +}; + +static int hdmi_init(struct snd_soc_pcm_runtime *rtd) +{ + struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *dai = rtd->codec_dai; + struct hdmi_pcm *pcm; + + pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + + /* dai_link id is 1:1 mapped to the PCM device */ + pcm->device = rtd->dai_link->id; + pcm->codec_dai = dai; + + list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + + return 0; +} + +#define NAME_SIZE 32 +static int card_late_probe(struct snd_soc_card *card) +{ + struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct hdmi_pcm *pcm; + struct snd_soc_component *component = NULL; + int err, i = 0; + char jack_name[NAME_SIZE]; + + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm, + head); + component = pcm->codec_dai->component; + + if (ctx->common_hdmi_codec_drv) + return hda_dsp_hdmi_build_controls(card, component); + + list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { + component = pcm->codec_dai->component; + snprintf(jack_name, sizeof(jack_name), + "HDMI/DP, pcm=%d Jack", pcm->device); + err = snd_soc_card_jack_new(card, jack_name, + SND_JACK_AVOUT, &hdmi[i], + NULL, 0); + + if (err) + return err; + + err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, + &hdmi[i]); + if (err < 0) + return err; + + i++; + } + + if (!component) + return -EINVAL; + + return hdac_hdmi_jack_port_init(component, &card->dapm); +} +#else +static int card_late_probe(struct snd_soc_card *card) +{ + return 0; +} +#endif + +static struct snd_soc_jack_pin sdw_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int headset_init(struct snd_soc_pcm_runtime *rtd) +{ + struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_component *component = rtd->codec_dai->component; + struct snd_soc_jack *jack; + int ret; + + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->sdw_headset, + sdw_jack_pins, + ARRAY_SIZE(sdw_jack_pins)); + if (ret) { + dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", + ret); + return ret; + } + + jack = &ctx->sdw_headset; + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + + ret = snd_soc_component_set_jack(component, jack, NULL); + + if (ret) + dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", + ret); + + return ret; +} + +static const struct snd_soc_dapm_widget widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_soc_dapm_route map[] = { + /*Headphones*/ + { "Headphone", NULL, "HP" }, + { "MIC2", NULL, "Headset Mic" }, +}; + +static const struct snd_kcontrol_new controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +SND_SOC_DAILINK_DEF(sdw0_pin2, + DAILINK_COMP_ARRAY(COMP_CPU("SDW0 Pin2"))); +SND_SOC_DAILINK_DEF(sdw0_pin3, + DAILINK_COMP_ARRAY(COMP_CPU("SDW0 Pin3"))); +SND_SOC_DAILINK_DEF(sdw0_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("sdw:0:25d:711:0", "rt711-aif1"))); + +SND_SOC_DAILINK_DEF(platform, + DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); + +struct snd_soc_dai_link dailink[] = { + { + .name = "SDW0-Playback", + .id = 0, + .init = headset_init, + .no_pcm = 1, + .dpcm_playback = 1, + .nonatomic = true, + SND_SOC_DAILINK_REG(sdw0_pin2, sdw0_codec, platform), + }, + { + .name = "SDW0-Capture", + .id = 1, + .no_pcm = 1, + .dpcm_capture = 1, + .nonatomic = true, + SND_SOC_DAILINK_REG(sdw0_pin3, sdw0_codec, platform), + }, +}; + +/* SoC card */ +static struct snd_soc_card card_sdw_rt711 = { + .name = "sdw-rt711", + .dai_link = dailink, + .num_links = ARRAY_SIZE(dailink), + .controls = controls, + .num_controls = ARRAY_SIZE(controls), + .dapm_widgets = widgets, + .num_dapm_widgets = ARRAY_SIZE(widgets), + .dapm_routes = map, + .num_dapm_routes = ARRAY_SIZE(map), + .late_probe = card_late_probe, +}; + +static int mc_probe(struct platform_device *pdev) +{ + struct mc_private *ctx; + struct snd_soc_acpi_mach *mach; + const char *platform_name; + struct snd_soc_card *card = &card_sdw_rt711; + int ret; + + dev_dbg(&pdev->dev, "Entry %s\n", __func__); + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + +#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI) + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); +#endif + + card->dev = &pdev->dev; + + /* override platform name, if required */ + mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; + + ret = snd_soc_fixup_dai_links_platform_name(card, platform_name); + if (ret) + return ret; + + ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; + + snd_soc_card_set_drvdata(card, ctx); + + /* Register the card */ + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) { + dev_err(card->dev, "snd_soc_register_card failed %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, card); + + return ret; +} + +static struct platform_driver sdw_rt711_driver = { + .driver = { + .name = "sdw_rt711", + .pm = &snd_soc_pm_ops, + }, + .probe = mc_probe, +}; + +module_platform_driver(sdw_rt711_driver); + +MODULE_DESCRIPTION("ASoC SoundWire RT711 Machine driver"); +MODULE_AUTHOR("Bard Liao "); +MODULE_AUTHOR("Pierre-Louis Bossart "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:sdw_rt711"); From 5132c0ed0264c0a8485bc30d865ec99cc72f0f96 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 25 Sep 2019 17:29:19 -0500 Subject: [PATCH 1888/1995] ASoC: Intel: boards: SoundWire rt711 + I2S RT1308 configuration This is the baseline for TGL RVP Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Kconfig | 11 +- sound/soc/intel/boards/Makefile | 4 +- .../{tgl_rt1308.c => sdw_rt711_i2s_rt1308.c} | 225 ++++++++++++------ 3 files changed, 163 insertions(+), 77 deletions(-) rename sound/soc/intel/boards/{tgl_rt1308.c => sdw_rt711_i2s_rt1308.c} (54%) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index cfaf741d090eb3..78f6305f0e3b04 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -515,23 +515,24 @@ config SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH endif ## SND_SOC_SOF_COMETLAKE_LP && SND_SOC_SOF_HDA_LINK -if SND_SOC_SOF_TIGERLAKE +if SND_SOC_SOF_TIGERLAKE && SND_SOC_SOF_INTEL_SOUNDWIRE -config SND_SOC_INTEL_TGL_RT1308_MACH - tristate "TGL with RT1308 in I2S Mode" +config SND_SOC_INTEL_TGL_RT711_RT1308_MACH + tristate "TGL with RT711 in SDW mode and RT1308 in I2S Mode" depends on I2C && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_RT711_SDW select SND_SOC_RT1308 select SND_SOC_DMIC select SND_HDA_CODEC_HDMI if SND_SOC_SOF_HDA_AUDIO_CODEC select SND_SOC_HDAC_HDMI if SND_SOC_SOF_HDA_LINK help This adds support for ASoC machine driver for Tigerlake platforms - with RT1308 I2S audio codec. + with SoundWire RT711 and RT1308 I2S audio codec. Say Y if you have such a device. If unsure select "N". -endif ## SND_SOC_SOF_TIGERLAKE +endif ## SND_SOC_SOF_TIGERLAKE && SND_SOC_SOF_INTEL_SOUNDWIRE if SND_SOC_SOF_JASPERLAKE diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 1abcfdf1417463..ae6890349e035a 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -31,8 +31,8 @@ snd-soc-skl_rt286-objs := skl_rt286.o snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o hda_dsp_common.o snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o -snd-soc-tgl-rt1308-objs := tgl_rt1308.o hda_dsp_common.o snd-soc-sof_da7219_max98373-objs := sof_da7219_max98373.o hda_dsp_common.o +snd-soc-tgl-rt711-rt1308-objs := sdw_rt711_i2s_rt1308.o hda_dsp_common.o snd-soc-sdw-rt700-objs := sdw_rt700.o hda_dsp_common.o snd-soc-sdw-rt711-objs := sdw_rt711.o hda_dsp_common.o snd-soc-sdw-rt711-rt1308-rt715-objs := sdw_rt711_rt1308_rt715.o hda_dsp_common.o @@ -69,8 +69,8 @@ obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o -obj-$(CONFIG_SND_SOC_INTEL_TGL_RT1308_MACH) += snd-soc-tgl-rt1308.o obj-$(CONFIG_SND_SOC_INTEL_SOF_DA7219_MAX98373_MACH) += snd-soc-sof_da7219_max98373.o +obj-$(CONFIG_SND_SOC_INTEL_TGL_RT711_RT1308_MACH) += snd-soc-tgl-rt711-rt1308.o obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_RT700_MACH) += snd-soc-sdw-rt700.o obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_RT711_MACH) += snd-soc-sdw-rt711.o obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_RT711_RT1308_RT715_MACH) += snd-soc-sdw-rt711-rt1308-rt715.o diff --git a/sound/soc/intel/boards/tgl_rt1308.c b/sound/soc/intel/boards/sdw_rt711_i2s_rt1308.c similarity index 54% rename from sound/soc/intel/boards/tgl_rt1308.c rename to sound/soc/intel/boards/sdw_rt711_i2s_rt1308.c index 6f8b5b2be66d40..6aa161b84da50e 100644 --- a/sound/soc/intel/boards/tgl_rt1308.c +++ b/sound/soc/intel/boards/sdw_rt711_i2s_rt1308.c @@ -3,45 +3,50 @@ // Copyright(c) 2019 Intel Corporation. All rights reserved. /* - * tgl_rt1308.c - ASoc Machine driver for Intel platforms - * with RT1308 codec. + * tgl_rt711_rt1308.c - ASoc Machine driver for Intel platforms + * with RT711 codec over SoundWire and RT1308 amplifier over I2S */ #include +#include #include +#include +#include +#include +#include +#include +#include #include -#include - -#include +#include #include #include #include #include #include - #include "../../codecs/rt1308.h" #include "../../codecs/hdac_hdmi.h" #include "hda_dsp_common.h" -struct tgl_card_private { +struct mc_private { struct list_head hdmi_pcm_list; bool common_hdmi_codec_drv; + struct snd_soc_jack sdw_headset; }; #if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) -static struct snd_soc_jack tgl_hdmi[4]; +static struct snd_soc_jack hdmi[4]; -struct tgl_hdmi_pcm { +struct hdmi_pcm { struct list_head head; struct snd_soc_dai *codec_dai; int device; }; -static int tgl_hdmi_init(struct snd_soc_pcm_runtime *rtd) +static int hdmi_init(struct snd_soc_pcm_runtime *rtd) { - struct tgl_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai = rtd->codec_dai; - struct tgl_hdmi_pcm *pcm; + struct hdmi_pcm *pcm; pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); if (!pcm) @@ -57,15 +62,15 @@ static int tgl_hdmi_init(struct snd_soc_pcm_runtime *rtd) } #define NAME_SIZE 32 -static int tgl_card_late_probe(struct snd_soc_card *card) +static int card_late_probe(struct snd_soc_card *card) { - struct tgl_card_private *ctx = snd_soc_card_get_drvdata(card); - struct tgl_hdmi_pcm *pcm; + struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct hdmi_pcm *pcm; struct snd_soc_component *component = NULL; int err, i = 0; char jack_name[NAME_SIZE]; - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct tgl_hdmi_pcm, + pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm, head); component = pcm->codec_dai->component; @@ -77,14 +82,14 @@ static int tgl_card_late_probe(struct snd_soc_card *card) snprintf(jack_name, sizeof(jack_name), "HDMI/DP, pcm=%d Jack", pcm->device); err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &tgl_hdmi[i], + SND_JACK_AVOUT, &hdmi[i], NULL, 0); if (err) return err; err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &tgl_hdmi[i]); + &hdmi[i]); if (err < 0) return err; @@ -97,14 +102,61 @@ static int tgl_card_late_probe(struct snd_soc_card *card) return hdac_hdmi_jack_port_init(component, &card->dapm); } #else -static int tgl_card_late_probe(struct snd_soc_card *card) +static int card_late_probe(struct snd_soc_card *card) { return 0; } #endif -static int tgl_rt1308_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static struct snd_soc_jack_pin sdw_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + +static int headset_init(struct snd_soc_pcm_runtime *rtd) +{ + struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_component *component = rtd->codec_dai->component; + struct snd_soc_jack *jack; + int ret; + + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + &ctx->sdw_headset, + sdw_jack_pins, + ARRAY_SIZE(sdw_jack_pins)); + if (ret) { + dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", + ret); + return ret; + } + + jack = &ctx->sdw_headset; + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); + + ret = snd_soc_component_set_jack(component, jack, NULL); + + if (ret) + dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", + ret); + + return ret; +} + +static int rt1308_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_card *card = rtd->card; @@ -136,27 +188,39 @@ static int tgl_rt1308_hw_params(struct snd_pcm_substream *substream, } /* machine stream operations */ -static struct snd_soc_ops tgl_rt1308_ops = { - .hw_params = tgl_rt1308_hw_params, +static struct snd_soc_ops rt1308_ops = { + .hw_params = rt1308_hw_params, }; -static const struct snd_soc_dapm_widget tgl_rt1308_dapm_widgets[] = { +static const struct snd_soc_dapm_widget widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_SPK("Speakers", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), }; -static const struct snd_kcontrol_new tgl_rt1308_controls[] = { - SOC_DAPM_PIN_SWITCH("Speakers"), -}; +static const struct snd_soc_dapm_route map[] = { + { "Headphone", NULL, "HP" }, + { "MIC2", NULL, "Headset Mic" }, -static const struct snd_soc_dapm_route tgl_rt1308_dapm_routes[] = { { "Speakers", NULL, "SPOL" }, { "Speakers", NULL, "SPOR" }, + { "DMic", NULL, "SoC DMIC"}, +}; - /* digital mics */ - {"DMic", NULL, "SoC DMIC"}, +static const struct snd_kcontrol_new controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Speakers"), }; +SND_SOC_DAILINK_DEF(sdw0_pin2, + DAILINK_COMP_ARRAY(COMP_CPU("SDW0 Pin2"))); +SND_SOC_DAILINK_DEF(sdw0_pin3, + DAILINK_COMP_ARRAY(COMP_CPU("SDW0 Pin3"))); +SND_SOC_DAILINK_DEF(sdw0_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("sdw:0:25d:711:0", "rt711-aif1"))); + SND_SOC_DAILINK_DEF(ssp2_pin, DAILINK_COMP_ARRAY(COMP_CPU("SSP2 Pin"))); @@ -195,19 +259,36 @@ SND_SOC_DAILINK_DEF(idisp4_codec, DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi4"))); #endif -static struct snd_soc_dai_link tgl_rt1308_dailink[] = { +struct snd_soc_dai_link dailink[] = { + { + .name = "SDW0-Playback", + .id = 0, + .init = headset_init, + .no_pcm = 1, + .dpcm_playback = 1, + .nonatomic = true, + SND_SOC_DAILINK_REG(sdw0_pin2, sdw0_codec, platform), + }, + { + .name = "SDW0-Capture", + .id = 1, + .no_pcm = 1, + .dpcm_capture = 1, + .nonatomic = true, + SND_SOC_DAILINK_REG(sdw0_pin3, sdw0_codec, platform), + }, { .name = "SSP2-Codec", - .id = 0, + .id = 2, .no_pcm = 1, - .ops = &tgl_rt1308_ops, + .ops = &rt1308_ops, .dpcm_playback = 1, .nonatomic = true, SND_SOC_DAILINK_REG(ssp2_pin, ssp2_codec, platform), }, { .name = "dmic01", - .id = 1, + .id = 3, .ignore_suspend = 1, .dpcm_capture = 1, .no_pcm = 1, @@ -215,7 +296,7 @@ static struct snd_soc_dai_link tgl_rt1308_dailink[] = { }, { .name = "dmic16k", - .id = 2, + .id = 4, .ignore_suspend = 1, .dpcm_capture = 1, .no_pcm = 1, @@ -224,32 +305,32 @@ static struct snd_soc_dai_link tgl_rt1308_dailink[] = { #if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) { .name = "iDisp1", - .id = 3, - .init = tgl_hdmi_init, + .id = 5, + .init = hdmi_init, .dpcm_playback = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), }, { .name = "iDisp2", - .id = 4, - .init = tgl_hdmi_init, + .id = 6, + .init = hdmi_init, .dpcm_playback = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), }, { .name = "iDisp3", - .id = 5, - .init = tgl_hdmi_init, + .id = 7, + .init = hdmi_init, .dpcm_playback = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), }, { .name = "iDisp4", - .id = 6, - .init = tgl_hdmi_init, + .id = 8, + .init = hdmi_init, .dpcm_playback = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp4_pin, idisp4_codec, platform), @@ -257,41 +338,45 @@ static struct snd_soc_dai_link tgl_rt1308_dailink[] = { #endif }; -/* audio machine driver */ -static struct snd_soc_card tgl_rt1308_card = { - .name = "tgl_rt1308", - .owner = THIS_MODULE, - .dai_link = tgl_rt1308_dailink, - .num_links = ARRAY_SIZE(tgl_rt1308_dailink), - .controls = tgl_rt1308_controls, - .num_controls = ARRAY_SIZE(tgl_rt1308_controls), - .dapm_widgets = tgl_rt1308_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(tgl_rt1308_dapm_widgets), - .dapm_routes = tgl_rt1308_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(tgl_rt1308_dapm_routes), - .late_probe = tgl_card_late_probe, +/* SoC card */ +static struct snd_soc_card card_rt711_rt1308 = { + .name = "rt711-rt1308", + .dai_link = dailink, + .num_links = ARRAY_SIZE(dailink), + .controls = controls, + .num_controls = ARRAY_SIZE(controls), + .dapm_widgets = widgets, + .num_dapm_widgets = ARRAY_SIZE(widgets), + .dapm_routes = map, + .num_dapm_routes = ARRAY_SIZE(map), + .late_probe = card_late_probe, }; -static int tgl_rt1308_probe(struct platform_device *pdev) +static int mc_probe(struct platform_device *pdev) { + struct mc_private *ctx; struct snd_soc_acpi_mach *mach; - struct tgl_card_private *ctx; - struct snd_soc_card *card = &tgl_rt1308_card; + const char *platform_name; + struct snd_soc_card *card = &card_rt711_rt1308; int ret; - card->dev = &pdev->dev; + dev_dbg(&pdev->dev, "Entry %s\n", __func__); ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; - if (IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)) - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); +#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) + INIT_LIST_HEAD(&ctx->hdmi_pcm_list); +#endif + + card->dev = &pdev->dev; + /* override platform name, if required */ mach = (&pdev->dev)->platform_data; + platform_name = mach->mach_params.platform; - ret = snd_soc_fixup_dai_links_platform_name(card, - mach->mach_params.platform); + ret = snd_soc_fixup_dai_links_platform_name(card, platform_name); if (ret) return ret; @@ -302,17 +387,17 @@ static int tgl_rt1308_probe(struct platform_device *pdev) return devm_snd_soc_register_card(&pdev->dev, card); } -static struct platform_driver tgl_rt1308_driver = { +static struct platform_driver rt711_rt1308_driver = { .driver = { - .name = "tgl_rt1308", + .name = "rt711_rt1308", .pm = &snd_soc_pm_ops, }, - .probe = tgl_rt1308_probe, + .probe = mc_probe, }; -module_platform_driver(tgl_rt1308_driver); +module_platform_driver(rt711_rt1308_driver); MODULE_AUTHOR("Xiuli Pan"); -MODULE_DESCRIPTION("ASoC Intel(R) Tiger Lake + RT1308 Machine driver"); +MODULE_DESCRIPTION("ASoC SoundWire RT711 + RT1308 Machine driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:tgl_rt1308"); +MODULE_ALIAS("platform:rt711_rt1308"); From fb23a0985fdd0edcc2161196d53e71fc9d27c471 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 24 Jun 2019 11:52:23 -0500 Subject: [PATCH 1889/1995] NOT FOR UPSTREAM: Add debug for boards Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index ae6890349e035a..4c5fbf647e0c19 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -1,3 +1,5 @@ +ccflags-y += -DDEBUG + # SPDX-License-Identifier: GPL-2.0 snd-soc-sst-haswell-objs := haswell.o snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o From 49f2131819f55b4ebf6c417189944b2dc092ade6 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 5 Nov 2019 14:50:11 +0800 Subject: [PATCH 1890/1995] ASoC: intel: sdw_rt711_rt1308_rt715: remove ENABLE_RT1308_SDW2 flag We can use quick to decide if we need 2nd rt1308 or not. Signed-off-by: Bard Liao --- .../soc/intel/boards/sdw_rt711_rt1308_rt715.c | 62 ++++++++++++------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c b/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c index b594e0a9effc46..919f77287ed06e 100644 --- a/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c +++ b/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c @@ -26,7 +26,6 @@ #include "hda_dsp_common.h" /* comment out this define for mono configurations */ -#define ENABLE_RT1308_SDW2 #define MAX_NO_PROPS 2 @@ -38,6 +37,7 @@ enum { }; #define SOF_RT711_JDSRC(quirk) ((quirk) & GENMASK(1, 0)) +#define SOF_SDW_MONO_SPK BIT(2) static unsigned long sof_rt711_rt1308_rt715_quirk = SOF_RT711_JD_SRC_JD1; @@ -186,7 +186,8 @@ static const struct dmi_system_id sof_sdw_rt711_rt1308_rt715_quirk_table[] = { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), }, - .driver_data = (void *)(SOF_RT711_JD_SRC_JD2), + .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 | + SOF_SDW_MONO_SPK), }, {} }; @@ -230,10 +231,11 @@ static const struct snd_soc_dapm_route map[] = { /* Speakers */ { "Speaker", NULL, "rt1308-1 SPOL" }, { "Speaker", NULL, "rt1308-1 SPOR" }, -#ifdef ENABLE_RT1308_SDW2 +}; + +static const struct snd_soc_dapm_route second_speaker_map[] = { { "Speaker", NULL, "rt1308-2 SPOL" }, { "Speaker", NULL, "rt1308-2 SPOR" }, -#endif }; static const struct snd_kcontrol_new controls[] = { @@ -242,6 +244,20 @@ static const struct snd_kcontrol_new controls[] = { SOC_DAPM_PIN_SWITCH("Speaker"), }; +static int second_spk_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_add_routes(&card->dapm, second_speaker_map, + ARRAY_SIZE(second_speaker_map)); + + if (ret) + dev_err(rtd->dev, "second Speaker map addition failed: %d\n", + ret); + return ret; +} + SND_SOC_DAILINK_DEF(sdw0_pin2, DAILINK_COMP_ARRAY(COMP_CPU("SDW0 Pin2"))); SND_SOC_DAILINK_DEF(sdw0_pin3, @@ -254,12 +270,10 @@ SND_SOC_DAILINK_DEF(sdw1_pin2, SND_SOC_DAILINK_DEF(sdw1_codec, DAILINK_COMP_ARRAY(COMP_CODEC("sdw:1:25d:1308:0", "rt1308-aif"))); -#ifdef ENABLE_RT1308_SDW2 SND_SOC_DAILINK_DEF(sdw2_pin2, DAILINK_COMP_ARRAY(COMP_CPU("SDW2 Pin2"))); SND_SOC_DAILINK_DEF(sdw2_codec, DAILINK_COMP_ARRAY(COMP_CODEC("sdw:2:25d:1308:0", "rt1308-aif"))); -#endif SND_SOC_DAILINK_DEF(sdw3_pin2, DAILINK_COMP_ARRAY(COMP_CPU("SDW3 Pin2"))); @@ -295,16 +309,14 @@ static struct snd_soc_codec_conf codec_conf[] = { .dev_name = "sdw:1:25d:1308:0", .name_prefix = "rt1308-1", }, -#ifdef ENABLE_RT1308_SDW2 - { - .dev_name = "sdw:2:25d:1308:0", - .name_prefix = "rt1308-2", - }, -#endif { .dev_name = "sdw:3:25d:715:0", .name_prefix = "rt715", }, + { + .dev_name = "sdw:2:25d:1308:0", + .name_prefix = "rt1308-2", + }, }; @@ -334,16 +346,6 @@ struct snd_soc_dai_link dailink[] = { .nonatomic = true, SND_SOC_DAILINK_REG(sdw1_pin2, sdw1_codec, platform), }, -#ifdef ENABLE_RT1308_SDW2 - { - .name = "SDW2-Playback", - .id = 3, - .no_pcm = 1, - .dpcm_playback = 1, - .nonatomic = true, - SND_SOC_DAILINK_REG(sdw2_pin2, sdw2_codec, platform), - }, -#endif { .name = "SDW3-Capture", .id = 4, @@ -379,6 +381,15 @@ struct snd_soc_dai_link dailink[] = { SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), }, #endif + { + .name = "SDW2-Playback", + .id = 3, + .init = second_spk_init, + .no_pcm = 1, + .dpcm_playback = 1, + .nonatomic = true, + SND_SOC_DAILINK_REG(sdw2_pin2, sdw2_codec, platform), + }, }; /* SoC card */ @@ -432,6 +443,13 @@ static int mc_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, ctx); sof_rt711_add_codec_device_props("sdw:0:25d:711:0"); + + if (sof_rt711_rt1308_rt715_quirk & SOF_SDW_MONO_SPK) { + /* Remove rt1308-2 codec from dailink and codec_conf */ + card->num_links--; + card->num_configs--; + } + /* Register the card */ ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) { From 057d93a21eb552e32f86259779886c5a1ae2858e Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 7 Nov 2019 16:34:27 +0800 Subject: [PATCH 1891/1995] ASoC: intel: sdw_rt711_rt1308_rt715: Use a fixed number of num_links and num__configs mc_probe could be called multiple times and card->num_links will decrease in each time when mc_probe is called. Same as num_configs. Signed-off-by: Bard Liao --- sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c b/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c index 919f77287ed06e..6c69a7ea57ec61 100644 --- a/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c +++ b/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c @@ -446,8 +446,8 @@ static int mc_probe(struct platform_device *pdev) if (sof_rt711_rt1308_rt715_quirk & SOF_SDW_MONO_SPK) { /* Remove rt1308-2 codec from dailink and codec_conf */ - card->num_links--; - card->num_configs--; + card->num_links = ARRAY_SIZE(dailink) - 1 ; + card->num_configs = ARRAY_SIZE(codec_conf) - 1; } /* Register the card */ From d2de5db3ff683c678950c77a778879a561d3f707 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 12 Nov 2019 13:16:39 +0800 Subject: [PATCH 1892/1995] ASoC: intel:sdw_rt711_i2s_rt1308: add quirk for rt711 Set rt711 device property on machine driver according to DMI. On TGL, JD1 is used for headphone. Signed-off-by: Rander Wang Signed-off-by: Bard Liao --- sound/soc/intel/boards/sdw_rt711_i2s_rt1308.c | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/sound/soc/intel/boards/sdw_rt711_i2s_rt1308.c b/sound/soc/intel/boards/sdw_rt711_i2s_rt1308.c index 6aa161b84da50e..31bd4003f6dfa7 100644 --- a/sound/soc/intel/boards/sdw_rt711_i2s_rt1308.c +++ b/sound/soc/intel/boards/sdw_rt711_i2s_rt1308.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -27,6 +29,17 @@ #include "../../codecs/hdac_hdmi.h" #include "hda_dsp_common.h" +#define MAX_NO_PROPS 2 + +enum { + SOF_RT711_JD_SRC_JD1 = 1, + SOF_RT711_JD_SRC_JD2 = 2, +}; + +#define SOF_RT711_JDSRC(quirk) ((quirk) & GENMASK(1, 0)) + +static unsigned long sof_rt711_rt1308_quirk = SOF_RT711_JD_SRC_JD1; + struct mc_private { struct list_head hdmi_pcm_list; bool common_hdmi_codec_drv; @@ -192,6 +205,50 @@ static struct snd_soc_ops rt1308_ops = { .hw_params = rt1308_hw_params, }; +static int sof_rt711_rt1308_quirk_cb(const struct dmi_system_id *id) +{ + sof_rt711_rt1308_quirk = (unsigned long)id->driver_data; + return 1; +} + +static const struct dmi_system_id sof_sdw_rt711_rt1308_quirk_table[] = { + { + .callback = sof_rt711_rt1308_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "IntelCorporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "Tiger Lake Client"), + }, + .driver_data = (void *)(SOF_RT711_JD_SRC_JD1), + }, + {} +}; + +/* + * Note this MUST be called before snd_soc_register_card(), so that the props + * are in place before the codec component driver's probe function parses them. + */ +static int sof_rt711_add_codec_device_props(const char *sdw_dev_name) +{ + struct property_entry props[MAX_NO_PROPS] = {}; + struct device *sdw_dev; + int ret, cnt = 0; + unsigned int quirk; + + sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_dev_name); + if (!sdw_dev) + return -EPROBE_DEFER; + + if (SOF_RT711_JDSRC(sof_rt711_rt1308_quirk)) { + quirk = SOF_RT711_JDSRC(sof_rt711_rt1308_quirk); + props[cnt++] = PROPERTY_ENTRY_U32("realtek,jd-src", quirk); + } + + ret = device_add_properties(sdw_dev, props); + put_device(sdw_dev); + + return ret; +} + static const struct snd_soc_dapm_widget widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), @@ -366,6 +423,8 @@ static int mc_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; + dmi_check_system(sof_sdw_rt711_rt1308_quirk_table); + #if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) INIT_LIST_HEAD(&ctx->hdmi_pcm_list); #endif @@ -384,6 +443,8 @@ static int mc_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(card, ctx); + sof_rt711_add_codec_device_props("sdw:0:25d:711:0"); + return devm_snd_soc_register_card(&pdev->dev, card); } From 3ed13659d6f90e38373d4d8d2bf484f203e7c3ec Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 12 Nov 2019 13:17:10 +0800 Subject: [PATCH 1893/1995] ASoC: intel: refine sdw_rt711_rt1308_rt715 Remove redundant definition. Signed-off-by: Rander Wang --- sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c b/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c index 6c69a7ea57ec61..c89515bd695420 100644 --- a/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c +++ b/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include #include @@ -29,8 +31,6 @@ #define MAX_NO_PROPS 2 -extern struct bus_type sdw_bus_type; - enum { SOF_RT711_JD_SRC_JD1 = 1, SOF_RT711_JD_SRC_JD2 = 2, From 2594892f3318be631ec87ccbe68560528d2c2893 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 21 Nov 2019 17:29:19 +0800 Subject: [PATCH 1894/1995] ASoC: Intel: sdw_rt711_rt1308_rt715: get more specific DMI info Not all Dell machine work with mono rt1308. Signed-off-by: Bard Liao --- sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c b/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c index c89515bd695420..24e17528f143dd 100644 --- a/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c +++ b/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c @@ -185,6 +185,7 @@ static const struct dmi_system_id sof_sdw_rt711_rt1308_rt715_quirk_table[] = { .callback = sof_rt711_rt1308_rt715_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), }, .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 | SOF_SDW_MONO_SPK), From 1f0004c0e0a844d4ca66b9b831ea64f0403b28f1 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 29 Nov 2019 14:52:51 +0800 Subject: [PATCH 1895/1995] ASoC: Intel: sdw_rt711_rt1308_rt715: add Dell XPS to DMI table To set proper configurations. Signed-off-by: Bard Liao --- sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c b/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c index 24e17528f143dd..af0bd2b8f23fb8 100644 --- a/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c +++ b/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c @@ -190,6 +190,14 @@ static const struct dmi_system_id sof_sdw_rt711_rt1308_rt715_quirk_table[] = { .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 | SOF_SDW_MONO_SPK), }, + { + .callback = sof_rt711_rt1308_rt715_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_MATCH(DMI_PRODUCT_NAME, "XPS"), + }, + .driver_data = (void *)(SOF_RT711_JD_SRC_JD2), + }, {} }; From 436723ee46097469754d6cfa7121d0bc9ad16876 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 7 Jan 2020 15:31:15 -0600 Subject: [PATCH 1896/1995] ASoC: Intel: sdw-rt711-rt1308-rt715: move to new CODEC_CONF representation Follow upstream move and convert to .dlc = COMP_CODEC_CONF Signed-off-by: Pierre-Louis Bossart --- sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c b/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c index af0bd2b8f23fb8..67e2b0ec5fa18d 100644 --- a/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c +++ b/sound/soc/intel/boards/sdw_rt711_rt1308_rt715.c @@ -311,19 +311,19 @@ SND_SOC_DAILINK_DEF(platform, static struct snd_soc_codec_conf codec_conf[] = { { - .dev_name = "sdw:0:25d:711:0", + .dlc = COMP_CODEC_CONF("sdw:0:25d:711:0"), .name_prefix = "rt711", }, { - .dev_name = "sdw:1:25d:1308:0", + .dlc = COMP_CODEC_CONF("sdw:1:25d:1308:0"), .name_prefix = "rt1308-1", }, { - .dev_name = "sdw:3:25d:715:0", + .dlc = COMP_CODEC_CONF("sdw:3:25d:715:0"), .name_prefix = "rt715", }, { - .dev_name = "sdw:2:25d:1308:0", + .dlc = COMP_CODEC_CONF("sdw:2:25d:1308:0"), .name_prefix = "rt1308-2", }, From 589b5236365735b3b7d70398050d9ef1dd13e5da Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 14 Nov 2019 11:14:55 -0600 Subject: [PATCH 1897/1995] soundwire: stream: remove redundant pr_err traces Only keep pr_err to flag critical configuration errors that will typically only happen during system integration. For errors on prepare/deprepare/enable/disable, the caller can do a much better job with more information on the DAI and device that caused the issue. Suggested-by: Cezary Rojewski Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/stream.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index e69f94a8c3a865..178ae92b8cc1cc 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1554,8 +1554,6 @@ int sdw_prepare_stream(struct sdw_stream_runtime *stream) sdw_acquire_bus_lock(stream); ret = _sdw_prepare_stream(stream); - if (ret < 0) - pr_err("Prepare for stream:%s failed: %d\n", stream->name, ret); sdw_release_bus_lock(stream); return ret; @@ -1622,8 +1620,6 @@ int sdw_enable_stream(struct sdw_stream_runtime *stream) sdw_acquire_bus_lock(stream); ret = _sdw_enable_stream(stream); - if (ret < 0) - pr_err("Enable for stream:%s failed: %d\n", stream->name, ret); sdw_release_bus_lock(stream); return ret; @@ -1698,8 +1694,6 @@ int sdw_disable_stream(struct sdw_stream_runtime *stream) sdw_acquire_bus_lock(stream); ret = _sdw_disable_stream(stream); - if (ret < 0) - pr_err("Disable for stream:%s failed: %d\n", stream->name, ret); sdw_release_bus_lock(stream); return ret; @@ -1756,8 +1750,6 @@ int sdw_deprepare_stream(struct sdw_stream_runtime *stream) sdw_acquire_bus_lock(stream); ret = _sdw_deprepare_stream(stream); - if (ret < 0) - pr_err("De-prepare for stream:%d failed: %d\n", ret, ret); sdw_release_bus_lock(stream); return ret; From 739bd911d5c4cd41c81579370c00b5aec71b2886 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 12 Oct 2019 14:38:06 -0500 Subject: [PATCH 1898/1995] soundwire: stream: update state machine and add state checks The state machine and notes don't accurately explain or allow transitions from STREAM_DEPREPARED and STREAM_DISABLED. Add more explanations and allow for more transitions as a result of a trigger_stop(), trigger_suspend() and prepare(), depending on the ALSA/ASoC layer behavior defined by the INFO_RESUME and INFO_PAUSE flags. Also add basic checks to help debug inconsistent states and illegal state machine transitions. Signed-off-by: Pierre-Louis Bossart --- Documentation/driver-api/soundwire/stream.rst | 63 +++++++++++++------ drivers/soundwire/stream.c | 37 +++++++++++ 2 files changed, 82 insertions(+), 18 deletions(-) diff --git a/Documentation/driver-api/soundwire/stream.rst b/Documentation/driver-api/soundwire/stream.rst index 5351bd2f34a870..9b7418ff8d59aa 100644 --- a/Documentation/driver-api/soundwire/stream.rst +++ b/Documentation/driver-api/soundwire/stream.rst @@ -156,22 +156,27 @@ Below shows the SoundWire stream states and state transition diagram. :: +-----------+ +------------+ +----------+ +----------+ | ALLOCATED +---->| CONFIGURED +---->| PREPARED +---->| ENABLED | | STATE | | STATE | | STATE | | STATE | - +-----------+ +------------+ +----------+ +----+-----+ - ^ - | - | - v - +----------+ +------------+ +----+-----+ + +-----------+ +------------+ +---+--+---+ +----+-----+ + ^ ^ ^ + | | | + __| |___________ | + | | | + v | v + +----------+ +-----+------+ +-+--+-----+ | RELEASED |<----------+ DEPREPARED |<-------+ DISABLED | | STATE | | STATE | | STATE | +----------+ +------------+ +----------+ -NOTE: State transition between prepare and deprepare is supported in Spec -but not in the software (subsystem) +NOTE: State transitions between ``SDW_STREAM_ENABLED`` and +``SDW_STREAM_DISABLED`` are only relevant when then INFO_PAUSE flag is +supported at the ALSA/ASoC level. Likewise the transition between +``SDW_DISABLED_STATE`` and ``SDW_PREPARED_STATE`` depends on the +INFO_RESUME flag. -NOTE2: Stream state transition checks need to be handled by caller -framework, for example ALSA/ASoC. No checks for stream transition exist in -SoundWire subsystem. +NOTE2: The framework implements basic state transition checks, but +does not e.g. check if a transition from DISABLED to ENABLED is valid +on a specific platform. Such tests need to be added at the ALSA/ASoC +level. Stream State Operations ----------------------- @@ -246,6 +251,9 @@ SDW_STREAM_PREPARED Prepare state of stream. Operations performed before entering in this state: + (0) Steps 1 and 2 are omitted in the case of a resume operation, + where the bus bandwidth is known. + (1) Bus parameters such as bandwidth, frame shape, clock frequency, are computed based on current stream as well as already active stream(s) on Bus. Re-computation is required to accommodate current @@ -270,13 +278,15 @@ Prepare state of stream. Operations performed before entering in this state: After all above operations are successful, stream state is set to ``SDW_STREAM_PREPARED``. -Bus implements below API for PREPARE state which needs to be called once per -stream. From ASoC DPCM framework, this stream state is linked to -.prepare() operation. +Bus implements below API for PREPARE state which needs to be called +once per stream. From ASoC DPCM framework, this stream state is linked +to .prepare() operation. Since the .trigger() operations may not +follow the .prepare(), a direct transitions from +``SDW_STREAM_PREPARED`` to ``SDW_STREAM_DEPREPARED`` is allowed. .. code-block:: c - int sdw_prepare_stream(struct sdw_stream_runtime * stream); + int sdw_prepare_stream(struct sdw_stream_runtime * stream, bool resume); SDW_STREAM_ENABLED @@ -332,6 +342,14 @@ Bus implements below API for DISABLED state which needs to be called once per stream. From ASoC DPCM framework, this stream state is linked to .trigger() stop operation. +When the INFO_PAUSE flag is supported, a direct transition to +``SDW_STREAM_ENABLED`` is allowed. + +For resume operations where ASoC will use the .prepare() callback, the +stream can transition from ``SDW_STREAM_DISABLED`` to +``SDW_STREAM_PREPARED``, with all required settings restored but +without updating the bandwidth and bit allocation. + .. code-block:: c int sdw_disable_stream(struct sdw_stream_runtime * stream); @@ -353,9 +371,18 @@ state: After all above operations are successful, stream state is set to ``SDW_STREAM_DEPREPARED``. -Bus implements below API for DEPREPARED state which needs to be called once -per stream. From ASoC DPCM framework, this stream state is linked to -.trigger() stop operation. +Bus implements below API for DEPREPARED state which needs to be called +once per stream. ALSA/ASoC do not have a concept of 'deprepare', and +the mapping from this stream state to ALSA/ASoC operation may be +implementation specific. + +When the INFO_PAUSE flag is supported, the stream state is linked to +the .hw_free() operation - the stream is not deprepared on a +TRIGGER_STOP. + +Other implementations may transition to the ``SDW_STREAM_DEPREPARED`` +state on TRIGGER_STOP, should they require a transition through the +``SDW_STREAM_PREPARED`` state. .. code-block:: c diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 178ae92b8cc1cc..6aa0b5d370c039 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1553,8 +1553,18 @@ int sdw_prepare_stream(struct sdw_stream_runtime *stream) sdw_acquire_bus_lock(stream); + if (stream->state != SDW_STREAM_CONFIGURED && + stream->state != SDW_STREAM_DEPREPARED && + stream->state != SDW_STREAM_DISABLED) { + pr_err("%s: %s: inconsistent state state %d\n", + __func__, stream->name, stream->state); + ret = -EINVAL; + goto state_err; + } + ret = _sdw_prepare_stream(stream); +state_err: sdw_release_bus_lock(stream); return ret; } @@ -1619,8 +1629,17 @@ int sdw_enable_stream(struct sdw_stream_runtime *stream) sdw_acquire_bus_lock(stream); + if (stream->state != SDW_STREAM_PREPARED && + stream->state != SDW_STREAM_DISABLED) { + pr_err("%s: %s: inconsistent state state %d\n", + __func__, stream->name, stream->state); + ret = -EINVAL; + goto state_err; + } + ret = _sdw_enable_stream(stream); +state_err: sdw_release_bus_lock(stream); return ret; } @@ -1693,8 +1712,16 @@ int sdw_disable_stream(struct sdw_stream_runtime *stream) sdw_acquire_bus_lock(stream); + if (stream->state != SDW_STREAM_ENABLED) { + pr_err("%s: %s: inconsistent state state %d\n", + __func__, stream->name, stream->state); + ret = -EINVAL; + goto state_err; + } + ret = _sdw_disable_stream(stream); +state_err: sdw_release_bus_lock(stream); return ret; } @@ -1749,8 +1776,18 @@ int sdw_deprepare_stream(struct sdw_stream_runtime *stream) } sdw_acquire_bus_lock(stream); + + if (stream->state != SDW_STREAM_PREPARED && + stream->state != SDW_STREAM_DISABLED) { + pr_err("%s: %s: inconsistent state state %d\n", + __func__, stream->name, stream->state); + ret = -EINVAL; + goto state_err; + } + ret = _sdw_deprepare_stream(stream); +state_err: sdw_release_bus_lock(stream); return ret; } From 2c7a19790cfe79574ef03c1c614447c6c03bb7ce Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 20 Sep 2019 14:48:26 +0800 Subject: [PATCH 1899/1995] soundwire: stream: only prepare stream when it is configured. We don't need to prepare the stream again if the stream is already prepared. sdw_prepare_stream() could be called multiple times without calling sdw_deprepare_stream(). We call sdw_prepare_stream() in the prepare dai ops and sdw_deprepare_stream() in the hw_free dai ops. If an xrun happens, sdw_prepare_stream() will be called but sdw_deprepare_stream() will not, which results in an imbalance and an invalid total bandwidth. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/stream.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 6aa0b5d370c039..bd0bddf738302a 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1544,7 +1544,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream) */ int sdw_prepare_stream(struct sdw_stream_runtime *stream) { - int ret = 0; + int ret; if (!stream) { pr_err("SoundWire: Handle not found for stream\n"); @@ -1553,6 +1553,11 @@ int sdw_prepare_stream(struct sdw_stream_runtime *stream) sdw_acquire_bus_lock(stream); + if (stream->state == SDW_STREAM_PREPARED) { + ret = 0; + goto state_err; + } + if (stream->state != SDW_STREAM_CONFIGURED && stream->state != SDW_STREAM_DEPREPARED && stream->state != SDW_STREAM_DISABLED) { From fa9d30950b8dc6f0638f7ebfd5753fdaf39fd420 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 15 Oct 2019 09:43:47 -0500 Subject: [PATCH 1900/1995] soundwire: stream: do not update parameters during DISABLED-PREPARED transition After a system suspend, the ALSA/ASoC core will invoke the .prepare() callback and a TRIGGER_START when INFO_RESUME is not supported. Likewise, when an underflow occurs, the .prepare callback will be invoked. In both cases, the stream can be in DISABLED mode, and will transition into the PREPARED mode. We however don't want the bus bandwidth to be recomputed. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/stream.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index bd0bddf738302a..c28ce7f0d7424f 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1460,7 +1460,8 @@ static void sdw_release_bus_lock(struct sdw_stream_runtime *stream) } } -static int _sdw_prepare_stream(struct sdw_stream_runtime *stream) +static int _sdw_prepare_stream(struct sdw_stream_runtime *stream, + bool update_params) { struct sdw_master_runtime *m_rt; struct sdw_bus *bus = NULL; @@ -1480,6 +1481,9 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream) return -EINVAL; } + if (!update_params) + goto program_params; + /* Increment cumulative bus bandwidth */ /* TODO: Update this during Device-Device support */ bus->params.bandwidth += m_rt->stream->params.rate * @@ -1495,6 +1499,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream) } } +program_params: /* Program params */ ret = sdw_program_params(bus); if (ret < 0) { @@ -1544,6 +1549,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream) */ int sdw_prepare_stream(struct sdw_stream_runtime *stream) { + bool update_params = true; int ret; if (!stream) { @@ -1567,7 +1573,16 @@ int sdw_prepare_stream(struct sdw_stream_runtime *stream) goto state_err; } - ret = _sdw_prepare_stream(stream); + /* + * when the stream is DISABLED, this means sdw_prepare_stream() + * is called as a result of an underflow or a resume operation. + * In this case, the bus parameters shall not be recomputed, but + * still need to be re-applied + */ + if (stream->state == SDW_STREAM_DISABLED) + update_params = false; + + ret = _sdw_prepare_stream(stream, update_params); state_err: sdw_release_bus_lock(stream); From 039d73b1d6275f060a5cc9a767f73193a9c34d8a Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 25 Dec 2019 13:28:40 +0800 Subject: [PATCH 1901/1995] soundwire: stream: fix support for multiple Slaves on the same link The existing code will unconditionally return after dealing with the first Slave on a link. This return should only happen when there is an error case. Tested on Comet Lake platform. Signed-off-by: Rander Wang --- drivers/soundwire/stream.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index c28ce7f0d7424f..da10f38298c068 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -587,10 +587,11 @@ static int sdw_notify_config(struct sdw_master_runtime *m_rt) if (slave->ops->bus_config) { ret = slave->ops->bus_config(slave, &bus->params); - if (ret < 0) + if (ret < 0) { dev_err(bus->dev, "Notify Slave: %d failed\n", slave->dev_num); - return ret; + return ret; + } } } From 0d9e04478bbcff526274be38dd73d432c0b5e610 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Tue, 7 Jan 2020 15:56:08 -0600 Subject: [PATCH 1902/1995] soundwire: stream: don't program ports when a stream that has not been prepared In the Intel QA multi-pipelines test case, there are two pipelines for playback and capture on the same bus. The test fails with an error when setting port params: [ 599.224812] rt711 sdw:0:25d:711:0: invalid dpn_prop direction 1 port_num 0 [ 599.224815] sdw_program_slave_port_params failed -22 [ 599.224819] intel-sdw sdw-master-0: Program transport params failed: -22 [ 599.224822] intel-sdw sdw-master-0: Program params failed: -22 [ 599.224828] sdw_enable_stream: SDW0 Pin2-Playback: done This problem is root-caused to the programming of the capture stream ports while it is not yet prepared, the calling sequence is: (1) hw_params for playback. The playback stream provide the port information to Bus. (2) stream_prepare for playback, Transport and port parameters are computed for playback. (3) hw_params for capture. The capture stream provide the port information to Bus, but it has not been prepared so is not accounted for in the bandwidth allocation. (4) stream_enable for playback. Program transport and port parameters for all masters and slaves. Since the transport and port parameters are not computed for capture stream, sdw_program_slave_port_params will generate a error when setting port params for capture. in step (4), we should only program the ports for the stream that have been prepared. A stream that is only in CONFIGURED state should be ignored, its ports will be programmed when it becomes PREPARED. Tested on Comet Lake. GitHub issue: https://github.com/thesofproject/linux/issues/1637 Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/stream.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index da10f38298c068..19837297718726 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -604,12 +604,23 @@ static int sdw_notify_config(struct sdw_master_runtime *m_rt) * * @bus: SDW bus instance */ -static int sdw_program_params(struct sdw_bus *bus) +static int sdw_program_params(struct sdw_bus *bus, bool prepare) { struct sdw_master_runtime *m_rt; int ret = 0; list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { + + /* + * this loop walks through all master runtimes for a + * bus, but the ports can only be configured while + * explicitly preparing a stream or handling an + * already-prepared stream otherwise. + */ + if (!prepare && + m_rt->stream->state == SDW_STREAM_CONFIGURED) + continue; + ret = sdw_program_port_params(m_rt); if (ret < 0) { dev_err(bus->dev, @@ -1502,7 +1513,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream, program_params: /* Program params */ - ret = sdw_program_params(bus); + ret = sdw_program_params(bus, true); if (ret < 0) { dev_err(bus->dev, "Program params failed: %d\n", ret); goto restore_params; @@ -1602,7 +1613,7 @@ static int _sdw_enable_stream(struct sdw_stream_runtime *stream) bus = m_rt->bus; /* Program params */ - ret = sdw_program_params(bus); + ret = sdw_program_params(bus, false); if (ret < 0) { dev_err(bus->dev, "Program params failed: %d\n", ret); return ret; @@ -1687,7 +1698,7 @@ static int _sdw_disable_stream(struct sdw_stream_runtime *stream) struct sdw_bus *bus = m_rt->bus; /* Program params */ - ret = sdw_program_params(bus); + ret = sdw_program_params(bus, false); if (ret < 0) { dev_err(bus->dev, "Program params failed: %d\n", ret); return ret; @@ -1769,7 +1780,7 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream) m_rt->ch_count * m_rt->stream->params.bps; /* Program params */ - ret = sdw_program_params(bus); + ret = sdw_program_params(bus, false); if (ret < 0) { dev_err(bus->dev, "Program params failed: %d\n", ret); return ret; From a8bf47ab6c71815333d19488ce4ef4bab1daadec Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 10 Sep 2019 18:46:08 -0500 Subject: [PATCH 1903/1995] soundwire: renames to prepare support for master drivers/devices Add clearer references to sdw_slave_driver for internal macros No change for sdw_driver and module_sdw_driver to avoid compatibility issues with existing codec devices No functionality change. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus_type.c | 21 +++++++++++---------- include/linux/soundwire/sdw_type.h | 18 ++++++++++-------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index 4a465f55039f4b..370b9475266228 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -34,7 +34,7 @@ sdw_get_device_id(struct sdw_slave *slave, struct sdw_driver *drv) static int sdw_bus_match(struct device *dev, struct device_driver *ddrv) { struct sdw_slave *slave = dev_to_sdw_dev(dev); - struct sdw_driver *drv = drv_to_sdw_driver(ddrv); + struct sdw_driver *drv = drv_to_sdw_slave_driver(ddrv); return !!sdw_get_device_id(slave, drv); } @@ -70,7 +70,7 @@ EXPORT_SYMBOL_GPL(sdw_bus_type); static int sdw_drv_probe(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); - struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); + struct sdw_driver *drv = drv_to_sdw_slave_driver(dev->driver); const struct sdw_device_id *id; int ret; @@ -116,7 +116,7 @@ static int sdw_drv_probe(struct device *dev) static int sdw_drv_remove(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); - struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); + struct sdw_driver *drv = drv_to_sdw_slave_driver(dev->driver); int ret = 0; if (drv->remove) @@ -130,20 +130,21 @@ static int sdw_drv_remove(struct device *dev) static void sdw_drv_shutdown(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); - struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); + struct sdw_driver *drv = drv_to_sdw_slave_driver(dev->driver); if (drv->shutdown) drv->shutdown(slave); } /** - * __sdw_register_driver() - register a SoundWire Slave driver + * __sdw_register_slave_driver() - register a SoundWire Slave driver * @drv: driver to register * @owner: owning module/driver * * Return: zero on success, else a negative error code. */ -int __sdw_register_driver(struct sdw_driver *drv, struct module *owner) +int __sdw_register_slave_driver(struct sdw_driver *drv, + struct module *owner) { drv->driver.bus = &sdw_bus_type; @@ -164,17 +165,17 @@ int __sdw_register_driver(struct sdw_driver *drv, struct module *owner) return driver_register(&drv->driver); } -EXPORT_SYMBOL_GPL(__sdw_register_driver); +EXPORT_SYMBOL_GPL(__sdw_register_slave_driver); /** - * sdw_unregister_driver() - unregisters the SoundWire Slave driver + * sdw_unregister_slave_driver() - unregisters the SoundWire Slave driver * @drv: driver to unregister */ -void sdw_unregister_driver(struct sdw_driver *drv) +void sdw_unregister_slave_driver(struct sdw_driver *drv) { driver_unregister(&drv->driver); } -EXPORT_SYMBOL_GPL(sdw_unregister_driver); +EXPORT_SYMBOL_GPL(sdw_unregister_slave_driver); static int __init sdw_bus_init(void) { diff --git a/include/linux/soundwire/sdw_type.h b/include/linux/soundwire/sdw_type.h index aaa7f4267c149a..abaa2127815254 100644 --- a/include/linux/soundwire/sdw_type.h +++ b/include/linux/soundwire/sdw_type.h @@ -6,13 +6,15 @@ extern struct bus_type sdw_bus_type; -#define drv_to_sdw_driver(_drv) container_of(_drv, struct sdw_driver, driver) +#define drv_to_sdw_slave_driver(_drv) \ + container_of(_drv, struct sdw_driver, driver) -#define sdw_register_driver(drv) \ - __sdw_register_driver(drv, THIS_MODULE) +#define sdw_register_slave_driver(drv) \ + __sdw_register_slave_driver(drv, THIS_MODULE) -int __sdw_register_driver(struct sdw_driver *drv, struct module *owner); -void sdw_unregister_driver(struct sdw_driver *drv); +int __sdw_register_slave_driver(struct sdw_driver *drv, + struct module *owner); +void sdw_unregister_slave_driver(struct sdw_driver *drv); int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size); @@ -24,7 +26,7 @@ int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size); * module init/exit. This eliminates a lot of boilerplate. Each module may only * use this macro once, and calling it replaces module_init() and module_exit() */ -#define module_sdw_driver(__sdw_driver) \ - module_driver(__sdw_driver, sdw_register_driver, \ - sdw_unregister_driver) +#define module_sdw_driver(__sdw_slave_driver) \ + module_driver(__sdw_slave_driver, sdw_register_slave_driver, \ + sdw_unregister_slave_driver) #endif /* __SOUNDWIRE_TYPES_H */ From eb68092907a2abfb25f9156a88fc96211da73dda Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 10 Sep 2019 19:58:17 -0500 Subject: [PATCH 1904/1995] soundwire: rename dev_to_sdw_dev macro Since we want to introduce master devices, rename macro so that we have consistency between slave and master device access. Signed-off-by: Pierre-Louis Bossart --- drivers/base/regmap/regmap-sdw.c | 4 ++-- drivers/soundwire/bus.c | 2 +- drivers/soundwire/bus_type.c | 11 ++++++----- drivers/soundwire/slave.c | 2 +- include/linux/soundwire/sdw.h | 3 ++- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/base/regmap/regmap-sdw.c b/drivers/base/regmap/regmap-sdw.c index 50a66382d87d09..d1fc0c22180a17 100644 --- a/drivers/base/regmap/regmap-sdw.c +++ b/drivers/base/regmap/regmap-sdw.c @@ -10,7 +10,7 @@ static int regmap_sdw_write(void *context, unsigned int reg, unsigned int val) { struct device *dev = context; - struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct sdw_slave *slave = to_sdw_slave_device(dev); return sdw_write(slave, reg, val); } @@ -18,7 +18,7 @@ static int regmap_sdw_write(void *context, unsigned int reg, unsigned int val) static int regmap_sdw_read(void *context, unsigned int reg, unsigned int *val) { struct device *dev = context; - struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct sdw_slave *slave = to_sdw_slave_device(dev); int read; read = sdw_read(slave, reg); diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index be5d437058ed19..4b22ee996a6566 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -110,7 +110,7 @@ EXPORT_SYMBOL(sdw_add_bus_master); static int sdw_delete_slave(struct device *dev, void *data) { - struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct sdw_slave *slave = to_sdw_slave_device(dev); struct sdw_bus *bus = slave->bus; sdw_slave_debugfs_exit(slave); diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index 370b9475266228..c0585bcc8a41b8 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -33,7 +33,7 @@ sdw_get_device_id(struct sdw_slave *slave, struct sdw_driver *drv) static int sdw_bus_match(struct device *dev, struct device_driver *ddrv) { - struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct sdw_slave *slave = to_sdw_slave_device(dev); struct sdw_driver *drv = drv_to_sdw_slave_driver(ddrv); return !!sdw_get_device_id(slave, drv); @@ -49,7 +49,7 @@ int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size) static int sdw_uevent(struct device *dev, struct kobj_uevent_env *env) { - struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct sdw_slave *slave = to_sdw_slave_device(dev); char modalias[32]; sdw_slave_modalias(slave, modalias, sizeof(modalias)); @@ -69,7 +69,7 @@ EXPORT_SYMBOL_GPL(sdw_bus_type); static int sdw_drv_probe(struct device *dev) { - struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct sdw_slave *slave = to_sdw_slave_device(dev); struct sdw_driver *drv = drv_to_sdw_slave_driver(dev->driver); const struct sdw_device_id *id; int ret; @@ -115,8 +115,9 @@ static int sdw_drv_probe(struct device *dev) static int sdw_drv_remove(struct device *dev) { - struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct sdw_slave *slave = to_sdw_slave_device(dev); struct sdw_driver *drv = drv_to_sdw_slave_driver(dev->driver); + int ret = 0; if (drv->remove) @@ -129,7 +130,7 @@ static int sdw_drv_remove(struct device *dev) static void sdw_drv_shutdown(struct device *dev) { - struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct sdw_slave *slave = to_sdw_slave_device(dev); struct sdw_driver *drv = drv_to_sdw_slave_driver(dev->driver); if (drv->shutdown) diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c index 19919975bb6da4..48a513680db665 100644 --- a/drivers/soundwire/slave.c +++ b/drivers/soundwire/slave.c @@ -9,7 +9,7 @@ static void sdw_slave_release(struct device *dev) { - struct sdw_slave *slave = dev_to_sdw_dev(dev); + struct sdw_slave *slave = to_sdw_slave_device(dev); kfree(slave); } diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index b7c9eca4332a3a..5b1180f1e6b558 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -582,7 +582,8 @@ struct sdw_slave { u32 unattach_request; }; -#define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev) +#define to_sdw_slave_device(d) \ + container_of(d, struct sdw_slave, dev) struct sdw_driver { const char *name; From 9f3ca448607080d3d6942b8f0cb89aa5252273ea Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 10 Sep 2019 20:27:41 -0500 Subject: [PATCH 1905/1995] soundwire: rename drv_to_sdw_slave_driver macro Align with previous renames and shorten macro No functionality change Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus_type.c | 9 ++++----- include/linux/soundwire/sdw_type.h | 3 ++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index c0585bcc8a41b8..2b2830b622faef 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -34,7 +34,7 @@ sdw_get_device_id(struct sdw_slave *slave, struct sdw_driver *drv) static int sdw_bus_match(struct device *dev, struct device_driver *ddrv) { struct sdw_slave *slave = to_sdw_slave_device(dev); - struct sdw_driver *drv = drv_to_sdw_slave_driver(ddrv); + struct sdw_driver *drv = to_sdw_slave_driver(ddrv); return !!sdw_get_device_id(slave, drv); } @@ -70,7 +70,7 @@ EXPORT_SYMBOL_GPL(sdw_bus_type); static int sdw_drv_probe(struct device *dev) { struct sdw_slave *slave = to_sdw_slave_device(dev); - struct sdw_driver *drv = drv_to_sdw_slave_driver(dev->driver); + struct sdw_driver *drv = to_sdw_slave_driver(dev->driver); const struct sdw_device_id *id; int ret; @@ -116,8 +116,7 @@ static int sdw_drv_probe(struct device *dev) static int sdw_drv_remove(struct device *dev) { struct sdw_slave *slave = to_sdw_slave_device(dev); - struct sdw_driver *drv = drv_to_sdw_slave_driver(dev->driver); - + struct sdw_driver *drv = to_sdw_slave_driver(dev->driver); int ret = 0; if (drv->remove) @@ -131,7 +130,7 @@ static int sdw_drv_remove(struct device *dev) static void sdw_drv_shutdown(struct device *dev) { struct sdw_slave *slave = to_sdw_slave_device(dev); - struct sdw_driver *drv = drv_to_sdw_slave_driver(dev->driver); + struct sdw_driver *drv = to_sdw_slave_driver(dev->driver); if (drv->shutdown) drv->shutdown(slave); diff --git a/include/linux/soundwire/sdw_type.h b/include/linux/soundwire/sdw_type.h index abaa2127815254..7d4bc6a979bf6b 100644 --- a/include/linux/soundwire/sdw_type.h +++ b/include/linux/soundwire/sdw_type.h @@ -6,7 +6,7 @@ extern struct bus_type sdw_bus_type; -#define drv_to_sdw_slave_driver(_drv) \ +#define to_sdw_slave_driver(_drv) \ container_of(_drv, struct sdw_driver, driver) #define sdw_register_slave_driver(drv) \ @@ -29,4 +29,5 @@ int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size); #define module_sdw_driver(__sdw_slave_driver) \ module_driver(__sdw_slave_driver, sdw_register_slave_driver, \ sdw_unregister_slave_driver) + #endif /* __SOUNDWIRE_TYPES_H */ From a3ea616f848307247d2c6e0d7c075e61e42952f4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 10 Sep 2019 21:53:10 -0500 Subject: [PATCH 1906/1995] soundwire: bus_type: rename sdw_drv_ to sdw_slave_drv Before we add master driver support, make sure there is no ambiguity and no occurrences of sdw_drv_ functions. No functionality change. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus_type.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index 2b2830b622faef..9a0fd3ee1014a7 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -67,7 +67,7 @@ struct bus_type sdw_bus_type = { }; EXPORT_SYMBOL_GPL(sdw_bus_type); -static int sdw_drv_probe(struct device *dev) +static int sdw_slave_drv_probe(struct device *dev) { struct sdw_slave *slave = to_sdw_slave_device(dev); struct sdw_driver *drv = to_sdw_slave_driver(dev->driver); @@ -113,7 +113,7 @@ static int sdw_drv_probe(struct device *dev) return 0; } -static int sdw_drv_remove(struct device *dev) +static int sdw_slave_drv_remove(struct device *dev) { struct sdw_slave *slave = to_sdw_slave_device(dev); struct sdw_driver *drv = to_sdw_slave_driver(dev->driver); @@ -127,7 +127,7 @@ static int sdw_drv_remove(struct device *dev) return ret; } -static void sdw_drv_shutdown(struct device *dev) +static void sdw_slave_drv_shutdown(struct device *dev) { struct sdw_slave *slave = to_sdw_slave_device(dev); struct sdw_driver *drv = to_sdw_slave_driver(dev->driver); @@ -155,13 +155,13 @@ int __sdw_register_slave_driver(struct sdw_driver *drv, } drv->driver.owner = owner; - drv->driver.probe = sdw_drv_probe; + drv->driver.probe = sdw_slave_drv_probe; if (drv->remove) - drv->driver.remove = sdw_drv_remove; + drv->driver.remove = sdw_slave_drv_remove; if (drv->shutdown) - drv->driver.shutdown = sdw_drv_shutdown; + drv->driver.shutdown = sdw_slave_drv_shutdown; return driver_register(&drv->driver); } From 4c50a137c7c85e616c6940d593662b36f24a10d6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 11 Sep 2019 14:26:53 -0500 Subject: [PATCH 1907/1995] soundwire: intel: rename res field as link_res There are too many fields called 'res' so add prefix to make it easier to track what the structures are. Pure rename, no functionality change Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 0371d3d5501a97..64f97bb1a13573 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -103,7 +103,7 @@ enum intel_pdi_type { struct sdw_intel { struct sdw_cdns cdns; int instance; - struct sdw_intel_link_res *res; + struct sdw_intel_link_res *link_res; #ifdef CONFIG_DEBUG_FS struct dentry *debugfs; #endif @@ -193,8 +193,8 @@ static ssize_t intel_sprintf(void __iomem *mem, bool l, static int intel_reg_show(struct seq_file *s_file, void *data) { struct sdw_intel *sdw = s_file->private; - void __iomem *s = sdw->res->shim; - void __iomem *a = sdw->res->alh; + void __iomem *s = sdw->link_res->shim; + void __iomem *a = sdw->link_res->alh; char *buf; ssize_t ret; int i, j; @@ -289,7 +289,7 @@ static void intel_debugfs_exit(struct sdw_intel *sdw) {} static int intel_link_power_up(struct sdw_intel *sdw) { unsigned int link_id = sdw->instance; - void __iomem *shim = sdw->res->shim; + void __iomem *shim = sdw->link_res->shim; int spa_mask, cpa_mask; int link_control, ret; @@ -309,7 +309,7 @@ static int intel_link_power_up(struct sdw_intel *sdw) static int intel_shim_init(struct sdw_intel *sdw) { - void __iomem *shim = sdw->res->shim; + void __iomem *shim = sdw->link_res->shim; unsigned int link_id = sdw->instance; int sync_reg, ret; u16 ioctl = 0, act = 0; @@ -370,7 +370,7 @@ static int intel_shim_init(struct sdw_intel *sdw) static void intel_pdi_init(struct sdw_intel *sdw, struct sdw_cdns_stream_config *config) { - void __iomem *shim = sdw->res->shim; + void __iomem *shim = sdw->link_res->shim; unsigned int link_id = sdw->instance; int pcm_cap, pdm_cap; @@ -404,7 +404,7 @@ static void intel_pdi_init(struct sdw_intel *sdw, static int intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num, bool pcm) { - void __iomem *shim = sdw->res->shim; + void __iomem *shim = sdw->link_res->shim; unsigned int link_id = sdw->instance; int count; @@ -476,7 +476,7 @@ static int intel_pdi_ch_update(struct sdw_intel *sdw) static void intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi) { - void __iomem *shim = sdw->res->shim; + void __iomem *shim = sdw->link_res->shim; unsigned int link_id = sdw->instance; int pdi_conf = 0; @@ -508,7 +508,7 @@ intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi) static void intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi) { - void __iomem *alh = sdw->res->alh; + void __iomem *alh = sdw->link_res->alh; unsigned int link_id = sdw->instance; unsigned int conf; @@ -535,7 +535,7 @@ static int intel_params_stream(struct sdw_intel *sdw, struct snd_pcm_hw_params *hw_params, int link_id, int alh_stream_id) { - struct sdw_intel_link_res *res = sdw->res; + struct sdw_intel_link_res *res = sdw->link_res; struct sdw_intel_stream_params_data params_data; params_data.substream = substream; @@ -558,7 +558,7 @@ static int intel_pre_bank_switch(struct sdw_bus *bus) { struct sdw_cdns *cdns = bus_to_cdns(bus); struct sdw_intel *sdw = cdns_to_intel(cdns); - void __iomem *shim = sdw->res->shim; + void __iomem *shim = sdw->link_res->shim; int sync_reg; /* Write to register only for multi-link */ @@ -577,7 +577,7 @@ static int intel_post_bank_switch(struct sdw_bus *bus) { struct sdw_cdns *cdns = bus_to_cdns(bus); struct sdw_intel *sdw = cdns_to_intel(cdns); - void __iomem *shim = sdw->res->shim; + void __iomem *shim = sdw->link_res->shim; int sync_reg, ret; /* Write to register only for multi-link */ @@ -934,9 +934,9 @@ static int intel_probe(struct platform_device *pdev) return -ENOMEM; sdw->instance = pdev->id; - sdw->res = dev_get_platdata(&pdev->dev); + sdw->link_res = dev_get_platdata(&pdev->dev); sdw->cdns.dev = &pdev->dev; - sdw->cdns.registers = sdw->res->registers; + sdw->cdns.registers = sdw->link_res->registers; sdw->cdns.instance = sdw->instance; sdw->cdns.msg_count = 0; sdw->cdns.bus.dev = &pdev->dev; @@ -976,11 +976,12 @@ static int intel_probe(struct platform_device *pdev) intel_pdi_ch_update(sdw); /* Acquire IRQ */ - ret = request_threaded_irq(sdw->res->irq, sdw_cdns_irq, sdw_cdns_thread, + ret = request_threaded_irq(sdw->link_res->irq, + sdw_cdns_irq, sdw_cdns_thread, IRQF_SHARED, KBUILD_MODNAME, &sdw->cdns); if (ret < 0) { dev_err(sdw->cdns.dev, "unable to grab IRQ %d, disabling device\n", - sdw->res->irq); + sdw->link_res->irq); goto err_init; } @@ -1010,7 +1011,7 @@ static int intel_probe(struct platform_device *pdev) err_interrupt: sdw_cdns_enable_interrupt(&sdw->cdns, false); - free_irq(sdw->res->irq, sdw); + free_irq(sdw->link_res->irq, sdw); err_init: sdw_delete_bus_master(&sdw->cdns.bus); return ret; @@ -1025,7 +1026,7 @@ static int intel_remove(struct platform_device *pdev) if (!sdw->cdns.bus.prop.hw_disabled) { intel_debugfs_exit(sdw); sdw_cdns_enable_interrupt(&sdw->cdns, false); - free_irq(sdw->res->irq, sdw); + free_irq(sdw->link_res->irq, sdw); snd_soc_unregister_component(sdw->cdns.dev); } sdw_delete_bus_master(&sdw->cdns.bus); From 193a78b7f59706eaca57b19eace276b564573933 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 10 Sep 2019 19:11:58 -0500 Subject: [PATCH 1908/1995] soundwire: add support for sdw_slave_type In the existing SoundWire code, the bus does not have any explicit representation for Master Devices - only SoundWire Slaves are exposed. In SoundWire, the Master Device provides the clock, synchronization information and command/control channels. When multiple links are supported, a Controller may expose more than one Master Device; they are typically embedded inside a larger audio cluster (be it in an SOC/chipset or an external audio codec), and we need to describe it using the Linux device and driver model. This will allow for configuration functions to account for external dependencies such as power rails, clock sources or wake-up mechanisms. This transition will also allow for better sysfs support without the reference count issues mentioned in the initial reviews. In this patch, we first convert the existing code to use an explicit sdw_slave_type and add error checks if this type is not set. In follow-up patches we can add support for the sdw_master_type. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus_type.c | 23 ++++++++++++++++++----- drivers/soundwire/slave.c | 7 ++++++- include/linux/soundwire/sdw_type.h | 6 ++++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index 9a0fd3ee1014a7..9719680a1e4846 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -49,13 +49,26 @@ int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size) static int sdw_uevent(struct device *dev, struct kobj_uevent_env *env) { - struct sdw_slave *slave = to_sdw_slave_device(dev); + struct sdw_slave *slave; char modalias[32]; - sdw_slave_modalias(slave, modalias, sizeof(modalias)); - - if (add_uevent_var(env, "MODALIAS=%s", modalias)) - return -ENOMEM; + if (is_sdw_slave(dev)) { + slave = to_sdw_slave_device(dev); + + sdw_slave_modalias(slave, modalias, sizeof(modalias)); + + if (add_uevent_var(env, "MODALIAS=%s", modalias)) + return -ENOMEM; + } else { + /* + * We only need to handle uevents for the Slave device + * type. This error cannot happen unless the .uevent + * callback is set to use this function for a + * different device type (e.g. Master or Monitor) + */ + dev_err(dev, "uevent for unknown Soundwire type\n"); + return -EINVAL; + } return 0; } diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c index 48a513680db665..c87267f12a3b97 100644 --- a/drivers/soundwire/slave.c +++ b/drivers/soundwire/slave.c @@ -14,6 +14,11 @@ static void sdw_slave_release(struct device *dev) kfree(slave); } +struct device_type sdw_slave_type = { + .name = "sdw_slave", + .release = sdw_slave_release, +}; + static int sdw_slave_add(struct sdw_bus *bus, struct sdw_slave_id *id, struct fwnode_handle *fwnode) { @@ -41,9 +46,9 @@ static int sdw_slave_add(struct sdw_bus *bus, id->class_id, id->unique_id); } - slave->dev.release = sdw_slave_release; slave->dev.bus = &sdw_bus_type; slave->dev.of_node = of_node_get(to_of_node(fwnode)); + slave->dev.type = &sdw_slave_type; slave->bus = bus; slave->status = SDW_SLAVE_UNATTACHED; slave->dev_num = 0; diff --git a/include/linux/soundwire/sdw_type.h b/include/linux/soundwire/sdw_type.h index 7d4bc6a979bf6b..c681b3426478e7 100644 --- a/include/linux/soundwire/sdw_type.h +++ b/include/linux/soundwire/sdw_type.h @@ -5,6 +5,12 @@ #define __SOUNDWIRE_TYPES_H extern struct bus_type sdw_bus_type; +extern struct device_type sdw_slave_type; + +static inline int is_sdw_slave(const struct device *dev) +{ + return dev->type == &sdw_slave_type; +} #define to_sdw_slave_driver(_drv) \ container_of(_drv, struct sdw_driver, driver) From 23bd428b86b59586cb25cd8dba9a7b043e2cf0d3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 14 Nov 2019 10:37:04 -0600 Subject: [PATCH 1909/1995] soundwire: slave: move uevent handling to slave device level Currently the .uevent callback is set at the bus level. This is not necessary, we only really need to deal with uevents for the Slave device, so move the uevent handling at that level. Suggested-by: Vinod Koul Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.h | 2 ++ drivers/soundwire/bus_type.c | 3 +-- drivers/soundwire/slave.c | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h index cb482da914da94..be01a5f3d00bae 100644 --- a/drivers/soundwire/bus.h +++ b/drivers/soundwire/bus.h @@ -6,6 +6,8 @@ #define DEFAULT_BANK_SWITCH_TIMEOUT 3000 +int sdw_uevent(struct device *dev, struct kobj_uevent_env *env); + #if IS_ENABLED(CONFIG_ACPI) int sdw_acpi_find_slaves(struct sdw_bus *bus); #else diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index 9719680a1e4846..605bc7ae57a8ed 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -47,7 +47,7 @@ int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size) slave->id.mfg_id, slave->id.part_id); } -static int sdw_uevent(struct device *dev, struct kobj_uevent_env *env) +int sdw_uevent(struct device *dev, struct kobj_uevent_env *env) { struct sdw_slave *slave; char modalias[32]; @@ -76,7 +76,6 @@ static int sdw_uevent(struct device *dev, struct kobj_uevent_env *env) struct bus_type sdw_bus_type = { .name = "soundwire", .match = sdw_bus_match, - .uevent = sdw_uevent, }; EXPORT_SYMBOL_GPL(sdw_bus_type); diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c index c87267f12a3b97..014c3ece1f1768 100644 --- a/drivers/soundwire/slave.c +++ b/drivers/soundwire/slave.c @@ -17,6 +17,7 @@ static void sdw_slave_release(struct device *dev) struct device_type sdw_slave_type = { .name = "sdw_slave", .release = sdw_slave_release, + .uevent = sdw_uevent, }; static int sdw_slave_add(struct sdw_bus *bus, From 7c7a818a5dbc5d4d2ade8864602c711e49ceec87 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 10 Sep 2019 19:23:22 -0500 Subject: [PATCH 1910/1995] soundwire: add initial definitions for sdw_master_device Since we want an explicit support for the SoundWire Master device, add the definitions, following the Greybus example of a 'Host Device'. A parent (such as the Intel audio controller) would use sdw_md_add() to create the device, passing a driver as a parameter. The sdw_md_release() would be called when put_device() is invoked by the parent. We use the shortcut 'md' for 'master device' to avoid very long function names. The 'Master Device' driver exposes interfaces for probe/startup/shutdown/remove and a placeholder for autonomous clock stop support (when the bus control is handed over to a lower-power solution, typically in D0ix modes). Module namespace support is added in a separate patch. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/Makefile | 2 +- drivers/soundwire/bus_type.c | 5 ++- drivers/soundwire/master.c | 63 ++++++++++++++++++++++++++++++ include/linux/soundwire/sdw.h | 38 ++++++++++++++++++ include/linux/soundwire/sdw_type.h | 9 +++++ 5 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 drivers/soundwire/master.c diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile index 563894e5ecaf50..89b29819dd3ad8 100644 --- a/drivers/soundwire/Makefile +++ b/drivers/soundwire/Makefile @@ -4,7 +4,7 @@ # #Bus Objs -soundwire-bus-objs := bus_type.o bus.o slave.o mipi_disco.o stream.o +soundwire-bus-objs := bus_type.o bus.o master.o slave.o mipi_disco.o stream.o obj-$(CONFIG_SOUNDWIRE) += soundwire-bus.o ifdef CONFIG_DEBUG_FS diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index 605bc7ae57a8ed..2e4e8c2e629f46 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -66,7 +66,10 @@ int sdw_uevent(struct device *dev, struct kobj_uevent_env *env) * callback is set to use this function for a * different device type (e.g. Master or Monitor) */ - dev_err(dev, "uevent for unknown Soundwire type\n"); + if (is_sdw_master_device(dev)) + dev_err(dev, "uevent for SoundWire Master type\n"); + else + dev_err(dev, "uevent for unknown Soundwire type\n"); return -EINVAL; } diff --git a/drivers/soundwire/master.c b/drivers/soundwire/master.c new file mode 100644 index 00000000000000..b018c561708e99 --- /dev/null +++ b/drivers/soundwire/master.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: (GPL-2.0) +// Copyright(c) 2019 Intel Corporation. + +#include +#include +#include +#include +#include "bus.h" + +static void sdw_md_release(struct device *dev) +{ + struct sdw_master_device *md = to_sdw_master_device(dev); + + kfree(md); +} + +struct device_type sdw_md_type = { + .name = "soundwire_master", + .release = sdw_md_release, +}; + +struct sdw_master_device *sdw_md_add(struct sdw_md_driver *driver, + struct device *parent, + struct fwnode_handle *fwnode, + int link_id) +{ + struct sdw_master_device *md; + int ret; + + if (!driver->probe) { + dev_err(parent, "mandatory probe callback missing\n"); + return ERR_PTR(-EINVAL); + } + + md = kzalloc(sizeof(*md), GFP_KERNEL); + if (!md) + return ERR_PTR(-ENOMEM); + + md->link_id = link_id; + + md->driver = driver; + + md->dev.parent = parent; + md->dev.fwnode = fwnode; + md->dev.bus = &sdw_bus_type; + md->dev.type = &sdw_md_type; + md->dev.dma_mask = md->dev.parent->dma_mask; + dev_set_name(&md->dev, "sdw-master-%d", md->link_id); + + ret = device_register(&md->dev); + if (ret) { + dev_err(parent, "Failed to add master: ret %d\n", ret); + /* + * On err, don't free but drop ref as this will be freed + * when release method is invoked. + */ + put_device(&md->dev); + return ERR_PTR(-ENOMEM); + } + + return md; +} +EXPORT_SYMBOL_GPL(sdw_md_add); diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 5b1180f1e6b558..f73c355de5e5cb 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -585,6 +585,16 @@ struct sdw_slave { #define to_sdw_slave_device(d) \ container_of(d, struct sdw_slave, dev) +struct sdw_master_device { + struct device dev; + int link_id; + struct sdw_md_driver *driver; + void *pdata; +}; + +#define to_sdw_master_device(d) \ + container_of(d, struct sdw_master_device, dev) + struct sdw_driver { const char *name; @@ -599,6 +609,29 @@ struct sdw_driver { struct device_driver driver; }; +/** + * struct sdw_md_driver - SoundWire 'Master Device' driver + * + * @probe: initializations and allocation (hardware may not be enabled yet) + * @startup: initialization handled after the hardware is enabled, all + * clock/power dependencies are available + * @shutdown: cleanups before hardware is disabled (optional) + * @free: free all remaining resources + * @autonomous_clock_stop_enable: enable/disable driver control while + * in clock-stop mode, typically in always-on/D0ix modes. When the driver + * yields control, another entity in the system (typically firmware + * running on an always-on microprocessor) is responsible to tracking + * Slave-initiated wakes + */ +struct sdw_md_driver { + int (*probe)(struct sdw_master_device *md, void *link_ctx); + int (*startup)(struct sdw_master_device *md); + int (*shutdown)(struct sdw_master_device *md); + int (*remove)(struct sdw_master_device *md); + int (*autonomous_clock_stop_enable)(struct sdw_master_device *md, + bool state); +}; + #define SDW_SLAVE_ENTRY(_mfg_id, _part_id, _drv_data) \ { .mfg_id = (_mfg_id), .part_id = (_part_id), \ .driver_data = (unsigned long)(_drv_data) } @@ -788,6 +821,11 @@ struct sdw_bus { int sdw_add_bus_master(struct sdw_bus *bus); void sdw_delete_bus_master(struct sdw_bus *bus); +struct sdw_master_device *sdw_md_add(struct sdw_md_driver *driver, + struct device *parent, + struct fwnode_handle *fwnode, + int link_id); + /** * sdw_port_config: Master or Slave Port configuration * diff --git a/include/linux/soundwire/sdw_type.h b/include/linux/soundwire/sdw_type.h index c681b3426478e7..a2a5ea7843a68d 100644 --- a/include/linux/soundwire/sdw_type.h +++ b/include/linux/soundwire/sdw_type.h @@ -6,15 +6,24 @@ extern struct bus_type sdw_bus_type; extern struct device_type sdw_slave_type; +extern struct device_type sdw_md_type; static inline int is_sdw_slave(const struct device *dev) { return dev->type == &sdw_slave_type; } +static inline int is_sdw_master_device(const struct device *dev) +{ + return dev->type == &sdw_md_type; +} + #define to_sdw_slave_driver(_drv) \ container_of(_drv, struct sdw_driver, driver) +#define to_sdw_md_driver(_drv) \ + container_of(_drv, struct sdw_md_driver, driver) + #define sdw_register_slave_driver(drv) \ __sdw_register_slave_driver(drv, THIS_MODULE) From 73e79a2f0976bce13372588728c0174005e9e805 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 23 Oct 2019 12:12:51 -0500 Subject: [PATCH 1911/1995] soundwire: intel: remove platform devices and use 'Master Devices' instead Use sdw_master_device and driver instead of platform devices To quote GregKH: "Don't mess with a platform device unless you really have no other possible choice. And even then, don't do it and try to do something else. Platform devices are really abused, don't perpetuate it " In addition, rather than a plain-vanilla init/exit, this patch provides 3 steps in the initialization (ACPI scan, probe, startup) which makes it easier to verify hardware support for SoundWire, allocate required resources as early as possible, and conversely help make the startup() callback lighter-weight with only hardware register setup. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 91 ++++++----- drivers/soundwire/intel.h | 8 +- drivers/soundwire/intel_init.c | 275 ++++++++++++++++++++++++--------- 3 files changed, 267 insertions(+), 107 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 64f97bb1a13573..36dbcbab0d65d6 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -92,8 +92,6 @@ #define SDW_ALH_STRMZCFG_DMAT GENMASK(7, 0) #define SDW_ALH_STRMZCFG_CHN GENMASK(19, 16) -#define SDW_INTEL_QUIRK_MASK_BUS_DISABLE BIT(1) - enum intel_pdi_type { INTEL_PDI_IN = 0, INTEL_PDI_OUT = 1, @@ -923,24 +921,23 @@ static int intel_init(struct sdw_intel *sdw) /* * probe and init */ -static int intel_probe(struct platform_device *pdev) +static int intel_master_probe(struct sdw_master_device *md, void *link_ctx) { - struct sdw_cdns_stream_config config; struct sdw_intel *sdw; int ret; - sdw = devm_kzalloc(&pdev->dev, sizeof(*sdw), GFP_KERNEL); + sdw = devm_kzalloc(&md->dev, sizeof(*sdw), GFP_KERNEL); if (!sdw) return -ENOMEM; - sdw->instance = pdev->id; - sdw->link_res = dev_get_platdata(&pdev->dev); - sdw->cdns.dev = &pdev->dev; + sdw->instance = md->link_id; + sdw->link_res = link_ctx; + sdw->cdns.dev = &md->dev; sdw->cdns.registers = sdw->link_res->registers; - sdw->cdns.instance = sdw->instance; + sdw->cdns.instance = md->link_id; sdw->cdns.msg_count = 0; - sdw->cdns.bus.dev = &pdev->dev; - sdw->cdns.bus.link_id = pdev->id; + sdw->cdns.bus.dev = &md->dev; + sdw->cdns.bus.link_id = md->link_id; sdw_cdns_probe(&sdw->cdns); @@ -948,16 +945,50 @@ static int intel_probe(struct platform_device *pdev) sdw_intel_ops.read_prop = intel_prop_read; sdw->cdns.bus.ops = &sdw_intel_ops; - platform_set_drvdata(pdev, sdw); + md->pdata = sdw; + + /* set driver data, accessed by snd_soc_dai_set_drvdata() */ + dev_set_drvdata(&md->dev, &sdw->cdns); ret = sdw_add_bus_master(&sdw->cdns.bus); if (ret) { - dev_err(&pdev->dev, "sdw_add_bus_master fail: %d\n", ret); + dev_err(&md->dev, "sdw_add_bus_master fail: %d\n", ret); return ret; } if (sdw->cdns.bus.prop.hw_disabled) { - dev_info(&pdev->dev, "SoundWire master %d is disabled, ignoring\n", + dev_info(&md->dev, "SoundWire master %d is disabled, ignoring\n", + sdw->cdns.bus.link_id); + return 0; + } + + /* Acquire IRQ */ + ret = request_threaded_irq(sdw->link_res->irq, + sdw_cdns_irq, sdw_cdns_thread, + IRQF_SHARED, KBUILD_MODNAME, &sdw->cdns); + if (ret < 0) { + dev_err(sdw->cdns.dev, "unable to grab IRQ %d, disabling device\n", + sdw->link_res->irq); + goto err_init; + } + + return 0; + +err_init: + sdw_delete_bus_master(&sdw->cdns.bus); + return ret; +} + +static int intel_master_startup(struct sdw_master_device *md) +{ + struct sdw_cdns_stream_config config; + struct sdw_intel *sdw; + int ret; + + sdw = md->pdata; + + if (sdw->cdns.bus.prop.hw_disabled) { + dev_info(&md->dev, "SoundWire master %d is disabled, ignoring\n", sdw->cdns.bus.link_id); return 0; } @@ -975,16 +1006,6 @@ static int intel_probe(struct platform_device *pdev) intel_pdi_ch_update(sdw); - /* Acquire IRQ */ - ret = request_threaded_irq(sdw->link_res->irq, - sdw_cdns_irq, sdw_cdns_thread, - IRQF_SHARED, KBUILD_MODNAME, &sdw->cdns); - if (ret < 0) { - dev_err(sdw->cdns.dev, "unable to grab IRQ %d, disabling device\n", - sdw->link_res->irq); - goto err_init; - } - ret = sdw_cdns_enable_interrupt(&sdw->cdns, true); if (ret < 0) { dev_err(sdw->cdns.dev, "cannot enable interrupts\n"); @@ -1011,17 +1032,17 @@ static int intel_probe(struct platform_device *pdev) err_interrupt: sdw_cdns_enable_interrupt(&sdw->cdns, false); - free_irq(sdw->link_res->irq, sdw); err_init: + free_irq(sdw->link_res->irq, sdw); sdw_delete_bus_master(&sdw->cdns.bus); return ret; } -static int intel_remove(struct platform_device *pdev) +static int intel_master_remove(struct sdw_master_device *md) { struct sdw_intel *sdw; - sdw = platform_get_drvdata(pdev); + sdw = md->pdata; if (!sdw->cdns.bus.prop.hw_disabled) { intel_debugfs_exit(sdw); @@ -1031,19 +1052,17 @@ static int intel_remove(struct platform_device *pdev) } sdw_delete_bus_master(&sdw->cdns.bus); + device_unregister(&md->dev); + return 0; } -static struct platform_driver sdw_intel_drv = { - .probe = intel_probe, - .remove = intel_remove, - .driver = { - .name = "int-sdw", - - }, +struct sdw_md_driver intel_sdw_driver = { + .probe = intel_master_probe, + .startup = intel_master_startup, + .remove = intel_master_remove, }; - -module_platform_driver(sdw_intel_drv); +EXPORT_SYMBOL(intel_sdw_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS("platform:int-sdw"); diff --git a/drivers/soundwire/intel.h b/drivers/soundwire/intel.h index 38b7c125fb1052..cfab2f00214d25 100644 --- a/drivers/soundwire/intel.h +++ b/drivers/soundwire/intel.h @@ -7,7 +7,7 @@ /** * struct sdw_intel_link_res - Soundwire Intel link resource structure, * typically populated by the controller driver. - * @pdev: platform_device + * @md: master device * @mmio_base: mmio base of SoundWire registers * @registers: Link IO registers base * @shim: Audio shim pointer @@ -17,7 +17,7 @@ * @dev: device implementing hw_params and free callbacks */ struct sdw_intel_link_res { - struct platform_device *pdev; + struct sdw_master_device *md; void __iomem *mmio_base; /* not strictly needed, useful for debug */ void __iomem *registers; void __iomem *shim; @@ -27,4 +27,8 @@ struct sdw_intel_link_res { struct device *dev; }; +#define SDW_INTEL_QUIRK_MASK_BUS_DISABLE BIT(1) + +extern struct sdw_md_driver intel_sdw_driver; + #endif /* __SDW_INTEL_LOCAL_H */ diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 4b769409f6f849..42f7ae034beabf 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include "intel.h" @@ -23,22 +23,47 @@ #define SDW_LINK_BASE 0x30000 #define SDW_LINK_SIZE 0x10000 -static int link_mask; -module_param_named(sdw_link_mask, link_mask, int, 0444); +static int ctrl_link_mask; +module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444); MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)"); -static int sdw_intel_cleanup_pdev(struct sdw_intel_ctx *ctx) +static bool is_link_enabled(struct fwnode_handle *fw_node, int i) +{ + struct fwnode_handle *link; + char name[32]; + u32 quirk_mask = 0; + + /* Find master handle */ + snprintf(name, sizeof(name), + "mipi-sdw-link-%d-subproperties", i); + + link = fwnode_get_named_child_node(fw_node, name); + if (!link) + return false; + + fwnode_property_read_u32(link, + "intel-quirk-mask", + &quirk_mask); + + if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE) + return false; + + return true; +} + +static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx) { struct sdw_intel_link_res *link = ctx->links; + struct sdw_master_device *md; int i; if (!link) return 0; - for (i = 0; i < ctx->count; i++) { - if (link->pdev) - platform_device_unregister(link->pdev); - link++; + for (i = 0; i < ctx->count; i++, link++) { + md = link->md; + if (md) + md->driver->remove(md); } kfree(ctx->links); @@ -47,112 +72,194 @@ static int sdw_intel_cleanup_pdev(struct sdw_intel_ctx *ctx) return 0; } -static struct sdw_intel_ctx -*sdw_intel_add_controller(struct sdw_intel_res *res) +static int +sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) { - struct platform_device_info pdevinfo; - struct platform_device *pdev; - struct sdw_intel_link_res *link; - struct sdw_intel_ctx *ctx; struct acpi_device *adev; int ret, i; u8 count; - u32 caps; - if (acpi_bus_get_device(res->handle, &adev)) - return NULL; + if (acpi_bus_get_device(info->handle, &adev)) + return -EINVAL; /* Found controller, find links supported */ count = 0; ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev), "mipi-sdw-master-count", &count, 1); - /* Don't fail on error, continue and use hw value */ + /* + * In theory we could check the number of links supported in + * hardware, but in that step we cannot assume SoundWire IP is + * powered. + * + * In addition, if the BIOS doesn't even provide this + * 'master-count' property then all the inits based on link + * masks will fail as well. + * + * We will check the hardware capabilities in the startup() step + */ + if (ret) { dev_err(&adev->dev, "Failed to read mipi-sdw-master-count: %d\n", ret); - count = SDW_MAX_LINKS; + return -EINVAL; } - /* Check SNDWLCAP.LCOUNT */ - caps = ioread32(res->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP); - caps &= GENMASK(2, 0); - - /* Check HW supported vs property value and use min of two */ - count = min_t(u8, caps, count); - /* Check count is within bounds */ if (count > SDW_MAX_LINKS) { dev_err(&adev->dev, "Link count %d exceeds max %d\n", count, SDW_MAX_LINKS); - return NULL; + return -EINVAL; } else if (!count) { dev_warn(&adev->dev, "No SoundWire links detected\n"); - return NULL; + return -EINVAL; } + dev_dbg(&adev->dev, "ACPI reports %d SDW Link devices\n", count); + + info->count = count; + for (i = 0; i < count; i++) { + if (ctrl_link_mask && !(ctrl_link_mask & BIT(i))) { + dev_dbg(&adev->dev, + "Link %d masked, will not be enabled\n", i); + continue; + } + + if (!is_link_enabled(acpi_fwnode_handle(adev), i)) { + dev_dbg(&adev->dev, + "Link %d not selected in firmware\n", i); + continue; + } + + info->link_mask |= BIT(i); + } + + return 0; +} + +static struct sdw_intel_ctx +*sdw_intel_probe_controller(struct sdw_intel_res *res) +{ + struct sdw_intel_link_res *link; + struct sdw_intel_ctx *ctx; + struct acpi_device *adev; + struct sdw_master_device *md; + u32 link_mask; + int count; + int i; + + if (!res) + return NULL; + + if (acpi_bus_get_device(res->handle, &adev)) + return NULL; + + if (!res->count) + return NULL; + + count = res->count; dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count); ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return NULL; - ctx->count = count; - ctx->links = kcalloc(ctx->count, sizeof(*ctx->links), GFP_KERNEL); + ctx->links = kcalloc(count, sizeof(*ctx->links), GFP_KERNEL); if (!ctx->links) goto link_err; + ctx->count = count; + ctx->mmio_base = res->mmio_base; + ctx->link_mask = res->link_mask; + ctx->handle = res->handle; + link = ctx->links; + link_mask = ctx->link_mask; /* Create SDW Master devices */ - for (i = 0; i < count; i++) { - if (link_mask && !(link_mask & BIT(i))) { - dev_dbg(&adev->dev, - "Link %d masked, will not be enabled\n", i); - link++; + for (i = 0; i < count; i++, link++) { + if (link_mask && !(link_mask & BIT(i))) continue; - } + md = sdw_md_add(&intel_sdw_driver, + res->parent, + acpi_fwnode_handle(adev), + i); + + if (IS_ERR(md)) { + dev_err(&adev->dev, "Could not create link %d\n", i); + goto err; + } + link->md = md; + link->mmio_base = res->mmio_base; link->registers = res->mmio_base + SDW_LINK_BASE - + (SDW_LINK_SIZE * i); + + (SDW_LINK_SIZE * i); link->shim = res->mmio_base + SDW_SHIM_BASE; link->alh = res->mmio_base + SDW_ALH_BASE; - + link->irq = res->irq; link->ops = res->ops; link->dev = res->dev; - memset(&pdevinfo, 0, sizeof(pdevinfo)); - - pdevinfo.parent = res->parent; - pdevinfo.name = "int-sdw"; - pdevinfo.id = i; - pdevinfo.fwnode = acpi_fwnode_handle(adev); - - pdev = platform_device_register_full(&pdevinfo); - if (IS_ERR(pdev)) { - dev_err(&adev->dev, - "platform device creation failed: %ld\n", - PTR_ERR(pdev)); - goto pdev_err; - } - - link->pdev = pdev; - link++; + /* let the SoundWire master driver to its probe */ + md->driver->probe(md, link); } return ctx; -pdev_err: - sdw_intel_cleanup_pdev(ctx); +err: + sdw_intel_cleanup(ctx); link_err: kfree(ctx); return NULL; } +static int +sdw_intel_startup_controller(struct sdw_intel_ctx *ctx) +{ + struct acpi_device *adev; + struct sdw_intel_link_res *link; + struct sdw_master_device *md; + u32 caps; + u32 link_mask; + int i; + + if (acpi_bus_get_device(ctx->handle, &adev)) + return -EINVAL; + + /* Check SNDWLCAP.LCOUNT */ + caps = ioread32(ctx->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP); + caps &= GENMASK(2, 0); + + /* Check HW supported vs property value */ + if (caps < ctx->count) { + dev_err(&adev->dev, + "BIOS master count is larger than hardware capabilities\n"); + return -EINVAL; + } + + if (!ctx->links) + return -EINVAL; + + link = ctx->links; + link_mask = ctx->link_mask; + + /* Create SDW Master devices */ + for (i = 0; i < ctx->count; i++, link++) { + if (link_mask && !(link_mask & BIT(i))) + continue; + + md = link->md; + + md->driver->startup(md); + } + + return 0; +} + static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, void *cdata, void **return_value) { - struct sdw_intel_res *res = cdata; + struct sdw_intel_acpi_info *info = cdata; struct acpi_device *adev; acpi_status status; u64 adr; @@ -166,7 +273,7 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, return AE_NOT_FOUND; } - res->handle = handle; + info->handle = handle; /* * On some Intel platforms, multiple children of the HDAS @@ -183,36 +290,66 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, } /** - * sdw_intel_init() - SoundWire Intel init routine + * sdw_intel_acpi_scan() - SoundWire Intel init routine * @parent_handle: ACPI parent handle - * @res: resource data + * @info: description of what firmware/DSDT tables expose * - * This scans the namespace and creates SoundWire link controller devices - * based on the info queried. + * This scans the namespace and queries firmware to figure out which + * links to enable. A follow-up use of sdw_intel_probe() and + * sdw_intel_startup() is required for creation of devices and bus + * startup */ -void *sdw_intel_init(acpi_handle *parent_handle, struct sdw_intel_res *res) +int sdw_intel_acpi_scan(acpi_handle *parent_handle, + struct sdw_intel_acpi_info *info) { acpi_status status; status = acpi_walk_namespace(ACPI_TYPE_DEVICE, parent_handle, 1, sdw_intel_acpi_cb, - NULL, res, NULL); + NULL, info, NULL); if (ACPI_FAILURE(status)) - return NULL; + return -ENODEV; - return sdw_intel_add_controller(res); + return sdw_intel_scan_controller(info); } +EXPORT_SYMBOL(sdw_intel_acpi_scan); +/** + * sdw_intel_probe() - SoundWire Intel probe routine + * @parent_handle: ACPI parent handle + * @res: resource data + * + * This creates SoundWire Master and Slave devices below the controller. + * All the information necessary is stored in the context, and the res + * argument pointer can be freed after this step. + */ +struct sdw_intel_ctx +*sdw_intel_probe(struct sdw_intel_res *res) +{ + return sdw_intel_probe_controller(res); +} +EXPORT_SYMBOL(sdw_intel_probe); + +/** + * sdw_intel_startup() - SoundWire Intel startup + * @ctx: SoundWire context allocated in the probe + * + */ +int sdw_intel_startup(struct sdw_intel_ctx *ctx) +{ + return sdw_intel_startup_controller(ctx); +} +EXPORT_SYMBOL(sdw_intel_startup); /** * sdw_intel_exit() - SoundWire Intel exit - * @arg: callback context + * @ctx: SoundWire context allocated in the probe * * Delete the controller instances created and cleanup */ void sdw_intel_exit(struct sdw_intel_ctx *ctx) { - sdw_intel_cleanup_pdev(ctx); + sdw_intel_cleanup(ctx); kfree(ctx); } EXPORT_SYMBOL(sdw_intel_exit); From 6692e49e10968dd3c277bb34ca80deabd13d1c55 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 12 Sep 2019 17:35:48 +0800 Subject: [PATCH 1912/1995] soundwire: register master device driver While we don't have a matching function, setting an device driver is still necessary for ASoC to register DAI components as well as power management. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 6 ++++++ drivers/soundwire/intel_init.c | 10 ++++++++++ drivers/soundwire/master.c | 1 + include/linux/soundwire/sdw.h | 1 + 4 files changed, 18 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 36dbcbab0d65d6..29ebdb07e6228d 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "cadence_master.h" #include "bus.h" #include "intel.h" @@ -1058,6 +1059,11 @@ static int intel_master_remove(struct sdw_master_device *md) } struct sdw_md_driver intel_sdw_driver = { + .driver = { + .name = "intel-sdw", + .owner = THIS_MODULE, + .bus = &sdw_bus_type, + }, .probe = intel_master_probe, .startup = intel_master_startup, .remove = intel_master_remove, diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 42f7ae034beabf..a30d95ee71b745 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -146,6 +146,7 @@ static struct sdw_intel_ctx struct sdw_master_device *md; u32 link_mask; int count; + int err; int i; if (!res) @@ -176,6 +177,12 @@ static struct sdw_intel_ctx link = ctx->links; link_mask = ctx->link_mask; + err = driver_register(&intel_sdw_driver.driver); + if (err) { + dev_err(&adev->dev, "failed to register sdw master driver\n"); + goto register_err; + } + /* Create SDW Master devices */ for (i = 0; i < count; i++, link++) { if (link_mask && !(link_mask & BIT(i))) @@ -209,6 +216,8 @@ static struct sdw_intel_ctx err: sdw_intel_cleanup(ctx); link_err: + driver_unregister(&intel_sdw_driver.driver); +register_err: kfree(ctx); return NULL; } @@ -350,6 +359,7 @@ EXPORT_SYMBOL(sdw_intel_startup); void sdw_intel_exit(struct sdw_intel_ctx *ctx) { sdw_intel_cleanup(ctx); + driver_unregister(&intel_sdw_driver.driver); kfree(ctx); } EXPORT_SYMBOL(sdw_intel_exit); diff --git a/drivers/soundwire/master.c b/drivers/soundwire/master.c index b018c561708e99..1c6bb293468cde 100644 --- a/drivers/soundwire/master.c +++ b/drivers/soundwire/master.c @@ -46,6 +46,7 @@ struct sdw_master_device *sdw_md_add(struct sdw_md_driver *driver, md->dev.type = &sdw_md_type; md->dev.dma_mask = md->dev.parent->dma_mask; dev_set_name(&md->dev, "sdw-master-%d", md->link_id); + md->dev.driver = &driver->driver; ret = device_register(&md->dev); if (ret) { diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index f73c355de5e5cb..58f50257dfa8d1 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -630,6 +630,7 @@ struct sdw_md_driver { int (*remove)(struct sdw_master_device *md); int (*autonomous_clock_stop_enable)(struct sdw_master_device *md, bool state); + struct device_driver driver; }; #define SDW_SLAVE_ENTRY(_mfg_id, _part_id, _drv_data) \ From afac897f2f438de0c04e9b0ae5143e68eafdc3f0 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 19 Aug 2019 16:43:06 +0800 Subject: [PATCH 1913/1995] soundwire: intel: add prepare support in sdw dai driver The existing code does not expose a prepare operation, which is very much needed to deal with underflow and resume operations. Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 29ebdb07e6228d..689eb350f15e26 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -698,6 +698,21 @@ static int intel_hw_params(struct snd_pcm_substream *substream, return ret; } +static int intel_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sdw_cdns_dma_data *dma; + + dma = snd_soc_dai_get_dma_data(dai, substream); + if (!dma) { + dev_err(dai->dev, "failed to get dma data in %s", + __func__); + return -EIO; + } + + return sdw_prepare_stream(dma->stream); +} + static int intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -744,6 +759,7 @@ static int intel_pdm_set_sdw_stream(struct snd_soc_dai *dai, static const struct snd_soc_dai_ops intel_pcm_dai_ops = { .hw_params = intel_hw_params, + .prepare = intel_prepare, .hw_free = intel_hw_free, .shutdown = intel_shutdown, .set_sdw_stream = intel_pcm_set_sdw_stream, @@ -751,6 +767,7 @@ static const struct snd_soc_dai_ops intel_pcm_dai_ops = { static const struct snd_soc_dai_ops intel_pdm_dai_ops = { .hw_params = intel_hw_params, + .prepare = intel_prepare, .hw_free = intel_hw_free, .shutdown = intel_shutdown, .set_sdw_stream = intel_pdm_set_sdw_stream, From f8c96ca5a63dae8c7f17295114932b7178b894c3 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 19 Aug 2019 16:48:46 +0800 Subject: [PATCH 1914/1995] soundwire: intel: add trigger support in sdw dai driver The existing code does not expose a trigger callback, which is very much required for streaming. The SoundWire stream is enabled and disabled in trigger function. Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 689eb350f15e26..4ff15327fbd758 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -713,6 +713,43 @@ static int intel_prepare(struct snd_pcm_substream *substream, return sdw_prepare_stream(dma->stream); } +static int intel_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct sdw_cdns_dma_data *dma; + int ret; + + dma = snd_soc_dai_get_dma_data(dai, substream); + if (!dma) { + dev_err(dai->dev, "failed to get dma data in %s", __func__); + return -EIO; + } + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + ret = sdw_enable_stream(dma->stream); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + ret = sdw_disable_stream(dma->stream); + break; + + default: + ret = -EINVAL; + break; + } + + if (ret) + dev_err(dai->dev, + "%s trigger %d failed: %d", + __func__, cmd, ret); + return ret; +} + static int intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -760,6 +797,7 @@ static int intel_pdm_set_sdw_stream(struct snd_soc_dai *dai, static const struct snd_soc_dai_ops intel_pcm_dai_ops = { .hw_params = intel_hw_params, .prepare = intel_prepare, + .trigger = intel_trigger, .hw_free = intel_hw_free, .shutdown = intel_shutdown, .set_sdw_stream = intel_pcm_set_sdw_stream, @@ -768,6 +806,7 @@ static const struct snd_soc_dai_ops intel_pcm_dai_ops = { static const struct snd_soc_dai_ops intel_pdm_dai_ops = { .hw_params = intel_hw_params, .prepare = intel_prepare, + .trigger = intel_trigger, .hw_free = intel_hw_free, .shutdown = intel_shutdown, .set_sdw_stream = intel_pdm_set_sdw_stream, From 807e97bfd374b794e80f4f565558b9c694fa54ed Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 19 Aug 2019 16:55:01 +0800 Subject: [PATCH 1915/1995] soundwire: intel: add sdw_stream_setup helper for .startup callback The sdw stream is allocated and stored in dai to share the sdw runtime information. Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 65 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 4ff15327fbd758..b4a9337b64d236 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -616,6 +616,69 @@ static int intel_post_bank_switch(struct sdw_bus *bus) * DAI routines */ +static int sdw_stream_setup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sdw_stream_runtime *sdw_stream = NULL; + char *name; + int i, ret; + + name = kzalloc(32, GFP_KERNEL); + if (!name) + return -ENOMEM; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snprintf(name, 32, "%s-Playback", dai->name); + else + snprintf(name, 32, "%s-Capture", dai->name); + + sdw_stream = sdw_alloc_stream(name); + if (!sdw_stream) { + dev_err(dai->dev, "alloc stream failed for DAI %s", dai->name); + ret = -ENOMEM; + goto error; + } + + /* Set stream pointer on CPU DAI */ + ret = snd_soc_dai_set_sdw_stream(dai, sdw_stream, substream->stream); + if (ret < 0) { + dev_err(dai->dev, "failed to set stream pointer on cpu dai %s", + dai->name); + goto release_stream; + } + + /* Set stream pointer on all CODEC DAIs */ + for (i = 0; i < rtd->num_codecs; i++) { + ret = snd_soc_dai_set_sdw_stream(rtd->codec_dais[i], sdw_stream, + substream->stream); + if (ret < 0) { + dev_err(dai->dev, "failed to set stream pointer on codec dai %s", + rtd->codec_dais[i]->name); + goto release_stream; + } + } + + return 0; + +release_stream: + sdw_release_stream(sdw_stream); +error: + kfree(name); + return ret; +} + +static int intel_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + /* + * TODO: add pm_runtime support here, the startup callback + * will make sure the IP is 'active' + */ + + return sdw_stream_setup(substream, dai); +} + static int intel_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -795,6 +858,7 @@ static int intel_pdm_set_sdw_stream(struct snd_soc_dai *dai, } static const struct snd_soc_dai_ops intel_pcm_dai_ops = { + .startup = intel_startup, .hw_params = intel_hw_params, .prepare = intel_prepare, .trigger = intel_trigger, @@ -804,6 +868,7 @@ static const struct snd_soc_dai_ops intel_pcm_dai_ops = { }; static const struct snd_soc_dai_ops intel_pdm_dai_ops = { + .startup = intel_startup, .hw_params = intel_hw_params, .prepare = intel_prepare, .trigger = intel_trigger, From 0a913366b1a714a70d17b6d4545b16a9db7bcebd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 23 Oct 2019 14:05:33 -0500 Subject: [PATCH 1916/1995] soundwire: intel: free all resources on hw_free() Make sure all calls to the SoundWire stream API are done and involve callback Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 40 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index b4a9337b64d236..0e77df0a776027 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -549,6 +549,25 @@ static int intel_params_stream(struct sdw_intel *sdw, return -EIO; } +static int intel_free_stream(struct sdw_intel *sdw, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai, + int link_id) +{ + struct sdw_intel_link_res *res = sdw->link_res; + struct sdw_intel_stream_free_data free_data; + + free_data.substream = substream; + free_data.dai = dai; + free_data.link_id = link_id; + + if (res->ops && res->ops->free_stream && res->dev) + return res->ops->free_stream(res->dev, + &free_data); + + return 0; +} + /* * bank switch routines */ @@ -817,6 +836,7 @@ static int intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); + struct sdw_intel *sdw = cdns_to_intel(cdns); struct sdw_cdns_dma_data *dma; int ret; @@ -824,12 +844,28 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) if (!dma) return -EIO; + ret = sdw_deprepare_stream(dma->stream); + if (ret) { + dev_err(dai->dev, "sdw_deprepare_stream: failed %d", ret); + return ret; + } + ret = sdw_stream_remove_master(&cdns->bus, dma->stream); - if (ret < 0) + if (ret < 0) { dev_err(dai->dev, "remove master from stream %s failed: %d\n", dma->stream->name, ret); + return ret; + } - return ret; + ret = intel_free_stream(sdw, substream, dai, sdw->instance); + if (ret < 0) { + dev_err(dai->dev, "intel_free_stream: failed %d", ret); + return ret; + } + + sdw_release_stream(dma->stream); + + return 0; } static void intel_shutdown(struct snd_pcm_substream *substream, From a923434dc7f18a354aa62f4ab72aa44e1044911b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 23 Oct 2019 14:38:00 -0500 Subject: [PATCH 1917/1995] soundwire: intel_init: add implementation of sdw_intel_enable_irq() This function is required to enable all interrupts across all links. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel_init.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index a30d95ee71b745..391e8763638f39 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -137,6 +137,30 @@ sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) return 0; } +#define HDA_DSP_REG_ADSPIC2 (0x10) +#define HDA_DSP_REG_ADSPIS2 (0x14) +#define HDA_DSP_REG_ADSPIC2_SNDW BIT(5) + +/** + * sdw_intel_enable_irq() - enable/disable Intel SoundWire IRQ + * @mmio_base: The mmio base of the control register + * @enable: true if enable + */ +void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable) +{ + u32 val; + + val = readl(mmio_base + HDA_DSP_REG_ADSPIC2); + + if (enable) + val |= HDA_DSP_REG_ADSPIC2_SNDW; + else + val &= ~HDA_DSP_REG_ADSPIC2_SNDW; + + writel(val, mmio_base + HDA_DSP_REG_ADSPIC2); +} +EXPORT_SYMBOL(sdw_intel_enable_irq); + static struct sdw_intel_ctx *sdw_intel_probe_controller(struct sdw_intel_res *res) { From 29be0fbc4d737540df373eb6a9966970f857550b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 16 Dec 2019 12:31:18 -0600 Subject: [PATCH 1918/1995] soundwire: intel_init: use EXPORT_SYMBOL_NS Make sure all symbols in this soundwire-intel-init module are exported with a namespace. The MODULE_IMPORT_NS will be used in Intel/SOF HDaudio modules to be posted in a separate series. Namespaces are only introduced for the Intel parts of the SoundWire code at this time, in future patches we should also add namespaces for Cadence parts and the SoundWire core. Suggested-by: Greg KH Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel_init.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 391e8763638f39..0f83907e1bc7b3 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -159,7 +159,7 @@ void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable) writel(val, mmio_base + HDA_DSP_REG_ADSPIC2); } -EXPORT_SYMBOL(sdw_intel_enable_irq); +EXPORT_SYMBOL_NS(sdw_intel_enable_irq, SOUNDWIRE_INTEL_INIT); static struct sdw_intel_ctx *sdw_intel_probe_controller(struct sdw_intel_res *res) @@ -346,7 +346,7 @@ int sdw_intel_acpi_scan(acpi_handle *parent_handle, return sdw_intel_scan_controller(info); } -EXPORT_SYMBOL(sdw_intel_acpi_scan); +EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, SOUNDWIRE_INTEL_INIT); /** * sdw_intel_probe() - SoundWire Intel probe routine @@ -362,7 +362,7 @@ struct sdw_intel_ctx { return sdw_intel_probe_controller(res); } -EXPORT_SYMBOL(sdw_intel_probe); +EXPORT_SYMBOL_NS(sdw_intel_probe, SOUNDWIRE_INTEL_INIT); /** * sdw_intel_startup() - SoundWire Intel startup @@ -373,7 +373,7 @@ int sdw_intel_startup(struct sdw_intel_ctx *ctx) { return sdw_intel_startup_controller(ctx); } -EXPORT_SYMBOL(sdw_intel_startup); +EXPORT_SYMBOL_NS(sdw_intel_startup, SOUNDWIRE_INTEL_INIT); /** * sdw_intel_exit() - SoundWire Intel exit * @ctx: SoundWire context allocated in the probe @@ -386,7 +386,7 @@ void sdw_intel_exit(struct sdw_intel_ctx *ctx) driver_unregister(&intel_sdw_driver.driver); kfree(ctx); } -EXPORT_SYMBOL(sdw_intel_exit); +EXPORT_SYMBOL_NS(sdw_intel_exit, SOUNDWIRE_INTEL_INIT); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("Intel Soundwire Init Library"); From 98905b8875452d89499fecc9eb57b8750c00588e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 16 Dec 2019 14:00:21 -0600 Subject: [PATCH 1919/1995] soundwire: intel: use EXPORT_SYMBOL_NS The soundwire-intel module exports an 'intel_sdw_driver' structure, which is declared with a namespace explicitly imported by the soundwire-intel-init module. The use of namespaces might be deemed overkill here, but it did help enforce a proper code partitioning for follow-up patches on clock-stop support. Suggested-by: Greg KH Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 2 +- drivers/soundwire/intel_init.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 0e77df0a776027..c24b5f30789d5d 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1225,7 +1225,7 @@ struct sdw_md_driver intel_sdw_driver = { .startup = intel_master_startup, .remove = intel_master_remove, }; -EXPORT_SYMBOL(intel_sdw_driver); +EXPORT_SYMBOL_NS(intel_sdw_driver, SOUNDWIRE_INTEL); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS("platform:int-sdw"); diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 0f83907e1bc7b3..0acb92a3c6d196 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -390,3 +390,4 @@ EXPORT_SYMBOL_NS(sdw_intel_exit, SOUNDWIRE_INTEL_INIT); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("Intel Soundwire Init Library"); +MODULE_IMPORT_NS(SOUNDWIRE_INTEL); From 96ccc29008c58c59c5563bfb7466ae704a4e3c91 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 24 Sep 2019 16:16:46 +0800 Subject: [PATCH 1920/1995] soundwire: intel/cadence: merge Soundwire interrupt handlers/threads The existing code uses one pair of interrupt handler/thread per link but at the hardware level the interrupt is shared. This works fine for legacy PCI interrupts, but leads to timeouts in MSI (Message-Signaled Interrupt) mode, likely due to edges being lost. This patch unifies interrupt handling for all links. The dedicated handler is removed since we use a common one for all shared interrupt sources, and the thread function takes care of dealing with interrupt sources. This partition follows the model used for the SOF IPC on HDaudio platforms, where similar timeout issues were noticed and doing all the interrupt handling/clearing in the thread improved reliability/stability. Validation results with 4 links active in parallel show a night-and-day improvement with no timeouts noticed even during stress tests. Latency and quality of service are not affected by the change - mostly because events on a SoundWire link are throttled by the bus frame rate (typically 8..48kHz). Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/cadence_master.c | 17 +++++++++-------- drivers/soundwire/cadence_master.h | 4 ++++ drivers/soundwire/intel.c | 27 ++++++--------------------- drivers/soundwire/intel.h | 2 ++ drivers/soundwire/intel_init.c | 20 +++++++++++++++++++- 5 files changed, 40 insertions(+), 30 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index fed21e2b22774d..362fb6e49bfe09 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "bus.h" #include "cadence_master.h" @@ -745,7 +746,7 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id) CDNS_MCP_INT_SLAVE_MASK, 0); int_status &= ~CDNS_MCP_INT_SLAVE_MASK; - ret = IRQ_WAKE_THREAD; + schedule_work(&cdns->work); } cdns_writel(cdns, CDNS_MCP_INTSTAT, int_status); @@ -754,13 +755,14 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id) EXPORT_SYMBOL(sdw_cdns_irq); /** - * sdw_cdns_thread() - Cadence irq thread handler - * @irq: irq number - * @dev_id: irq context + * To update slave status in a work since we will need to handle + * other interrupts eg. CDNS_MCP_INT_RX_WL during the update slave + * process. */ -irqreturn_t sdw_cdns_thread(int irq, void *dev_id) +static void cdns_update_slave_status_work(struct work_struct *work) { - struct sdw_cdns *cdns = dev_id; + struct sdw_cdns *cdns = + container_of(work, struct sdw_cdns, work); u32 slave0, slave1; dev_dbg_ratelimited(cdns->dev, "Slave status change\n"); @@ -777,9 +779,7 @@ irqreturn_t sdw_cdns_thread(int irq, void *dev_id) cdns_updatel(cdns, CDNS_MCP_INTMASK, CDNS_MCP_INT_SLAVE_MASK, CDNS_MCP_INT_SLAVE_MASK); - return IRQ_HANDLED; } -EXPORT_SYMBOL(sdw_cdns_thread); /* * init routines @@ -1187,6 +1187,7 @@ int sdw_cdns_probe(struct sdw_cdns *cdns) init_completion(&cdns->tx_complete); cdns->bus.port_ops = &cdns_port_ops; + INIT_WORK(&cdns->work, cdns_update_slave_status_work); return 0; } EXPORT_SYMBOL(sdw_cdns_probe); diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index 001457cbe5ad2e..0f108fd31fd943 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -126,6 +126,10 @@ struct sdw_cdns { bool link_up; unsigned int msg_count; + + struct work_struct work; + + struct list_head list; }; #define bus_to_cdns(_bus) container_of(_bus, struct sdw_cdns, bus) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index c24b5f30789d5d..dc12bfdfaaa9e5 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1096,6 +1096,7 @@ static int intel_master_probe(struct sdw_master_device *md, void *link_ctx) sdw->cdns.msg_count = 0; sdw->cdns.bus.dev = &md->dev; sdw->cdns.bus.link_id = md->link_id; + sdw->link_res->cdns = &sdw->cdns; sdw_cdns_probe(&sdw->cdns); @@ -1114,27 +1115,12 @@ static int intel_master_probe(struct sdw_master_device *md, void *link_ctx) return ret; } - if (sdw->cdns.bus.prop.hw_disabled) { - dev_info(&md->dev, "SoundWire master %d is disabled, ignoring\n", + if (sdw->cdns.bus.prop.hw_disabled) + dev_info(&md->dev, + "SoundWire master %d is disabled, will be ignored\n", sdw->cdns.bus.link_id); - return 0; - } - - /* Acquire IRQ */ - ret = request_threaded_irq(sdw->link_res->irq, - sdw_cdns_irq, sdw_cdns_thread, - IRQF_SHARED, KBUILD_MODNAME, &sdw->cdns); - if (ret < 0) { - dev_err(sdw->cdns.dev, "unable to grab IRQ %d, disabling device\n", - sdw->link_res->irq); - goto err_init; - } return 0; - -err_init: - sdw_delete_bus_master(&sdw->cdns.bus); - return ret; } static int intel_master_startup(struct sdw_master_device *md) @@ -1146,7 +1132,8 @@ static int intel_master_startup(struct sdw_master_device *md) sdw = md->pdata; if (sdw->cdns.bus.prop.hw_disabled) { - dev_info(&md->dev, "SoundWire master %d is disabled, ignoring\n", + dev_info(&md->dev, + "SoundWire master %d is disabled, ignoring\n", sdw->cdns.bus.link_id); return 0; } @@ -1191,7 +1178,6 @@ static int intel_master_startup(struct sdw_master_device *md) err_interrupt: sdw_cdns_enable_interrupt(&sdw->cdns, false); err_init: - free_irq(sdw->link_res->irq, sdw); sdw_delete_bus_master(&sdw->cdns.bus); return ret; } @@ -1205,7 +1191,6 @@ static int intel_master_remove(struct sdw_master_device *md) if (!sdw->cdns.bus.prop.hw_disabled) { intel_debugfs_exit(sdw); sdw_cdns_enable_interrupt(&sdw->cdns, false); - free_irq(sdw->link_res->irq, sdw); snd_soc_unregister_component(sdw->cdns.dev); } sdw_delete_bus_master(&sdw->cdns.bus); diff --git a/drivers/soundwire/intel.h b/drivers/soundwire/intel.h index cfab2f00214d25..2ae4fa7486861d 100644 --- a/drivers/soundwire/intel.h +++ b/drivers/soundwire/intel.h @@ -25,6 +25,8 @@ struct sdw_intel_link_res { int irq; const struct sdw_intel_ops *ops; struct device *dev; + struct sdw_cdns *cdns; + struct list_head list; }; #define SDW_INTEL_QUIRK_MASK_BUS_DISABLE BIT(1) diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 0acb92a3c6d196..82aeb350c9bc15 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -11,8 +11,10 @@ #include #include #include +#include #include #include +#include "cadence_master.h" #include "intel.h" #define SDW_LINK_TYPE 4 /* from Intel ACPI documentation */ @@ -161,6 +163,19 @@ void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable) } EXPORT_SYMBOL_NS(sdw_intel_enable_irq, SOUNDWIRE_INTEL_INIT); +irqreturn_t sdw_intel_thread(int irq, void *dev_id) +{ + struct sdw_intel_ctx *ctx = dev_id; + struct sdw_intel_link_res *link; + + list_for_each_entry(link, &ctx->link_list, list) + sdw_cdns_irq(irq, link->cdns); + + sdw_intel_enable_irq(ctx->mmio_base, true); + return IRQ_HANDLED; +} +EXPORT_SYMBOL(sdw_intel_thread); + static struct sdw_intel_ctx *sdw_intel_probe_controller(struct sdw_intel_res *res) { @@ -207,6 +222,8 @@ static struct sdw_intel_ctx goto register_err; } + INIT_LIST_HEAD(&ctx->link_list); + /* Create SDW Master devices */ for (i = 0; i < count; i++, link++) { if (link_mask && !(link_mask & BIT(i))) @@ -227,12 +244,13 @@ static struct sdw_intel_ctx + (SDW_LINK_SIZE * i); link->shim = res->mmio_base + SDW_SHIM_BASE; link->alh = res->mmio_base + SDW_ALH_BASE; - link->irq = res->irq; link->ops = res->ops; link->dev = res->dev; /* let the SoundWire master driver to its probe */ md->driver->probe(md, link); + + list_add_tail(&link->list, &ctx->link_list); } return ctx; From 663e4b32210bf4c0d337801dd5fbb8f2862d1def Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 1 Aug 2019 19:53:15 -0500 Subject: [PATCH 1921/1995] soundwire: bus: fix race condition with probe_complete signaling The driver probe takes care of basic initialization and is invoked when a Slave becomes attached, after a match between the Slave DevID registers and ACPI/DT entries. The update_status callback is invoked when a Slave state changes, e.g. when it is assigned a non-zero Device Number and it reports with an ATTACHED/ALERT state. The state change detection is usually hardware-based and based on the SoundWire frame rate (e.g. double-digit microseconds) while the probe is a pure software operation, which may involve a kernel module load. In corner cases, it's possible that the state changes before the probe completes. This patch suggests the use of wait_for_completion to avoid races on startup, so that the update_status callback does not rely on invalid pointers/data structures. Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.c | 25 ++++++++++++++++++++++--- drivers/soundwire/bus.h | 1 + drivers/soundwire/bus_type.c | 5 +++++ drivers/soundwire/slave.c | 2 ++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 4b22ee996a6566..d99acbc614c68b 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -961,10 +961,29 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) static int sdw_update_slave_status(struct sdw_slave *slave, enum sdw_slave_status status) { - if (slave->ops && slave->ops->update_status) - return slave->ops->update_status(slave, status); + unsigned long time; - return 0; + if (!slave->probed) { + /* + * the slave status update is typically handled in an + * interrupt thread, which can race with the driver + * probe, e.g. when a module needs to be loaded. + * + * make sure the probe is complete before updating + * status. + */ + time = wait_for_completion_timeout(&slave->probe_complete, + msecs_to_jiffies(DEFAULT_PROBE_TIMEOUT)); + if (!time) { + dev_err(&slave->dev, "Probe not complete, timed out\n"); + return -ETIMEDOUT; + } + } + + if (!slave->ops || !slave->ops->update_status) + return 0; + + return slave->ops->update_status(slave, status); } /** diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h index be01a5f3d00bae..93e7bbab0938fd 100644 --- a/drivers/soundwire/bus.h +++ b/drivers/soundwire/bus.h @@ -5,6 +5,7 @@ #define __SDW_BUS_H #define DEFAULT_BANK_SWITCH_TIMEOUT 3000 +#define DEFAULT_PROBE_TIMEOUT 2000 int sdw_uevent(struct device *dev, struct kobj_uevent_env *env); diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index 2e4e8c2e629f46..5dd13c74556618 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -125,6 +125,11 @@ static int sdw_slave_drv_probe(struct device *dev) slave->bus->clk_stop_timeout = max_t(u32, slave->bus->clk_stop_timeout, slave->prop.clk_stop_timeout); + slave->probed = true; + complete(&slave->probe_complete); + + dev_dbg(dev, "probe complete\n"); + return 0; } diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c index 014c3ece1f1768..15ac89ecae0109 100644 --- a/drivers/soundwire/slave.c +++ b/drivers/soundwire/slave.c @@ -53,6 +53,8 @@ static int sdw_slave_add(struct sdw_bus *bus, slave->bus = bus; slave->status = SDW_SLAVE_UNATTACHED; slave->dev_num = 0; + init_completion(&slave->probe_complete); + slave->probed = false; mutex_lock(&bus->bus_lock); list_add_tail(&slave->node, &bus->slaves); From cbbae867bafe3761d6930ead7726253ba62898ce Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 10 Jun 2019 19:09:14 -0500 Subject: [PATCH 1922/1995] soundwire: bus: add PM/no-PM versions of read/write functions Add support for pm_runtime with the appropriate error checks for sdw_write/read functions, e.g. when pm_runtime is not supported. Also expose internal functions without pm_runtime support, which are required to perform any sort of suspend/resume operation, as well as any enumeration tasks. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.c | 68 +++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index d99acbc614c68b..9d64bb4a82422f 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -317,6 +317,46 @@ int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave, return 0; } +/* + * Read/Write IO functions. + * no_pm versions can only be called by the bus, e.g. while enumerating or + * handling suspend-resume sequences. + * all clients need to use the pm versions + */ + +static int +sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val) +{ + struct sdw_msg msg; + int ret; + + ret = sdw_fill_msg(&msg, slave, addr, count, + slave->dev_num, SDW_MSG_FLAG_READ, val); + if (ret < 0) + return ret; + + return sdw_transfer(slave->bus, &msg); +} + +static int +sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val) +{ + struct sdw_msg msg; + int ret; + + ret = sdw_fill_msg(&msg, slave, addr, count, + slave->dev_num, SDW_MSG_FLAG_WRITE, val); + if (ret < 0) + return ret; + + return sdw_transfer(slave->bus, &msg); +} + +static int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value) +{ + return sdw_nwrite_no_pm(slave, addr, 1, &value); +} + /** * sdw_nread() - Read "n" contiguous SDW Slave registers * @slave: SDW Slave @@ -326,19 +366,17 @@ int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave, */ int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val) { - struct sdw_msg msg; int ret; - ret = sdw_fill_msg(&msg, slave, addr, count, - slave->dev_num, SDW_MSG_FLAG_READ, val); - if (ret < 0) - return ret; - ret = pm_runtime_get_sync(slave->bus->dev); - if (ret < 0) + if (ret < 0 && ret != -EACCES) { + pm_runtime_put_noidle(slave->bus->dev); return ret; + } + + ret = sdw_nread_no_pm(slave, addr, count, val); - ret = sdw_transfer(slave->bus, &msg); + pm_runtime_mark_last_busy(slave->bus->dev); pm_runtime_put(slave->bus->dev); return ret; @@ -354,19 +392,17 @@ EXPORT_SYMBOL(sdw_nread); */ int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val) { - struct sdw_msg msg; int ret; - ret = sdw_fill_msg(&msg, slave, addr, count, - slave->dev_num, SDW_MSG_FLAG_WRITE, val); - if (ret < 0) - return ret; - ret = pm_runtime_get_sync(slave->bus->dev); - if (ret < 0) + if (ret < 0 && ret != -EACCES) { + pm_runtime_put_noidle(slave->bus->dev); return ret; + } + + ret = sdw_nwrite_no_pm(slave, addr, count, val); - ret = sdw_transfer(slave->bus, &msg); + pm_runtime_mark_last_busy(slave->bus->dev); pm_runtime_put(slave->bus->dev); return ret; From 131273e0575273493d20b4804a6ce7bda40edc37 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 26 Sep 2019 16:19:00 -0500 Subject: [PATCH 1923/1995] soundwire: bus: write Slave Device Number without runtime_pm While handling the Device0, we can safely use sdw_write_no_pm. This move will also helps us track that all other usages of sdw_write() happen when the Slave is already enumerated. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 9d64bb4a82422f..4ddab1e94c9958 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -513,7 +513,7 @@ static int sdw_assign_device_num(struct sdw_slave *slave) slave->dev_num = 0; } - ret = sdw_write(slave, SDW_SCP_DEVNUMBER, dev_num); + ret = sdw_write_no_pm(slave, SDW_SCP_DEVNUMBER, dev_num); if (ret < 0) { dev_err(&slave->dev, "Program device_num %d failed: %d\n", dev_num, ret); From 1d7de96203fd878bfc3f30ca7af4af19a40ed960 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 20 Sep 2019 14:08:57 -0500 Subject: [PATCH 1924/1995] soundwire: intel: add helpers for link power down and shim wake These routines are required for power management Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index dc12bfdfaaa9e5..ebe75ac568f93e 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -363,6 +363,59 @@ static int intel_shim_init(struct sdw_intel *sdw) return ret; } +static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) +{ + void __iomem *shim = sdw->link_res->shim; + unsigned int link_id = sdw->instance; + u16 wake_en, wake_sts; + + if (wake_enable) { + /* Enable the wakeup */ + intel_writew(shim, SDW_SHIM_WAKEEN, + (SDW_SHIM_WAKEEN_ENABLE << link_id)); + } else { + /* Disable the wake up interrupt */ + wake_en = intel_readw(shim, SDW_SHIM_WAKEEN); + wake_en &= ~(SDW_SHIM_WAKEEN_ENABLE << link_id); + intel_writew(shim, SDW_SHIM_WAKEEN, wake_en); + + /* Clear wake status */ + wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS); + wake_sts |= (SDW_SHIM_WAKEEN_ENABLE << link_id); + intel_writew(shim, SDW_SHIM_WAKESTS_STATUS, wake_sts); + } +} + +static int intel_link_power_down(struct sdw_intel *sdw) +{ + int link_control, spa_mask, cpa_mask, ret; + unsigned int link_id = sdw->instance; + void __iomem *shim = sdw->link_res->shim; + u16 ioctl; + + /* Glue logic */ + ioctl = intel_readw(shim, SDW_SHIM_IOCTL(link_id)); + ioctl |= SDW_SHIM_IOCTL_BKE; + ioctl |= SDW_SHIM_IOCTL_COE; + intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); + + ioctl &= ~(SDW_SHIM_IOCTL_MIF); + intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); + + /* Link power down sequence */ + link_control = intel_readl(shim, SDW_SHIM_LCTL); + spa_mask = ~(SDW_SHIM_LCTL_SPA << link_id); + cpa_mask = (SDW_SHIM_LCTL_CPA << link_id); + link_control &= spa_mask; + + ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask); + if (ret < 0) + return ret; + + sdw->cdns.link_up = false; + return 0; +} + /* * PDI routines */ From 34a19e80cb4cf64bcee9722894e4eca890ab0cce Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 20 Sep 2019 14:21:18 -0500 Subject: [PATCH 1925/1995] soundwire: intel: Add basic power management support Implement suspend/resume capabilities (not runtime_pm for now) The resume part is essentially a full-blown re-enumeration. When S0ix is supported, we will select clock stop mode when the ACPI target state is S0, and tear down the link for S3. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 75 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index ebe75ac568f93e..62f0aaf769e188 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1253,11 +1253,86 @@ static int intel_master_remove(struct sdw_master_device *md) return 0; } +/* + * PM calls + */ + +#ifdef CONFIG_PM + +static int intel_suspend(struct device *dev) +{ + struct sdw_cdns *cdns = dev_get_drvdata(dev); + struct sdw_intel *sdw = cdns_to_intel(cdns); + int ret; + + if (cdns->bus.prop.hw_disabled) { + dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", + cdns->bus.link_id); + return 0; + } + + ret = sdw_cdns_enable_interrupt(cdns, false); + if (ret < 0) { + dev_err(dev, "cannot disable interrupts on suspend\n"); + return ret; + } + + ret = intel_link_power_down(sdw); + if (ret) { + dev_err(dev, "Link power down failed: %d", ret); + return ret; + } + + intel_shim_wake(sdw, false); + + return 0; +} + +static int intel_resume(struct device *dev) +{ + struct sdw_cdns *cdns = dev_get_drvdata(dev); + struct sdw_intel *sdw = cdns_to_intel(cdns); + int ret; + + if (cdns->bus.prop.hw_disabled) { + dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", + cdns->bus.link_id); + return 0; + } + + ret = intel_init(sdw); + if (ret) { + dev_err(dev, "%s failed: %d", __func__, ret); + return ret; + } + + ret = sdw_cdns_enable_interrupt(cdns, true); + if (ret < 0) { + dev_err(dev, "cannot enable interrupts during resume\n"); + return ret; + } + + ret = sdw_cdns_exit_reset(cdns); + if (ret < 0) { + dev_err(dev, "unable to exit bus reset sequence during resume\n"); + return ret; + } + + return ret; +} + +#endif + +static const struct dev_pm_ops intel_pm = { + SET_SYSTEM_SLEEP_PM_OPS(intel_suspend, intel_resume) +}; + struct sdw_md_driver intel_sdw_driver = { .driver = { .name = "intel-sdw", .owner = THIS_MODULE, .bus = &sdw_bus_type, + .pm = &intel_pm, }, .probe = intel_master_probe, .startup = intel_master_startup, From 4222f1e0abeb379d958963c2d2acb6ed49551da1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 20 Sep 2019 14:51:39 -0500 Subject: [PATCH 1926/1995] soundwire: intel: add pm_runtime support Add basic hooks in DAI .startup and .shutdown callbacks. The SoundWire IP should be powered between those two calls. The power dependencies between SoundWire and DSP are handled with the parent/child relationship, before the SoundWire master device becomes active the parent device will become active and power-up the shared rails. For now the strategy is to rely on complete enumeration when the device becomes active, so the code is a copy/paste of the sequence for system suspend/resume. In future patches, the strategy will optionally be to rely on clock stop if the enumeration time is prohibitive or when the devices connected to a link can signal a wake. A module parameter is added to make integration of new Slave devices easier, to e.g. keep the device active or prevent clock-stop. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 108 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 4 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 62f0aaf769e188..aaf7b6d9befdbf 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,20 @@ #include "bus.h" #include "intel.h" +/* + * debug/config flags for the Intel SoundWire Master. + * + * Since we may have multiple masters active, we can have up to 8 + * flags reused in each byte, with master0 using the ls-byte, etc. + */ + +#define SDW_INTEL_MASTER_DISABLE_PM_RUNTIME BIT(0) +#define SDW_INTEL_MASTER_DISABLE_CLOCK_STOP BIT(1) + +static int md_flags; +module_param_named(sdw_md_flags, md_flags, int, 0444); +MODULE_PARM_DESC(sdw_md_flags, "SoundWire Intel Master device flags (0x0 all off)"); + /* Intel SHIM Registers Definition */ #define SDW_SHIM_LCAP 0x0 #define SDW_SHIM_LCTL 0x4 @@ -743,10 +758,16 @@ static int sdw_stream_setup(struct snd_pcm_substream *substream, static int intel_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - /* - * TODO: add pm_runtime support here, the startup callback - * will make sure the IP is 'active' - */ + struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); + int ret; + + ret = pm_runtime_get_sync(cdns->dev); + if (ret < 0 && ret != -EACCES) { + dev_err_ratelimited(cdns->dev, + "pm_runtime_get_sync failed in %s, ret %d\n", + __func__, ret); + pm_runtime_put_noidle(cdns->dev); + } return sdw_stream_setup(substream, dai); } @@ -925,6 +946,7 @@ static void intel_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct sdw_cdns_dma_data *dma; + struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); dma = snd_soc_dai_get_dma_data(dai, substream); if (!dma) @@ -932,6 +954,9 @@ static void intel_shutdown(struct snd_pcm_substream *substream, snd_soc_dai_set_dma_data(dai, substream, NULL); kfree(dma); + + pm_runtime_mark_last_busy(cdns->dev); + pm_runtime_put_autosuspend(cdns->dev); } static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai, @@ -1180,6 +1205,7 @@ static int intel_master_startup(struct sdw_master_device *md) { struct sdw_cdns_stream_config config; struct sdw_intel *sdw; + int link_flags; int ret; sdw = md->pdata; @@ -1226,6 +1252,17 @@ static int intel_master_startup(struct sdw_master_device *md) intel_debugfs_init(sdw); + /* Enable runtime PM */ + link_flags = md_flags >> (sdw->cdns.bus.link_id * 8); + if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME)) { + pm_runtime_set_autosuspend_delay(&md->dev, 3000); + pm_runtime_use_autosuspend(&md->dev); + pm_runtime_mark_last_busy(&md->dev); + + pm_runtime_set_active(&md->dev); + pm_runtime_enable(&md->dev); + } + return 0; err_interrupt: @@ -1288,6 +1325,35 @@ static int intel_suspend(struct device *dev) return 0; } +static int intel_suspend_runtime(struct device *dev) +{ + struct sdw_cdns *cdns = dev_get_drvdata(dev); + struct sdw_intel *sdw = cdns_to_intel(cdns); + int ret; + + if (cdns->bus.prop.hw_disabled) { + dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", + cdns->bus.link_id); + return 0; + } + + ret = sdw_cdns_enable_interrupt(cdns, false); + if (ret < 0) { + dev_err(dev, "cannot disable interrupts on suspend\n"); + return ret; + } + + ret = intel_link_power_down(sdw); + if (ret) { + dev_err(dev, "Link power down failed: %d", ret); + return ret; + } + + intel_shim_wake(sdw, false); + + return 0; +} + static int intel_resume(struct device *dev) { struct sdw_cdns *cdns = dev_get_drvdata(dev); @@ -1321,10 +1387,44 @@ static int intel_resume(struct device *dev) return ret; } +static int intel_resume_runtime(struct device *dev) +{ + struct sdw_cdns *cdns = dev_get_drvdata(dev); + struct sdw_intel *sdw = cdns_to_intel(cdns); + int ret; + + if (cdns->bus.prop.hw_disabled) { + dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", + cdns->bus.link_id); + return 0; + } + + ret = intel_init(sdw); + if (ret) { + dev_err(dev, "%s failed: %d", __func__, ret); + return ret; + } + + ret = sdw_cdns_enable_interrupt(cdns, true); + if (ret < 0) { + dev_err(dev, "cannot enable interrupts during resume\n"); + return ret; + } + + ret = sdw_cdns_exit_reset(cdns); + if (ret < 0) { + dev_err(dev, "unable to exit bus reset sequence during resume\n"); + return ret; + } + + return ret; +} + #endif static const struct dev_pm_ops intel_pm = { SET_SYSTEM_SLEEP_PM_OPS(intel_suspend, intel_resume) + SET_RUNTIME_PM_OPS(intel_suspend_runtime, intel_resume_runtime, NULL) }; struct sdw_md_driver intel_sdw_driver = { From 8eb64ac3b57d26b1f4d9a2bce34c9edf53a73914 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 11 Oct 2019 17:15:41 -0500 Subject: [PATCH 1927/1995] soundwire: intel: reset pm_runtime status during system resume The system resume does the entire bus re-initialization and brings it to full-power. If the device was pm_runtime suspended, there is no need to run the pm_runtime resume sequence after the system runtime. Follow the documentation from runtime_pm.rst, and conditionally disable, set_active and re-enable the device on system resume. Note that pm_runtime_suspended() is used instead of pm_runtime_status_suspended() so that we can deal with the case where pm_runtime is disabled. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 30 ++++++++++++++++++++++++++++++ include/linux/soundwire/sdw.h | 1 + 2 files changed, 31 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index aaf7b6d9befdbf..96df563bdb2185 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1298,6 +1298,7 @@ static int intel_master_remove(struct sdw_master_device *md) static int intel_suspend(struct device *dev) { + struct sdw_master_device *md = to_sdw_master_device(dev); struct sdw_cdns *cdns = dev_get_drvdata(dev); struct sdw_intel *sdw = cdns_to_intel(cdns); int ret; @@ -1308,6 +1309,20 @@ static int intel_suspend(struct device *dev) return 0; } + if (pm_runtime_suspended(dev)) { + dev_dbg(dev, + "%s: pm_runtime status: suspended\n", + __func__); + + /* + * keep track of the state for the system resume, where + * we will need to reset the pm_runtime status to active + */ + md->pm_runtime_suspended = true; + + return 0; + } + ret = sdw_cdns_enable_interrupt(cdns, false); if (ret < 0) { dev_err(dev, "cannot disable interrupts on suspend\n"); @@ -1356,6 +1371,7 @@ static int intel_suspend_runtime(struct device *dev) static int intel_resume(struct device *dev) { + struct sdw_master_device *md = to_sdw_master_device(dev); struct sdw_cdns *cdns = dev_get_drvdata(dev); struct sdw_intel *sdw = cdns_to_intel(cdns); int ret; @@ -1366,6 +1382,20 @@ static int intel_resume(struct device *dev) return 0; } + if (md->pm_runtime_suspended) { + dev_dbg(dev, + "%s: pm_runtime status was suspended, forcing active\n", + __func__); + + /* follow required sequence from runtime_pm.rst */ + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_enable(dev); + + md->pm_runtime_suspended = false; + } + ret = intel_init(sdw); if (ret) { dev_err(dev, "%s failed: %d", __func__, ret); diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 58f50257dfa8d1..1a765b10b8bbaa 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -590,6 +590,7 @@ struct sdw_master_device { int link_id; struct sdw_md_driver *driver; void *pdata; + bool pm_runtime_suspended; }; #define to_sdw_master_device(d) \ From 658ebae47c4ea31a8c073f09e31717221e8e3899 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 25 Nov 2019 18:22:20 -0600 Subject: [PATCH 1928/1995] soundwire: intel: fix race condition on system resume Previous patches took care of the case where the master device is pm_runtime 'suspended' when a system suspend occurs. In the case where the master device was not suspended, e.g. if suspend occurred while streaming audio, Intel validation noticed a race condition the enumeration started by the system resume may race with pm_runtime suspend. This can be simply fixed by updating the status before exiting system resume. GitHub issue: https://github.com/thesofproject/linux/issues/1482 Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 96df563bdb2185..8e973a6e38e1d9 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1414,6 +1414,18 @@ static int intel_resume(struct device *dev) return ret; } + /* + * after system resume, the pm_runtime suspend() may kick in + * during the enumeration, before any children device force the + * master device to remain active. Using pm_runtime_get() + * routines is not really possible, since it'd prevent the + * master from suspending. + * A reasonable compromise is to update the pm_runtime + * counters and delay the pm_runtime suspend by several + * seconds, by which all enumeration should be complete. + */ + pm_runtime_mark_last_busy(cdns->dev); + return ret; } From cd30960a82668779905a499eea81ce0ac23b042e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 26 Sep 2019 18:26:11 -0500 Subject: [PATCH 1929/1995] soundwire: bus: add helper to reset Slave status to UNATTACHED When resuming, we need to re-enumerate and restart from UNATTACHED. This will help implement a more robust state machine avoiding race conditions on resume. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.c | 24 ++++++++++++++++++++++++ drivers/soundwire/bus.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 4ddab1e94c9958..455962555ef8b8 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -1108,3 +1108,27 @@ int sdw_handle_slave_status(struct sdw_bus *bus, return ret; } EXPORT_SYMBOL(sdw_handle_slave_status); + +void sdw_clear_slave_status(struct sdw_bus *bus) +{ + struct sdw_slave *slave; + int i; + + /* Check all non-zero devices */ + for (i = 1; i <= SDW_MAX_DEVICES; i++) { + mutex_lock(&bus->bus_lock); + if (test_bit(i, bus->assigned) == false) { + mutex_unlock(&bus->bus_lock); + continue; + } + mutex_unlock(&bus->bus_lock); + + slave = sdw_get_slave(bus, i); + if (!slave) + continue; + + if (slave->status != SDW_SLAVE_UNATTACHED) + sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); + } +} +EXPORT_SYMBOL(sdw_clear_slave_status); diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h index 93e7bbab0938fd..4e6fb5d2f5ccd9 100644 --- a/drivers/soundwire/bus.h +++ b/drivers/soundwire/bus.h @@ -167,4 +167,6 @@ sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val) return sdw_write(slave, addr, tmp); } +void sdw_clear_slave_status(struct sdw_bus *bus); + #endif /* __SDW_BUS_H */ From afd2851a8b4575a00439df55949a8a6371c6696d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 26 Sep 2019 18:32:52 -0500 Subject: [PATCH 1930/1995] soundwire: intel: call helper to reset Slave states on resume This helps make sure they are all UNATTACHED and reset the state machines. At the moment we perform a bus reset both for resume and pm_resume, this will be modified when clock-stop mode is supported Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 8e973a6e38e1d9..bb02dd023199f7 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1402,6 +1402,9 @@ static int intel_resume(struct device *dev) return ret; } + /* make sure all Slaves are tagged as UNATTACHED */ + sdw_clear_slave_status(&sdw->cdns.bus); + ret = sdw_cdns_enable_interrupt(cdns, true); if (ret < 0) { dev_err(dev, "cannot enable interrupts during resume\n"); @@ -1447,6 +1450,9 @@ static int intel_resume_runtime(struct device *dev) return ret; } + /* make sure all Slaves are tagged as UNATTACHED */ + sdw_clear_slave_status(&sdw->cdns.bus); + ret = sdw_cdns_enable_interrupt(cdns, true); if (ret < 0) { dev_err(dev, "cannot enable interrupts during resume\n"); From 56e6000327f96619570ee160ece03b24b38f9cf7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 26 Sep 2019 18:37:00 -0500 Subject: [PATCH 1931/1995] soundwire: bus: check first if Slaves become UNATTACHED Before checking for the presence of Device0, we first need to clean-up the internal state of Slaves that are no longer attached. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 455962555ef8b8..b76c0a10ef7a27 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -1034,6 +1034,24 @@ int sdw_handle_slave_status(struct sdw_bus *bus, struct sdw_slave *slave; int i, ret = 0; + /* first check if any Slaves fell off the bus */ + for (i = 1; i <= SDW_MAX_DEVICES; i++) { + mutex_lock(&bus->bus_lock); + if (test_bit(i, bus->assigned) == false) { + mutex_unlock(&bus->bus_lock); + continue; + } + mutex_unlock(&bus->bus_lock); + + slave = sdw_get_slave(bus, i); + if (!slave) + continue; + + if (status[i] == SDW_SLAVE_UNATTACHED && + slave->status != SDW_SLAVE_UNATTACHED) + sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); + } + if (status[0] == SDW_SLAVE_ATTACHED) { dev_dbg(bus->dev, "Slave attached, programming device number\n"); ret = sdw_program_device_num(bus); From 70263dbb6596851b7674e6580ecdc5af34482c4c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 26 Sep 2019 18:47:35 -0500 Subject: [PATCH 1932/1995] soundwire: bus: fix race condition with enumeration_complete signaling This patch adds the signaling needed for Slave drivers to wait until the enumeration completes so that race conditions when issuing read/write commands are avoided. The calls for wait_for_completion() will be added in codec drivers in follow-up patches. The order between init_completion() and complete() is deterministic, the Slave is marked as UNATTACHED either during a Master-initiated HardReset, or when the hardware detects the Slave no longer reports as ATTACHED. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.c | 20 ++++++++++++++++++++ drivers/soundwire/slave.c | 1 + 2 files changed, 21 insertions(+) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index b76c0a10ef7a27..61bbeeb3e8eb6d 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -637,6 +637,26 @@ static void sdw_modify_slave_status(struct sdw_slave *slave, enum sdw_slave_status status) { mutex_lock(&slave->bus->bus_lock); + + dev_vdbg(&slave->dev, + "%s: changing status slave %d status %d new status %d\n", + __func__, slave->dev_num, slave->status, status); + + if (status == SDW_SLAVE_UNATTACHED) { + dev_dbg(&slave->dev, + "%s: initializing completion for Slave %d\n", + __func__, slave->dev_num); + + init_completion(&slave->enumeration_complete); + + } else if ((status == SDW_SLAVE_ATTACHED) && + (slave->status == SDW_SLAVE_UNATTACHED)) { + dev_dbg(&slave->dev, + "%s: signaling completion for Slave %d\n", + __func__, slave->dev_num); + + complete(&slave->enumeration_complete); + } slave->status = status; mutex_unlock(&slave->bus->bus_lock); } diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c index 15ac89ecae0109..76fdfbd8b50d5d 100644 --- a/drivers/soundwire/slave.c +++ b/drivers/soundwire/slave.c @@ -52,6 +52,7 @@ static int sdw_slave_add(struct sdw_bus *bus, slave->dev.type = &sdw_slave_type; slave->bus = bus; slave->status = SDW_SLAVE_UNATTACHED; + init_completion(&slave->enumeration_complete); slave->dev_num = 0; init_completion(&slave->probe_complete); slave->probed = false; From 53e3e050b4dc481b65ad7de314f594ace7e953d7 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 4 Nov 2019 12:47:01 -0600 Subject: [PATCH 1933/1995] soundwire: bus: fix race condition with initialization_complete signaling Waiting for the enumeration to be complete may not be enough for a Slave driver, there is a possible race condition between resume operations and initializations handled in an interrupt thread, which can results in settings not being fully restored after system or pm_runtime resume. This patch builds on the changes added for enumeration_complete, init_completion() is called when the Slave device becomes UNATTACHED, as done with enumeration_complete. The difference with the enumeration_complete case is that complete() is signaled after the Slave device is fully initialized after the .update_status() callback is called. A Slave device driver can decide to wait on either of the two complete() cases, depending on its initialization code and requirements. Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.c | 8 ++++++++ drivers/soundwire/slave.c | 1 + 2 files changed, 9 insertions(+) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 61bbeeb3e8eb6d..09c19bc0af59a3 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -648,6 +648,7 @@ static void sdw_modify_slave_status(struct sdw_slave *slave, __func__, slave->dev_num); init_completion(&slave->enumeration_complete); + init_completion(&slave->initialization_complete); } else if ((status == SDW_SLAVE_ATTACHED) && (slave->status == SDW_SLAVE_UNATTACHED)) { @@ -1052,6 +1053,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, { enum sdw_slave_status prev_status; struct sdw_slave *slave; + bool attached_initializing; int i, ret = 0; /* first check if any Slaves fell off the bus */ @@ -1097,6 +1099,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, if (!slave) continue; + attached_initializing = false; + switch (status[i]) { case SDW_SLAVE_UNATTACHED: if (slave->status == SDW_SLAVE_UNATTACHED) @@ -1123,6 +1127,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, if (prev_status == SDW_SLAVE_ALERT) break; + attached_initializing = true; + ret = sdw_initialize_slave(slave); if (ret) dev_err(bus->dev, @@ -1141,6 +1147,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, if (ret) dev_err(slave->bus->dev, "Update Slave status failed:%d\n", ret); + if (attached_initializing) + complete(&slave->initialization_complete); } return ret; diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c index 76fdfbd8b50d5d..d2a952d9bd4755 100644 --- a/drivers/soundwire/slave.c +++ b/drivers/soundwire/slave.c @@ -53,6 +53,7 @@ static int sdw_slave_add(struct sdw_bus *bus, slave->bus = bus; slave->status = SDW_SLAVE_UNATTACHED; init_completion(&slave->enumeration_complete); + init_completion(&slave->initialization_complete); slave->dev_num = 0; init_completion(&slave->probe_complete); slave->probed = false; From 6edda30616bc00e5a1c334a5595ff14e11696330 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 8 Nov 2019 17:13:22 -0600 Subject: [PATCH 1934/1995] soundwire: bus: fix race condition by tracking UNATTACHED transition In previous patches, we added enumeration_ and initialization_complete fields to avoid race conditions. When streaming restarts, the Master first resumes, then requests all Slaves to renumerate/reinitialized, and then the Slave devices resume. Intel validation exposed a corner case where the Slave device may transition to D3 when streaming stops, but streaming restarts before the Master transitions to D3. In that case, the Slave status was not cleared as UNATTACHED, and the wait_for_completion will time out. The proposed solution is that when the Master clears the Slave(s) status, the reason for the Slave(s) becoming unattached is memorized. When the slave resumes, it can check if a Master-initiated re-enumeration and initialization takes place and skip the wait_for_completion() if there is no reason to wait. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.c | 5 ++++- drivers/soundwire/bus.h | 8 +++++++- drivers/soundwire/intel.c | 16 ++++++++++++---- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 09c19bc0af59a3..be4e0946433ff6 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -1155,7 +1155,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, } EXPORT_SYMBOL(sdw_handle_slave_status); -void sdw_clear_slave_status(struct sdw_bus *bus) +void sdw_clear_slave_status(struct sdw_bus *bus, u32 request) { struct sdw_slave *slave; int i; @@ -1175,6 +1175,9 @@ void sdw_clear_slave_status(struct sdw_bus *bus) if (slave->status != SDW_SLAVE_UNATTACHED) sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); + + /* keep track of request, used in pm_runtime resume */ + slave->unattach_request = request; } } EXPORT_SYMBOL(sdw_clear_slave_status); diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h index 4e6fb5d2f5ccd9..ee362472003a93 100644 --- a/drivers/soundwire/bus.h +++ b/drivers/soundwire/bus.h @@ -167,6 +167,12 @@ sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val) return sdw_write(slave, addr, tmp); } -void sdw_clear_slave_status(struct sdw_bus *bus); +/* + * At the moment we only track Master-initiated hw_reset. + * Additional fields can be added as needed + */ +#define SDW_UNATTACH_REQUEST_MASTER_RESET BIT(0) + +void sdw_clear_slave_status(struct sdw_bus *bus, u32 request); #endif /* __SDW_BUS_H */ diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index bb02dd023199f7..4d4d41af9b5935 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1402,8 +1402,12 @@ static int intel_resume(struct device *dev) return ret; } - /* make sure all Slaves are tagged as UNATTACHED */ - sdw_clear_slave_status(&sdw->cdns.bus); + /* + * make sure all Slaves are tagged as UNATTACHED and provide + * reason for reinitialization + */ + sdw_clear_slave_status(&sdw->cdns.bus, + SDW_UNATTACH_REQUEST_MASTER_RESET); ret = sdw_cdns_enable_interrupt(cdns, true); if (ret < 0) { @@ -1450,8 +1454,12 @@ static int intel_resume_runtime(struct device *dev) return ret; } - /* make sure all Slaves are tagged as UNATTACHED */ - sdw_clear_slave_status(&sdw->cdns.bus); + /* + * make sure all Slaves are tagged as UNATTACHED and provide + * reason for reinitialization + */ + sdw_clear_slave_status(&sdw->cdns.bus, + SDW_UNATTACH_REQUEST_MASTER_RESET); ret = sdw_cdns_enable_interrupt(cdns, true); if (ret < 0) { From e5a7eb060c3395da1e26bfaf6f70aac1edcee6ab Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 8 Oct 2019 21:05:13 -0500 Subject: [PATCH 1935/1995] soundwire: intel: disable pm_runtime when removing a master Prevent race conditions between remove and resume by disabling pm_runtime. Note that this only takes care of pm_runtime at the Master level, the same precautions are needed when removing a Slave device. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 4d4d41af9b5935..ae120102001d7b 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1276,6 +1276,8 @@ static int intel_master_remove(struct sdw_master_device *md) { struct sdw_intel *sdw; + pm_runtime_disable(&md->dev); + sdw = md->pdata; if (!sdw->cdns.bus.prop.hw_disabled) { From a5a0e4d4d69c0fbb97707d4d04c26aa6903109f4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 8 Oct 2019 21:02:08 -0500 Subject: [PATCH 1936/1995] soundwire: bus: disable pm_runtime in sdw_slave_delete Before removing the slave device, disable pm_runtime to prevent any race condition with the resume being executed after the bus and slave devices are removed. Since this pm_runtime_disable() is handled in common routines, implementations of Slave drivers do not need to call it in their .remove() routine. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index be4e0946433ff6..4f2128b6746a01 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -113,6 +113,8 @@ static int sdw_delete_slave(struct device *dev, void *data) struct sdw_slave *slave = to_sdw_slave_device(dev); struct sdw_bus *bus = slave->bus; + pm_runtime_disable(dev); + sdw_slave_debugfs_exit(slave); mutex_lock(&bus->bus_lock); From 5227c4da17df00fbc816e578d181011ac6eb161f Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 14 Oct 2019 17:35:52 +0800 Subject: [PATCH 1937/1995] soundwire: intel: reinitialize IP+DSP in .prepare(), but only when resuming The .prepare() callback is invoked for normal streaming, underflows or during the system resume transition. In the latter case, the context for the ALH PDIs is lost, and the DSP is not initialized properly either, but the bus parameters don't need to be recomputed. Conversely, when doing a regular .prepare() during an underflow, the ALH/SHIM registers shall not be changed as the hardware cannot be reprogrammed after the DMA started (hardware spec requirement). This patch adds storage of PDI and hw_params in the DAI dma context, and the difference between the types of .prepare() usages is handled via a simple boolean, updated when suspending, and tested for in the .prepare() case. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/cadence_master.h | 4 ++ drivers/soundwire/intel.c | 69 +++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index 0f108fd31fd943..cd4feef0b9001b 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -81,6 +81,8 @@ struct sdw_cdns_stream_config { * @bus: Bus handle * @stream_type: Stream type * @link_id: Master link id + * @hw_params: hw_params to be applied in .prepare step + * @suspended: status set when suspended, to be used in .prepare */ struct sdw_cdns_dma_data { char *name; @@ -89,6 +91,8 @@ struct sdw_cdns_dma_data { struct sdw_bus *bus; enum sdw_stream_type stream_type; int link_id; + struct snd_pcm_hw_params *hw_params; + bool suspended; }; /** diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index ae120102001d7b..be450e14d94756 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -814,6 +814,10 @@ static int intel_hw_params(struct snd_pcm_substream *substream, intel_pdi_alh_configure(sdw, pdi); sdw_cdns_config_stream(cdns, ch, dir, pdi); + /* store pdi and hw_params, may be needed in prepare step */ + dma->suspended = false; + dma->pdi = pdi; + dma->hw_params = params; /* Inform DSP about PDI stream number */ ret = intel_params_stream(sdw, substream, dai, params, @@ -857,7 +861,11 @@ static int intel_hw_params(struct snd_pcm_substream *substream, static int intel_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { + struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); + struct sdw_intel *sdw = cdns_to_intel(cdns); struct sdw_cdns_dma_data *dma; + int ch, dir; + int ret; dma = snd_soc_dai_get_dma_data(dai, substream); if (!dma) { @@ -866,7 +874,42 @@ static int intel_prepare(struct snd_pcm_substream *substream, return -EIO; } - return sdw_prepare_stream(dma->stream); + if (dma->suspended) { + + dma->suspended = false; + + /* + * .prepare() is called after system resume, where we + * need to reinitialize the SHIM/ALH/Cadence IP. + * .prepare() is also called to deal with underflows, + * but in those cases we cannot touch ALH/SHIM + * registers + */ + + /* configure stream */ + ch = params_channels(dma->hw_params); + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + dir = SDW_DATA_DIR_RX; + else + dir = SDW_DATA_DIR_TX; + + intel_pdi_shim_configure(sdw, dma->pdi); + intel_pdi_alh_configure(sdw, dma->pdi); + sdw_cdns_config_stream(cdns, ch, dir, dma->pdi); + + /* Inform DSP about PDI stream number */ + ret = intel_params_stream(sdw, substream, dai, + dma->hw_params, + sdw->instance, + dma->pdi->intel_alh_id); + if (ret) + goto err; + } + + ret = sdw_prepare_stream(dma->stream); + +err: + return ret; } static int intel_trigger(struct snd_pcm_substream *substream, int cmd, @@ -937,6 +980,8 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) return ret; } + dma->hw_params = NULL; + dma->pdi = NULL; sdw_release_stream(dma->stream); return 0; @@ -959,6 +1004,26 @@ static void intel_shutdown(struct snd_pcm_substream *substream, pm_runtime_put_autosuspend(cdns->dev); } +static int intel_dai_suspend(struct snd_soc_dai *dai) +{ + struct sdw_cdns_dma_data *dma; + + /* + * we don't have a .suspend dai_ops, and we don't have access + * to the substream, so let's mark both capture and playback + * DMA contexts as suspended + */ + dma = dai->playback_dma_data; + if (dma) + dma->suspended = true; + + dma = dai->capture_dma_data; + if (dma) + dma->suspended = true; + + return 0; +} + static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai, void *stream, int direction) { @@ -1030,6 +1095,8 @@ static int intel_create_dai(struct sdw_cdns *cdns, dais[i].ops = &intel_pcm_dai_ops; else dais[i].ops = &intel_pdm_dai_ops; + + dais[i].suspend = intel_dai_suspend; } return 0; From a5e86e193e820de63d67ebb6f2b39b20fcb27a1d Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Oct 2019 13:43:14 -0500 Subject: [PATCH 1938/1995] soundwire: intel: pm_runtime idle scheduling Add quirk and pm_runtime idle scheduling to let the Master suspend if no Slaves become attached. This can happen when a link is not marked as disabled and has devices exposed in the DSDT, if the power is controlled by sideband means or the link includes a pluggable connector. Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index be450e14d94756..da29fe6e375272 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -30,8 +30,9 @@ * flags reused in each byte, with master0 using the ls-byte, etc. */ -#define SDW_INTEL_MASTER_DISABLE_PM_RUNTIME BIT(0) -#define SDW_INTEL_MASTER_DISABLE_CLOCK_STOP BIT(1) +#define SDW_INTEL_MASTER_DISABLE_PM_RUNTIME BIT(0) +#define SDW_INTEL_MASTER_DISABLE_CLOCK_STOP BIT(1) +#define SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE BIT(2) static int md_flags; module_param_named(sdw_md_flags, md_flags, int, 0444); @@ -1330,6 +1331,22 @@ static int intel_master_startup(struct sdw_master_device *md) pm_runtime_enable(&md->dev); } + /* + * Slave devices have an pm_runtime of 'Unsupported' until + * they report as ATTACHED. If they don't, e.g. because there + * are no Slave devices populated or if the power-on is + * delayed or dependent on a power switch, the Master will + * remain active and prevent its parent from suspending. + * + * Conditionally force the pm_runtime core to re-evaluate the + * Master status in the absence of any Slave activity. A quirk + * is provided to e.g. deal with Slaves that may be powered on + * with a delay. A more complete solution would require the + * definition of Master properties. + */ + if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE)) + pm_runtime_idle(&md->dev); + return 0; err_interrupt: @@ -1443,6 +1460,7 @@ static int intel_resume(struct device *dev) struct sdw_master_device *md = to_sdw_master_device(dev); struct sdw_cdns *cdns = dev_get_drvdata(dev); struct sdw_intel *sdw = cdns_to_intel(cdns); + int link_flags; int ret; if (cdns->bus.prop.hw_disabled) { @@ -1463,6 +1481,10 @@ static int intel_resume(struct device *dev) pm_runtime_enable(dev); md->pm_runtime_suspended = false; + + link_flags = md_flags >> (sdw->cdns.bus.link_id * 8); + if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE)) + pm_runtime_idle(&md->dev); } ret = intel_init(sdw); From 56e0426fcf0e895717ec9f50852787819e631e30 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 12 Oct 2019 12:32:57 -0500 Subject: [PATCH 1939/1995] [HACK] add traces to debug aplay suspend/resume issue Signed-off-by: Pierre-Louis Bossart Signed-off-by: Bard Liao --- drivers/soundwire/intel.c | 52 +++++++++++++++++++++++++++++++++++--- drivers/soundwire/stream.c | 11 ++++++++ sound/soc/Makefile | 2 ++ sound/soc/sof/pcm.c | 7 +++++ sound/soc/sof/pm.c | 11 ++++++++ 5 files changed, 80 insertions(+), 3 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index da29fe6e375272..6e7e1be77dcd75 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -762,6 +762,8 @@ static int intel_startup(struct snd_pcm_substream *substream, struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); int ret; + dev_err(dai->dev, "%s: %s: start\n", __func__, dai->name); + ret = pm_runtime_get_sync(cdns->dev); if (ret < 0 && ret != -EACCES) { dev_err_ratelimited(cdns->dev, @@ -770,7 +772,11 @@ static int intel_startup(struct snd_pcm_substream *substream, pm_runtime_put_noidle(cdns->dev); } - return sdw_stream_setup(substream, dai); + ret = sdw_stream_setup(substream, dai); + + dev_err(dai->dev, "%s: %s: done\n", __func__, dai->name); + + return ret; } static int intel_hw_params(struct snd_pcm_substream *substream, @@ -787,6 +793,8 @@ static int intel_hw_params(struct snd_pcm_substream *substream, int ret; bool pcm = true; + dev_err(dai->dev, "%s: %s: start\n", __func__, dai->name); + dma = snd_soc_dai_get_dma_data(dai, substream); if (!dma) return -EIO; @@ -856,6 +864,8 @@ static int intel_hw_params(struct snd_pcm_substream *substream, kfree(pconfig); error: + + dev_err(dai->dev, "%s: %s: done\n", __func__, dai->name); return ret; } @@ -868,6 +878,8 @@ static int intel_prepare(struct snd_pcm_substream *substream, int ch, dir; int ret; + dev_err(dai->dev, "%s: %s: start\n", __func__, dai->name); + dma = snd_soc_dai_get_dma_data(dai, substream); if (!dma) { dev_err(dai->dev, "failed to get dma data in %s", @@ -909,6 +921,7 @@ static int intel_prepare(struct snd_pcm_substream *substream, ret = sdw_prepare_stream(dma->stream); + dev_err(dai->dev, "%s: %s: done\n", __func__, dai->name); err: return ret; } @@ -919,6 +932,8 @@ static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct sdw_cdns_dma_data *dma; int ret; + dev_err(dai->dev, "%s: %s: start\n", __func__, dai->name); + dma = snd_soc_dai_get_dma_data(dai, substream); if (!dma) { dev_err(dai->dev, "failed to get dma data in %s", __func__); @@ -926,14 +941,18 @@ static int intel_trigger(struct snd_pcm_substream *substream, int cmd, } switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + dev_err(dai->dev, "%s: %s: resume\n", __func__, dai->name); + /* fallthrough */ case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: ret = sdw_enable_stream(dma->stream); break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: + dev_err(dai->dev, "%s: %s: suspend\n", __func__, dai->name); + /* fallthrough */ + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_STOP: ret = sdw_disable_stream(dma->stream); break; @@ -947,6 +966,9 @@ static int intel_trigger(struct snd_pcm_substream *substream, int cmd, dev_err(dai->dev, "%s trigger %d failed: %d", __func__, cmd, ret); + + dev_err(dai->dev, "%s: %s: done\n", __func__, dai->name); + return ret; } @@ -958,6 +980,8 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) struct sdw_cdns_dma_data *dma; int ret; + dev_err(dai->dev, "%s: %s: start\n", __func__, dai->name); + dma = snd_soc_dai_get_dma_data(dai, substream); if (!dma) return -EIO; @@ -985,6 +1009,8 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) dma->pdi = NULL; sdw_release_stream(dma->stream); + dev_err(dai->dev, "%s: %s: done\n", __func__, dai->name); + return 0; } @@ -994,6 +1020,8 @@ static void intel_shutdown(struct snd_pcm_substream *substream, struct sdw_cdns_dma_data *dma; struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); + dev_err(dai->dev, "%s: %s: start\n", __func__, dai->name); + dma = snd_soc_dai_get_dma_data(dai, substream); if (!dma) return; @@ -1003,6 +1031,8 @@ static void intel_shutdown(struct snd_pcm_substream *substream, pm_runtime_mark_last_busy(cdns->dev); pm_runtime_put_autosuspend(cdns->dev); + + dev_err(dai->dev, "%s: %s: done\n", __func__, dai->name); } static int intel_dai_suspend(struct snd_soc_dai *dai) @@ -1395,6 +1425,8 @@ static int intel_suspend(struct device *dev) return 0; } + dev_err(dev, "%s start\n", __func__); + if (pm_runtime_suspended(dev)) { dev_dbg(dev, "%s: pm_runtime status: suspended\n", @@ -1423,6 +1455,8 @@ static int intel_suspend(struct device *dev) intel_shim_wake(sdw, false); + dev_err(dev, "%s done\n", __func__); + return 0; } @@ -1438,6 +1472,8 @@ static int intel_suspend_runtime(struct device *dev) return 0; } + dev_err(dev, "%s start\n", __func__); + ret = sdw_cdns_enable_interrupt(cdns, false); if (ret < 0) { dev_err(dev, "cannot disable interrupts on suspend\n"); @@ -1452,6 +1488,8 @@ static int intel_suspend_runtime(struct device *dev) intel_shim_wake(sdw, false); + dev_err(dev, "%s done\n", __func__); + return 0; } @@ -1469,6 +1507,8 @@ static int intel_resume(struct device *dev) return 0; } + dev_err(dev, "%s start\n", __func__); + if (md->pm_runtime_suspended) { dev_dbg(dev, "%s: pm_runtime status was suspended, forcing active\n", @@ -1524,6 +1564,8 @@ static int intel_resume(struct device *dev) */ pm_runtime_mark_last_busy(cdns->dev); + dev_err(dev, "%s done\n", __func__); + return ret; } @@ -1539,6 +1581,8 @@ static int intel_resume_runtime(struct device *dev) return 0; } + dev_err(dev, "%s start\n", __func__); + ret = intel_init(sdw); if (ret) { dev_err(dev, "%s failed: %d", __func__, ret); @@ -1564,6 +1608,8 @@ static int intel_resume_runtime(struct device *dev) return ret; } + dev_err(dev, "%s done\n", __func__); + return ret; } diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 19837297718726..a016364593de4f 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1598,6 +1598,9 @@ int sdw_prepare_stream(struct sdw_stream_runtime *stream) state_err: sdw_release_bus_lock(stream); + + pr_err("%s: %s: done\n", __func__, stream->name); + return ret; } EXPORT_SYMBOL(sdw_prepare_stream); @@ -1673,6 +1676,8 @@ int sdw_enable_stream(struct sdw_stream_runtime *stream) state_err: sdw_release_bus_lock(stream); + + pr_err("%s: %s: done\n", __func__, stream->name); return ret; } EXPORT_SYMBOL(sdw_enable_stream); @@ -1755,6 +1760,9 @@ int sdw_disable_stream(struct sdw_stream_runtime *stream) state_err: sdw_release_bus_lock(stream); + + pr_err("%s: %s: done\n", __func__, stream->name); + return ret; } EXPORT_SYMBOL(sdw_disable_stream); @@ -1821,6 +1829,9 @@ int sdw_deprepare_stream(struct sdw_stream_runtime *stream) state_err: sdw_release_bus_lock(stream); + + pr_err("%s: %s: done\n", __func__, stream->name); + return ret; } EXPORT_SYMBOL(sdw_deprepare_stream); diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 861a21b7948443..429add4afe3827 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -1,3 +1,5 @@ +ccflags-y += -DDEBUG + # SPDX-License-Identifier: GPL-2.0 snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-utils.o soc-dai.o soc-component.o snd-soc-core-objs += soc-pcm.o soc-io.o soc-devres.o soc-ops.o diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index 9bb6388742e1a3..d6f72352141db7 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -341,6 +341,9 @@ static int sof_pcm_trigger(struct snd_soc_component *component, return 0; } + dev_dbg(sdev->dev, "pcm: trigger resume stream %d dir %d cmd %d\n", + spcm->pcm.pcm_id, substream->stream, cmd); + /* set up hw_params */ ret = sof_pcm_prepare(component, substream); if (ret < 0) { @@ -374,6 +377,10 @@ static int sof_pcm_trigger(struct snd_soc_component *component, spcm->stream[substream->stream].suspend_ignored = true; return 0; } + + dev_dbg(sdev->dev, "pcm: trigger suspend stream %d dir %d cmd %d\n", + spcm->pcm.pcm_id, substream->stream, cmd); + /* fallthrough */ case SNDRV_PCM_TRIGGER_STOP: stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 84290bbeebddb0..76c301a5ecf374 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -52,6 +52,8 @@ static int sof_resume(struct device *dev, bool runtime_resume) struct snd_sof_dev *sdev = dev_get_drvdata(dev); int ret; + dev_err(dev, "%s\n", __func__); + /* do nothing if dsp resume callbacks are not set */ if (!sof_ops(sdev)->resume || !sof_ops(sdev)->runtime_resume) return 0; @@ -131,6 +133,8 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) struct snd_sof_dev *sdev = dev_get_drvdata(dev); int ret; + dev_err(dev, "%s\n", __func__); + /* do nothing if dsp suspend callback is not set */ if (!sof_ops(sdev)->suspend) return 0; @@ -199,6 +203,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend) int snd_sof_runtime_suspend(struct device *dev) { + dev_err(dev, "%s\n", __func__); return sof_suspend(dev, true); } EXPORT_SYMBOL(snd_sof_runtime_suspend); @@ -207,12 +212,14 @@ int snd_sof_runtime_idle(struct device *dev) { struct snd_sof_dev *sdev = dev_get_drvdata(dev); + dev_err(dev, "%s\n", __func__); return snd_sof_dsp_runtime_idle(sdev); } EXPORT_SYMBOL(snd_sof_runtime_idle); int snd_sof_runtime_resume(struct device *dev) { + dev_err(dev, "%s\n", __func__); return sof_resume(dev, true); } EXPORT_SYMBOL(snd_sof_runtime_resume); @@ -274,6 +281,8 @@ int snd_sof_resume(struct device *dev) struct snd_sof_dev *sdev = dev_get_drvdata(dev); int ret; + dev_err(dev, "%s\n", __func__); + if (snd_sof_dsp_d0i3_on_suspend(sdev)) { /* resume from D0I3 */ dev_dbg(sdev->dev, "DSP will exit from D0i3...\n"); @@ -303,6 +312,8 @@ int snd_sof_suspend(struct device *dev) struct snd_sof_dev *sdev = dev_get_drvdata(dev); int ret; + dev_err(dev, "%s\n", __func__); + if (snd_sof_dsp_d0i3_on_suspend(sdev)) { /* suspend to D0i3 */ dev_dbg(sdev->dev, "DSP is trying to enter D0i3...\n"); From 473e81e0ac6560c20e911259d5a5a13a1d27d8b1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 21 Nov 2019 17:01:15 -0600 Subject: [PATCH 1940/1995] pm: add more traces Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/pm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 76c301a5ecf374..aa0b3ad957127f 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -17,6 +17,8 @@ static int sof_send_pm_ctx_ipc(struct snd_sof_dev *sdev, int cmd) struct sof_ipc_pm_ctx pm_ctx; struct sof_ipc_reply reply; + dev_err(sdev->dev, "%s\n", __func__); + memset(&pm_ctx, 0, sizeof(pm_ctx)); /* configure ctx save ipc message */ From bc3b762289fc56d857430ed0efe0f4b3bdee8d9f Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Mon, 2 Dec 2019 13:05:46 +0800 Subject: [PATCH 1941/1995] soundwire: cadence_master: remove config update for interrupt setting Config only needs to be updated when setting MCP_Config, MCP_Control and MCP_CmdCtrl to make these register setting effective. When updating config in master, master will communicate with slave to update status. Communication will be failed when masters and slaves are in clock stop state, and this unnecessary config update makes interrupt setting failed. Tested on Comet Lake with soundwire enabled Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/cadence_master.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 362fb6e49bfe09..25002ff6766bfb 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -812,7 +812,7 @@ int sdw_cdns_exit_reset(struct sdw_cdns *cdns) EXPORT_SYMBOL(sdw_cdns_exit_reset); /** - * sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config + * sdw_cdns_enable_interrupt() - Enable SDW interrupts * @cdns: Cadence instance */ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state) @@ -853,8 +853,7 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state) cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1, slave_intmask1); cdns_writel(cdns, CDNS_MCP_INTMASK, mask); - /* commit changes */ - return cdns_update_config(cdns); + return 0; } EXPORT_SYMBOL(sdw_cdns_enable_interrupt); From 118918c14e1b9b3d66cd3c2f12224d9b0f9f76d8 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 2 Dec 2019 16:05:13 -0600 Subject: [PATCH 1942/1995] soundwire: intel: add mutex to prevent concurrent access to SHIM registers Some of the SHIM registers exposed fields that are link specific, and in addition some of the power-related registers (SPA/CPA) take time to be updated. Uncontrolled access leads to timeouts or errors. Add a mutex at the controller level, shared by all links, so that all accesses to such registers are serialized, and follow a pattern of read-modify-write. GitHub issue: https://github.com/thesofproject/linux/issues/1555 Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 37 ++++++++++++++++++++++++++++------ drivers/soundwire/intel.h | 2 ++ drivers/soundwire/intel_init.c | 3 +++ 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 6e7e1be77dcd75..711526dfd018fe 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -308,6 +308,8 @@ static int intel_link_power_up(struct sdw_intel *sdw) int spa_mask, cpa_mask; int link_control, ret; + mutex_lock(sdw->link_res->shim_lock); + /* Link power up sequence */ link_control = intel_readl(shim, SDW_SHIM_LCTL); spa_mask = (SDW_SHIM_LCTL_SPA << link_id); @@ -315,6 +317,8 @@ static int intel_link_power_up(struct sdw_intel *sdw) link_control |= spa_mask; ret = intel_set_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask); + mutex_unlock(sdw->link_res->shim_lock); + if (ret < 0) return ret; @@ -329,6 +333,8 @@ static int intel_shim_init(struct sdw_intel *sdw) int sync_reg, ret; u16 ioctl = 0, act = 0; + mutex_lock(sdw->link_res->shim_lock); + /* Initialize Shim */ ioctl |= SDW_SHIM_IOCTL_BKE; intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); @@ -373,6 +379,8 @@ static int intel_shim_init(struct sdw_intel *sdw) sync_reg |= SDW_SHIM_SYNC_SYNCCPU; ret = intel_clear_bit(shim, SDW_SHIM_SYNC, sync_reg, SDW_SHIM_SYNC_SYNCCPU); + mutex_unlock(sdw->link_res->shim_lock); + if (ret < 0) dev_err(sdw->cdns.dev, "Failed to set sync period: %d\n", ret); @@ -385,13 +393,15 @@ static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) unsigned int link_id = sdw->instance; u16 wake_en, wake_sts; + mutex_lock(sdw->link_res->shim_lock); + wake_en = intel_readw(shim, SDW_SHIM_WAKEEN); + if (wake_enable) { /* Enable the wakeup */ - intel_writew(shim, SDW_SHIM_WAKEEN, - (SDW_SHIM_WAKEEN_ENABLE << link_id)); + wake_en |= (SDW_SHIM_WAKEEN_ENABLE << link_id); + intel_writew(shim, SDW_SHIM_WAKEEN, wake_en); } else { /* Disable the wake up interrupt */ - wake_en = intel_readw(shim, SDW_SHIM_WAKEEN); wake_en &= ~(SDW_SHIM_WAKEEN_ENABLE << link_id); intel_writew(shim, SDW_SHIM_WAKEEN, wake_en); @@ -400,6 +410,7 @@ static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) wake_sts |= (SDW_SHIM_WAKEEN_ENABLE << link_id); intel_writew(shim, SDW_SHIM_WAKESTS_STATUS, wake_sts); } + mutex_unlock(sdw->link_res->shim_lock); } static int intel_link_power_down(struct sdw_intel *sdw) @@ -409,6 +420,8 @@ static int intel_link_power_down(struct sdw_intel *sdw) void __iomem *shim = sdw->link_res->shim; u16 ioctl; + mutex_lock(sdw->link_res->shim_lock); + /* Glue logic */ ioctl = intel_readw(shim, SDW_SHIM_IOCTL(link_id)); ioctl |= SDW_SHIM_IOCTL_BKE; @@ -425,6 +438,8 @@ static int intel_link_power_down(struct sdw_intel *sdw) link_control &= spa_mask; ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask); + mutex_unlock(sdw->link_res->shim_lock); + if (ret < 0) return ret; @@ -652,11 +667,15 @@ static int intel_pre_bank_switch(struct sdw_bus *bus) if (!bus->multi_link) return 0; + mutex_lock(sdw->link_res->shim_lock); + /* Read SYNC register */ sync_reg = intel_readl(shim, SDW_SHIM_SYNC); sync_reg |= SDW_SHIM_SYNC_CMDSYNC << sdw->instance; intel_writel(shim, SDW_SHIM_SYNC, sync_reg); + mutex_unlock(sdw->link_res->shim_lock); + return 0; } @@ -671,6 +690,8 @@ static int intel_post_bank_switch(struct sdw_bus *bus) if (!bus->multi_link) return 0; + mutex_lock(sdw->link_res->shim_lock); + /* Read SYNC register */ sync_reg = intel_readl(shim, SDW_SHIM_SYNC); @@ -682,9 +703,10 @@ static int intel_post_bank_switch(struct sdw_bus *bus) * * So, set the SYNCGO bit only if CMDSYNC bit is set for any Master. */ - if (!(sync_reg & SDW_SHIM_SYNC_CMDSYNC_MASK)) - return 0; - + if (!(sync_reg & SDW_SHIM_SYNC_CMDSYNC_MASK)) { + ret = 0; + goto unlock; + } /* * Set SyncGO bit to synchronously trigger a bank switch for * all the masters. A write to SYNCGO bit clears CMDSYNC bit for all @@ -694,6 +716,9 @@ static int intel_post_bank_switch(struct sdw_bus *bus) ret = intel_clear_bit(shim, SDW_SHIM_SYNC, sync_reg, SDW_SHIM_SYNC_SYNCGO); +unlock: + mutex_unlock(sdw->link_res->shim_lock); + if (ret < 0) dev_err(sdw->cdns.dev, "Post bank switch failed: %d\n", ret); diff --git a/drivers/soundwire/intel.h b/drivers/soundwire/intel.h index 2ae4fa7486861d..1d8740b452c6e0 100644 --- a/drivers/soundwire/intel.h +++ b/drivers/soundwire/intel.h @@ -15,6 +15,7 @@ * @irq: Interrupt line * @ops: Shim callback ops * @dev: device implementing hw_params and free callbacks + * @shim_lock: mutex to handle access to shared SHIM registers */ struct sdw_intel_link_res { struct sdw_master_device *md; @@ -27,6 +28,7 @@ struct sdw_intel_link_res { struct device *dev; struct sdw_cdns *cdns; struct list_head list; + struct mutex *shim_lock; /* protect shared registers */ }; #define SDW_INTEL_QUIRK_MASK_BUS_DISABLE BIT(1) diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 82aeb350c9bc15..018e4e23dd0509 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -212,6 +212,7 @@ static struct sdw_intel_ctx ctx->mmio_base = res->mmio_base; ctx->link_mask = res->link_mask; ctx->handle = res->handle; + mutex_init(&ctx->shim_lock); link = ctx->links; link_mask = ctx->link_mask; @@ -299,6 +300,8 @@ sdw_intel_startup_controller(struct sdw_intel_ctx *ctx) if (link_mask && !(link_mask & BIT(i))) continue; + link->shim_lock = &ctx->shim_lock; + md = link->md; md->driver->startup(md); From 6f73ad999501ec315cd753a444a57808d280d6cd Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 3 Dec 2019 17:02:10 -0600 Subject: [PATCH 1943/1995] soundwire: intel: add CLK_STOP_TEARDOWN for pm_runtime suspend Now that we have options, add support for TEARDOWN mode (same functionality as existing code) All other modes will be added in follow-up patches. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 82 ++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 32 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 711526dfd018fe..9795ba3caab180 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1489,6 +1489,7 @@ static int intel_suspend_runtime(struct device *dev) { struct sdw_cdns *cdns = dev_get_drvdata(dev); struct sdw_intel *sdw = cdns_to_intel(cdns); + u32 clock_stop_quirks; int ret; if (cdns->bus.prop.hw_disabled) { @@ -1499,23 +1500,31 @@ static int intel_suspend_runtime(struct device *dev) dev_err(dev, "%s start\n", __func__); - ret = sdw_cdns_enable_interrupt(cdns, false); - if (ret < 0) { - dev_err(dev, "cannot disable interrupts on suspend\n"); - return ret; - } + clock_stop_quirks = sdw->link_res->clock_stop_quirks; - ret = intel_link_power_down(sdw); - if (ret) { - dev_err(dev, "Link power down failed: %d", ret); - return ret; - } + if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) { + ret = sdw_cdns_enable_interrupt(cdns, false); + if (ret < 0) { + dev_err(dev, "cannot disable interrupts on suspend\n"); + return ret; + } - intel_shim_wake(sdw, false); + ret = intel_link_power_down(sdw); + if (ret) { + dev_err(dev, "Link power down failed: %d", ret); + return ret; + } + + intel_shim_wake(sdw, false); + } else { + dev_err(dev, "%s clock_stop_quirks %x unsupported\n", + __func__, clock_stop_quirks); + ret = -EINVAL; + } dev_err(dev, "%s done\n", __func__); - return 0; + return ret; } static int intel_resume(struct device *dev) @@ -1598,6 +1607,7 @@ static int intel_resume_runtime(struct device *dev) { struct sdw_cdns *cdns = dev_get_drvdata(dev); struct sdw_intel *sdw = cdns_to_intel(cdns); + u32 clock_stop_quirks; int ret; if (cdns->bus.prop.hw_disabled) { @@ -1608,29 +1618,37 @@ static int intel_resume_runtime(struct device *dev) dev_err(dev, "%s start\n", __func__); - ret = intel_init(sdw); - if (ret) { - dev_err(dev, "%s failed: %d", __func__, ret); - return ret; - } + clock_stop_quirks = sdw->link_res->clock_stop_quirks; - /* - * make sure all Slaves are tagged as UNATTACHED and provide - * reason for reinitialization - */ - sdw_clear_slave_status(&sdw->cdns.bus, - SDW_UNATTACH_REQUEST_MASTER_RESET); + if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) { + ret = intel_init(sdw); + if (ret) { + dev_err(dev, "%s failed: %d", __func__, ret); + return ret; + } - ret = sdw_cdns_enable_interrupt(cdns, true); - if (ret < 0) { - dev_err(dev, "cannot enable interrupts during resume\n"); - return ret; - } + /* + * make sure all Slaves are tagged as UNATTACHED and + * provide reason for reinitialization + */ + sdw_clear_slave_status(&sdw->cdns.bus, + SDW_UNATTACH_REQUEST_MASTER_RESET); - ret = sdw_cdns_exit_reset(cdns); - if (ret < 0) { - dev_err(dev, "unable to exit bus reset sequence during resume\n"); - return ret; + ret = sdw_cdns_enable_interrupt(cdns, true); + if (ret < 0) { + dev_err(dev, "cannot enable interrupts during resume\n"); + return ret; + } + + ret = sdw_cdns_exit_reset(cdns); + if (ret < 0) { + dev_err(dev, "unable to exit bus reset sequence during resume\n"); + return ret; + } + } else { + dev_err(dev, "%s clock_stop_quirks %x unsupported\n", + __func__, clock_stop_quirks); + ret = -EINVAL; } dev_err(dev, "%s done\n", __func__); From 58ff3a738739c7c3ac6fed97991e8173fd4de430 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 8 Nov 2019 16:30:56 +0800 Subject: [PATCH 1944/1995] soundwire: bus: add clock stop helpers SoundWire supports two clock stop modes. Add support to handle the clock stop modes and add pm_runtime calls in the bus. Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.c | 335 ++++++++++++++++++++++++++++++++++ include/linux/soundwire/sdw.h | 24 +++ 2 files changed, 359 insertions(+) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 4f2128b6746a01..16f4458f302ac1 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -2,6 +2,7 @@ // Copyright(c) 2015-17 Intel Corporation. #include +#include #include #include #include @@ -359,6 +360,52 @@ static int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value) return sdw_nwrite_no_pm(slave, addr, 1, &value); } +static int +sdw_bread_no_pm(struct sdw_bus *bus, u16 dev_num, u32 addr) +{ + struct sdw_msg msg; + u8 buf; + int ret; + + ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, + SDW_MSG_FLAG_READ, &buf); + if (ret) + return ret; + + ret = sdw_transfer(bus, &msg); + if (ret < 0) + return ret; + else + return buf; +} + +static int +sdw_bwrite_no_pm(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 value) +{ + struct sdw_msg msg; + int ret; + + ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, + SDW_MSG_FLAG_WRITE, &value); + if (ret) + return ret; + + return sdw_transfer(bus, &msg); +} + +static int +sdw_read_no_pm(struct sdw_slave *slave, u32 addr) +{ + u8 buf; + int ret; + + ret = sdw_nread_no_pm(slave, addr, 1, &buf); + if (ret < 0) + return ret; + else + return buf; +} + /** * sdw_nread() - Read "n" contiguous SDW Slave registers * @slave: SDW Slave @@ -664,6 +711,294 @@ static void sdw_modify_slave_status(struct sdw_slave *slave, mutex_unlock(&slave->bus->bus_lock); } +static enum sdw_clk_stop_mode sdw_get_clk_stop_mode(struct sdw_slave *slave) +{ + enum sdw_clk_stop_mode mode; + + /* + * Query for clock stop mode if Slave implements + * ops->get_clk_stop_mode, else read from property. + */ + if (slave->ops && slave->ops->get_clk_stop_mode) { + mode = slave->ops->get_clk_stop_mode(slave); + } else { + if (slave->prop.clk_stop_mode1) + mode = SDW_CLK_STOP_MODE1; + else + mode = SDW_CLK_STOP_MODE0; + } + + return mode; +} + +static int sdw_slave_clk_stop_callback(struct sdw_slave *slave, + enum sdw_clk_stop_mode mode, + enum sdw_clk_stop_type type) +{ + int ret; + + if (slave->ops && slave->ops->clk_stop) { + ret = slave->ops->clk_stop(slave, mode, type); + if (ret < 0) { + dev_err(&slave->dev, + "Clk Stop type =%d failed: %d\n", type, ret); + return ret; + } + } + + return 0; +} + +static int sdw_slave_clk_stop_prepare(struct sdw_slave *slave, + enum sdw_clk_stop_mode mode, + bool prepare) +{ + bool wake_en; + u32 val = 0; + int ret; + + wake_en = slave->prop.wake_capable; + + if (prepare) { + val = SDW_SCP_SYSTEMCTRL_CLK_STP_PREP; + + if (mode == SDW_CLK_STOP_MODE1) + val |= SDW_SCP_SYSTEMCTRL_CLK_STP_MODE1; + + if (wake_en) + val |= SDW_SCP_SYSTEMCTRL_WAKE_UP_EN; + } else { + val = sdw_read_no_pm(slave, SDW_SCP_SYSTEMCTRL); + + val &= ~(SDW_SCP_SYSTEMCTRL_CLK_STP_PREP); + } + + ret = sdw_write_no_pm(slave, SDW_SCP_SYSTEMCTRL, val); + + if (ret != 0) + dev_err(&slave->dev, + "Clock Stop prepare failed for slave: %d", ret); + + return ret; +} + +static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num) +{ + int retry = bus->clk_stop_timeout; + int val; + + do { + val = sdw_bread_no_pm(bus, dev_num, SDW_SCP_STAT) & + SDW_SCP_STAT_CLK_STP_NF; + if (!val) + break; + + usleep_range(1000, 1500); + retry--; + } while (retry); + + if (retry && !val) { + dev_info(bus->dev, "clock stop prep/de-prep done slave:%d", + dev_num); + return 0; + } + + dev_err(bus->dev, "clock stop prep/de-prep failed slave:%d", + dev_num); + + return -ETIMEDOUT; +} + +/** + * sdw_bus_prep_clk_stop: prepare Slave(s) for clock stop + * + * @bus: SDW bus instance + * + * Query Slave for clock stop mode and prepare for that mode. + */ +int sdw_bus_prep_clk_stop(struct sdw_bus *bus) +{ + enum sdw_clk_stop_mode slave_mode; + bool simple_clk_stop = true; + struct sdw_slave *slave; + bool is_slave = false; + int ret = 0; + + /* + * In order to save on transition time, prepare + * each Slave and then wait for all Slave(s) to be + * prepared for clock stop. + */ + list_for_each_entry(slave, &bus->slaves, node) { + if (!slave->dev_num) + continue; + + /* Identify if Slave(s) are available on Bus */ + is_slave = true; + + if (slave->status != SDW_SLAVE_ATTACHED && + slave->status != SDW_SLAVE_ALERT) + continue; + + slave_mode = sdw_get_clk_stop_mode(slave); + slave->curr_clk_stop_mode = slave_mode; + + ret = sdw_slave_clk_stop_callback(slave, slave_mode, + SDW_CLK_PRE_PREPARE); + if (ret < 0) { + dev_err(&slave->dev, + "pre-prepare failed:%d", ret); + return ret; + } + + ret = sdw_slave_clk_stop_prepare(slave, + slave_mode, true); + if (ret < 0) { + dev_err(&slave->dev, + "pre-prepare failed:%d", ret); + return ret; + } + + if (slave_mode == SDW_CLK_STOP_MODE1) + simple_clk_stop = false; + } + + if (is_slave && !simple_clk_stop) { + ret = sdw_bus_wait_for_clk_prep_deprep(bus, + SDW_BROADCAST_DEV_NUM); + if (ret < 0) + return ret; + } + + /* Inform slaves that prep is done */ + list_for_each_entry(slave, &bus->slaves, node) { + if (!slave->dev_num) + continue; + + if (slave->status != SDW_SLAVE_ATTACHED && + slave->status != SDW_SLAVE_ALERT) + continue; + + slave_mode = slave->curr_clk_stop_mode; + + if (slave_mode == SDW_CLK_STOP_MODE1) { + ret = sdw_slave_clk_stop_callback(slave, + slave_mode, + SDW_CLK_POST_PREPARE); + + if (ret < 0) { + dev_err(&slave->dev, + "post-prepare failed:%d", ret); + } + } + } + + return ret; +} +EXPORT_SYMBOL(sdw_bus_prep_clk_stop); + +/** + * sdw_bus_clk_stop: stop bus clock + * + * @bus: SDW bus instance + * + * After preparing the Slaves for clock stop, stop the clock by broadcasting + * write to SCP_CTRL register. + */ +int sdw_bus_clk_stop(struct sdw_bus *bus) +{ + int ret; + + /* + * broadcast clock stop now, attached Slaves will ACK this, + * unattached will ignore + */ + ret = sdw_bwrite_no_pm(bus, SDW_BROADCAST_DEV_NUM, + SDW_SCP_CTRL, SDW_SCP_CTRL_CLK_STP_NOW); + if (ret < 0) { + dev_err(bus->dev, + "ClockStopNow Broadcast message failed %d", ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL(sdw_bus_clk_stop); + +/** + * sdw_bus_exit_clk_stop: Exit clock stop mode + * + * @bus: SDW bus instance + * + * This De-prepares the Slaves by exiting Clock Stop Mode 0. For the Slaves + * exiting Clock Stop Mode 1, they will be de-prepared after they enumerate + * back. + */ +int sdw_bus_exit_clk_stop(struct sdw_bus *bus) +{ + enum sdw_clk_stop_mode mode; + bool simple_clk_stop = true; + struct sdw_slave *slave; + bool is_slave = false; + int ret; + + /* + * In order to save on transition time, de-prepare + * each Slave and then wait for all Slave(s) to be + * de-prepared after clock resume. + */ + list_for_each_entry(slave, &bus->slaves, node) { + if (!slave->dev_num) + continue; + + /* Identify if Slave(s) are available on Bus */ + is_slave = true; + + if (slave->status != SDW_SLAVE_ATTACHED && + slave->status != SDW_SLAVE_ALERT) + continue; + + mode = slave->curr_clk_stop_mode; + + if (mode == SDW_CLK_STOP_MODE1) { + simple_clk_stop = false; + continue; + } + + ret = sdw_slave_clk_stop_callback(slave, mode, + SDW_CLK_PRE_DEPREPARE); + if (ret < 0) + dev_warn(&slave->dev, + "clk stop deprep failed:%d", ret); + + ret = sdw_slave_clk_stop_prepare(slave, mode, + false); + + if (ret < 0) + dev_warn(&slave->dev, + "clk stop deprep failed:%d", ret); + } + + if (is_slave && !simple_clk_stop) + sdw_bus_wait_for_clk_prep_deprep(bus, SDW_BROADCAST_DEV_NUM); + + list_for_each_entry(slave, &bus->slaves, node) { + if (!slave->dev_num) + continue; + + if (slave->status != SDW_SLAVE_ATTACHED && + slave->status != SDW_SLAVE_ALERT) + continue; + + mode = slave->curr_clk_stop_mode; + sdw_slave_clk_stop_callback(slave, mode, + SDW_CLK_POST_DEPREPARE); + } + + return 0; +} +EXPORT_SYMBOL(sdw_bus_exit_clk_stop); + int sdw_configure_dpn_intr(struct sdw_slave *slave, int port, bool enable, int mask) { diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 1a765b10b8bbaa..1d3a1eca66d110 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -79,6 +79,21 @@ enum sdw_slave_status { SDW_SLAVE_RESERVED = 3, }; +/** + * enum sdw_clk_stop_type: clock stop operations + * + * @SDW_CLK_PRE_PREPARE: pre clock stop prepare + * @SDW_CLK_POST_PREPARE: post clock stop prepare + * @SDW_CLK_PRE_DEPREPARE: pre clock stop de-prepare + * @SDW_CLK_POST_DEPREPARE: post clock stop de-prepare + */ +enum sdw_clk_stop_type { + SDW_CLK_PRE_PREPARE = 0, + SDW_CLK_POST_PREPARE, + SDW_CLK_PRE_DEPREPARE, + SDW_CLK_POST_DEPREPARE, +}; + /** * enum sdw_command_response - Command response as defined by SDW spec * @SDW_CMD_OK: cmd was successful @@ -533,6 +548,11 @@ struct sdw_slave_ops { int (*port_prep)(struct sdw_slave *slave, struct sdw_prepare_ch *prepare_ch, enum sdw_port_prep_ops pre_ops); + int (*get_clk_stop_mode)(struct sdw_slave *slave); + int (*clk_stop)(struct sdw_slave *slave, + enum sdw_clk_stop_mode mode, + enum sdw_clk_stop_type type); + }; /** @@ -574,6 +594,7 @@ struct sdw_slave { #endif struct list_head node; struct completion *port_ready; + enum sdw_clk_stop_mode curr_clk_stop_mode; u16 dev_num; bool probed; struct completion probe_complete; @@ -931,6 +952,9 @@ int sdw_prepare_stream(struct sdw_stream_runtime *stream); int sdw_enable_stream(struct sdw_stream_runtime *stream); int sdw_disable_stream(struct sdw_stream_runtime *stream); int sdw_deprepare_stream(struct sdw_stream_runtime *stream); +int sdw_bus_prep_clk_stop(struct sdw_bus *bus); +int sdw_bus_clk_stop(struct sdw_bus *bus); +int sdw_bus_exit_clk_stop(struct sdw_bus *bus); /* messaging and data APIs */ From c46a5d62258155da889016fa99d94f602906ee1a Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Thu, 5 Dec 2019 11:57:09 -0600 Subject: [PATCH 1945/1995] soundwire: cadence_master: simplifiy cdns_init() There is no need for the clock_stop_exit argument with the latest implementation Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/cadence_master.c | 12 +----------- drivers/soundwire/cadence_master.h | 2 +- drivers/soundwire/intel.c | 2 +- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 25002ff6766bfb..caf5b7edb83714 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -978,22 +978,12 @@ static u32 cdns_set_initial_frame_shape(int n_rows, int n_cols) * sdw_cdns_init() - Cadence initialization * @cdns: Cadence instance */ -int sdw_cdns_init(struct sdw_cdns *cdns, bool clock_stop_exit) +int sdw_cdns_init(struct sdw_cdns *cdns) { struct sdw_bus *bus = &cdns->bus; struct sdw_master_prop *prop = &bus->prop; u32 val; int divider; - int ret; - - if (clock_stop_exit) { - ret = cdns_clear_bit(cdns, CDNS_MCP_CONTROL, - CDNS_MCP_CONTROL_CLK_STOP_CLR); - if (ret < 0) { - dev_err(cdns->dev, "Couldn't exit from clock stop\n"); - return ret; - } - } /* Set clock divider */ divider = (prop->mclk_freq / prop->max_clk_freq) - 1; diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index cd4feef0b9001b..a7c0cbbbd09657 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -146,7 +146,7 @@ extern struct sdw_master_ops sdw_cdns_master_ops; irqreturn_t sdw_cdns_irq(int irq, void *dev_id); irqreturn_t sdw_cdns_thread(int irq, void *dev_id); -int sdw_cdns_init(struct sdw_cdns *cdns, bool clock_stop_exit); +int sdw_cdns_init(struct sdw_cdns *cdns); int sdw_cdns_pdi_init(struct sdw_cdns *cdns, struct sdw_cdns_stream_config config); int sdw_cdns_exit_reset(struct sdw_cdns *cdns); diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 9795ba3caab180..f44ebbc99848dc 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1274,7 +1274,7 @@ static int intel_init(struct sdw_intel *sdw) intel_link_power_up(sdw); intel_shim_init(sdw); - return sdw_cdns_init(&sdw->cdns, false); + return sdw_cdns_init(&sdw->cdns); } /* From b23943f71f7a35d5a0911d56b47cea496f22b847 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Thu, 5 Dec 2019 12:11:52 -0600 Subject: [PATCH 1946/1995] soundwire: cadence_master: add clock_stop/restart routines Add support for clock stop and restart, with two configuration parameters: 1) when entering the ClockStop mode, Slave-initiated wakes can be prevented. 2) When exiting the ClockStop mode, the caller can request a Bus Reset (either if all Slaves were configured in ClockStopMode1 or the Master IP lost context and enumeration is required) Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/cadence_master.c | 158 ++++++++++++++++++++++++++++- drivers/soundwire/cadence_master.h | 3 + 2 files changed, 160 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index caf5b7edb83714..3f5cb76f535e23 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -223,12 +223,30 @@ static int cdns_clear_bit(struct sdw_cdns *cdns, int offset, u32 value) return 0; timeout--; - udelay(50); + usleep_range(50, 100); } while (timeout != 0); return -EAGAIN; } +static int cdns_set_wait(struct sdw_cdns *cdns, int offset, u32 mask, u32 value) +{ + int timeout = 10; + u32 reg_read; + + /* Wait for bit to be set */ + do { + reg_read = readl(cdns->registers + offset); + if ((reg_read & mask) == value) + return 0; + + timeout--; + usleep_range(50, 100); + } while (timeout != 0); + + return -ETIMEDOUT; +} + /* * all changes to the MCP_CONFIG, MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL * need to be confirmed with a write to MCP_CONFIG_UPDATE @@ -1167,6 +1185,144 @@ static const struct sdw_master_port_ops cdns_port_ops = { .dpn_port_enable_ch = cdns_port_enable, }; +/** + * sdw_cdns_clock_stop: Cadence clock stop configuration routine + * + * @cdns: Cadence instance + * @block_wake: prevent wakes if required by the platform + */ +int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) +{ + bool slave_attached = false; + struct sdw_slave *slave; + u32 status; + int ret; + + /* Check suspend status */ + status = cdns_readl(cdns, CDNS_MCP_STAT); + if (status & CDNS_MCP_STAT_CLK_STOP) { + dev_dbg(cdns->dev, "Clock is already stopped\n"); + return 1; + } + + /* + * For specific platforms, it is required to be able to put + * master into a state in which it ignores wake-up trials + * in clock stop state + */ + if (block_wake) + cdns_updatel(cdns, CDNS_MCP_CONTROL, + CDNS_MCP_CONTROL_BLOCK_WAKEUP, + CDNS_MCP_CONTROL_BLOCK_WAKEUP); + + list_for_each_entry(slave, &cdns->bus.slaves, node) { + if (slave->status == SDW_SLAVE_ATTACHED || + slave->status == SDW_SLAVE_ALERT) { + slave_attached = true; + break; + } + } + + /* + * This CMD_ACCEPT should be used when there are no devices + * attached on the link when entering clock stop mode. If this is + * not set and there is a broadcast write then the command ignored + * will be treated as a failure + */ + if (!slave_attached) + cdns_updatel(cdns, CDNS_MCP_CONTROL, + CDNS_MCP_CONTROL_CMD_ACCEPT, 1); + else + cdns_updatel(cdns, CDNS_MCP_CONTROL, + CDNS_MCP_CONTROL_CMD_ACCEPT, 0); + + /* commit changes */ + cdns_update_config(cdns); + + /* Prepare slaves for clock stop */ + ret = sdw_bus_prep_clk_stop(&cdns->bus); + if (ret < 0) { + dev_err(cdns->dev, "prepare clock stop failed %d", ret); + return ret; + } + + /* Enter clock stop */ + ret = sdw_bus_clk_stop(&cdns->bus); + if (ret < 0) { + dev_err(cdns->dev, "bus clock stop failed %d", ret); + return ret; + } + + ret = cdns_set_wait(cdns, CDNS_MCP_STAT, + CDNS_MCP_STAT_CLK_STOP, + CDNS_MCP_STAT_CLK_STOP); + if (ret < 0) + dev_err(cdns->dev, "Clock stop failed %d\n", ret); + + return ret; +} +EXPORT_SYMBOL(sdw_cdns_clock_stop); + +/** + * sdw_cdns_clock_restart: Cadence PM clock restart configuration routine + * + * @cdns: Cadence instance + * @bus_reset: context may be lost while in low power modes and the bus + * may require a Severe Reset and re-enumeration after a wake. + */ +int sdw_cdns_clock_restart(struct sdw_cdns *cdns, bool bus_reset) +{ + int ret; + + ret = cdns_clear_bit(cdns, CDNS_MCP_CONTROL, + CDNS_MCP_CONTROL_CLK_STOP_CLR); + if (ret < 0) { + dev_err(cdns->dev, "Couldn't exit from clock stop\n"); + return ret; + } + + ret = cdns_set_wait(cdns, CDNS_MCP_STAT, CDNS_MCP_STAT_CLK_STOP, 0); + if (ret < 0) { + dev_err(cdns->dev, "clock stop exit failed %d\n", ret); + return ret; + } + + cdns_updatel(cdns, CDNS_MCP_CONTROL, + CDNS_MCP_CONTROL_BLOCK_WAKEUP, 0); + + /* + * clear CMD_ACCEPT so that the command ignored + * will be treated as a failure during a broadcast write + */ + cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT, 0); + + if (bus_reset) { + /* program maximum length reset to be safe */ + cdns_updatel(cdns, CDNS_MCP_CONTROL, + CDNS_MCP_CONTROL_RST_DELAY, + CDNS_MCP_CONTROL_RST_DELAY); + + /* use hardware generated reset */ + cdns_updatel(cdns, CDNS_MCP_CONTROL, + CDNS_MCP_CONTROL_HW_RST, + CDNS_MCP_CONTROL_HW_RST); + } + + /* enable bus operations with clock and data */ + cdns_updatel(cdns, CDNS_MCP_CONFIG, + CDNS_MCP_CONFIG_OP, + CDNS_MCP_CONFIG_OP_NORMAL); + + cdns_update_config(cdns); + + ret = sdw_bus_exit_clk_stop(&cdns->bus); + if (ret < 0) + dev_err(cdns->dev, "bus failed to exit clock stop %d\n", ret); + + return ret; +} +EXPORT_SYMBOL(sdw_cdns_clock_restart); + /** * sdw_cdns_probe() - Cadence probe routine * @cdns: Cadence instance diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index a7c0cbbbd09657..8dff77f5d91fa5 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -152,6 +152,9 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns, int sdw_cdns_exit_reset(struct sdw_cdns *cdns); int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state); +int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake); +int sdw_cdns_clock_restart(struct sdw_cdns *cdns, bool bus_reset); + #ifdef CONFIG_DEBUG_FS void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root); #endif From 3a5bc97841905ac10765b79a951a146f108ab337 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Thu, 5 Dec 2019 13:46:53 +0800 Subject: [PATCH 1947/1995] soundwire: intel: add CLK_STOP_BUS_RESET support Move existing pm_runtime suspend under the CLK_STOP_TEARDOWN case. In this mode the Master IP will lose all context but in-band wakes are supported. On pm_runtime resume a complete re-enumeration will be performed after a bus reset. Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 45 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index f44ebbc99848dc..ea8694c4c2afa4 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1516,6 +1516,26 @@ static int intel_suspend_runtime(struct device *dev) } intel_shim_wake(sdw, false); + } else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) { + ret = sdw_cdns_clock_stop(cdns, true); + if (ret < 0) { + dev_err(dev, "cannot enable clock stop on suspend\n"); + return ret; + } + + ret = sdw_cdns_enable_interrupt(cdns, false); + if (ret < 0) { + dev_err(dev, "cannot disable interrupts on suspend\n"); + return ret; + } + + ret = intel_link_power_down(sdw); + if (ret) { + dev_err(dev, "Link power down failed: %d", ret); + return ret; + } + + intel_shim_wake(sdw, true); } else { dev_err(dev, "%s clock_stop_quirks %x unsupported\n", __func__, clock_stop_quirks); @@ -1645,6 +1665,31 @@ static int intel_resume_runtime(struct device *dev) dev_err(dev, "unable to exit bus reset sequence during resume\n"); return ret; } + } else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) { + ret = intel_init(sdw); + if (ret) { + dev_err(dev, "%s failed: %d", __func__, ret); + return ret; + } + + /* + * make sure all Slaves are tagged as UNATTACHED and + * provide reason for reinitialization + */ + sdw_clear_slave_status(&sdw->cdns.bus, + SDW_UNATTACH_REQUEST_MASTER_RESET); + + ret = sdw_cdns_enable_interrupt(cdns, true); + if (ret < 0) { + dev_err(dev, "cannot enable interrupts during resume\n"); + return ret; + } + + ret = sdw_cdns_clock_restart(cdns, true); + if (ret < 0) { + dev_err(dev, "unable to restart clock during resume\n"); + return ret; + } } else { dev_err(dev, "%s clock_stop_quirks %x unsupported\n", __func__, clock_stop_quirks); From 78db255260a7549078d4383fd8135904fb3e5cf3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 5 Dec 2019 13:51:49 -0600 Subject: [PATCH 1948/1995] soundwire: intel: add CLK_STOP_NOT_ALLOWED support In case the clock needs to keep running, we need to prevent the Master from entering pm_runtime suspend. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index ea8694c4c2afa4..4fb2e9775e331a 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1329,6 +1329,7 @@ static int intel_master_startup(struct sdw_master_device *md) struct sdw_cdns_stream_config config; struct sdw_intel *sdw; int link_flags; + u32 clock_stop_quirks; int ret; sdw = md->pdata; @@ -1386,6 +1387,20 @@ static int intel_master_startup(struct sdw_master_device *md) pm_runtime_enable(&md->dev); } + clock_stop_quirks = sdw->link_res->clock_stop_quirks; + if (clock_stop_quirks & SDW_INTEL_CLK_STOP_NOT_ALLOWED) { + /* + * To keep the clock running we need to prevent + * pm_runtime suspend from happening by increasing the + * reference count. + * This quirk is specified by the parent PCI device in + * case of specific latency requirements. It will have + * no effect if pm_runtime is disabled by the user via + * a module parameter for testing purposes. + */ + pm_runtime_get_noresume(&md->dev); + } + /* * Slave devices have an pm_runtime of 'Unsupported' until * they report as ATTACHED. If they don't, e.g. because there @@ -1419,6 +1434,12 @@ static int intel_master_remove(struct sdw_master_device *md) sdw = md->pdata; + /* + * Since pm_runtime is already disabled, we don't decrease + * the refcount when the clock_stop_quirk is + * SDW_INTEL_CLK_STOP_NOT_ALLOWED + */ + if (!sdw->cdns.bus.prop.hw_disabled) { intel_debugfs_exit(sdw); sdw_cdns_enable_interrupt(&sdw->cdns, false); From 44c2d1167694158d13fd47afe80fab28fcb451ed Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 16 Dec 2019 12:58:55 -0600 Subject: [PATCH 1949/1995] soundwire: intel: add interface to process wake events Add driver interface to process external wake events processed by the PCI subsystem. Signed-off-by: Pierre-Louis Bossart --- include/linux/soundwire/sdw.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 1d3a1eca66d110..347d2cda76d022 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -652,6 +652,7 @@ struct sdw_md_driver { int (*remove)(struct sdw_master_device *md); int (*autonomous_clock_stop_enable)(struct sdw_master_device *md, bool state); + void (*process_wake_event)(struct sdw_master_device *md); struct device_driver driver; }; From 29b877cd0f8809205cb50a63e07fe43f2a628a7c Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 6 Dec 2019 15:00:12 -0600 Subject: [PATCH 1950/1995] soundwire: intel: add wake interrupt support When system is suspended in clock stop mode on intel platforms, both master and slave are in clock stop mode and soundwire bus is taken over by a glue hardware. The bus message for jack event is processed by this glue hardware, which will trigger an interrupt to resume audio pci device. Then audio pci driver will resume soundwire master and slave, transfer bus ownership to master, finally slave will report jack event to master and codec driver is triggered to check jack status. Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 44 ++++++++++++++++++++++++++++++++++ drivers/soundwire/intel_init.c | 17 +++++++++++++ 2 files changed, 61 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 4fb2e9775e331a..ee62459903e04a 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1452,6 +1452,49 @@ static int intel_master_remove(struct sdw_master_device *md) return 0; } +static void intel_master_process_wakeen_event(struct sdw_master_device *md) +{ + struct sdw_intel *sdw; + struct sdw_slave *slave; + struct sdw_bus *bus; + void __iomem *shim; + u16 wake_sts; + + sdw = md->pdata; + + if (sdw->cdns.bus.prop.hw_disabled) { + dev_info(&md->dev, + "SoundWire master %d is disabled, ignoring\n", + sdw->cdns.bus.link_id); + return; + } + + shim = sdw->link_res->shim; + wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS); + + if (!(wake_sts & BIT(sdw->instance))) + return; + + /* disable WAKEEN interrupt ASAP to prevent interrupt flood */ + intel_shim_wake(sdw, false); + + bus = &sdw->cdns.bus; + + /* + * wake up master and slave so that slave can notify master + * the wakeen event and let codec driver check codec status + */ + list_for_each_entry(slave, &bus->slaves, node) { + if (slave->prop.wake_capable) { + if (slave->status != SDW_SLAVE_ATTACHED && + slave->status != SDW_SLAVE_ALERT) + continue; + + pm_request_resume(&slave->dev); + } + } +} + /* * PM calls */ @@ -1738,6 +1781,7 @@ struct sdw_md_driver intel_sdw_driver = { }, .probe = intel_master_probe, .startup = intel_master_startup, + .process_wake_event = intel_master_process_wakeen_event, .remove = intel_master_remove, }; EXPORT_SYMBOL_NS(intel_sdw_driver, SOUNDWIRE_INTEL); diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 018e4e23dd0509..12c9df488daece 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -409,6 +409,23 @@ void sdw_intel_exit(struct sdw_intel_ctx *ctx) } EXPORT_SYMBOL_NS(sdw_intel_exit, SOUNDWIRE_INTEL_INIT); +void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx) +{ + struct sdw_intel_link_res *link; + struct sdw_master_device *md; + + if (!ctx->links) + return; + + list_for_each_entry(link, &ctx->link_list, list) { + + md = link->md; + + md->driver->process_wake_event(md); + } +} +EXPORT_SYMBOL_NS(sdw_intel_process_wakeen_event, SOUNDWIRE_INTEL_INIT); + MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("Intel Soundwire Init Library"); MODULE_IMPORT_NS(SOUNDWIRE_INTEL); From 8974dabce26c75d2b2d16412eaeccb1d22214ba0 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 5 Dec 2019 14:15:27 -0600 Subject: [PATCH 1951/1995] soundwire: intel_init: handle power rail dependencies for clock stop mode When none of the clock stop quirks is specified, the Master IP will assume the context is preserved and will not reset the Bus and restart enumeration. Due to power rail dependencies, the HDaudio controller needs to remain powered and prevented from executing its pm_runtime suspend routine. This choice of course has a power impact, and this mode should only be selected when latency requirements are critical or the parent device can enter D0ix modes. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel_init.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 12c9df488daece..534c6cfbf4afdd 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include "cadence_master.h" @@ -57,12 +58,21 @@ static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx) { struct sdw_intel_link_res *link = ctx->links; struct sdw_master_device *md; + u32 link_mask; int i; if (!link) return 0; + link_mask = ctx->link_mask; + for (i = 0; i < ctx->count; i++, link++) { + if (link_mask && !(link_mask & BIT(i))) + continue; + + if (!link->clock_stop_quirks) + pm_runtime_put_noidle(link->dev); + md = link->md; if (md) md->driver->remove(md); @@ -305,6 +315,16 @@ sdw_intel_startup_controller(struct sdw_intel_ctx *ctx) md = link->md; md->driver->startup(md); + + if (!link->clock_stop_quirks) { + /* + * we need to prevent the parent PCI device + * from entering pm_runtime suspend, so that + * power rails to the SoundWire IP are not + * turned off. + */ + pm_runtime_get_noresume(link->dev); + } } return 0; From 64c319a95560cd444b18da448d32490a5006b7af Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 5 Dec 2019 14:24:47 -0600 Subject: [PATCH 1952/1995] soundwire: intel: support clock_stop mode without quirks In this mode, on restart the bus restarts immediately, the Slaves remain synchronized and all context is kept intact. Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index ee62459903e04a..42d4cd818da834 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1580,7 +1580,8 @@ static int intel_suspend_runtime(struct device *dev) } intel_shim_wake(sdw, false); - } else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) { + } else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET || + !clock_stop_quirks) { ret = sdw_cdns_clock_stop(cdns, true); if (ret < 0) { dev_err(dev, "cannot enable clock stop on suspend\n"); @@ -1754,6 +1755,24 @@ static int intel_resume_runtime(struct device *dev) dev_err(dev, "unable to restart clock during resume\n"); return ret; } + } else if (!clock_stop_quirks) { + ret = intel_init(sdw); + if (ret) { + dev_err(dev, "%s failed: %d", __func__, ret); + return ret; + } + + ret = sdw_cdns_enable_interrupt(cdns, true); + if (ret < 0) { + dev_err(dev, "cannot enable interrupts during resume\n"); + return ret; + } + + ret = sdw_cdns_clock_restart(cdns, false); + if (ret < 0) { + dev_err(dev, "unable to resume master during resume\n"); + return ret; + } } else { dev_err(dev, "%s clock_stop_quirks %x unsupported\n", __func__, clock_stop_quirks); From d9606e1ab3b7bf6b93e912fe03be6776ada55ff5 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 6 Dec 2019 15:49:57 +0800 Subject: [PATCH 1953/1995] soundwire: cadence_master: add interface to check clock status If master is in clock stop state, driver can't modify registers in master except the registers for clock stop setting. Signed-off-by: Rander Wang --- drivers/soundwire/cadence_master.c | 19 +++++++++++++++++++ drivers/soundwire/cadence_master.h | 1 + 2 files changed, 20 insertions(+) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 3f5cb76f535e23..89e9148f510ca0 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1185,6 +1185,25 @@ static const struct sdw_master_port_ops cdns_port_ops = { .dpn_port_enable_ch = cdns_port_enable, }; +/** + * sdw_cdns_is_clock_stop: Check clock status + * + * @cdns: Cadence instance + */ +bool sdw_cdns_is_clock_stop(struct sdw_cdns *cdns) +{ + u32 status; + + status = cdns_readl(cdns, CDNS_MCP_STAT) & CDNS_MCP_STAT_CLK_STOP; + if (status) { + dev_dbg(cdns->dev, "Clock is stopped\n"); + return true; + } + + return false; +} +EXPORT_SYMBOL(sdw_cdns_is_clock_stop); + /** * sdw_cdns_clock_stop: Cadence clock stop configuration routine * diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index 8dff77f5d91fa5..516ed26c40e3ae 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -152,6 +152,7 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns, int sdw_cdns_exit_reset(struct sdw_cdns *cdns); int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state); +bool sdw_cdns_is_clock_stop(struct sdw_cdns *cdns); int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake); int sdw_cdns_clock_restart(struct sdw_cdns *cdns, bool bus_reset); From dc1f6dfb0c7458d0870dbd143d556c80dabe2b60 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 6 Dec 2019 15:56:09 +0800 Subject: [PATCH 1954/1995] soundwire: intel: Fix a io timeout issue if SDW_INTEL_CLK_STOP_BUS_RESET is set If two masters are working and one of them become suspended and activated again, this master will be failed to resumed in SDW_INTEL_CLK_STOP_BUS_RESET mode. The reason is: on intel platform, there are four masters in the same power domain. If one master is active, all other masters are always powered on. Each master will be set to clock stop when it is inactive. And in resume function each master will be initialized because it asummes it is powered off. But if the master is not powered off, it should be in clock stop state, and the normal initialization will be failed in this state. Now check clock status and don't initialize master if it is in clock stop mode. Signed-off-by: Rander Wang --- drivers/soundwire/intel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 42d4cd818da834..22bca43fc47a65 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1274,6 +1274,9 @@ static int intel_init(struct sdw_intel *sdw) intel_link_power_up(sdw); intel_shim_init(sdw); + if (sdw_cdns_is_clock_stop(&sdw->cdns)) + return 0; + return sdw_cdns_init(&sdw->cdns); } From 7bee702f16f5b138812416748f2296054755c156 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 9 Dec 2019 13:56:03 -0600 Subject: [PATCH 1955/1995] soundwire: bus: treat CMD_IGNORED as success on ClockStop If there are no Slaves in ATTACHED or ALERT mode, the CMD_IGNORED/-ENODATA error code is perfectly legit. Filter this case to report errors and let the caller deal with the CMD_IGNORED case. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 16f4458f302ac1..6864241f0a94ed 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -916,8 +916,12 @@ int sdw_bus_clk_stop(struct sdw_bus *bus) ret = sdw_bwrite_no_pm(bus, SDW_BROADCAST_DEV_NUM, SDW_SCP_CTRL, SDW_SCP_CTRL_CLK_STP_NOW); if (ret < 0) { - dev_err(bus->dev, - "ClockStopNow Broadcast message failed %d", ret); + if (ret == -ENODATA) + dev_dbg(bus->dev, + "ClockStopNow Broadcast msg ignored %d", ret); + else + dev_err(bus->dev, + "ClockStopNow Broadcast msg failed %d", ret); return ret; } From 369b75b80309a30a165d62d68bcefcccb6083b22 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 9 Dec 2019 14:39:59 -0600 Subject: [PATCH 1956/1995] soundwire: cadence_master: fix usage of CMD_ACCEPT cdns_updatel() applies its parameter assuming it's already shifted by the correct amount. Using '1' instead of BIT(1) is incorrect, fix. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/cadence_master.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 89e9148f510ca0..075c49bb4a670a 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1250,7 +1250,8 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) */ if (!slave_attached) cdns_updatel(cdns, CDNS_MCP_CONTROL, - CDNS_MCP_CONTROL_CMD_ACCEPT, 1); + CDNS_MCP_CONTROL_CMD_ACCEPT, + CDNS_MCP_CONTROL_CMD_ACCEPT); else cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT, 0); From bbe5d7d43a29f3eb3adbf9735dfa6d0ba0d11974 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 9 Dec 2019 16:41:24 -0600 Subject: [PATCH 1957/1995] soundwire: cadence_master: log more useful information during timeouts Add the type of command, device number, register offset and length to reverse engineer what caused the issue. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/cadence_master.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 075c49bb4a670a..161ae60693e596 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -463,7 +463,8 @@ _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd, time = wait_for_completion_timeout(&cdns->tx_complete, msecs_to_jiffies(CDNS_TX_TIMEOUT)); if (!time) { - dev_err(cdns->dev, "IO transfer timed out\n"); + dev_err(cdns->dev, "IO transfer timed out, cmd %d device %d addr %x len %d\n", + cmd, msg->dev_num, msg->addr, msg->len); msg->len = 0; return SDW_CMD_TIMEOUT; } From d47836af2f1c025904c613dee45eb43f6545a212 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 3 Dec 2019 16:46:48 -0600 Subject: [PATCH 1958/1995] soundwire: intel_init: add support for clock_stop quirks Just pass the information provided by the parent (SOF driver) Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.h | 2 ++ drivers/soundwire/intel_init.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/soundwire/intel.h b/drivers/soundwire/intel.h index 1d8740b452c6e0..0e6b8a5fd7c2a3 100644 --- a/drivers/soundwire/intel.h +++ b/drivers/soundwire/intel.h @@ -16,6 +16,7 @@ * @ops: Shim callback ops * @dev: device implementing hw_params and free callbacks * @shim_lock: mutex to handle access to shared SHIM registers + * @clock_stop_quirks: mask defining requested behavior on pm_suspend */ struct sdw_intel_link_res { struct sdw_master_device *md; @@ -29,6 +30,7 @@ struct sdw_intel_link_res { struct sdw_cdns *cdns; struct list_head list; struct mutex *shim_lock; /* protect shared registers */ + u32 clock_stop_quirks; }; #define SDW_INTEL_QUIRK_MASK_BUS_DISABLE BIT(1) diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 534c6cfbf4afdd..fe5944ddb16121 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -257,6 +257,7 @@ static struct sdw_intel_ctx link->alh = res->mmio_base + SDW_ALH_BASE; link->ops = res->ops; link->dev = res->dev; + link->clock_stop_quirks = res->clock_stop_quirks; /* let the SoundWire master driver to its probe */ md->driver->probe(md, link); From b01de1d58c409975293337a3ed7296eeed382ab6 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 9 Dec 2019 13:50:03 -0600 Subject: [PATCH 1959/1995] soundwire: cadence_master: enter clock stop if there are no Slaves present If there aren't any Slaves present (ATTACHED or ALERT status), we can safely infore CMD_IGNORED/-ENODATA error codes. The Cadence IP is configured to handle such cases as success. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/cadence_master.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 161ae60693e596..bb5c95cfecc5ab 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1213,7 +1213,7 @@ EXPORT_SYMBOL(sdw_cdns_is_clock_stop); */ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) { - bool slave_attached = false; + bool slave_present = false; struct sdw_slave *slave; u32 status; int ret; @@ -1238,7 +1238,7 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) list_for_each_entry(slave, &cdns->bus.slaves, node) { if (slave->status == SDW_SLAVE_ATTACHED || slave->status == SDW_SLAVE_ALERT) { - slave_attached = true; + slave_present = true; break; } } @@ -1249,7 +1249,7 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) * not set and there is a broadcast write then the command ignored * will be treated as a failure */ - if (!slave_attached) + if (!slave_present) cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT, CDNS_MCP_CONTROL_CMD_ACCEPT); @@ -1267,9 +1267,12 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) return ret; } - /* Enter clock stop */ + /* + * Enter clock stop mode and only report errors if there are + * Slave devices present (ALERT or ATTACHED) + */ ret = sdw_bus_clk_stop(&cdns->bus); - if (ret < 0) { + if (ret < 0 && slave_present && ret != -ENODATA) { dev_err(cdns->dev, "bus clock stop failed %d", ret); return ret; } From 689655c0b665b240a3514e2cc5a82a74c35010cc Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 13 Dec 2019 08:50:40 +0800 Subject: [PATCH 1960/1995] Soundwire: bus: return in the while loop rather than break and return So we don't need extra if condition outside the while loop. Signed-off-by: Bard Liao --- drivers/soundwire/bus.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 6864241f0a94ed..27c0b0eb0512dc 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -790,19 +790,16 @@ static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num) do { val = sdw_bread_no_pm(bus, dev_num, SDW_SCP_STAT) & SDW_SCP_STAT_CLK_STP_NF; - if (!val) - break; + if (!val) { + dev_info(bus->dev, "clock stop prep/de-prep done slave:%d", + dev_num); + return 0; + } usleep_range(1000, 1500); retry--; } while (retry); - if (retry && !val) { - dev_info(bus->dev, "clock stop prep/de-prep done slave:%d", - dev_num); - return 0; - } - dev_err(bus->dev, "clock stop prep/de-prep failed slave:%d", dev_num); From 79f6806cf342bbdde5f5f9124f618004318fa176 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 13 Dec 2019 08:58:24 +0800 Subject: [PATCH 1961/1995] Soundwire: set is_slave only if the slave is attached We don't need to do anything for the slave if it is unattached. Signed-off-by: Bard Liao --- drivers/soundwire/bus.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 27c0b0eb0512dc..c11dd307813a1e 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -830,13 +830,13 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus) if (!slave->dev_num) continue; - /* Identify if Slave(s) are available on Bus */ - is_slave = true; - if (slave->status != SDW_SLAVE_ATTACHED && slave->status != SDW_SLAVE_ALERT) continue; + /* Identify if Slave(s) are available on Bus */ + is_slave = true; + slave_mode = sdw_get_clk_stop_mode(slave); slave->curr_clk_stop_mode = slave_mode; @@ -952,13 +952,13 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus) if (!slave->dev_num) continue; - /* Identify if Slave(s) are available on Bus */ - is_slave = true; - if (slave->status != SDW_SLAVE_ATTACHED && slave->status != SDW_SLAVE_ALERT) continue; + /* Identify if Slave(s) are available on Bus */ + is_slave = true; + mode = slave->curr_clk_stop_mode; if (mode == SDW_CLK_STOP_MODE1) { From 28f7dc89ec8649af9ff36d3ab8eb31c39841e331 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 13 Dec 2019 09:26:21 +0800 Subject: [PATCH 1962/1995] soundwire: test is_slave before list_for_each_entry(slave, &bus->slaves, node) We don't need to test each slave's status if we already know there is no slave attached. Signed-off-by: Bard Liao --- drivers/soundwire/bus.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index c11dd307813a1e..ba88d88dda8bcd 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -867,6 +867,10 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus) return ret; } + /* Don't need to inform slaves if there is no slave attached */ + if (!is_slave) + return ret; + /* Inform slaves that prep is done */ list_for_each_entry(slave, &bus->slaves, node) { if (!slave->dev_num) @@ -983,6 +987,13 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus) if (is_slave && !simple_clk_stop) sdw_bus_wait_for_clk_prep_deprep(bus, SDW_BROADCAST_DEV_NUM); + /* + * Don't need to call slave callback function if there is no slave + * attached + */ + if (!is_slave) + return 0; + list_for_each_entry(slave, &bus->slaves, node) { if (!slave->dev_num) continue; From a348a09666558442466ff55e9c7ff963683fa54f Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 11 Dec 2019 16:58:20 +0800 Subject: [PATCH 1963/1995] soundwire: intel: refine runtime pm for SDW_INTEL_CLK_STOP_BUS_RESET When all the links are suspended, the HDaudio controller may suspend and the power rails to the SoundWire IP may be disabled, requiring a complete re-initialization/enumeration on resume. However, if one or more Masters remained active, the HDaudio controller will remain active and the power rails will remain enabled. As a result, during the link resume step we can check if the context was preserved by verifying if the clock was stopped, and avoid doing a complete bus reset and re-enumeration. Signed-off-by: Rander Wang --- drivers/soundwire/intel.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 22bca43fc47a65..c1699af2f6f169 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1696,6 +1696,8 @@ static int intel_resume_runtime(struct device *dev) struct sdw_cdns *cdns = dev_get_drvdata(dev); struct sdw_intel *sdw = cdns_to_intel(cdns); u32 clock_stop_quirks; + bool clock_stop0; + int status; int ret; if (cdns->bus.prop.hw_disabled) { @@ -1740,12 +1742,23 @@ static int intel_resume_runtime(struct device *dev) return ret; } + /* + * An exception condition occurs for the CLK_STOP_BUS_RESET + * case if one or more masters remain active. In this condition, + * all the masters are powered on for they are in the same power + * domain. Master can preserve its context for clock stop0, so + * there is no need to clear slave status and reset bus. + */ + clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns); + /* * make sure all Slaves are tagged as UNATTACHED and * provide reason for reinitialization */ - sdw_clear_slave_status(&sdw->cdns.bus, - SDW_UNATTACH_REQUEST_MASTER_RESET); + if (!clock_stop0) { + status = SDW_UNATTACH_REQUEST_MASTER_RESET; + sdw_clear_slave_status(&sdw->cdns.bus, status); + } ret = sdw_cdns_enable_interrupt(cdns, true); if (ret < 0) { @@ -1753,7 +1766,7 @@ static int intel_resume_runtime(struct device *dev) return ret; } - ret = sdw_cdns_clock_restart(cdns, true); + ret = sdw_cdns_clock_restart(cdns, !clock_stop0); if (ret < 0) { dev_err(dev, "unable to restart clock during resume\n"); return ret; From a660bbede7b79aa41d8cbbfc385b096cf2219b95 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 18 Dec 2019 20:52:23 -0600 Subject: [PATCH 1964/1995] soundwire: cadence_master: filter out bad interrupts If somehow we read the interrupt status while the IP is not powered the result is probably undefined or 0xffffffff. We do know that some of the bits are reserved and read as zero, so use as a filter to discard invalid configurations. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/cadence_master.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index bb5c95cfecc5ab..1ae1fca9c2f9bc 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -75,6 +75,7 @@ MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask"); #define CDNS_MCP_INTMASK 0x48 #define CDNS_MCP_INT_IRQ BIT(31) +#define CDNS_MCP_INT_RESERVED1 GENMASK(30, 17) #define CDNS_MCP_INT_WAKEUP BIT(16) #define CDNS_MCP_INT_SLAVE_RSVD BIT(15) #define CDNS_MCP_INT_SLAVE_ALERT BIT(14) @@ -86,10 +87,12 @@ MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask"); #define CDNS_MCP_INT_DATA_CLASH BIT(9) #define CDNS_MCP_INT_PARITY BIT(8) #define CDNS_MCP_INT_CMD_ERR BIT(7) +#define CDNS_MCP_INT_RESERVED2 GENMASK(6, 4) #define CDNS_MCP_INT_RX_NE BIT(3) #define CDNS_MCP_INT_RX_WL BIT(2) #define CDNS_MCP_INT_TXE BIT(1) #define CDNS_MCP_INT_TXF BIT(0) +#define CDNS_MCP_INT_RESERVED (CDNS_MCP_INT_RESERVED1 | CDNS_MCP_INT_RESERVED2) #define CDNS_MCP_INTSET 0x4C @@ -725,6 +728,10 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id) int_status = cdns_readl(cdns, CDNS_MCP_INTSTAT); + /* check for reserved values read as zero */ + if (int_status & CDNS_MCP_INT_RESERVED) + return IRQ_NONE; + if (!(int_status & CDNS_MCP_INT_IRQ)) return IRQ_NONE; From 8a144cb8fa97223bbc7d4a2cc1c2577b6d0c55ac Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 19 Dec 2019 18:47:30 -0600 Subject: [PATCH 1965/1995] soundwire: cadence: disable exit_clock_stop when doing a bus_reset This function is broken due to race conditions and bad ideas... When a bus reset occurs, the clock stop is no longer prepared. FIXME: the clock stop mode1 needs to wait for the device to re-enumerate. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/cadence_master.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 1ae1fca9c2f9bc..be85b178894658 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1346,9 +1346,11 @@ int sdw_cdns_clock_restart(struct sdw_cdns *cdns, bool bus_reset) cdns_update_config(cdns); - ret = sdw_bus_exit_clk_stop(&cdns->bus); - if (ret < 0) - dev_err(cdns->dev, "bus failed to exit clock stop %d\n", ret); + if (!bus_reset) { + ret = sdw_bus_exit_clk_stop(&cdns->bus); + if (ret < 0) + dev_err(cdns->dev, "bus failed to exit clock stop %d\n", ret); + } return ret; } From a823e38eb51fc594ccf1c31fe8dbc2b7191c2b30 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 19 Dec 2019 20:05:12 -0600 Subject: [PATCH 1966/1995] soundwire: intel: don't program Sync registers in clock stop mode This leads to a "Failed to set sync period" error log, but the values don't need to be reprogrammed. FIXME: is this the right fix? Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index c1699af2f6f169..cf37eb75108659 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -326,11 +326,11 @@ static int intel_link_power_up(struct sdw_intel *sdw) return 0; } -static int intel_shim_init(struct sdw_intel *sdw) +static int intel_shim_init(struct sdw_intel *sdw, bool clock_stop) { void __iomem *shim = sdw->link_res->shim; unsigned int link_id = sdw->instance; - int sync_reg, ret; + int sync_reg, ret = 0; u16 ioctl = 0, act = 0; mutex_lock(sdw->link_res->shim_lock); @@ -370,19 +370,21 @@ static int intel_shim_init(struct sdw_intel *sdw) act |= SDW_SHIM_CTMCTL_DODS; intel_writew(shim, SDW_SHIM_CTMCTL(link_id), act); - /* Now set SyncPRD period */ - sync_reg = intel_readl(shim, SDW_SHIM_SYNC); - sync_reg |= (SDW_SHIM_SYNC_SYNCPRD_VAL << - SDW_REG_SHIFT(SDW_SHIM_SYNC_SYNCPRD)); + if (!clock_stop) { + /* Now set SyncPRD period */ + sync_reg = intel_readl(shim, SDW_SHIM_SYNC); + sync_reg |= (SDW_SHIM_SYNC_SYNCPRD_VAL << + SDW_REG_SHIFT(SDW_SHIM_SYNC_SYNCPRD)); - /* Set SyncCPU bit */ - sync_reg |= SDW_SHIM_SYNC_SYNCCPU; - ret = intel_clear_bit(shim, SDW_SHIM_SYNC, sync_reg, - SDW_SHIM_SYNC_SYNCCPU); - mutex_unlock(sdw->link_res->shim_lock); + /* Set SyncCPU bit */ + sync_reg |= SDW_SHIM_SYNC_SYNCCPU; + ret = intel_clear_bit(shim, SDW_SHIM_SYNC, sync_reg, + SDW_SHIM_SYNC_SYNCCPU); + if (ret < 0) + dev_err(sdw->cdns.dev, "Failed to set sync period: %d\n", ret); - if (ret < 0) - dev_err(sdw->cdns.dev, "Failed to set sync period: %d\n", ret); + } + mutex_unlock(sdw->link_res->shim_lock); return ret; } @@ -1270,11 +1272,16 @@ static struct sdw_master_ops sdw_intel_ops = { static int intel_init(struct sdw_intel *sdw) { + bool clock_stop; + /* Initialize shim and controller */ intel_link_power_up(sdw); - intel_shim_init(sdw); - if (sdw_cdns_is_clock_stop(&sdw->cdns)) + clock_stop = sdw_cdns_is_clock_stop(&sdw->cdns); + + intel_shim_init(sdw, clock_stop); + + if (clock_stop) return 0; return sdw_cdns_init(&sdw->cdns); From 487e4b1f6c01851c207ef1c50d5ba6667ead531b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 19 Dec 2019 19:07:12 -0600 Subject: [PATCH 1967/1995] soundwire: intel: add traces to track clock restart mode Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index cf37eb75108659..da373705ea8230 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1718,6 +1718,9 @@ static int intel_resume_runtime(struct device *dev) clock_stop_quirks = sdw->link_res->clock_stop_quirks; if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) { + + dev_dbg(dev, "%s resume from TEARDOWN\n", __func__); + ret = intel_init(sdw); if (ret) { dev_err(dev, "%s failed: %d", __func__, ret); @@ -1743,6 +1746,9 @@ static int intel_resume_runtime(struct device *dev) return ret; } } else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) { + + dev_dbg(dev, "%s resume from BUS_RESET\n", __func__); + ret = intel_init(sdw); if (ret) { dev_err(dev, "%s failed: %d", __func__, ret); @@ -1779,6 +1785,9 @@ static int intel_resume_runtime(struct device *dev) return ret; } } else if (!clock_stop_quirks) { + + dev_err(dev, "%s resume with no quirks\n", __func__); + ret = intel_init(sdw); if (ret) { dev_err(dev, "%s failed: %d", __func__, ret); From a3a90477b9ebe9adbd4c6a5cd4fd5aa6bccb19a4 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 24 Oct 2019 19:18:41 -0500 Subject: [PATCH 1968/1995] ASoC: Intel: add SoundWire _ADR for machine matching Now, we can add SoundWire _ADR to struct snd_soc_acpi_mach{} to match the machine in more specific ways, e.g. to account for the fact that some CML devices have stereo or mono speaker amplifiers. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Bard Liao --- .../intel/common/soc-acpi-intel-cml-match.c | 68 +++++++++++++++- .../intel/common/soc-acpi-intel-icl-match.c | 81 +++++++++++++++++++ .../intel/common/soc-acpi-intel-tgl-match.c | 47 ++++++++++- 3 files changed, 193 insertions(+), 3 deletions(-) diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c index 70d53cafbc4474..f55634c4c2e8eb 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c @@ -59,15 +59,81 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = { }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cml_machines); +static const u64 rt711_0_adr[] = { + 0x000010025D071100 +}; + +static const u64 rt1308_1_adr[] = { + 0x000110025D130800 +}; + +static const u64 rt1308_2_adr[] = { + 0x000210025D130800 +}; + +static const u64 rt715_3_adr[] = { + 0x000310025D071500 +}; + +static const struct snd_soc_acpi_link_adr cml_3_in_1_default[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_0_adr), + .adr = rt711_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1308_1_adr), + .adr = rt1308_1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1308_2_adr), + .adr = rt1308_2_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt715_3_adr), + .adr = rt715_3_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr cml_3_in_1_mono_amp[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_0_adr), + .adr = rt711_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1308_1_adr), + .adr = rt1308_1_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt715_3_adr), + .adr = rt715_3_adr, + }, + {} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_sdw_machines[] = { { .link_mask = 0xF, /* 4 active links required */ + .links = cml_3_in_1_default, .drv_name = "sdw_rt711_rt1308_rt715", .sof_fw_filename = "sof-cml.ri", .sof_tplg_filename = "sof-cml-rt711-rt1308-rt715.tplg", }, { - .link_mask = 0xB, /* 3 active links required */ + /* + * link_mask should be 0xB, but all links are enabled by BIOS. + * This entry will be selected if there is no rt1308 exposed + * on link2 since it will fail to match the above entry. + */ + .link_mask = 0xF, + .links = cml_3_in_1_mono_amp, .drv_name = "sdw_rt711_rt1308_rt715", .sof_fw_filename = "sof-cml.ri", .sof_tplg_filename = "sof-cml-rt711-rt1308-mono-rt715.tplg", diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c index 63b6197a605606..67e9da4635f254 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -33,15 +33,96 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_icl_machines); +static const u64 rt700_0_adr[] = { + 0x000010025D070000 +}; + +static const struct snd_soc_acpi_link_adr icl_rvp[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt700_0_adr), + .adr = rt700_0_adr, + }, + {} +}; + +static const u64 rt711_0_adr[] = { + 0x000010025D071100 +}; + +static const u64 rt1308_1_adr[] = { + 0x000110025D130800 +}; + +static const u64 rt1308_2_adr[] = { + 0x000210025D130800 +}; + +static const u64 rt715_3_adr[] = { + 0x000310025D715000 +}; + +static const struct snd_soc_acpi_link_adr icl_3_in_1_default[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_0_adr), + .adr = rt711_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1308_1_adr), + .adr = rt1308_1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1308_2_adr), + .adr = rt1308_2_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt715_3_adr), + .adr = rt715_3_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr icl_3_in_1_mono_amp[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_0_adr), + .adr = rt711_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1308_1_adr), + .adr = rt1308_1_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt715_3_adr), + .adr = rt715_3_adr, + }, + {} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_sdw_machines[] = { { .link_mask = 0xF, /* 4 active links required */ + .links = icl_3_in_1_default, .drv_name = "sdw_rt711_rt1308_rt715", .sof_fw_filename = "sof-icl.ri", .sof_tplg_filename = "sof-icl-rt711-rt1308-rt715.tplg", }, + { + .link_mask = 0xB, /* 3 active links required */ + .links = icl_3_in_1_mono_amp, + .drv_name = "sdw_rt711_rt1308_rt715", + .sof_fw_filename = "sof-icl.ri", + .sof_tplg_filename = "sof-icl-rt711-rt1308-rt715-mono.tplg", + }, { .link_mask = 0x1, /* rt700 connected on link0 */ + .links = icl_rvp, .drv_name = "sdw_rt700", .sof_fw_filename = "sof-icl.ri", .sof_tplg_filename = "sof-icl-rt700.tplg", diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c index 3d8daacfb334d4..eed5865bcacf63 100644 --- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -14,11 +14,52 @@ static struct snd_soc_acpi_codecs tgl_codecs = { .codecs = {"MX98357A"} }; +static const u64 rt711_0_adr[] = { + 0x000010025D071100 +}; + +static const u64 rt1308_1_1_adr[] = { + 0x000120025D130800 +}; + +static const u64 rt1308_1_2_adr[] = { + 0x000122025D130800 +}; + +static const struct snd_soc_acpi_link_adr tgl_i2s_rt1308[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_0_adr), + .adr = rt711_0_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr tgl_rvp[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_0_adr), + .adr = rt711_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1308_1_1_adr), + .adr = rt1308_1_1_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1308_1_2_adr), + .adr = rt1308_1_2_adr, + }, + {} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { { .id = "10EC1308", .drv_name = "rt711_rt1308", .link_mask = 0x1, /* RT711 on SoundWire link0 */ + .links = tgl_i2s_rt1308, .sof_fw_filename = "sof-tgl.ri", .sof_tplg_filename = "sof-tgl-rt711-rt1308.tplg", }, @@ -34,12 +75,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_machines); +/* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = { { - .link_mask = 0x1, /* this will only enable rt711 for now */ + .link_mask = 0x3, /* rt711 on link 0 and 2 rt1308s on link 1 */ + .links = tgl_rvp, .drv_name = "sdw_rt711_rt1308_rt715", .sof_fw_filename = "sof-tgl.ri", - .sof_tplg_filename = "sof-tgl-rt711-rt1308-rt715.tplg", + .sof_tplg_filename = "sof-tgl-rt711-rt1308.tplg", }, {}, }; From cb004321cc67114fb00eae16c0283c072f1278af Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 8 Jan 2020 13:10:44 +0800 Subject: [PATCH 1969/1995] soundwire: cadence_master: clear interrupt status before enabling interrupt make sure all interrupts status are cleared before enabling interrupt so that there is no unexpected interrupt triggered. Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/cadence_master.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index be85b178894658..aa87cc4f2da37d 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -875,6 +875,16 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state) mask = interrupt_mask; update_masks: + /* clear slave interrupt status before enabling interrupt */ + if (state) { + u32 slave_state; + + slave_state = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0); + cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT0, slave_state); + slave_state = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1); + cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT1, slave_state); + } + cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0, slave_intmask0); cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1, slave_intmask1); cdns_writel(cdns, CDNS_MCP_INTMASK, mask); From 40faefdc94af172cc4fd51343390550b90736213 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 8 Jan 2020 13:27:19 +0800 Subject: [PATCH 1970/1995] soundwire: intel: add delay between hardware states in transition There are a few intermediate states in the transition of control between master and glue hw. According to spec, a tiny delay should be inserted to make sure each intermediate state is achieved. After many tests, we found 10 ~ 15us was feasible. Tested on Comet Lake. Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index da373705ea8230..4ccd8a752bc89e 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -338,37 +338,45 @@ static int intel_shim_init(struct sdw_intel *sdw, bool clock_stop) /* Initialize Shim */ ioctl |= SDW_SHIM_IOCTL_BKE; intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); + usleep_range(10, 15); ioctl |= SDW_SHIM_IOCTL_WPDD; intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); + usleep_range(10, 15); ioctl |= SDW_SHIM_IOCTL_DO; intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); + usleep_range(10, 15); ioctl |= SDW_SHIM_IOCTL_DOE; intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); + usleep_range(10, 15); /* Switch to MIP from Glue logic */ ioctl = intel_readw(shim, SDW_SHIM_IOCTL(link_id)); ioctl &= ~(SDW_SHIM_IOCTL_DOE); intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); + usleep_range(10, 15); ioctl &= ~(SDW_SHIM_IOCTL_DO); intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); + usleep_range(10, 15); ioctl |= (SDW_SHIM_IOCTL_MIF); intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); + usleep_range(10, 15); ioctl &= ~(SDW_SHIM_IOCTL_BKE); ioctl &= ~(SDW_SHIM_IOCTL_COE); - intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); + usleep_range(10, 15); act |= 0x1 << SDW_REG_SHIFT(SDW_SHIM_CTMCTL_DOAIS); act |= SDW_SHIM_CTMCTL_DACTQE; act |= SDW_SHIM_CTMCTL_DODS; intel_writew(shim, SDW_SHIM_CTMCTL(link_id), act); + usleep_range(10, 15); if (!clock_stop) { /* Now set SyncPRD period */ @@ -429,9 +437,11 @@ static int intel_link_power_down(struct sdw_intel *sdw) ioctl |= SDW_SHIM_IOCTL_BKE; ioctl |= SDW_SHIM_IOCTL_COE; intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); + usleep_range(10, 15); ioctl &= ~(SDW_SHIM_IOCTL_MIF); intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); + usleep_range(10, 15); /* Link power down sequence */ link_control = intel_readl(shim, SDW_SHIM_LCTL); From 14fe59b432b151ca61c5213db34afca0073a3d21 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 27 Dec 2019 17:18:14 +0800 Subject: [PATCH 1971/1995] Soundwire: intel_init: add sdw adr info to sdw_intel_ctx So we can match machine driver with sdw _ADR information. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel_init.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index fe5944ddb16121..689f6f10916133 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -80,6 +80,9 @@ static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx) kfree(ctx->links); ctx->links = NULL; + if (ctx->ids) + kfree(ctx->ids); + ctx->ids = NULL; return 0; } @@ -193,7 +196,10 @@ static struct sdw_intel_ctx struct sdw_intel_ctx *ctx; struct acpi_device *adev; struct sdw_master_device *md; + struct sdw_slave *slave; + struct sdw_bus *bus; u32 link_mask; + int num_slaves = 0; int count; int err; int i; @@ -263,6 +269,25 @@ static struct sdw_intel_ctx md->driver->probe(md, link); list_add_tail(&link->list, &ctx->link_list); + bus = &link->cdns->bus; + /* Calculate number of slaves */ + list_for_each_entry(slave, &bus->slaves, node) + num_slaves++; + } + + ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL); + if (!ctx->ids) + goto err; + + ctx->num_slaves = num_slaves; + i = 0; + list_for_each_entry(link, &ctx->link_list, list) { + bus = &link->cdns->bus; + list_for_each_entry(slave, &bus->slaves, node) { + ctx->ids[i].id = slave->id; + ctx->ids[i].link_id = bus->link_id; + i++; + } } return ctx; From aa85a698ad25db1ca48acb16c0661c4b998bd7ee Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 27 Dec 2019 17:18:14 +0800 Subject: [PATCH 1972/1995] ASoC: SOF: select machine driver with sdw adr. Matching machine driver with _ADR information allow us to select different machine driver with the same link_mask. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- sound/soc/sof/intel/hda.c | 83 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index f469d3bdbca183..3248d43074a69e 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1039,6 +1039,62 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev) #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) +/* Check if all Slaves defined on the link can be found */ +static bool link_slaves_found(struct snd_sof_dev *sdev, + struct snd_soc_acpi_link_adr *link, + struct sdw_intel_ctx *sdw) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + struct sdw_intel_slave_id *ids = sdw->ids; + int num_slaves = sdw->num_slaves; + unsigned int part_id, link_id, unique_id, mfg_id; + int i, j; + + /* + * ADR definition + * Bit Contents + * 63:48 link_id + * 47:44 sdw_version + * 43:40 unique_id + * 39:32 mfg_id [15:8] + * 31:24 mfg_id [7:0] + * 23:16 part_id [15:8] + * 15:08 part_id [7:0] + * 07:00 class_id + */ + for (i = 0; i < link->num_adr; i++) { + mfg_id = (link->adr[i] >> 24) & GENMASK(15, 0); + part_id = (link->adr[i] >> 8) & GENMASK(15, 0); + link_id = (link->adr[i] >> 48) & GENMASK(15, 0); + for (j = 0; j < num_slaves; j++) { + if (ids[j].link_id != link_id || + ids[j].id.part_id != part_id || + ids[j].id.mfg_id != mfg_id) + continue; + /* + * we have to check unique id + * if there is more than one + * Slave on the link + */ + unique_id = (link->adr[i] >> 40) & GENMASK(3, 0); + if (link->num_adr == 1 || + ids[j].id.unique_id == unique_id) { + dev_dbg(bus->dev, + "found %x at link %d\n", + part_id, link_id); + break; + } + } + if (j == num_slaves) { + dev_dbg(bus->dev, + "Slave %x not found\n", + part_id); + return false; + } + } + return true; +} + static int hda_sdw_machine_select(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); @@ -1046,6 +1102,8 @@ static int hda_sdw_machine_select(struct snd_sof_dev *sdev) struct snd_sof_pdata *pdata = sdev->pdata; struct sof_intel_hda_dev *hdev = pdata->hw_pdata; u32 link_mask; + struct snd_soc_acpi_link_adr *link; + int i; link_mask = hdev->info.link_mask; @@ -1056,9 +1114,28 @@ static int hda_sdw_machine_select(struct snd_sof_dev *sdev) * on the HID list. */ if (link_mask && !pdata->machine) { - mach = pdata->desc->alt_machines; - while (mach && mach->link_mask && mach->link_mask != link_mask) - mach++; + for (mach = pdata->desc->alt_machines; + mach && mach->link_mask; mach++) { + if (mach->link_mask != link_mask) + continue; + + /* No need to match adr if there is no links defined */ + if (!mach->links) + break; + + link = mach->links; + for (i = 0; i < hdev->info.count; i++, link++) { + /* + * Try next machine if any expected Slaves + * are not found on this link. + */ + if (!link_slaves_found(sdev, link, hdev->sdw)) + break; + } + /* Found if all Slaves are checked */ + if (i == hdev->info.count) + break; + } if (mach && mach->link_mask) { dev_dbg(bus->dev, "SoundWire machine driver %s topology %s\n", From c7d1f2c59c62f1d784e782c64f02c99c3c1a52ea Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 5 Nov 2019 10:44:49 +0800 Subject: [PATCH 1973/1995] ALSA: HDA: intel-dsp-config: add DMI info for Dell laptop The laptop doesn't use DMIC, but use SOF. Signed-off-by: Bard Liao --- sound/hda/intel-dsp-config.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index be1df80ed01337..6e6e8662534d8a 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -204,6 +204,12 @@ static const struct config_entry config_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Google"), } }, + { + .ident = "Dell laptop", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + } + }, {} } }, From edd7d4433f3762008cb1478b72f8f2d3b6d256d3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 10 Jun 2019 19:31:58 -0500 Subject: [PATCH 1974/1995] soundwire: cadence_master: handle multiple status reports per Slave When a Slave reports multiple status in the sticky bits, find the latest configuration from the mirror of the PING frame status and update the status directly. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/cadence_master.c | 35 +++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index aa87cc4f2da37d..8bf9fd42a6b690 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -695,13 +695,36 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns, /* first check if Slave reported multiple status */ if (set_status > 1) { + u32 val; + dev_warn_ratelimited(cdns->dev, - "Slave reported multiple Status: %d\n", - mask); - /* - * TODO: we need to reread the status here by - * issuing a PING cmd - */ + "Slave %d reported multiple Status: %d\n", + i, mask); + + /* check latest status extracted from PING commands */ + val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT); + val >>= (i * 2); + + switch (val & 0x3) { + case 0: + status[i] = SDW_SLAVE_UNATTACHED; + break; + case 1: + status[i] = SDW_SLAVE_ATTACHED; + break; + case 2: + status[i] = SDW_SLAVE_ALERT; + break; + case 3: + default: + status[i] = SDW_SLAVE_RESERVED; + break; + } + + dev_warn_ratelimited(cdns->dev, + "Slave %d status updated to %d\n", + i, status[i]); + } } From 146815535f1680837bc2541f57b6be871b6e4911 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 24 Apr 2018 15:28:28 +0530 Subject: [PATCH 1975/1995] soundwire: Add generic bandwidth allocation algorithm This algorithm computes bus parameters like clock frequency, frame shape and port transport parameters based on active stream(s) running on the bus. Developers can also implement their own .compute_params() callback for specific resource management algorithm, and set if before calling sdw_add_bus_master() Credits: this patch is based on an earlier internal contribution by Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah. All hard-coded values were removed from the initial contribution to use BIOS information instead. FIXME: remove checkpatch report WARNING: Reusing the krealloc arg is almost always a bug + group->rates = krealloc(group->rates, Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/Kconfig | 4 + drivers/soundwire/Makefile | 3 + drivers/soundwire/bus.c | 6 + drivers/soundwire/bus.h | 46 +- .../soundwire/generic_bandwidth_allocation.c | 407 ++++++++++++++++++ drivers/soundwire/intel.c | 3 + drivers/soundwire/stream.c | 12 + include/linux/soundwire/sdw.h | 3 + 8 files changed, 482 insertions(+), 2 deletions(-) create mode 100644 drivers/soundwire/generic_bandwidth_allocation.c diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig index c725d0a8b288b6..eb73c91b7dba87 100644 --- a/drivers/soundwire/Kconfig +++ b/drivers/soundwire/Kconfig @@ -24,6 +24,7 @@ config SOUNDWIRE_CADENCE config SOUNDWIRE_INTEL tristate "Intel SoundWire Master driver" select SOUNDWIRE_CADENCE + select SOUNDWIRE_GENERIC_ALLOCATION depends on ACPI && SND_SOC help SoundWire Intel Master driver. @@ -31,4 +32,7 @@ config SOUNDWIRE_INTEL enable this config option to get the SoundWire support for that device. +config SOUNDWIRE_GENERIC_ALLOCATION + tristate + endif diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile index 89b29819dd3ad8..eb37d69cbdca96 100644 --- a/drivers/soundwire/Makefile +++ b/drivers/soundwire/Makefile @@ -7,6 +7,9 @@ soundwire-bus-objs := bus_type.o bus.o master.o slave.o mipi_disco.o stream.o obj-$(CONFIG_SOUNDWIRE) += soundwire-bus.o +soundwire-generic-allocation-objs := generic_bandwidth_allocation.o +obj-$(CONFIG_SOUNDWIRE_GENERIC_ALLOCATION) += soundwire-generic-allocation.o + ifdef CONFIG_DEBUG_FS soundwire-bus-objs += debugfs.o endif diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index ba88d88dda8bcd..011bd37c5ca171 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -31,6 +31,12 @@ int sdw_add_bus_master(struct sdw_bus *bus) return -EINVAL; } + if (!bus->compute_params) { + dev_err(bus->dev, + "Bandwidth allocation not configured, compute_parems no set\n"); + return -EINVAL; + } + mutex_init(&bus->msg_lock); mutex_init(&bus->bus_lock); INIT_LIST_HEAD(&bus->slaves); diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h index ee362472003a93..39a433b2cfb0c6 100644 --- a/drivers/soundwire/bus.h +++ b/drivers/soundwire/bus.h @@ -68,6 +68,7 @@ struct sdw_msg { }; #define SDW_DOUBLE_RATE_FACTOR 2 +#define SDW_STRM_RATE_GROUPING 1 extern int sdw_rows[SDW_FRAME_ROWS]; extern int sdw_cols[SDW_FRAME_COLS]; @@ -153,9 +154,50 @@ int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg, int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave, u32 addr, size_t count, u16 dev_num, u8 flags, u8 *buf); +/* Retrieve and return channel count from channel mask */ +static inline int sdw_ch_mask_to_ch(int ch_mask) +{ + int c = 0; + + for (c = 0; ch_mask; ch_mask >>= 1) + c += ch_mask & 1; + + return c; +} + +/* Fill transport parameter data structure */ +static inline void sdw_fill_xport_params(struct sdw_transport_params *params, + int port_num, bool grp_ctrl_valid, + int grp_ctrl, int sample_int, + int off1, int off2, + int hstart, int hstop, + int pack_mode, int lane_ctrl) +{ + params->port_num = port_num; + params->blk_grp_ctrl_valid = grp_ctrl_valid; + params->blk_grp_ctrl = grp_ctrl; + params->sample_interval = sample_int; + params->offset1 = off1; + params->offset2 = off2; + params->hstart = hstart; + params->hstop = hstop; + params->blk_pkg_mode = pack_mode; + params->lane_ctrl = lane_ctrl; +} + +/* Fill port parameter data structure */ +static inline void sdw_fill_port_params(struct sdw_port_params *params, + int port_num, int bps, + int flow_mode, int data_mode) +{ + params->num = port_num; + params->bps = bps; + params->flow_mode = flow_mode; + params->data_mode = data_mode; +} + /* Read-Modify-Write Slave register */ -static inline int -sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val) +static inline int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val) { int tmp; diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c new file mode 100644 index 00000000000000..dc7ffa987963ac --- /dev/null +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -0,0 +1,407 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2015-2019 Intel Corporation. + +/* + * Bandwidth management algorithm based on 2^n gears + * + */ + +#include +#include +#include +#include +#include +#include "bus.h" + +#define SDW_STRM_RATE_GROUPING 1 + +struct sdw_group_params { + unsigned int rate; + int full_bw; + int payload_bw; + int hwidth; +}; + +struct sdw_group { + unsigned int count; + unsigned int max_size; + unsigned int *rates; +}; + +struct sdw_transport_data { + int hstart; + int hstop; + int block_offset; + int sub_block_offset; +}; + +static void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt, + struct sdw_transport_data *t_data) +{ + struct sdw_slave_runtime *s_rt = NULL; + struct sdw_port_runtime *p_rt; + int port_bo, sample_int; + unsigned int rate, bps, ch = 0; + + port_bo = t_data->block_offset; + + list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { + rate = m_rt->stream->params.rate; + bps = m_rt->stream->params.bps; + sample_int = (m_rt->bus->params.curr_dr_freq / rate); + + list_for_each_entry(p_rt, &s_rt->port_list, port_node) { + ch = sdw_ch_mask_to_ch(p_rt->ch_mask); + + sdw_fill_xport_params(&p_rt->transport_params, + p_rt->num, true, + SDW_BLK_GRP_CNT_1, + sample_int, port_bo, port_bo >> 8, + t_data->hstart, + t_data->hstop, + (SDW_BLK_GRP_CNT_1 * ch), 0x0); + + sdw_fill_port_params(&p_rt->port_params, + p_rt->num, bps, + SDW_PORT_FLOW_MODE_ISOCH, + SDW_PORT_DATA_MODE_NORMAL); + + port_bo += bps * ch; + } + } +} + +static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, + struct sdw_group_params *params, + int port_bo, int hstop) +{ + struct sdw_transport_data t_data = {0}; + struct sdw_port_runtime *p_rt; + struct sdw_bus *bus = m_rt->bus; + int sample_int, hstart = 0; + unsigned int rate, bps, ch, no_ch; + + rate = m_rt->stream->params.rate; + bps = m_rt->stream->params.bps; + ch = m_rt->ch_count; + sample_int = (bus->params.curr_dr_freq / rate); + + if (rate != params->rate) + return; + + t_data.hstop = hstop; + hstart = hstop - params->hwidth + 1; + t_data.hstart = hstart; + + list_for_each_entry(p_rt, &m_rt->port_list, port_node) { + no_ch = sdw_ch_mask_to_ch(p_rt->ch_mask); + + sdw_fill_xport_params(&p_rt->transport_params, p_rt->num, + true, SDW_BLK_GRP_CNT_1, sample_int, + port_bo, port_bo >> 8, hstart, hstop, + (SDW_BLK_GRP_CNT_1 * no_ch), 0x0); + + sdw_fill_port_params(&p_rt->port_params, + p_rt->num, bps, + SDW_PORT_FLOW_MODE_ISOCH, + SDW_PORT_DATA_MODE_NORMAL); + + /* Check for first entry */ + if (!(p_rt == list_first_entry(&m_rt->port_list, + struct sdw_port_runtime, + port_node))) { + port_bo += bps * ch; + continue; + } + + t_data.hstart = hstart; + t_data.hstop = hstop; + t_data.block_offset = port_bo; + t_data.sub_block_offset = 0; + port_bo += bps * ch; + } + + sdw_compute_slave_ports(m_rt, &t_data); +} + +static void _sdw_compute_port_params(struct sdw_bus *bus, + struct sdw_group_params *params, int count) +{ + struct sdw_master_runtime *m_rt = NULL; + int hstop = bus->params.col - 1; + int block_offset, port_bo, i; + + /* Run loop for all groups to compute transport parameters */ + for (i = 0; i < count; i++) { + port_bo = 1; + block_offset = 1; + + list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { + sdw_compute_master_ports(m_rt, ¶ms[i], + port_bo, hstop); + + block_offset += m_rt->ch_count * + m_rt->stream->params.bps; + port_bo = block_offset; + } + + hstop = hstop - params[i].hwidth; + } +} + +static int sdw_compute_group_params(struct sdw_bus *bus, + struct sdw_group_params *params, + int *rates, int count) +{ + struct sdw_master_runtime *m_rt = NULL; + int sel_col = bus->params.col; + unsigned int rate, bps, ch; + int i, column_needed = 0; + + /* Calculate bandwidth per group */ + for (i = 0; i < count; i++) { + params[i].rate = rates[i]; + params[i].full_bw = bus->params.curr_dr_freq / params[i].rate; + } + + list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { + rate = m_rt->stream->params.rate; + bps = m_rt->stream->params.bps; + ch = m_rt->ch_count; + + for (i = 0; i < count; i++) { + if (rate == params[i].rate) + params[i].payload_bw += bps * ch; + } + } + + for (i = 0; i < count; i++) { + params[i].hwidth = (sel_col * + params[i].payload_bw + params[i].full_bw - 1) / + params[i].full_bw; + + column_needed += params[i].hwidth; + } + + if (column_needed > sel_col - 1) + return -EINVAL; + + return 0; +} + +static int sdw_add_element_group_count(struct sdw_group *group, + unsigned int rate) +{ + int num = group->count; + int i; + + for (i = 0; i <= num; i++) { + if (rate == group->rates[i]) + break; + + if (i != num) + continue; + + if (group->count >= group->max_size) { + group->max_size += 1; + group->rates = krealloc(group->rates, + (sizeof(int) * group->max_size), + GFP_KERNEL); + if (!group->rates) + return -ENOMEM; + } + + group->rates[group->count++] = rate; + } + + return 0; +} + +static int sdw_get_group_count(struct sdw_bus *bus, + struct sdw_group *group) +{ + struct sdw_master_runtime *m_rt; + unsigned int rate; + int ret = 0; + + group->count = 0; + group->max_size = SDW_STRM_RATE_GROUPING; + group->rates = kcalloc(group->max_size, sizeof(int), GFP_KERNEL); + if (!group->rates) + return -ENOMEM; + + list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { + rate = m_rt->stream->params.rate; + if (m_rt == list_first_entry(&bus->m_rt_list, + struct sdw_master_runtime, + bus_node)) { + group->rates[group->count++] = rate; + + } else { + ret = sdw_add_element_group_count(group, rate); + if (ret < 0) + return ret; + } + } + + return ret; +} + +/** + * sdw_compute_port_params: Compute transport and port parameters + * + * @bus: SDW Bus instance + */ +static int sdw_compute_port_params(struct sdw_bus *bus) +{ + struct sdw_group_params *params = NULL; + struct sdw_group group; + int ret; + + ret = sdw_get_group_count(bus, &group); + if (ret < 0) + goto out; + + if (group.count == 0) + goto out; + + params = kcalloc(group.count, sizeof(*params), GFP_KERNEL); + if (!params) { + ret = -ENOMEM; + goto out; + } + + /* Compute transport parameters for grouped streams */ + ret = sdw_compute_group_params(bus, params, + &group.rates[0], group.count); + if (ret < 0) + goto out; + + _sdw_compute_port_params(bus, params, group.count); + +out: + kfree(params); + kfree(group.rates); + + return ret; +} + +static int sdw_select_row_col(struct sdw_bus *bus, int clk_freq) +{ + struct sdw_master_prop *prop = &bus->prop; + int frame_int, frame_freq; + int r, c; + + for (c = 0; c < SDW_FRAME_COLS; c++) { + for (r = 0; r < SDW_FRAME_ROWS; r++) { + if (sdw_rows[r] != prop->default_row || + sdw_cols[c] != prop->default_col) + continue; + + frame_int = sdw_rows[r] * sdw_cols[c]; + frame_freq = clk_freq / frame_int; + + if ((clk_freq - (frame_freq * SDW_FRAME_CTRL_BITS)) < + bus->params.bandwidth) + continue; + + bus->params.row = sdw_rows[r]; + bus->params.col = sdw_cols[c]; + return 0; + } + } + + return -EINVAL; +} + +/** + * sdw_compute_bus_params: Compute bus parameters + * + * @bus: SDW Bus instance + */ +static int sdw_compute_bus_params(struct sdw_bus *bus) +{ + unsigned int max_dr_freq, curr_dr_freq = 0; + struct sdw_master_prop *mstr_prop = NULL; + int i, clk_values, ret; + bool is_gear = false; + u32 *clk_buf; + + mstr_prop = &bus->prop; + if (!mstr_prop) + return -EINVAL; + + if (mstr_prop->num_clk_gears) { + clk_values = mstr_prop->num_clk_gears; + clk_buf = mstr_prop->clk_gears; + is_gear = true; + } else if (mstr_prop->num_clk_freq) { + clk_values = mstr_prop->num_clk_freq; + clk_buf = mstr_prop->clk_freq; + } else { + clk_values = 1; + clk_buf = NULL; + } + + max_dr_freq = mstr_prop->max_clk_freq * SDW_DOUBLE_RATE_FACTOR; + + for (i = 0; i < clk_values; i++) { + if (!clk_buf) + curr_dr_freq = max_dr_freq; + else + curr_dr_freq = (is_gear) ? + (max_dr_freq >> clk_buf[i]) : + clk_buf[i] * SDW_DOUBLE_RATE_FACTOR; + + if (curr_dr_freq <= bus->params.bandwidth) + continue; + + break; + + /* + * TODO: Check all the Slave(s) port(s) audio modes and find + * whether given clock rate is supported with glitchless + * transition. + */ + } + + if (i == clk_values) + return -EINVAL; + + ret = sdw_select_row_col(bus, curr_dr_freq); + if (ret < 0) + return -EINVAL; + + bus->params.curr_dr_freq = curr_dr_freq; + return 0; +} + +/** + * sdw_compute_params: Compute bus, transport and port parameters + * + * @bus: SDW Bus instance + */ +int sdw_compute_params(struct sdw_bus *bus) +{ + int ret; + + /* Computes clock frequency, frame shape and frame frequency */ + ret = sdw_compute_bus_params(bus); + if (ret < 0) { + dev_err(bus->dev, "Compute bus params failed: %d", ret); + return ret; + } + + /* Compute transport and port params */ + ret = sdw_compute_port_params(bus); + if (ret < 0) { + dev_err(bus->dev, "Compute transport params failed: %d", ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL(sdw_compute_params); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("SoundWire Generic Bandwidth Allocation"); diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 4ccd8a752bc89e..f1050c30f24833 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1330,6 +1330,9 @@ static int intel_master_probe(struct sdw_master_device *md, void *link_ctx) /* set driver data, accessed by snd_soc_dai_set_drvdata() */ dev_set_drvdata(&md->dev, &sdw->cdns); + /* use generic bandwidth allocation algorithm */ + sdw->cdns.bus.compute_params = sdw_compute_params; + ret = sdw_add_bus_master(&sdw->cdns.bus); if (ret) { dev_err(&md->dev, "sdw_add_bus_master fail: %d\n", ret); diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index a016364593de4f..795baa2cf19ca6 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -26,6 +26,8 @@ int sdw_rows[SDW_FRAME_ROWS] = {48, 50, 60, 64, 75, 80, 125, 147, 192, 200, 240, 256, 72, 144, 90, 180}; int sdw_cols[SDW_FRAME_COLS] = {2, 4, 6, 8, 10, 12, 14, 16}; +EXPORT_SYMBOL(sdw_rows); +EXPORT_SYMBOL(sdw_cols); int sdw_find_col_index(int col) { @@ -1787,6 +1789,16 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream) bus->params.bandwidth -= m_rt->stream->params.rate * m_rt->ch_count * m_rt->stream->params.bps; + /* Compute params */ + if (bus->compute_params) { + ret = bus->compute_params(bus); + if (ret < 0) { + dev_err(bus->dev, "Compute params failed: %d", + ret); + return ret; + } + } + /* Program params */ ret = sdw_program_params(bus, false); if (ret < 0) { diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 347d2cda76d022..33ed48df83a8bb 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -935,6 +935,9 @@ struct sdw_stream_runtime { struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name); void sdw_release_stream(struct sdw_stream_runtime *stream); + +int sdw_compute_params(struct sdw_bus *bus); + int sdw_stream_add_master(struct sdw_bus *bus, struct sdw_stream_config *stream_config, struct sdw_port_config *port_config, From 86180b8deb4ca691ae2c504b9200f7e961ae6b8a Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 2 Aug 2019 10:14:46 +0800 Subject: [PATCH 1976/1995] soundwire: dynamic_allocation: set grp_ctrl_valid false Some Realtek codecs don't support grp_ctrl_valid. Set it to false to prevent DPN_BlockCtrl2 reg write failed. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/generic_bandwidth_allocation.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index dc7ffa987963ac..6124c6f8561f32 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -54,7 +54,7 @@ static void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt, ch = sdw_ch_mask_to_ch(p_rt->ch_mask); sdw_fill_xport_params(&p_rt->transport_params, - p_rt->num, true, + p_rt->num, false, SDW_BLK_GRP_CNT_1, sample_int, port_bo, port_bo >> 8, t_data->hstart, @@ -97,7 +97,7 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, no_ch = sdw_ch_mask_to_ch(p_rt->ch_mask); sdw_fill_xport_params(&p_rt->transport_params, p_rt->num, - true, SDW_BLK_GRP_CNT_1, sample_int, + false, SDW_BLK_GRP_CNT_1, sample_int, port_bo, port_bo >> 8, hstart, hstop, (SDW_BLK_GRP_CNT_1 * no_ch), 0x0); From 98eaa6ab62ba883c86334f8bee90f59b8c2682eb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Tue, 30 Jul 2019 16:14:18 -0500 Subject: [PATCH 1977/1995] soundwire: bus: fix device number leak on errors If the programming of the dev_number fails due to an IO error, a new device_number will be assigned, resulting in a leak. Make sure we only assign a device_number once per Slave device. Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.c | 39 ++++++++++++++++++++++------------- include/linux/soundwire/sdw.h | 4 +++- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 011bd37c5ca171..c0467978a0e872 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -547,26 +547,37 @@ static int sdw_get_device_num(struct sdw_slave *slave) static int sdw_assign_device_num(struct sdw_slave *slave) { int ret, dev_num; + bool new_device = false; + + dev_dbg(slave->bus->dev, "in %s\n", __func__); /* check first if device number is assigned, if so reuse that */ if (!slave->dev_num) { - mutex_lock(&slave->bus->bus_lock); - dev_num = sdw_get_device_num(slave); - mutex_unlock(&slave->bus->bus_lock); - if (dev_num < 0) { - dev_err(slave->bus->dev, "Get dev_num failed: %d\n", - dev_num); - return dev_num; + if (!slave->dev_num_sticky) { + mutex_lock(&slave->bus->bus_lock); + dev_num = sdw_get_device_num(slave); + mutex_unlock(&slave->bus->bus_lock); + if (dev_num < 0) { + dev_err(slave->bus->dev, "Get dev_num failed: %d\n", + dev_num); + return dev_num; + } + slave->dev_num = dev_num; + slave->dev_num_sticky = dev_num; + new_device = true; + } else { + slave->dev_num = slave->dev_num_sticky; } - } else { + } + + if (!new_device) dev_info(slave->bus->dev, - "Slave already registered dev_num:%d\n", + "Slave already registered, reusing dev_num:%d\n", slave->dev_num); - /* Clear the slave->dev_num to transfer message on device 0 */ - dev_num = slave->dev_num; - slave->dev_num = 0; - } + /* Clear the slave->dev_num to transfer message on device 0 */ + dev_num = slave->dev_num; + slave->dev_num = 0; ret = sdw_write_no_pm(slave, SDW_SCP_DEVNUMBER, dev_num); if (ret < 0) { @@ -576,7 +587,7 @@ static int sdw_assign_device_num(struct sdw_slave *slave) } /* After xfer of msg, restore dev_num */ - slave->dev_num = dev_num; + slave->dev_num = slave->dev_num_sticky; return 0; } diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 33ed48df83a8bb..c4d6f96b39292b 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -566,7 +566,8 @@ struct sdw_slave_ops { * @debugfs: Slave debugfs * @node: node for bus list * @port_ready: Port ready completion flag for each Slave port - * @dev_num: Device Number assigned by Bus + * @dev_num: Current Device Number, values can be 0 or dev_num_sticky + * @dev_num_sticky: one-time static Device Number assigned by Bus * @probed: boolean tracking driver state * @probe_complete: completion utility to control potential races * on startup between driver probe/initialization and SoundWire @@ -596,6 +597,7 @@ struct sdw_slave { struct completion *port_ready; enum sdw_clk_stop_mode curr_clk_stop_mode; u16 dev_num; + u16 dev_num_sticky; bool probed; struct completion probe_complete; struct completion enumeration_complete; From 0f8a45a7b003e8abe4f518bac4faa0ef07431071 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 19 Aug 2019 12:13:03 -0500 Subject: [PATCH 1978/1995] soundwire: intel: modify DMAT field for ALH The current value for this field is too low and results in some samples getting dropped and playback being faster than normal. Increase the value to a safer value. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index f1050c30f24833..be10c7400d46f7 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -105,7 +105,7 @@ MODULE_PARM_DESC(sdw_md_flags, "SoundWire Intel Master device flags (0x0 all off #define SDW_ALH_STRMZCFG(x) (0x000 + (0x4 * (x))) #define SDW_ALH_NUM_STREAMS 64 -#define SDW_ALH_STRMZCFG_DMAT_VAL 0x3 +#define SDW_ALH_STRMZCFG_DMAT_VAL 0xf #define SDW_ALH_STRMZCFG_DMAT GENMASK(7, 0) #define SDW_ALH_STRMZCFG_CHN GENMASK(19, 16) From 9a5d380ed4c5d9a91f55f890359b78cd0553654a Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 19 Aug 2019 12:18:05 -0500 Subject: [PATCH 1979/1995] soundwire: intel: fix factor of two in MCLK handling Somehow Intel folks were confused, the property is 2x what the mclk frequency actually is, as checked with the actual bus frequency. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/intel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index be10c7400d46f7..6868be6961b553 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1249,6 +1249,7 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus) "intel-sdw-ip-clock", &prop->mclk_freq); + prop->mclk_freq /= 2; fwnode_property_read_u32(link, "intel-quirk-mask", &quirk_mask); From 76f305da5eae9a9e4be5fde700225029c3b2c2e9 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 26 Jun 2019 12:29:42 -0500 Subject: [PATCH 1980/1995] soundwire: cadence_master: log register write info useful for debug, but can be verbose so only enable if strictly needed. Signed-off-by: Bard Liao Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/cadence_master.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 8bf9fd42a6b690..9febc6d2aa2bd2 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -199,6 +199,7 @@ static inline u32 cdns_readl(struct sdw_cdns *cdns, int offset) static inline void cdns_writel(struct sdw_cdns *cdns, int offset, u32 value) { + dev_vdbg(cdns->dev, "%s %x %x\n", __func__, offset, value); writel(value, cdns->registers + offset); } From 40118b0a77f1d71dc187d53986ec7d96aa834dee Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 10 Jun 2019 19:21:39 -0500 Subject: [PATCH 1981/1995] add more traces to bus code Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index c0467978a0e872..c637fe742febdc 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -549,6 +549,9 @@ static int sdw_assign_device_num(struct sdw_slave *slave) int ret, dev_num; bool new_device = false; + dev_dbg(slave->bus->dev, "in %s\n", __func__); + + dev_dbg(slave->bus->dev, "in %s\n", __func__); /* check first if device number is assigned, if so reuse that */ @@ -579,6 +582,7 @@ static int sdw_assign_device_num(struct sdw_slave *slave) dev_num = slave->dev_num; slave->dev_num = 0; + dev_dbg(slave->bus->dev, "in %s, writing dev_num %d\n", __func__, dev_num); ret = sdw_write_no_pm(slave, SDW_SCP_DEVNUMBER, dev_num); if (ret < 0) { dev_err(&slave->dev, "Program device_num %d failed: %d\n", @@ -696,6 +700,8 @@ static int sdw_program_device_num(struct sdw_bus *bus) } while (ret == 0 && count < (SDW_MAX_DEVICES * 2)); + dev_err(bus->dev, "End of %s ret %d\n", __func__, ret); + return ret; } @@ -1484,14 +1490,17 @@ int sdw_handle_slave_status(struct sdw_bus *bus, break; case SDW_SLAVE_ATTACHED: - if (slave->status == SDW_SLAVE_ATTACHED) + if (slave->status == SDW_SLAVE_ATTACHED) { + dev_err(bus->dev, "Slave %d status attached, was already attached, ignoring\n", i); break; - + } prev_status = slave->status; sdw_modify_slave_status(slave, SDW_SLAVE_ATTACHED); - if (prev_status == SDW_SLAVE_ALERT) + if (prev_status == SDW_SLAVE_ALERT) { + dev_err(bus->dev, "Slave %d status attached, was alert, ignoring\n", i); break; + } attached_initializing = true; @@ -1509,6 +1518,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, break; } + dev_err(bus->dev, "Updating Slave %d status\n", i); ret = sdw_update_slave_status(slave, status[i]); if (ret) dev_err(slave->bus->dev, From a56cf3910934e73c826c71d535db632048a5274f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 1 Aug 2019 18:31:34 -0500 Subject: [PATCH 1982/1995] add traces for bus Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index c637fe742febdc..29836d34a357d1 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -1428,6 +1428,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, bool attached_initializing; int i, ret = 0; + dev_dbg(bus->dev, "%s: start\n", __func__); + /* first check if any Slaves fell off the bus */ for (i = 1; i <= SDW_MAX_DEVICES; i++) { mutex_lock(&bus->bus_lock); @@ -1523,10 +1525,16 @@ int sdw_handle_slave_status(struct sdw_bus *bus, if (ret) dev_err(slave->bus->dev, "Update Slave status failed:%d\n", ret); + if (attached_initializing) complete(&slave->initialization_complete); + + dev_err(bus->dev, "%s: Updating Slave %d status done\n", + __func__, i); } + dev_dbg(bus->dev, "%s: end\n", __func__); + return ret; } EXPORT_SYMBOL(sdw_handle_slave_status); From b47b719b988f94f0386cf7fdfdc677ab4ce51335 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 11 Sep 2019 20:18:19 -0500 Subject: [PATCH 1983/1995] [HACK] soundwire: add dynamic DEBUG in makefile Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile index eb37d69cbdca96..76a5c52b12b412 100644 --- a/drivers/soundwire/Makefile +++ b/drivers/soundwire/Makefile @@ -2,6 +2,7 @@ # # Makefile for soundwire core # +ccflags-y += -DDEBUG #Bus Objs soundwire-bus-objs := bus_type.o bus.o master.o slave.o mipi_disco.o stream.o From bef1b207e1baec450240a506b3e4187ff2610b46 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 20 Nov 2019 10:23:24 +0800 Subject: [PATCH 1984/1995] ALSA: HDA: intel-dsp-config: add DMI info for Dell laptop Another Dell laptop uses SOF with CML platform Signed-off-by: Bard Liao --- sound/hda/intel-dsp-config.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index 6e6e8662534d8a..72c64bf42dec3e 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -220,6 +220,19 @@ static const struct config_entry config_table[] = { #endif /* Cometlake-H */ #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE_H) + { + .flags = FLAG_SOF, + .device = 0x06c8, + .dmi_table = (const struct dmi_system_id []) { + { + .ident = "Dell laptop", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell"), + } + }, + {} + } + }, { .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC, .device = 0x06c8, From 9c9c7392f2945290f3d055d3babc2bc457397990 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 2 Dec 2019 16:41:11 +0800 Subject: [PATCH 1985/1995] Soundwire: generic_bandwidth_allocation: don't free params if it is null We will free params when we goto out in sdw_compute_port_params(). But we can't free params if it is not allocated successfully. Signed-off-by: Bard Liao --- drivers/soundwire/generic_bandwidth_allocation.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index 6124c6f8561f32..7a747a302caf5d 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -239,8 +239,10 @@ static int sdw_get_group_count(struct sdw_bus *bus, } else { ret = sdw_add_element_group_count(group, rate); - if (ret < 0) + if (ret < 0) { + kfree(group->rates); return ret; + } } } @@ -260,7 +262,7 @@ static int sdw_compute_port_params(struct sdw_bus *bus) ret = sdw_get_group_count(bus, &group); if (ret < 0) - goto out; + return ret; if (group.count == 0) goto out; @@ -275,12 +277,13 @@ static int sdw_compute_port_params(struct sdw_bus *bus) ret = sdw_compute_group_params(bus, params, &group.rates[0], group.count); if (ret < 0) - goto out; + goto free_params; _sdw_compute_port_params(bus, params, group.count); -out: +free_params: kfree(params); +out: kfree(group.rates); return ret; From 3b4acb292c56358a001381c20e45394f04d5f551 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 6 Dec 2019 10:37:38 -0600 Subject: [PATCH 1986/1995] soundwire: cadence_master: remove useless variable incrementation Fix cppcheck warning: drivers/soundwire/cadence_master.c:992:9: style: Variable 'offset' is assigned a value that is never used. [unreadVariable] offset += stream->num_out; ^ Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/cadence_master.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 9febc6d2aa2bd2..1702a00b237e04 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1007,8 +1007,6 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns, ret = cdns_allocate_pdi(cdns, &stream->out, stream->num_out, offset); - offset += stream->num_out; - if (ret) return ret; From 1850fd9f448c15e39b1de4876582d7ebb9d67150 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 11 Dec 2019 10:18:53 +0800 Subject: [PATCH 1987/1995] soundwire: cadence_master: fix a io timeout issue in S3 test After system resumes from S3, io timeout occurs when setting one unused master on Comet Lake platform. In this case, the master is reset to default state, and FIFOLEVEL is reset to default value, but msg_count used for tracing FIFOLEVEL is still with old value, so FIFOLEVEL will not be set if a new msg FIFO usage is equal to the old msg_count. This patch updates msg_count to default value of FIFOLEVEL when resetting master. Tested on Comet Lake platform. Signed-off-by: Rander Wang --- drivers/soundwire/cadence_master.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 1702a00b237e04..cac1775a121a07 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1063,6 +1063,9 @@ int sdw_cdns_init(struct sdw_cdns *cdns) cdns_writel(cdns, CDNS_MCP_SSP_CTRL0, CDNS_DEFAULT_SSP_INTERVAL); cdns_writel(cdns, CDNS_MCP_SSP_CTRL1, CDNS_DEFAULT_SSP_INTERVAL); + /* reset msg_count to default value of FIFOLEVEL */ + cdns->msg_count = cdns_readl(cdns, CDNS_MCP_FIFOLEVEL); + /* flush command FIFOs */ cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_RST, CDNS_MCP_CONTROL_CMD_RST); From 51b1a9a2341160f8229a662c426e6e7baa4cc290 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 4 Dec 2019 14:32:09 +0800 Subject: [PATCH 1988/1995] soundwire: bus: fix io error when processing alert event There are two types of io error when processing alert event. The first one is: master receives a alert event for jack event and invokes implement_def function in slave to check jack status. At this time codec is just suspended, so io registers can't be accessed. Another one is: when waken up from clock stop state and bus needs a complete re-enumeration for synchronization issue , slave register can't be accessed. This patch wakes up codec and wait for initialization complete when processing slave alert event, so that io registers can be accessed. Signed-off-by: Rander Wang Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 29836d34a357d1..3e28aaa36e7f99 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -1251,12 +1251,19 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) sdw_modify_slave_status(slave, SDW_SLAVE_ALERT); + ret = pm_runtime_get_sync(&slave->dev); + if (ret < 0 && ret != -EACCES) { + dev_err(&slave->dev, "Failed to resume device: %d\n", ret); + pm_runtime_put_noidle(slave->bus->dev); + return ret; + } + /* Read Instat 1, Instat 2 and Instat 3 registers */ ret = sdw_read(slave, SDW_SCP_INT1); if (ret < 0) { dev_err(slave->bus->dev, "SDW_SCP_INT1 read failed:%d\n", ret); - return ret; + goto io_err; } buf = ret; @@ -1264,7 +1271,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) if (ret < 0) { dev_err(slave->bus->dev, "SDW_SCP_INT2/3 read failed:%d\n", ret); - return ret; + goto io_err; } do { @@ -1344,7 +1351,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) if (ret < 0) { dev_err(slave->bus->dev, "SDW_SCP_INT1 write failed:%d\n", ret); - return ret; + goto io_err; } /* @@ -1355,7 +1362,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) if (ret < 0) { dev_err(slave->bus->dev, "SDW_SCP_INT1 read failed:%d\n", ret); - return ret; + goto io_err; } _buf = ret; @@ -1363,7 +1370,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) if (ret < 0) { dev_err(slave->bus->dev, "SDW_SCP_INT2/3 read failed:%d\n", ret); - return ret; + goto io_err; } /* Make sure no interrupts are pending */ @@ -1384,6 +1391,10 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) if (count == SDW_READ_INTR_CLEAR_RETRY) dev_warn(slave->bus->dev, "Reached MAX_RETRY on alert read\n"); +io_err: + pm_runtime_mark_last_busy(&slave->dev); + pm_runtime_put_autosuspend(&slave->dev); + return ret; } From 568ece72c79bc6a92562f77d889cf4a3c827f33b Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 5 Dec 2019 15:57:25 -0600 Subject: [PATCH 1989/1995] soundwire: cadence_master: debug error on Olympic device in clock_stop Somehow the master-2 fails to stop the clock [ 24.007288] intel-sdw sdw-master-2: intel_suspend_runtime start [ 24.007297] intel-sdw sdw-master-2: sdw_cdns_clock_stop: start [ 24.007303] intel-sdw sdw-master-2: sdw_cdns_clock_stop: slave attached 0 [ 24.007498] intel-sdw sdw-master-2: Msg ignored for Slave 15 [ 24.007501] intel-sdw sdw-master-2: ClockStopNow Broadcast message failed -61 [ 24.007505] intel-sdw sdw-master-2: bus clock stop failed -61 [ 24.007508] intel-sdw sdw-master-2: cannot enable clock stop on suspend there are not slaves attached, so the command ignored should be accepted what's not clear is what the CMD_ACCEPT (1) is already the default? Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/cadence_master.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index cac1775a121a07..da248bc33b8c38 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1260,6 +1260,8 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) u32 status; int ret; + dev_dbg(cdns->dev, "%s: start\n", __func__); + /* Check suspend status */ status = cdns_readl(cdns, CDNS_MCP_STAT); if (status & CDNS_MCP_STAT_CLK_STOP) { @@ -1285,6 +1287,8 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) } } + dev_dbg(cdns->dev, "%s: slave attached %d\n", __func__, slave_present); + /* * This CMD_ACCEPT should be used when there are no devices * attached on the link when entering clock stop mode. If this is @@ -1325,6 +1329,8 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) if (ret < 0) dev_err(cdns->dev, "Clock stop failed %d\n", ret); + dev_dbg(cdns->dev, "%s: end\n", __func__); + return ret; } EXPORT_SYMBOL(sdw_cdns_clock_stop); From 9df08eeebd48df55a7b9e788b947aabb98248755 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 5 Dec 2019 15:07:33 -0600 Subject: [PATCH 1990/1995] soundwire: bus: add traces for slave alerts Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 3e28aaa36e7f99..99bbe4979de03a 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -1249,6 +1249,8 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) bool slave_notify = false; u8 buf, buf2[2], _buf, _buf2[2]; + dev_dbg(slave->bus->dev, "%s: start\n", __func__); + sdw_modify_slave_status(slave, SDW_SLAVE_ALERT); ret = pm_runtime_get_sync(&slave->dev); @@ -1395,6 +1397,8 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) pm_runtime_mark_last_busy(&slave->dev); pm_runtime_put_autosuspend(&slave->dev); + dev_dbg(slave->bus->dev, "%s: end\n", __func__); + return ret; } From efa39ed61c18f4798329e1f696fb988cb3ff2014 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 6 Dec 2019 12:29:43 -0600 Subject: [PATCH 1991/1995] soundwire: cadence_master: add traces for Slave state change Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/cadence_master.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index da248bc33b8c38..63cf4a1b753f67 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -680,16 +680,19 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns, } if (mask & CDNS_MCP_SLAVE_INTSTAT_ATTACHED) { + dev_dbg(cdns->dev, "Slave %d ATTACHED\n", i); status[i] = SDW_SLAVE_ATTACHED; set_status++; } if (mask & CDNS_MCP_SLAVE_INTSTAT_ALERT) { + dev_dbg(cdns->dev, "Slave %d ALERT\n", i); status[i] = SDW_SLAVE_ALERT; set_status++; } if (mask & CDNS_MCP_SLAVE_INTSTAT_NPRESENT) { + dev_dbg(cdns->dev, "Slave %d UNATTACHED\n", i); status[i] = SDW_SLAVE_UNATTACHED; set_status++; } From 35a8c89713b2d4eb3f8d7ad1eefcfee7dc4d4c9c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Fri, 6 Dec 2019 12:31:08 -0600 Subject: [PATCH 1992/1995] soundwire: bus: add traces for Slave state changes Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 99bbe4979de03a..b58df4de3f817e 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -710,7 +710,7 @@ static void sdw_modify_slave_status(struct sdw_slave *slave, { mutex_lock(&slave->bus->bus_lock); - dev_vdbg(&slave->dev, + dev_dbg(&slave->dev, "%s: changing status slave %d status %d new status %d\n", __func__, slave->dev_num, slave->status, status); From abab764f8b3fdca61c5e0f13a1061636eb2875c3 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 9 Dec 2019 16:35:31 -0600 Subject: [PATCH 1993/1995] soundwire: cadence_master: add traces for clock_restart Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/cadence_master.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 63cf4a1b753f67..b17c3ed5391bb3 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1349,6 +1349,8 @@ int sdw_cdns_clock_restart(struct sdw_cdns *cdns, bool bus_reset) { int ret; + dev_dbg(cdns->dev, "%s: start\n", __func__); + ret = cdns_clear_bit(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CLK_STOP_CLR); if (ret < 0) { @@ -1396,6 +1398,8 @@ int sdw_cdns_clock_restart(struct sdw_cdns *cdns, bool bus_reset) dev_err(cdns->dev, "bus failed to exit clock stop %d\n", ret); } + dev_dbg(cdns->dev, "%s: end\n", __func__); + return ret; } EXPORT_SYMBOL(sdw_cdns_clock_restart); From d39d994a910b4a3797bdc6497ac2a2ffe31355c7 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Wed, 11 Dec 2019 15:03:20 +0800 Subject: [PATCH 1994/1995] soundwire: intel: refine function for wakeen event processing if a slave has been attached to a bus, the slave->dev_num_sticky should be non-zero, so we can check this value to skip the ghost devices defined in ACPI table but not populated in hardware. Signed-off-by: Rander Wang --- drivers/soundwire/intel.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 6868be6961b553..d727f538ebb00d 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1509,13 +1509,13 @@ static void intel_master_process_wakeen_event(struct sdw_master_device *md) * the wakeen event and let codec driver check codec status */ list_for_each_entry(slave, &bus->slaves, node) { - if (slave->prop.wake_capable) { - if (slave->status != SDW_SLAVE_ATTACHED && - slave->status != SDW_SLAVE_ALERT) - continue; - + /* + * discard devices that are defined in ACPI tables but + * not physically present and devices that cannot + * generate wakes + */ + if (slave->dev_num_sticky && slave->prop.wake_capable) pm_request_resume(&slave->dev); - } } } From b4ad345c7f7e5a5d028aa424dfdb56a88f01d5cc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 18 Dec 2019 18:16:43 -0600 Subject: [PATCH 1995/1995] soundwire: stream: add traces to debug "transport params" error Signed-off-by: Pierre-Louis Bossart --- drivers/soundwire/stream.c | 49 ++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 795baa2cf19ca6..528ad9fc62d8ea 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -138,8 +138,12 @@ static int sdw_program_slave_port_params(struct sdw_bus *bus, dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave, s_rt->direction, t_params->port_num); - if (!dpn_prop) + if (!dpn_prop) { + dev_err(&s_rt->slave->dev, + "invalid dpn_prop direction %d port_num %d\n", + s_rt->direction, t_params->port_num); return -EINVAL; + } addr1 = SDW_DPN_PORTCTRL(t_params->port_num); addr2 = SDW_DPN_BLOCKCTRL1(t_params->port_num); @@ -245,12 +249,21 @@ static int sdw_program_master_port_params(struct sdw_bus *bus, ret = bus->port_ops->dpn_set_port_transport_params(bus, &p_rt->transport_params, bus->params.next_bank); - if (ret < 0) + if (ret < 0) { + dev_err(bus->dev, "%s dpn_set_port_transport_params failed: %d\n", + __func__, ret); return ret; + } - return bus->port_ops->dpn_set_port_params(bus, - &p_rt->port_params, - bus->params.next_bank); + ret = bus->port_ops->dpn_set_port_params(bus, + &p_rt->port_params, + bus->params.next_bank); + + if (ret < 0) + dev_err(bus->dev, "%s dpn_set_port_params failed: %d\n", + __func__, ret); + + return ret; } /** @@ -270,16 +283,20 @@ static int sdw_program_port_params(struct sdw_master_runtime *m_rt) list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { list_for_each_entry(p_rt, &s_rt->port_list, port_node) { ret = sdw_program_slave_port_params(bus, s_rt, p_rt); - if (ret < 0) + if (ret < 0) { + pr_err("sdw_program_slave_port_params failed %d\n", ret); return ret; + } } } /* Program transport & port parameters for Master(s) */ list_for_each_entry(p_rt, &m_rt->port_list, port_node) { ret = sdw_program_master_port_params(bus, p_rt); - if (ret < 0) + if (ret < 0) { + pr_err("sdw_program_master_port_params failed %d\n", ret); return ret; + } } return 0; @@ -454,8 +471,12 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus, if (prep && intr) { ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep, dpn_prop->imp_def_interrupts); - if (ret < 0) + if (ret < 0) { + dev_err(&s_rt->slave->dev, + "sdw_configure_dpn_intr failed %d\n", ret); + return ret; + } } /* Inform slave about the impending port prepare */ @@ -495,10 +516,16 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus, sdw_do_port_prep(s_rt, prep_ch, SDW_OPS_PORT_POST_PREP); /* Disable interrupt after Port de-prepare */ - if (!prep && intr) + if (!prep && intr) { ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep, dpn_prop->imp_def_interrupts); + if (ret < 0) { + dev_err(&s_rt->slave->dev, + "sdw_configure_dpn_intr failed %d\n", ret); + } + } + return ret; } @@ -580,8 +607,10 @@ static int sdw_notify_config(struct sdw_master_runtime *m_rt) if (bus->ops->set_bus_conf) { ret = bus->ops->set_bus_conf(bus, &bus->params); - if (ret < 0) + if (ret < 0) { + dev_err(bus->dev, "%s: set_bus_conf failed %d\n", __func__, ret); return ret; + } } list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {