aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCharles Keepax <ckeepax@opensource.wolfsonmicro.com>2017-01-06 09:24:41 -0500
committerMark Brown <broonie@kernel.org>2017-01-06 13:09:01 -0500
commitaf813a6fd8740537bfa5801768e90cc95d9262a3 (patch)
treee083666c3b09a46e2dbec460b9c686fc57ec1dd4
parenta5de5b74a50113564a1e0850e2da96c37c35e55d (diff)
ASoC: wm_adsp: Add mechanism to preload firmware on a core
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>
-rw-r--r--sound/soc/codecs/arizona.h1
-rw-r--r--sound/soc/codecs/cs47l24.c3
-rw-r--r--sound/soc/codecs/wm5102.c2
-rw-r--r--sound/soc/codecs/wm5110.c5
-rw-r--r--sound/soc/codecs/wm_adsp.c45
-rw-r--r--sound/soc/codecs/wm_adsp.h11
6 files changed, 66 insertions, 1 deletions
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index 56707860657c..1822e3b3de80 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -192,6 +192,7 @@ extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
192#define ARIZONA_DSP_ROUTES(name) \ 192#define ARIZONA_DSP_ROUTES(name) \
193 { name, NULL, name " Preloader"}, \ 193 { name, NULL, name " Preloader"}, \
194 { name " Preloader", NULL, "SYSCLK" }, \ 194 { name " Preloader", NULL, "SYSCLK" }, \
195 { name " Preload", NULL, name " Preloader"}, \
195 { name, NULL, name " Aux 1" }, \ 196 { name, NULL, name " Aux 1" }, \
196 { name, NULL, name " Aux 2" }, \ 197 { name, NULL, name " Aux 2" }, \
197 { name, NULL, name " Aux 3" }, \ 198 { name, NULL, name " Aux 3" }, \
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
index 73559ae864b6..0dd721e3005d 100644
--- a/sound/soc/codecs/cs47l24.c
+++ b/sound/soc/codecs/cs47l24.c
@@ -173,6 +173,9 @@ SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
173SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]), 173SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
174SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1), 174SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1),
175 175
176WM_ADSP2_PRELOAD_SWITCH("DSP2", 2),
177WM_ADSP2_PRELOAD_SWITCH("DSP3", 3),
178
176ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE), 179ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
177ARIZONA_MIXER_CONTROLS("DSP2R", ARIZONA_DSP2RMIX_INPUT_1_SOURCE), 180ARIZONA_MIXER_CONTROLS("DSP2R", ARIZONA_DSP2RMIX_INPUT_1_SOURCE),
178ARIZONA_MIXER_CONTROLS("DSP3L", ARIZONA_DSP3LMIX_INPUT_1_SOURCE), 181ARIZONA_MIXER_CONTROLS("DSP3L", ARIZONA_DSP3LMIX_INPUT_1_SOURCE),
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index e7ab37d0dd32..9edd239c3b06 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -855,6 +855,8 @@ ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2),
855ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2), 855ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2),
856ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2), 856ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2),
857 857
858WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
859
858ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE), 860ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
859ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE), 861ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
860 862
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 585fc706c1b0..01b5b6c66417 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -778,6 +778,11 @@ SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
778SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]), 778SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
779SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1), 779SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1),
780 780
781WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
782WM_ADSP2_PRELOAD_SWITCH("DSP2", 2),
783WM_ADSP2_PRELOAD_SWITCH("DSP3", 3),
784WM_ADSP2_PRELOAD_SWITCH("DSP4", 4),
785
781ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE), 786ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
782ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE), 787ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
783ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE), 788ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 593b7d1aed46..ed615ce8a496 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -2500,6 +2500,43 @@ static void wm_adsp2_set_dspclk(struct wm_adsp *dsp, unsigned int freq)
2500 adsp_err(dsp, "Failed to set clock rate: %d\n", ret); 2500 adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
2501} 2501}
2502 2502
2503int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
2504 struct snd_ctl_elem_value *ucontrol)
2505{
2506 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2507 struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
2508
2509 ucontrol->value.integer.value[0] = dsp->preloaded;
2510
2511 return 0;
2512}
2513EXPORT_SYMBOL_GPL(wm_adsp2_preloader_get);
2514
2515int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
2516 struct snd_ctl_elem_value *ucontrol)
2517{
2518 struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
2519 struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
2520 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
2521 struct soc_mixer_control *mc =
2522 (struct soc_mixer_control *)kcontrol->private_value;
2523 char preload[32];
2524
2525 snprintf(preload, ARRAY_SIZE(preload), "DSP%d Preload", mc->shift);
2526
2527 dsp->preloaded = ucontrol->value.integer.value[0];
2528
2529 if (ucontrol->value.integer.value[0])
2530 snd_soc_dapm_force_enable_pin(dapm, preload);
2531 else
2532 snd_soc_dapm_disable_pin(dapm, preload);
2533
2534 snd_soc_dapm_sync(dapm);
2535
2536 return 0;
2537}
2538EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
2539
2503int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, 2540int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
2504 struct snd_kcontrol *kcontrol, int event, 2541 struct snd_kcontrol *kcontrol, int event,
2505 unsigned int freq) 2542 unsigned int freq)
@@ -2631,10 +2668,16 @@ EXPORT_SYMBOL_GPL(wm_adsp2_event);
2631 2668
2632int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec) 2669int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec)
2633{ 2670{
2634 dsp->codec = codec; 2671 struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
2672 char preload[32];
2673
2674 snprintf(preload, ARRAY_SIZE(preload), "DSP%d Preload", dsp->num);
2675 snd_soc_dapm_disable_pin(dapm, preload);
2635 2676
2636 wm_adsp2_init_debugfs(dsp, codec); 2677 wm_adsp2_init_debugfs(dsp, codec);
2637 2678
2679 dsp->codec = codec;
2680
2638 return snd_soc_add_codec_controls(codec, 2681 return snd_soc_add_codec_controls(codec,
2639 &wm_adsp_fw_controls[dsp->num - 1], 2682 &wm_adsp_fw_controls[dsp->num - 1],
2640 1); 2683 1);
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index 411d062c13f2..3706b11053a3 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -62,6 +62,7 @@ struct wm_adsp {
62 int fw; 62 int fw;
63 int fw_ver; 63 int fw_ver;
64 64
65 bool preloaded;
65 bool booted; 66 bool booted;
66 bool running; 67 bool running;
67 68
@@ -86,7 +87,12 @@ struct wm_adsp {
86 SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \ 87 SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
87 wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD) 88 wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
88 89
90#define WM_ADSP2_PRELOAD_SWITCH(wname, num) \
91 SOC_SINGLE_EXT(wname " Preload Switch", SND_SOC_NOPM, num, 1, 0, \
92 wm_adsp2_preloader_get, wm_adsp2_preloader_put)
93
89#define WM_ADSP2(wname, num, event_fn) \ 94#define WM_ADSP2(wname, num, event_fn) \
95 SND_SOC_DAPM_SPK(wname " Preload", NULL), \
90{ .id = snd_soc_dapm_supply, .name = wname " Preloader", \ 96{ .id = snd_soc_dapm_supply, .name = wname " Preloader", \
91 .reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \ 97 .reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \
92 .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD, \ 98 .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,
110int wm_adsp2_event(struct snd_soc_dapm_widget *w, 116int wm_adsp2_event(struct snd_soc_dapm_widget *w,
111 struct snd_kcontrol *kcontrol, int event); 117 struct snd_kcontrol *kcontrol, int event);
112 118
119int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
120 struct snd_ctl_elem_value *ucontrol);
121int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
122 struct snd_ctl_elem_value *ucontrol);
123
113int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream); 124int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream);
114int wm_adsp_compr_free(struct snd_compr_stream *stream); 125int wm_adsp_compr_free(struct snd_compr_stream *stream);
115int wm_adsp_compr_set_params(struct snd_compr_stream *stream, 126int wm_adsp_compr_set_params(struct snd_compr_stream *stream,