]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ASoC: wm_adsp: Add mechanism to preload firmware on a core
authorCharles Keepax <ckeepax@opensource.wolfsonmicro.com>
Fri, 6 Jan 2017 14:24:41 +0000 (14:24 +0000)
committerMark Brown <broonie@kernel.org>
Fri, 6 Jan 2017 18:09:01 +0000 (18:09 +0000)
As requirements to bring up audio paths are continuous getting tighter
and the DSP download to most ADSP devices happens over an external bus
it can become an important factor in the path bring up time. As such
sometimes it is a reasonable trade off to download the firmware ahead of
when it will be required and take a small hit on power consumption for
keeping the core powered up.

This "preloading" adds an additional control for each DSP core "DSPx
Preload Switch" that when set to true will power up the DSP core and
download the firmware currently selected in the "DSPx Firmware" control.
Whilst the core is preloaded the current firmware can not be changed and
the CODEC will be kept powered up and SYSCLK held on. Although future
improvements may allow the SYSCLK to be powered down as well because
the hardware only requires SYSCLK whilst the download is actually taking
place, but this is not covered in this series.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/arizona.h
sound/soc/codecs/cs47l24.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wm_adsp.h

index 56707860657cca129df30ed0d64d4081efdedbbf..1822e3b3de805986001f8a037fb0b91f1f83d8c0 100644 (file)
@@ -192,6 +192,7 @@ extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
 #define ARIZONA_DSP_ROUTES(name) \
        { name, NULL, name " Preloader"}, \
        { name " Preloader", NULL, "SYSCLK" }, \
+       { name " Preload", NULL, name " Preloader"}, \
        { name, NULL, name " Aux 1" }, \
        { name, NULL, name " Aux 2" }, \
        { name, NULL, name " Aux 3" }, \
index 73559ae864b656aa224564a089bd336fd9b39dc4..0dd721e3005d6d4d3b82d4e671f7075d8e7c4252 100644 (file)
@@ -173,6 +173,9 @@ SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
 SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
 SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1),
 
+WM_ADSP2_PRELOAD_SWITCH("DSP2", 2),
+WM_ADSP2_PRELOAD_SWITCH("DSP3", 3),
+
 ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("DSP2R", ARIZONA_DSP2RMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("DSP3L", ARIZONA_DSP3LMIX_INPUT_1_SOURCE),
index e7ab37d0dd325c0614e18ce6b2c671acee1c2915..9edd239c3b06c272684e60f62146e0f9809136e3 100644 (file)
@@ -855,6 +855,8 @@ ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2),
 ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2),
 ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2),
 
+WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
+
 ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
 
index 585fc706c1b0e7b112887be058a755b800ed1ca9..01b5b6c6641747517f874954d3552b51fc44779b 100644 (file)
@@ -778,6 +778,11 @@ SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
 SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
 SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1),
 
+WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
+WM_ADSP2_PRELOAD_SWITCH("DSP2", 2),
+WM_ADSP2_PRELOAD_SWITCH("DSP3", 3),
+WM_ADSP2_PRELOAD_SWITCH("DSP4", 4),
+
 ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
index 593b7d1aed4695bbf6e538fa924bc6263901041f..ed615ce8a496a9cf1ed3f4ba09300b2435525b17 100644 (file)
@@ -2500,6 +2500,43 @@ static void wm_adsp2_set_dspclk(struct wm_adsp *dsp, unsigned int freq)
                adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
 }
 
+int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.integer.value[0] = dsp->preloaded;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp2_preloader_get);
+
+int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       char preload[32];
+
+       snprintf(preload, ARRAY_SIZE(preload), "DSP%d Preload", mc->shift);
+
+       dsp->preloaded = ucontrol->value.integer.value[0];
+
+       if (ucontrol->value.integer.value[0])
+               snd_soc_dapm_force_enable_pin(dapm, preload);
+       else
+               snd_soc_dapm_disable_pin(dapm, preload);
+
+       snd_soc_dapm_sync(dapm);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
+
 int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event,
                         unsigned int freq)
@@ -2631,10 +2668,16 @@ EXPORT_SYMBOL_GPL(wm_adsp2_event);
 
 int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec)
 {
-       dsp->codec = codec;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+       char preload[32];
+
+       snprintf(preload, ARRAY_SIZE(preload), "DSP%d Preload", dsp->num);
+       snd_soc_dapm_disable_pin(dapm, preload);
 
        wm_adsp2_init_debugfs(dsp, codec);
 
+       dsp->codec = codec;
+
        return snd_soc_add_codec_controls(codec,
                                          &wm_adsp_fw_controls[dsp->num - 1],
                                          1);
index 411d062c13f2a6f422a671215e86e4029a0c5caf..3706b11053a331856e7049bc880870f3849fabc8 100644 (file)
@@ -62,6 +62,7 @@ struct wm_adsp {
        int fw;
        int fw_ver;
 
+       bool preloaded;
        bool booted;
        bool running;
 
@@ -86,7 +87,12 @@ struct wm_adsp {
        SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
                wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
 
+#define WM_ADSP2_PRELOAD_SWITCH(wname, num) \
+       SOC_SINGLE_EXT(wname " Preload Switch", SND_SOC_NOPM, num, 1, 0, \
+               wm_adsp2_preloader_get, wm_adsp2_preloader_put)
+
 #define WM_ADSP2(wname, num, event_fn) \
+       SND_SOC_DAPM_SPK(wname " Preload", NULL), \
 {      .id = snd_soc_dapm_supply, .name = wname " Preloader", \
        .reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \
        .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD, \
@@ -110,6 +116,11 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
 int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol, int event);
 
+int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol);
+int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol);
+
 int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream);
 int wm_adsp_compr_free(struct snd_compr_stream *stream);
 int wm_adsp_compr_set_params(struct snd_compr_stream *stream,