diff options
| -rw-r--r-- | include/sound/pcm_params.h | 7 | ||||
| -rw-r--r-- | include/sound/soc.h | 3 | ||||
| -rw-r--r-- | sound/soc/intel/broadwell.c | 32 | ||||
| -rw-r--r-- | sound/soc/intel/bytcr_dpcm_rt5640.c | 4 | ||||
| -rw-r--r-- | sound/soc/intel/cht_bsw_rt5645.c | 4 | ||||
| -rw-r--r-- | sound/soc/intel/cht_bsw_rt5672.c | 49 | ||||
| -rw-r--r-- | sound/soc/intel/haswell.c | 4 | ||||
| -rw-r--r-- | sound/soc/intel/sst-dsp-priv.h | 13 | ||||
| -rw-r--r-- | sound/soc/intel/sst-firmware.c | 1 | ||||
| -rw-r--r-- | sound/soc/intel/sst-haswell-dsp.c | 6 | ||||
| -rw-r--r-- | sound/soc/intel/sst-haswell-ipc.c | 451 | ||||
| -rw-r--r-- | sound/soc/intel/sst-haswell-ipc.h | 53 | ||||
| -rw-r--r-- | sound/soc/intel/sst-haswell-pcm.c | 139 | ||||
| -rw-r--r-- | sound/soc/intel/sst-mfld-platform-pcm.c | 60 | ||||
| -rw-r--r-- | sound/soc/intel/sst-mfld-platform.h | 1 | ||||
| -rw-r--r-- | sound/soc/intel/sst/sst.c | 128 | ||||
| -rw-r--r-- | sound/soc/intel/sst/sst.h | 12 | ||||
| -rw-r--r-- | sound/soc/intel/sst/sst_drv_interface.c | 65 | ||||
| -rw-r--r-- | sound/soc/intel/sst/sst_loader.c | 10 | ||||
| -rw-r--r-- | sound/soc/soc-pcm.c | 1 |
20 files changed, 980 insertions, 63 deletions
diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h index 3c45f3924ba7..c704357775fc 100644 --- a/include/sound/pcm_params.h +++ b/include/sound/pcm_params.h | |||
| @@ -366,4 +366,11 @@ static inline int params_physical_width(const struct snd_pcm_hw_params *p) | |||
| 366 | return snd_pcm_format_physical_width(params_format(p)); | 366 | return snd_pcm_format_physical_width(params_format(p)); |
| 367 | } | 367 | } |
| 368 | 368 | ||
| 369 | static inline void | ||
| 370 | params_set_format(struct snd_pcm_hw_params *p, snd_pcm_format_t fmt) | ||
| 371 | { | ||
| 372 | snd_mask_set(hw_param_mask(p, SNDRV_PCM_HW_PARAM_FORMAT), | ||
| 373 | (__force int)fmt); | ||
| 374 | } | ||
| 375 | |||
| 369 | #endif /* __SOUND_PCM_PARAMS_H */ | 376 | #endif /* __SOUND_PCM_PARAMS_H */ |
diff --git a/include/sound/soc.h b/include/sound/soc.h index 0d1ade195628..76bc944dcb5c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
| @@ -954,6 +954,9 @@ struct snd_soc_dai_link { | |||
| 954 | unsigned int symmetric_channels:1; | 954 | unsigned int symmetric_channels:1; |
| 955 | unsigned int symmetric_samplebits:1; | 955 | unsigned int symmetric_samplebits:1; |
| 956 | 956 | ||
| 957 | /* Mark this pcm with non atomic ops */ | ||
| 958 | bool nonatomic; | ||
| 959 | |||
| 957 | /* Do not create a PCM for this DAI link (Backend link) */ | 960 | /* Do not create a PCM for this DAI link (Backend link) */ |
| 958 | unsigned int no_pcm:1; | 961 | unsigned int no_pcm:1; |
| 959 | 962 | ||
diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c index 9cf7d01479ad..af5d73070f60 100644 --- a/sound/soc/intel/broadwell.c +++ b/sound/soc/intel/broadwell.c | |||
| @@ -110,9 +110,7 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, | |||
| 110 | channels->min = channels->max = 2; | 110 | channels->min = channels->max = 2; |
| 111 | 111 | ||
| 112 | /* set SSP0 to 16 bit */ | 112 | /* set SSP0 to 16 bit */ |
| 113 | snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - | 113 | params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); |
| 114 | SNDRV_PCM_HW_PARAM_FIRST_MASK], | ||
| 115 | SNDRV_PCM_FORMAT_S16_LE); | ||
| 116 | return 0; | 114 | return 0; |
| 117 | } | 115 | } |
| 118 | 116 | ||
| @@ -227,6 +225,32 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { | |||
| 227 | }, | 225 | }, |
| 228 | }; | 226 | }; |
| 229 | 227 | ||
| 228 | static int broadwell_suspend(struct snd_soc_card *card){ | ||
| 229 | struct snd_soc_codec *codec; | ||
| 230 | |||
| 231 | list_for_each_entry(codec, &card->codec_dev_list, card_list) { | ||
| 232 | if (!strcmp(codec->component.name, "i2c-INT343A:00")) { | ||
| 233 | dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n"); | ||
| 234 | rt286_mic_detect(codec, NULL); | ||
| 235 | break; | ||
| 236 | } | ||
| 237 | } | ||
| 238 | return 0; | ||
| 239 | } | ||
| 240 | |||
| 241 | static int broadwell_resume(struct snd_soc_card *card){ | ||
| 242 | struct snd_soc_codec *codec; | ||
| 243 | |||
| 244 | list_for_each_entry(codec, &card->codec_dev_list, card_list) { | ||
| 245 | if (!strcmp(codec->component.name, "i2c-INT343A:00")) { | ||
| 246 | dev_dbg(codec->dev, "enabling jack detect for resume.\n"); | ||
| 247 | rt286_mic_detect(codec, &broadwell_headset); | ||
| 248 | break; | ||
| 249 | } | ||
| 250 | } | ||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | |||
| 230 | /* broadwell audio machine driver for WPT + RT286S */ | 254 | /* broadwell audio machine driver for WPT + RT286S */ |
| 231 | static struct snd_soc_card broadwell_rt286 = { | 255 | static struct snd_soc_card broadwell_rt286 = { |
| 232 | .name = "broadwell-rt286", | 256 | .name = "broadwell-rt286", |
| @@ -240,6 +264,8 @@ static struct snd_soc_card broadwell_rt286 = { | |||
| 240 | .dapm_routes = broadwell_rt286_map, | 264 | .dapm_routes = broadwell_rt286_map, |
| 241 | .num_dapm_routes = ARRAY_SIZE(broadwell_rt286_map), | 265 | .num_dapm_routes = ARRAY_SIZE(broadwell_rt286_map), |
| 242 | .fully_routed = true, | 266 | .fully_routed = true, |
| 267 | .suspend_pre = broadwell_suspend, | ||
| 268 | .resume_post = broadwell_resume, | ||
| 243 | }; | 269 | }; |
| 244 | 270 | ||
| 245 | static int broadwell_audio_probe(struct platform_device *pdev) | 271 | static int broadwell_audio_probe(struct platform_device *pdev) |
diff --git a/sound/soc/intel/bytcr_dpcm_rt5640.c b/sound/soc/intel/bytcr_dpcm_rt5640.c index 59308629043e..3b262d01c1b3 100644 --- a/sound/soc/intel/bytcr_dpcm_rt5640.c +++ b/sound/soc/intel/bytcr_dpcm_rt5640.c | |||
| @@ -113,9 +113,7 @@ static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd, | |||
| 113 | channels->min = channels->max = 2; | 113 | channels->min = channels->max = 2; |
| 114 | 114 | ||
| 115 | /* set SSP2 to 24-bit */ | 115 | /* set SSP2 to 24-bit */ |
| 116 | snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - | 116 | params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); |
| 117 | SNDRV_PCM_HW_PARAM_FIRST_MASK], | ||
| 118 | SNDRV_PCM_FORMAT_S24_LE); | ||
| 119 | return 0; | 117 | return 0; |
| 120 | } | 118 | } |
| 121 | 119 | ||
diff --git a/sound/soc/intel/cht_bsw_rt5645.c b/sound/soc/intel/cht_bsw_rt5645.c index bd29617a9ab9..dd935255a020 100644 --- a/sound/soc/intel/cht_bsw_rt5645.c +++ b/sound/soc/intel/cht_bsw_rt5645.c | |||
| @@ -203,9 +203,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, | |||
| 203 | channels->min = channels->max = 2; | 203 | channels->min = channels->max = 2; |
| 204 | 204 | ||
| 205 | /* set SSP2 to 24-bit */ | 205 | /* set SSP2 to 24-bit */ |
| 206 | snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - | 206 | params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); |
| 207 | SNDRV_PCM_HW_PARAM_FIRST_MASK], | ||
| 208 | SNDRV_PCM_FORMAT_S24_LE); | ||
| 209 | return 0; | 207 | return 0; |
| 210 | } | 208 | } |
| 211 | 209 | ||
diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c index ff016621583a..279df4c43de1 100644 --- a/sound/soc/intel/cht_bsw_rt5672.c +++ b/sound/soc/intel/cht_bsw_rt5672.c | |||
| @@ -50,6 +50,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, | |||
| 50 | struct snd_soc_dapm_context *dapm = w->dapm; | 50 | struct snd_soc_dapm_context *dapm = w->dapm; |
| 51 | struct snd_soc_card *card = dapm->card; | 51 | struct snd_soc_card *card = dapm->card; |
| 52 | struct snd_soc_dai *codec_dai; | 52 | struct snd_soc_dai *codec_dai; |
| 53 | int ret; | ||
| 53 | 54 | ||
| 54 | codec_dai = cht_get_codec_dai(card); | 55 | codec_dai = cht_get_codec_dai(card); |
| 55 | if (!codec_dai) { | 56 | if (!codec_dai) { |
| @@ -57,17 +58,31 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, | |||
| 57 | return -EIO; | 58 | return -EIO; |
| 58 | } | 59 | } |
| 59 | 60 | ||
| 60 | if (!SND_SOC_DAPM_EVENT_OFF(event)) | 61 | if (SND_SOC_DAPM_EVENT_ON(event)) { |
| 61 | return 0; | 62 | /* set codec PLL source to the 19.2MHz platform clock (MCLK) */ |
| 62 | 63 | ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK, | |
| 63 | /* Set codec sysclk source to its internal clock because codec PLL will | 64 | CHT_PLAT_CLK_3_HZ, 48000 * 512); |
| 64 | * be off when idle and MCLK will also be off by ACPI when codec is | 65 | if (ret < 0) { |
| 65 | * runtime suspended. Codec needs clock for jack detection and button | 66 | dev_err(card->dev, "can't set codec pll: %d\n", ret); |
| 66 | * press. | 67 | return ret; |
| 67 | */ | 68 | } |
| 68 | snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, | 69 | |
| 69 | 0, SND_SOC_CLOCK_IN); | 70 | /* set codec sysclk source to PLL */ |
| 70 | 71 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1, | |
| 72 | 48000 * 512, SND_SOC_CLOCK_IN); | ||
| 73 | if (ret < 0) { | ||
| 74 | dev_err(card->dev, "can't set codec sysclk: %d\n", ret); | ||
| 75 | return ret; | ||
| 76 | } | ||
| 77 | } else { | ||
| 78 | /* Set codec sysclk source to its internal clock because codec | ||
| 79 | * PLL will be off when idle and MCLK will also be off by ACPI | ||
| 80 | * when codec is runtime suspended. Codec needs clock for jack | ||
| 81 | * detection and button press. | ||
| 82 | */ | ||
| 83 | snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, | ||
| 84 | 48000 * 512, SND_SOC_CLOCK_IN); | ||
| 85 | } | ||
| 71 | return 0; | 86 | return 0; |
| 72 | } | 87 | } |
| 73 | 88 | ||
| @@ -77,7 +92,8 @@ static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { | |||
| 77 | SND_SOC_DAPM_MIC("Int Mic", NULL), | 92 | SND_SOC_DAPM_MIC("Int Mic", NULL), |
| 78 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | 93 | SND_SOC_DAPM_SPK("Ext Spk", NULL), |
| 79 | SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, | 94 | SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, |
| 80 | platform_clock_control, SND_SOC_DAPM_POST_PMD), | 95 | platform_clock_control, SND_SOC_DAPM_PRE_PMU | |
| 96 | SND_SOC_DAPM_POST_PMD), | ||
| 81 | }; | 97 | }; |
| 82 | 98 | ||
| 83 | static const struct snd_soc_dapm_route cht_audio_map[] = { | 99 | static const struct snd_soc_dapm_route cht_audio_map[] = { |
| @@ -178,9 +194,7 @@ static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, | |||
| 178 | channels->min = channels->max = 2; | 194 | channels->min = channels->max = 2; |
| 179 | 195 | ||
| 180 | /* set SSP2 to 24-bit */ | 196 | /* set SSP2 to 24-bit */ |
| 181 | snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - | 197 | params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); |
| 182 | SNDRV_PCM_HW_PARAM_FIRST_MASK], | ||
| 183 | SNDRV_PCM_FORMAT_S24_LE); | ||
| 184 | return 0; | 198 | return 0; |
| 185 | } | 199 | } |
| 186 | 200 | ||
| @@ -217,7 +231,7 @@ static struct snd_soc_dai_link cht_dailink[] = { | |||
| 217 | .codec_dai_name = "snd-soc-dummy-dai", | 231 | .codec_dai_name = "snd-soc-dummy-dai", |
| 218 | .codec_name = "snd-soc-dummy", | 232 | .codec_name = "snd-soc-dummy", |
| 219 | .platform_name = "sst-mfld-platform", | 233 | .platform_name = "sst-mfld-platform", |
| 220 | .ignore_suspend = 1, | 234 | .nonatomic = true, |
| 221 | .dynamic = 1, | 235 | .dynamic = 1, |
| 222 | .dpcm_playback = 1, | 236 | .dpcm_playback = 1, |
| 223 | .dpcm_capture = 1, | 237 | .dpcm_capture = 1, |
| @@ -240,13 +254,13 @@ static struct snd_soc_dai_link cht_dailink[] = { | |||
| 240 | .cpu_dai_name = "ssp2-port", | 254 | .cpu_dai_name = "ssp2-port", |
| 241 | .platform_name = "sst-mfld-platform", | 255 | .platform_name = "sst-mfld-platform", |
| 242 | .no_pcm = 1, | 256 | .no_pcm = 1, |
| 257 | .nonatomic = true, | ||
| 243 | .codec_dai_name = "rt5670-aif1", | 258 | .codec_dai_name = "rt5670-aif1", |
| 244 | .codec_name = "i2c-10EC5670:00", | 259 | .codec_name = "i2c-10EC5670:00", |
| 245 | .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | 260 | .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF |
| 246 | | SND_SOC_DAIFMT_CBS_CFS, | 261 | | SND_SOC_DAIFMT_CBS_CFS, |
| 247 | .init = cht_codec_init, | 262 | .init = cht_codec_init, |
| 248 | .be_hw_params_fixup = cht_codec_fixup, | 263 | .be_hw_params_fixup = cht_codec_fixup, |
| 249 | .ignore_suspend = 1, | ||
| 250 | .dpcm_playback = 1, | 264 | .dpcm_playback = 1, |
| 251 | .dpcm_capture = 1, | 265 | .dpcm_capture = 1, |
| 252 | .ops = &cht_be_ssp2_ops, | 266 | .ops = &cht_be_ssp2_ops, |
| @@ -285,7 +299,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) | |||
| 285 | static struct platform_driver snd_cht_mc_driver = { | 299 | static struct platform_driver snd_cht_mc_driver = { |
| 286 | .driver = { | 300 | .driver = { |
| 287 | .name = "cht-bsw-rt5672", | 301 | .name = "cht-bsw-rt5672", |
| 288 | .pm = &snd_soc_pm_ops, | ||
| 289 | }, | 302 | }, |
| 290 | .probe = snd_cht_mc_probe, | 303 | .probe = snd_cht_mc_probe, |
| 291 | }; | 304 | }; |
diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c index 35edf51a52aa..00fddd3f5dfb 100644 --- a/sound/soc/intel/haswell.c +++ b/sound/soc/intel/haswell.c | |||
| @@ -56,9 +56,7 @@ static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, | |||
| 56 | channels->min = channels->max = 2; | 56 | channels->min = channels->max = 2; |
| 57 | 57 | ||
| 58 | /* set SSP0 to 16 bit */ | 58 | /* set SSP0 to 16 bit */ |
| 59 | snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - | 59 | params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); |
| 60 | SNDRV_PCM_HW_PARAM_FIRST_MASK], | ||
| 61 | SNDRV_PCM_FORMAT_S16_LE); | ||
| 62 | return 0; | 60 | return 0; |
| 63 | } | 61 | } |
| 64 | 62 | ||
diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h index b9da030e312d..396d54510350 100644 --- a/sound/soc/intel/sst-dsp-priv.h +++ b/sound/soc/intel/sst-dsp-priv.h | |||
| @@ -173,6 +173,16 @@ struct sst_module_runtime_context { | |||
| 173 | }; | 173 | }; |
| 174 | 174 | ||
| 175 | /* | 175 | /* |
| 176 | * Audio DSP Module State | ||
| 177 | */ | ||
| 178 | enum sst_module_state { | ||
| 179 | SST_MODULE_STATE_UNLOADED = 0, /* default state */ | ||
| 180 | SST_MODULE_STATE_LOADED, | ||
| 181 | SST_MODULE_STATE_INITIALIZED, /* and inactive */ | ||
| 182 | SST_MODULE_STATE_ACTIVE, | ||
| 183 | }; | ||
| 184 | |||
| 185 | /* | ||
| 176 | * Audio DSP Generic Module. | 186 | * Audio DSP Generic Module. |
| 177 | * | 187 | * |
| 178 | * Each Firmware file can consist of 1..N modules. A module can span multiple | 188 | * Each Firmware file can consist of 1..N modules. A module can span multiple |
| @@ -203,6 +213,9 @@ struct sst_module { | |||
| 203 | struct list_head list; /* DSP list of modules */ | 213 | struct list_head list; /* DSP list of modules */ |
| 204 | struct list_head list_fw; /* FW list of modules */ | 214 | struct list_head list_fw; /* FW list of modules */ |
| 205 | struct list_head runtime_list; /* list of runtime module objects*/ | 215 | struct list_head runtime_list; /* list of runtime module objects*/ |
| 216 | |||
| 217 | /* state */ | ||
| 218 | enum sst_module_state state; | ||
| 206 | }; | 219 | }; |
| 207 | 220 | ||
| 208 | /* | 221 | /* |
diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c index 5f71ef607a57..5e5800897da2 100644 --- a/sound/soc/intel/sst-firmware.c +++ b/sound/soc/intel/sst-firmware.c | |||
| @@ -498,6 +498,7 @@ struct sst_module *sst_module_new(struct sst_fw *sst_fw, | |||
| 498 | sst_module->scratch_size = template->scratch_size; | 498 | sst_module->scratch_size = template->scratch_size; |
| 499 | sst_module->persistent_size = template->persistent_size; | 499 | sst_module->persistent_size = template->persistent_size; |
| 500 | sst_module->entry = template->entry; | 500 | sst_module->entry = template->entry; |
| 501 | sst_module->state = SST_MODULE_STATE_UNLOADED; | ||
| 501 | 502 | ||
| 502 | INIT_LIST_HEAD(&sst_module->block_list); | 503 | INIT_LIST_HEAD(&sst_module->block_list); |
| 503 | INIT_LIST_HEAD(&sst_module->runtime_list); | 504 | INIT_LIST_HEAD(&sst_module->runtime_list); |
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c index c42ffae5fe9f..b3e957d46933 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/sst-haswell-dsp.c | |||
| @@ -100,6 +100,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
| 100 | && module->type != SST_HSW_MODULE_PCM | 100 | && module->type != SST_HSW_MODULE_PCM |
| 101 | && module->type != SST_HSW_MODULE_PCM_REFERENCE | 101 | && module->type != SST_HSW_MODULE_PCM_REFERENCE |
| 102 | && module->type != SST_HSW_MODULE_PCM_CAPTURE | 102 | && module->type != SST_HSW_MODULE_PCM_CAPTURE |
| 103 | && module->type != SST_HSW_MODULE_WAVES | ||
| 103 | && module->type != SST_HSW_MODULE_LPAL) | 104 | && module->type != SST_HSW_MODULE_LPAL) |
| 104 | return 0; | 105 | return 0; |
| 105 | 106 | ||
| @@ -139,6 +140,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
| 139 | mod->type = SST_MEM_IRAM; | 140 | mod->type = SST_MEM_IRAM; |
| 140 | break; | 141 | break; |
| 141 | case SST_HSW_DRAM: | 142 | case SST_HSW_DRAM: |
| 143 | case SST_HSW_REGS: | ||
| 142 | ram = dsp->addr.lpe; | 144 | ram = dsp->addr.lpe; |
| 143 | mod->offset = block->ram_offset; | 145 | mod->offset = block->ram_offset; |
| 144 | mod->type = SST_MEM_DRAM; | 146 | mod->type = SST_MEM_DRAM; |
| @@ -169,6 +171,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
| 169 | 171 | ||
| 170 | block = (void *)block + sizeof(*block) + block->size; | 172 | block = (void *)block + sizeof(*block) + block->size; |
| 171 | } | 173 | } |
| 174 | mod->state = SST_MODULE_STATE_LOADED; | ||
| 172 | 175 | ||
| 173 | return 0; | 176 | return 0; |
| 174 | } | 177 | } |
| @@ -207,9 +210,6 @@ static int hsw_parse_fw_image(struct sst_fw *sst_fw) | |||
| 207 | module = (void *)module + sizeof(*module) + module->mod_size; | 210 | module = (void *)module + sizeof(*module) + module->mod_size; |
| 208 | } | 211 | } |
| 209 | 212 | ||
| 210 | /* allocate scratch mem regions */ | ||
| 211 | sst_block_alloc_scratch(dsp); | ||
| 212 | |||
| 213 | return 0; | 213 | return 0; |
| 214 | } | 214 | } |
| 215 | 215 | ||
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 394af5684c05..43fb5f339168 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c | |||
| @@ -79,6 +79,15 @@ | |||
| 79 | #define IPC_LOG_ID_MASK (0xf << IPC_LOG_ID_SHIFT) | 79 | #define IPC_LOG_ID_MASK (0xf << IPC_LOG_ID_SHIFT) |
| 80 | #define IPC_LOG_ID(x) (x << IPC_LOG_ID_SHIFT) | 80 | #define IPC_LOG_ID(x) (x << IPC_LOG_ID_SHIFT) |
| 81 | 81 | ||
| 82 | /* Module Message */ | ||
| 83 | #define IPC_MODULE_OPERATION_SHIFT 20 | ||
| 84 | #define IPC_MODULE_OPERATION_MASK (0xf << IPC_MODULE_OPERATION_SHIFT) | ||
| 85 | #define IPC_MODULE_OPERATION(x) (x << IPC_MODULE_OPERATION_SHIFT) | ||
| 86 | |||
| 87 | #define IPC_MODULE_ID_SHIFT 16 | ||
| 88 | #define IPC_MODULE_ID_MASK (0xf << IPC_MODULE_ID_SHIFT) | ||
| 89 | #define IPC_MODULE_ID(x) (x << IPC_MODULE_ID_SHIFT) | ||
| 90 | |||
| 82 | /* IPC message timeout (msecs) */ | 91 | /* IPC message timeout (msecs) */ |
| 83 | #define IPC_TIMEOUT_MSECS 300 | 92 | #define IPC_TIMEOUT_MSECS 300 |
| 84 | #define IPC_BOOT_MSECS 200 | 93 | #define IPC_BOOT_MSECS 200 |
| @@ -115,6 +124,7 @@ enum ipc_glb_type { | |||
| 115 | IPC_GLB_ENTER_DX_STATE = 12, | 124 | IPC_GLB_ENTER_DX_STATE = 12, |
| 116 | IPC_GLB_GET_MIXER_STREAM_INFO = 13, /* Request mixer stream params */ | 125 | IPC_GLB_GET_MIXER_STREAM_INFO = 13, /* Request mixer stream params */ |
| 117 | IPC_GLB_DEBUG_LOG_MESSAGE = 14, /* Message to or from the debug logger. */ | 126 | IPC_GLB_DEBUG_LOG_MESSAGE = 14, /* Message to or from the debug logger. */ |
| 127 | IPC_GLB_MODULE_OPERATION = 15, /* Message to loadable fw module */ | ||
| 118 | IPC_GLB_REQUEST_TRANSFER = 16, /* < Request Transfer for host */ | 128 | IPC_GLB_REQUEST_TRANSFER = 16, /* < Request Transfer for host */ |
| 119 | IPC_GLB_MAX_IPC_MESSAGE_TYPE = 17, /* Maximum message number */ | 129 | IPC_GLB_MAX_IPC_MESSAGE_TYPE = 17, /* Maximum message number */ |
| 120 | }; | 130 | }; |
| @@ -133,6 +143,16 @@ enum ipc_glb_reply { | |||
| 133 | IPC_GLB_REPLY_SOURCE_NOT_STARTED = 10, /* Source was not started. */ | 143 | IPC_GLB_REPLY_SOURCE_NOT_STARTED = 10, /* Source was not started. */ |
| 134 | }; | 144 | }; |
| 135 | 145 | ||
| 146 | enum ipc_module_operation { | ||
| 147 | IPC_MODULE_NOTIFICATION = 0, | ||
| 148 | IPC_MODULE_ENABLE = 1, | ||
| 149 | IPC_MODULE_DISABLE = 2, | ||
| 150 | IPC_MODULE_GET_PARAMETER = 3, | ||
| 151 | IPC_MODULE_SET_PARAMETER = 4, | ||
| 152 | IPC_MODULE_GET_INFO = 5, | ||
| 153 | IPC_MODULE_MAX_MESSAGE | ||
| 154 | }; | ||
| 155 | |||
| 136 | /* Stream Message - Types */ | 156 | /* Stream Message - Types */ |
| 137 | enum ipc_str_operation { | 157 | enum ipc_str_operation { |
| 138 | IPC_STR_RESET = 0, | 158 | IPC_STR_RESET = 0, |
| @@ -317,6 +337,15 @@ struct sst_hsw { | |||
| 317 | 337 | ||
| 318 | /* FW log stream */ | 338 | /* FW log stream */ |
| 319 | struct sst_hsw_log_stream log_stream; | 339 | struct sst_hsw_log_stream log_stream; |
| 340 | |||
| 341 | /* flags bit field to track module state when resume from RTD3, | ||
| 342 | * each bit represent state (enabled/disabled) of single module */ | ||
| 343 | u32 enabled_modules_rtd3; | ||
| 344 | |||
| 345 | /* buffer to store parameter lines */ | ||
| 346 | u32 param_idx_w; /* write index */ | ||
| 347 | u32 param_idx_r; /* read index */ | ||
| 348 | u8 param_buf[WAVES_PARAM_LINES][WAVES_PARAM_COUNT]; | ||
| 320 | }; | 349 | }; |
| 321 | 350 | ||
| 322 | #define CREATE_TRACE_POINTS | 351 | #define CREATE_TRACE_POINTS |
| @@ -352,6 +381,16 @@ static inline u32 msg_get_notify_reason(u32 msg) | |||
| 352 | return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT; | 381 | return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT; |
| 353 | } | 382 | } |
| 354 | 383 | ||
| 384 | static inline u32 msg_get_module_operation(u32 msg) | ||
| 385 | { | ||
| 386 | return (msg & IPC_MODULE_OPERATION_MASK) >> IPC_MODULE_OPERATION_SHIFT; | ||
| 387 | } | ||
| 388 | |||
| 389 | static inline u32 msg_get_module_id(u32 msg) | ||
| 390 | { | ||
| 391 | return (msg & IPC_MODULE_ID_MASK) >> IPC_MODULE_ID_SHIFT; | ||
| 392 | } | ||
| 393 | |||
| 355 | u32 create_channel_map(enum sst_hsw_channel_config config) | 394 | u32 create_channel_map(enum sst_hsw_channel_config config) |
| 356 | { | 395 | { |
| 357 | switch (config) { | 396 | switch (config) { |
| @@ -795,6 +834,31 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) | |||
| 795 | return 1; | 834 | return 1; |
| 796 | } | 835 | } |
| 797 | 836 | ||
| 837 | static int hsw_module_message(struct sst_hsw *hsw, u32 header) | ||
| 838 | { | ||
| 839 | u32 operation, module_id; | ||
| 840 | int handled = 0; | ||
| 841 | |||
| 842 | operation = msg_get_module_operation(header); | ||
| 843 | module_id = msg_get_module_id(header); | ||
| 844 | dev_dbg(hsw->dev, "received module message header: 0x%8.8x\n", | ||
| 845 | header); | ||
| 846 | dev_dbg(hsw->dev, "operation: 0x%8.8x module_id: 0x%8.8x\n", | ||
| 847 | operation, module_id); | ||
| 848 | |||
| 849 | switch (operation) { | ||
| 850 | case IPC_MODULE_NOTIFICATION: | ||
| 851 | dev_dbg(hsw->dev, "module notification received"); | ||
| 852 | handled = 1; | ||
| 853 | break; | ||
| 854 | default: | ||
| 855 | handled = hsw_process_reply(hsw, header); | ||
| 856 | break; | ||
| 857 | } | ||
| 858 | |||
| 859 | return handled; | ||
| 860 | } | ||
| 861 | |||
| 798 | static int hsw_stream_message(struct sst_hsw *hsw, u32 header) | 862 | static int hsw_stream_message(struct sst_hsw *hsw, u32 header) |
| 799 | { | 863 | { |
| 800 | u32 stream_msg, stream_id, stage_type; | 864 | u32 stream_msg, stream_id, stage_type; |
| @@ -890,6 +954,9 @@ static int hsw_process_notification(struct sst_hsw *hsw) | |||
| 890 | case IPC_GLB_DEBUG_LOG_MESSAGE: | 954 | case IPC_GLB_DEBUG_LOG_MESSAGE: |
| 891 | handled = hsw_log_message(hsw, header); | 955 | handled = hsw_log_message(hsw, header); |
| 892 | break; | 956 | break; |
| 957 | case IPC_GLB_MODULE_OPERATION: | ||
| 958 | handled = hsw_module_message(hsw, header); | ||
| 959 | break; | ||
| 893 | default: | 960 | default: |
| 894 | dev_err(hsw->dev, "error: unexpected type %d hdr 0x%8.8x\n", | 961 | dev_err(hsw->dev, "error: unexpected type %d hdr 0x%8.8x\n", |
| 895 | type, header); | 962 | type, header); |
| @@ -1732,6 +1799,7 @@ static void sst_hsw_drop_all(struct sst_hsw *hsw) | |||
| 1732 | int sst_hsw_dsp_load(struct sst_hsw *hsw) | 1799 | int sst_hsw_dsp_load(struct sst_hsw *hsw) |
| 1733 | { | 1800 | { |
| 1734 | struct sst_dsp *dsp = hsw->dsp; | 1801 | struct sst_dsp *dsp = hsw->dsp; |
| 1802 | struct sst_fw *sst_fw, *t; | ||
| 1735 | int ret; | 1803 | int ret; |
| 1736 | 1804 | ||
| 1737 | dev_dbg(hsw->dev, "loading audio DSP...."); | 1805 | dev_dbg(hsw->dev, "loading audio DSP...."); |
| @@ -1748,12 +1816,17 @@ int sst_hsw_dsp_load(struct sst_hsw *hsw) | |||
| 1748 | return ret; | 1816 | return ret; |
| 1749 | } | 1817 | } |
| 1750 | 1818 | ||
| 1751 | ret = sst_fw_reload(hsw->sst_fw); | 1819 | list_for_each_entry_safe_reverse(sst_fw, t, &dsp->fw_list, list) { |
| 1752 | if (ret < 0) { | 1820 | ret = sst_fw_reload(sst_fw); |
| 1753 | dev_err(hsw->dev, "error: SST FW reload failed\n"); | 1821 | if (ret < 0) { |
| 1754 | sst_dsp_dma_put_channel(dsp); | 1822 | dev_err(hsw->dev, "error: SST FW reload failed\n"); |
| 1755 | return -ENOMEM; | 1823 | sst_dsp_dma_put_channel(dsp); |
| 1824 | return -ENOMEM; | ||
| 1825 | } | ||
| 1756 | } | 1826 | } |
| 1827 | ret = sst_block_alloc_scratch(hsw->dsp); | ||
| 1828 | if (ret < 0) | ||
| 1829 | return -EINVAL; | ||
| 1757 | 1830 | ||
| 1758 | sst_dsp_dma_put_channel(dsp); | 1831 | sst_dsp_dma_put_channel(dsp); |
| 1759 | return 0; | 1832 | return 0; |
| @@ -1809,12 +1882,17 @@ int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw) | |||
| 1809 | 1882 | ||
| 1810 | int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw) | 1883 | int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw) |
| 1811 | { | 1884 | { |
| 1812 | sst_fw_unload(hsw->sst_fw); | 1885 | struct sst_fw *sst_fw, *t; |
| 1813 | sst_block_free_scratch(hsw->dsp); | 1886 | struct sst_dsp *dsp = hsw->dsp; |
| 1887 | |||
| 1888 | list_for_each_entry_safe(sst_fw, t, &dsp->fw_list, list) { | ||
| 1889 | sst_fw_unload(sst_fw); | ||
| 1890 | } | ||
| 1891 | sst_block_free_scratch(dsp); | ||
| 1814 | 1892 | ||
| 1815 | hsw->boot_complete = false; | 1893 | hsw->boot_complete = false; |
| 1816 | 1894 | ||
| 1817 | sst_dsp_sleep(hsw->dsp); | 1895 | sst_dsp_sleep(dsp); |
| 1818 | 1896 | ||
| 1819 | return 0; | 1897 | return 0; |
| 1820 | } | 1898 | } |
| @@ -1833,6 +1911,8 @@ int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw) | |||
| 1833 | if (ret < 0) | 1911 | if (ret < 0) |
| 1834 | dev_err(dev, "error: audio DSP boot failure\n"); | 1912 | dev_err(dev, "error: audio DSP boot failure\n"); |
| 1835 | 1913 | ||
| 1914 | sst_hsw_init_module_state(hsw); | ||
| 1915 | |||
| 1836 | ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete, | 1916 | ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete, |
| 1837 | msecs_to_jiffies(IPC_BOOT_MSECS)); | 1917 | msecs_to_jiffies(IPC_BOOT_MSECS)); |
| 1838 | if (ret == 0) { | 1918 | if (ret == 0) { |
| @@ -1875,6 +1955,337 @@ struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw) | |||
| 1875 | return hsw->dsp; | 1955 | return hsw->dsp; |
| 1876 | } | 1956 | } |
| 1877 | 1957 | ||
| 1958 | void sst_hsw_init_module_state(struct sst_hsw *hsw) | ||
| 1959 | { | ||
| 1960 | struct sst_module *module; | ||
| 1961 | enum sst_hsw_module_id id; | ||
| 1962 | |||
| 1963 | /* the base fw contains several modules */ | ||
| 1964 | for (id = SST_HSW_MODULE_BASE_FW; id < SST_HSW_MAX_MODULE_ID; id++) { | ||
| 1965 | module = sst_module_get_from_id(hsw->dsp, id); | ||
| 1966 | if (module) { | ||
| 1967 | /* module waves is active only after being enabled */ | ||
| 1968 | if (id == SST_HSW_MODULE_WAVES) | ||
| 1969 | module->state = SST_MODULE_STATE_INITIALIZED; | ||
| 1970 | else | ||
| 1971 | module->state = SST_MODULE_STATE_ACTIVE; | ||
| 1972 | } | ||
| 1973 | } | ||
| 1974 | } | ||
| 1975 | |||
| 1976 | bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id) | ||
| 1977 | { | ||
| 1978 | struct sst_module *module; | ||
| 1979 | |||
| 1980 | module = sst_module_get_from_id(hsw->dsp, module_id); | ||
| 1981 | if (module == NULL || module->state == SST_MODULE_STATE_UNLOADED) | ||
| 1982 | return false; | ||
| 1983 | else | ||
| 1984 | return true; | ||
| 1985 | } | ||
| 1986 | |||
| 1987 | bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id) | ||
| 1988 | { | ||
| 1989 | struct sst_module *module; | ||
| 1990 | |||
| 1991 | module = sst_module_get_from_id(hsw->dsp, module_id); | ||
| 1992 | if (module != NULL && module->state == SST_MODULE_STATE_ACTIVE) | ||
| 1993 | return true; | ||
| 1994 | else | ||
| 1995 | return false; | ||
| 1996 | } | ||
| 1997 | |||
| 1998 | void sst_hsw_set_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id) | ||
| 1999 | { | ||
| 2000 | hsw->enabled_modules_rtd3 |= (1 << module_id); | ||
| 2001 | } | ||
| 2002 | |||
| 2003 | void sst_hsw_set_module_disabled_rtd3(struct sst_hsw *hsw, u32 module_id) | ||
| 2004 | { | ||
| 2005 | hsw->enabled_modules_rtd3 &= ~(1 << module_id); | ||
| 2006 | } | ||
| 2007 | |||
| 2008 | bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id) | ||
| 2009 | { | ||
| 2010 | return hsw->enabled_modules_rtd3 & (1 << module_id); | ||
| 2011 | } | ||
| 2012 | |||
| 2013 | void sst_hsw_reset_param_buf(struct sst_hsw *hsw) | ||
| 2014 | { | ||
| 2015 | hsw->param_idx_w = 0; | ||
| 2016 | hsw->param_idx_r = 0; | ||
| 2017 | memset((void *)hsw->param_buf, 0, sizeof(hsw->param_buf)); | ||
| 2018 | } | ||
| 2019 | |||
| 2020 | int sst_hsw_store_param_line(struct sst_hsw *hsw, u8 *buf) | ||
| 2021 | { | ||
| 2022 | /* save line to the first available position of param buffer */ | ||
| 2023 | if (hsw->param_idx_w > WAVES_PARAM_LINES - 1) { | ||
| 2024 | dev_warn(hsw->dev, "warning: param buffer overflow!\n"); | ||
| 2025 | return -EPERM; | ||
| 2026 | } | ||
| 2027 | memcpy(hsw->param_buf[hsw->param_idx_w], buf, WAVES_PARAM_COUNT); | ||
| 2028 | hsw->param_idx_w++; | ||
| 2029 | return 0; | ||
| 2030 | } | ||
| 2031 | |||
| 2032 | int sst_hsw_load_param_line(struct sst_hsw *hsw, u8 *buf) | ||
| 2033 | { | ||
| 2034 | u8 id = 0; | ||
| 2035 | |||
| 2036 | /* read the first matching line from param buffer */ | ||
| 2037 | while (hsw->param_idx_r < WAVES_PARAM_LINES) { | ||
| 2038 | id = hsw->param_buf[hsw->param_idx_r][0]; | ||
| 2039 | hsw->param_idx_r++; | ||
| 2040 | if (buf[0] == id) { | ||
| 2041 | memcpy(buf, hsw->param_buf[hsw->param_idx_r], | ||
| 2042 | WAVES_PARAM_COUNT); | ||
| 2043 | break; | ||
| 2044 | } | ||
| 2045 | } | ||
| 2046 | if (hsw->param_idx_r > WAVES_PARAM_LINES - 1) { | ||
| 2047 | dev_dbg(hsw->dev, "end of buffer, roll to the beginning\n"); | ||
| 2048 | hsw->param_idx_r = 0; | ||
| 2049 | return 0; | ||
| 2050 | } | ||
| 2051 | return 0; | ||
| 2052 | } | ||
| 2053 | |||
| 2054 | int sst_hsw_launch_param_buf(struct sst_hsw *hsw) | ||
| 2055 | { | ||
| 2056 | int ret, idx; | ||
| 2057 | |||
| 2058 | /* put all param lines to DSP through ipc */ | ||
| 2059 | for (idx = 0; idx < hsw->param_idx_w; idx++) { | ||
| 2060 | ret = sst_hsw_module_set_param(hsw, | ||
| 2061 | SST_HSW_MODULE_WAVES, 0, hsw->param_buf[idx][0], | ||
| 2062 | WAVES_PARAM_COUNT, hsw->param_buf[idx]); | ||
| 2063 | if (ret < 0) | ||
| 2064 | return ret; | ||
| 2065 | } | ||
| 2066 | return 0; | ||
| 2067 | } | ||
| 2068 | |||
| 2069 | int sst_hsw_module_load(struct sst_hsw *hsw, | ||
| 2070 | u32 module_id, u32 instance_id, char *name) | ||
| 2071 | { | ||
| 2072 | int ret = 0; | ||
| 2073 | const struct firmware *fw = NULL; | ||
| 2074 | struct sst_fw *hsw_sst_fw; | ||
| 2075 | struct sst_module *module; | ||
| 2076 | struct device *dev = hsw->dev; | ||
| 2077 | struct sst_dsp *dsp = hsw->dsp; | ||
| 2078 | |||
| 2079 | dev_dbg(dev, "sst_hsw_module_load id=%d, name='%s'", module_id, name); | ||
| 2080 | |||
| 2081 | module = sst_module_get_from_id(dsp, module_id); | ||
| 2082 | if (module == NULL) { | ||
| 2083 | /* loading for the first time */ | ||
| 2084 | if (module_id == SST_HSW_MODULE_BASE_FW) { | ||
| 2085 | /* for base module: use fw requested in acpi probe */ | ||
| 2086 | fw = dsp->pdata->fw; | ||
| 2087 | if (!fw) { | ||
| 2088 | dev_err(dev, "request Base fw failed\n"); | ||
| 2089 | return -ENODEV; | ||
| 2090 | } | ||
| 2091 | } else { | ||
| 2092 | /* try and load any other optional modules if they are | ||
| 2093 | * available. Use dev_info instead of dev_err in case | ||
| 2094 | * request firmware failed */ | ||
| 2095 | ret = request_firmware(&fw, name, dev); | ||
| 2096 | if (ret) { | ||
| 2097 | dev_info(dev, "fw image %s not available(%d)\n", | ||
| 2098 | name, ret); | ||
| 2099 | return ret; | ||
| 2100 | } | ||
| 2101 | } | ||
| 2102 | hsw_sst_fw = sst_fw_new(dsp, fw, hsw); | ||
| 2103 | if (hsw_sst_fw == NULL) { | ||
| 2104 | dev_err(dev, "error: failed to load firmware\n"); | ||
| 2105 | ret = -ENOMEM; | ||
| 2106 | goto out; | ||
| 2107 | } | ||
| 2108 | module = sst_module_get_from_id(dsp, module_id); | ||
| 2109 | if (module == NULL) { | ||
| 2110 | dev_err(dev, "error: no module %d in firmware %s\n", | ||
| 2111 | module_id, name); | ||
| 2112 | } | ||
| 2113 | } else | ||
| 2114 | dev_info(dev, "module %d (%s) already loaded\n", | ||
| 2115 | module_id, name); | ||
| 2116 | out: | ||
| 2117 | /* release fw, but base fw should be released by acpi driver */ | ||
| 2118 | if (fw && module_id != SST_HSW_MODULE_BASE_FW) | ||
| 2119 | release_firmware(fw); | ||
| 2120 | |||
| 2121 | return ret; | ||
| 2122 | } | ||
| 2123 | |||
| 2124 | int sst_hsw_module_enable(struct sst_hsw *hsw, | ||
| 2125 | u32 module_id, u32 instance_id) | ||
| 2126 | { | ||
| 2127 | int ret; | ||
| 2128 | u32 header = 0; | ||
| 2129 | struct sst_hsw_ipc_module_config config; | ||
| 2130 | struct sst_module *module; | ||
| 2131 | struct sst_module_runtime *runtime; | ||
| 2132 | struct device *dev = hsw->dev; | ||
| 2133 | struct sst_dsp *dsp = hsw->dsp; | ||
| 2134 | |||
| 2135 | if (!sst_hsw_is_module_loaded(hsw, module_id)) { | ||
| 2136 | dev_dbg(dev, "module %d not loaded\n", module_id); | ||
| 2137 | return 0; | ||
| 2138 | } | ||
| 2139 | |||
| 2140 | if (sst_hsw_is_module_active(hsw, module_id)) { | ||
| 2141 | dev_info(dev, "module %d already enabled\n", module_id); | ||
| 2142 | return 0; | ||
| 2143 | } | ||
| 2144 | |||
| 2145 | module = sst_module_get_from_id(dsp, module_id); | ||
| 2146 | if (module == NULL) { | ||
| 2147 | dev_err(dev, "module %d not valid\n", module_id); | ||
| 2148 | return -ENXIO; | ||
| 2149 | } | ||
| 2150 | |||
| 2151 | runtime = sst_module_runtime_get_from_id(module, module_id); | ||
| 2152 | if (runtime == NULL) { | ||
| 2153 | dev_err(dev, "runtime %d not valid", module_id); | ||
| 2154 | return -ENXIO; | ||
| 2155 | } | ||
| 2156 | |||
| 2157 | header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | | ||
| 2158 | IPC_MODULE_OPERATION(IPC_MODULE_ENABLE) | | ||
| 2159 | IPC_MODULE_ID(module_id); | ||
| 2160 | dev_dbg(dev, "module enable header: %x\n", header); | ||
| 2161 | |||
| 2162 | config.map.module_entries_count = 1; | ||
| 2163 | config.map.module_entries[0].module_id = module->id; | ||
| 2164 | config.map.module_entries[0].entry_point = module->entry; | ||
| 2165 | |||
| 2166 | config.persistent_mem.offset = | ||
| 2167 | sst_dsp_get_offset(dsp, | ||
| 2168 | runtime->persistent_offset, SST_MEM_DRAM); | ||
| 2169 | config.persistent_mem.size = module->persistent_size; | ||
| 2170 | |||
| 2171 | config.scratch_mem.offset = | ||
| 2172 | sst_dsp_get_offset(dsp, | ||
| 2173 | dsp->scratch_offset, SST_MEM_DRAM); | ||
| 2174 | config.scratch_mem.size = module->scratch_size; | ||
| 2175 | dev_dbg(dev, "mod %d enable p:%d @ %x, s:%d @ %x, ep: %x", | ||
| 2176 | config.map.module_entries[0].module_id, | ||
| 2177 | config.persistent_mem.size, | ||
| 2178 | config.persistent_mem.offset, | ||
| 2179 | config.scratch_mem.size, config.scratch_mem.offset, | ||
| 2180 | config.map.module_entries[0].entry_point); | ||
| 2181 | |||
| 2182 | ret = ipc_tx_message_wait(hsw, header, | ||
| 2183 | &config, sizeof(config), NULL, 0); | ||
| 2184 | if (ret < 0) | ||
| 2185 | dev_err(dev, "ipc: module enable failed - %d\n", ret); | ||
| 2186 | else | ||
| 2187 | module->state = SST_MODULE_STATE_ACTIVE; | ||
| 2188 | |||
| 2189 | return ret; | ||
| 2190 | } | ||
| 2191 | |||
| 2192 | int sst_hsw_module_disable(struct sst_hsw *hsw, | ||
| 2193 | u32 module_id, u32 instance_id) | ||
| 2194 | { | ||
| 2195 | int ret; | ||
| 2196 | u32 header; | ||
| 2197 | struct sst_module *module; | ||
| 2198 | struct device *dev = hsw->dev; | ||
| 2199 | struct sst_dsp *dsp = hsw->dsp; | ||
| 2200 | |||
| 2201 | if (!sst_hsw_is_module_loaded(hsw, module_id)) { | ||
| 2202 | dev_dbg(dev, "module %d not loaded\n", module_id); | ||
| 2203 | return 0; | ||
| 2204 | } | ||
| 2205 | |||
| 2206 | if (!sst_hsw_is_module_active(hsw, module_id)) { | ||
| 2207 | dev_info(dev, "module %d already disabled\n", module_id); | ||
| 2208 | return 0; | ||
| 2209 | } | ||
| 2210 | |||
| 2211 | module = sst_module_get_from_id(dsp, module_id); | ||
| 2212 | if (module == NULL) { | ||
| 2213 | dev_err(dev, "module %d not valid\n", module_id); | ||
| 2214 | return -ENXIO; | ||
| 2215 | } | ||
| 2216 | |||
| 2217 | header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | | ||
| 2218 | IPC_MODULE_OPERATION(IPC_MODULE_DISABLE) | | ||
| 2219 | IPC_MODULE_ID(module_id); | ||
| 2220 | |||
| 2221 | ret = ipc_tx_message_wait(hsw, header, NULL, 0, NULL, 0); | ||
| 2222 | if (ret < 0) | ||
| 2223 | dev_err(dev, "module disable failed - %d\n", ret); | ||
| 2224 | else | ||
| 2225 | module->state = SST_MODULE_STATE_INITIALIZED; | ||
| 2226 | |||
| 2227 | return ret; | ||
| 2228 | } | ||
| 2229 | |||
| 2230 | int sst_hsw_module_set_param(struct sst_hsw *hsw, | ||
| 2231 | u32 module_id, u32 instance_id, u32 parameter_id, | ||
| 2232 | u32 param_size, char *param) | ||
| 2233 | { | ||
| 2234 | int ret; | ||
| 2235 | unsigned char *data = NULL; | ||
| 2236 | u32 header = 0; | ||
| 2237 | u32 payload_size = 0, transfer_parameter_size = 0; | ||
| 2238 | dma_addr_t dma_addr = 0; | ||
| 2239 | struct sst_hsw_transfer_parameter *parameter; | ||
| 2240 | struct device *dev = hsw->dev; | ||
| 2241 | |||
| 2242 | header = IPC_GLB_TYPE(IPC_GLB_MODULE_OPERATION) | | ||
| 2243 | IPC_MODULE_OPERATION(IPC_MODULE_SET_PARAMETER) | | ||
| 2244 | IPC_MODULE_ID(module_id); | ||
| 2245 | dev_dbg(dev, "sst_hsw_module_set_param header=%x\n", header); | ||
| 2246 | |||
| 2247 | payload_size = param_size + | ||
| 2248 | sizeof(struct sst_hsw_transfer_parameter) - | ||
| 2249 | sizeof(struct sst_hsw_transfer_list); | ||
| 2250 | dev_dbg(dev, "parameter size : %d\n", param_size); | ||
| 2251 | dev_dbg(dev, "payload size : %d\n", payload_size); | ||
| 2252 | |||
| 2253 | if (payload_size <= SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE) { | ||
| 2254 | /* short parameter, mailbox can contain data */ | ||
| 2255 | dev_dbg(dev, "transfer parameter size : %d\n", | ||
| 2256 | transfer_parameter_size); | ||
| 2257 | |||
| 2258 | transfer_parameter_size = ALIGN(payload_size, 4); | ||
| 2259 | dev_dbg(dev, "transfer parameter aligned size : %d\n", | ||
| 2260 | transfer_parameter_size); | ||
| 2261 | |||
| 2262 | parameter = kzalloc(transfer_parameter_size, GFP_KERNEL); | ||
| 2263 | if (parameter == NULL) | ||
| 2264 | return -ENOMEM; | ||
| 2265 | |||
| 2266 | memcpy(parameter->data, param, param_size); | ||
| 2267 | } else { | ||
| 2268 | dev_warn(dev, "transfer parameter size too large!"); | ||
| 2269 | return 0; | ||
| 2270 | } | ||
| 2271 | |||
| 2272 | parameter->parameter_id = parameter_id; | ||
| 2273 | parameter->data_size = param_size; | ||
| 2274 | |||
| 2275 | ret = ipc_tx_message_wait(hsw, header, | ||
| 2276 | parameter, transfer_parameter_size , NULL, 0); | ||
| 2277 | if (ret < 0) | ||
| 2278 | dev_err(dev, "ipc: module set parameter failed - %d\n", ret); | ||
| 2279 | |||
| 2280 | kfree(parameter); | ||
| 2281 | |||
| 2282 | if (data) | ||
| 2283 | dma_free_coherent(hsw->dsp->dma_dev, | ||
| 2284 | param_size, (void *)data, dma_addr); | ||
| 2285 | |||
| 2286 | return ret; | ||
| 2287 | } | ||
| 2288 | |||
| 1878 | static struct sst_dsp_device hsw_dev = { | 2289 | static struct sst_dsp_device hsw_dev = { |
| 1879 | .thread = hsw_irq_thread, | 2290 | .thread = hsw_irq_thread, |
| 1880 | .ops = &haswell_ops, | 2291 | .ops = &haswell_ops, |
| @@ -1936,12 +2347,21 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
| 1936 | /* keep the DSP in reset state for base FW loading */ | 2347 | /* keep the DSP in reset state for base FW loading */ |
| 1937 | sst_dsp_reset(hsw->dsp); | 2348 | sst_dsp_reset(hsw->dsp); |
| 1938 | 2349 | ||
| 1939 | hsw->sst_fw = sst_fw_new(hsw->dsp, pdata->fw, hsw); | 2350 | /* load base module and other modules in base firmware image */ |
| 1940 | if (hsw->sst_fw == NULL) { | 2351 | ret = sst_hsw_module_load(hsw, SST_HSW_MODULE_BASE_FW, 0, "Base"); |
| 1941 | ret = -ENODEV; | 2352 | if (ret < 0) |
| 1942 | dev_err(dev, "error: failed to load firmware\n"); | ||
| 1943 | goto fw_err; | 2353 | goto fw_err; |
| 1944 | } | 2354 | |
| 2355 | /* try to load module waves */ | ||
| 2356 | sst_hsw_module_load(hsw, SST_HSW_MODULE_WAVES, 0, "intel/IntcPP01.bin"); | ||
| 2357 | |||
| 2358 | /* allocate scratch mem regions */ | ||
| 2359 | ret = sst_block_alloc_scratch(hsw->dsp); | ||
| 2360 | if (ret < 0) | ||
| 2361 | goto boot_err; | ||
| 2362 | |||
| 2363 | /* init param buffer */ | ||
| 2364 | sst_hsw_reset_param_buf(hsw); | ||
| 1945 | 2365 | ||
| 1946 | /* wait for DSP boot completion */ | 2366 | /* wait for DSP boot completion */ |
| 1947 | sst_dsp_boot(hsw->dsp); | 2367 | sst_dsp_boot(hsw->dsp); |
| @@ -1955,6 +2375,9 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
| 1955 | goto boot_err; | 2375 | goto boot_err; |
| 1956 | } | 2376 | } |
| 1957 | 2377 | ||
| 2378 | /* init module state after boot */ | ||
| 2379 | sst_hsw_init_module_state(hsw); | ||
| 2380 | |||
| 1958 | /* get the FW version */ | 2381 | /* get the FW version */ |
| 1959 | sst_hsw_fw_get_version(hsw, &version); | 2382 | sst_hsw_fw_get_version(hsw, &version); |
| 1960 | 2383 | ||
| @@ -1970,7 +2393,7 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
| 1970 | 2393 | ||
| 1971 | boot_err: | 2394 | boot_err: |
| 1972 | sst_dsp_reset(hsw->dsp); | 2395 | sst_dsp_reset(hsw->dsp); |
| 1973 | sst_fw_free(hsw->sst_fw); | 2396 | sst_fw_free_all(hsw->dsp); |
| 1974 | fw_err: | 2397 | fw_err: |
| 1975 | dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, | 2398 | dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, |
| 1976 | hsw->dx_context, hsw->dx_context_paddr); | 2399 | hsw->dx_context, hsw->dx_context_paddr); |
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index 858096041cb1..06d71aefa1fe 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h | |||
| @@ -37,6 +37,9 @@ | |||
| 37 | #define SST_HSW_IPC_MAX_PAYLOAD_SIZE 400 | 37 | #define SST_HSW_IPC_MAX_PAYLOAD_SIZE 400 |
| 38 | #define SST_HSW_MAX_INFO_SIZE 64 | 38 | #define SST_HSW_MAX_INFO_SIZE 64 |
| 39 | #define SST_HSW_BUILD_HASH_LENGTH 40 | 39 | #define SST_HSW_BUILD_HASH_LENGTH 40 |
| 40 | #define SST_HSW_IPC_MAX_SHORT_PARAMETER_SIZE 500 | ||
| 41 | #define WAVES_PARAM_COUNT 128 | ||
| 42 | #define WAVES_PARAM_LINES 160 | ||
| 40 | 43 | ||
| 41 | struct sst_hsw; | 44 | struct sst_hsw; |
| 42 | struct sst_hsw_stream; | 45 | struct sst_hsw_stream; |
| @@ -187,6 +190,28 @@ enum sst_hsw_performance_action { | |||
| 187 | SST_HSW_PERF_STOP = 1, | 190 | SST_HSW_PERF_STOP = 1, |
| 188 | }; | 191 | }; |
| 189 | 192 | ||
| 193 | struct sst_hsw_transfer_info { | ||
| 194 | uint32_t destination; /* destination address */ | ||
| 195 | uint32_t reverse:1; /* if 1 data flows from destination */ | ||
| 196 | uint32_t size:31; /* transfer size in bytes.*/ | ||
| 197 | uint16_t first_page_offset; /* offset to data in the first page. */ | ||
| 198 | uint8_t packed_pages; /* page addresses. Each occupies 20 bits */ | ||
| 199 | } __attribute__((packed)); | ||
| 200 | |||
| 201 | struct sst_hsw_transfer_list { | ||
| 202 | uint32_t transfers_count; | ||
| 203 | struct sst_hsw_transfer_info transfers; | ||
| 204 | } __attribute__((packed)); | ||
| 205 | |||
| 206 | struct sst_hsw_transfer_parameter { | ||
| 207 | uint32_t parameter_id; | ||
| 208 | uint32_t data_size; | ||
| 209 | union { | ||
| 210 | uint8_t data[1]; | ||
| 211 | struct sst_hsw_transfer_list transfer_list; | ||
| 212 | }; | ||
| 213 | } __attribute__((packed)); | ||
| 214 | |||
| 190 | /* SST firmware module info */ | 215 | /* SST firmware module info */ |
| 191 | struct sst_hsw_module_info { | 216 | struct sst_hsw_module_info { |
| 192 | u8 name[SST_HSW_MAX_INFO_SIZE]; | 217 | u8 name[SST_HSW_MAX_INFO_SIZE]; |
| @@ -215,6 +240,12 @@ struct sst_hsw_fx_enable { | |||
| 215 | struct sst_hsw_memory_info persistent_mem; | 240 | struct sst_hsw_memory_info persistent_mem; |
| 216 | } __attribute__((packed)); | 241 | } __attribute__((packed)); |
| 217 | 242 | ||
| 243 | struct sst_hsw_ipc_module_config { | ||
| 244 | struct sst_hsw_module_map map; | ||
| 245 | struct sst_hsw_memory_info persistent_mem; | ||
| 246 | struct sst_hsw_memory_info scratch_mem; | ||
| 247 | } __attribute__((packed)); | ||
| 248 | |||
| 218 | struct sst_hsw_get_fx_param { | 249 | struct sst_hsw_get_fx_param { |
| 219 | u32 parameter_id; | 250 | u32 parameter_id; |
| 220 | u32 param_size; | 251 | u32 param_size; |
| @@ -467,6 +498,28 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata); | |||
| 467 | void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata); | 498 | void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata); |
| 468 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); | 499 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); |
| 469 | 500 | ||
| 501 | /* fw module function */ | ||
| 502 | void sst_hsw_init_module_state(struct sst_hsw *hsw); | ||
| 503 | bool sst_hsw_is_module_loaded(struct sst_hsw *hsw, u32 module_id); | ||
| 504 | bool sst_hsw_is_module_active(struct sst_hsw *hsw, u32 module_id); | ||
| 505 | void sst_hsw_set_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id); | ||
| 506 | void sst_hsw_set_module_disabled_rtd3(struct sst_hsw *hsw, u32 module_id); | ||
| 507 | bool sst_hsw_is_module_enabled_rtd3(struct sst_hsw *hsw, u32 module_id); | ||
| 508 | void sst_hsw_reset_param_buf(struct sst_hsw *hsw); | ||
| 509 | int sst_hsw_store_param_line(struct sst_hsw *hsw, u8 *buf); | ||
| 510 | int sst_hsw_load_param_line(struct sst_hsw *hsw, u8 *buf); | ||
| 511 | int sst_hsw_launch_param_buf(struct sst_hsw *hsw); | ||
| 512 | |||
| 513 | int sst_hsw_module_load(struct sst_hsw *hsw, | ||
| 514 | u32 module_id, u32 instance_id, char *name); | ||
| 515 | int sst_hsw_module_enable(struct sst_hsw *hsw, | ||
| 516 | u32 module_id, u32 instance_id); | ||
| 517 | int sst_hsw_module_disable(struct sst_hsw *hsw, | ||
| 518 | u32 module_id, u32 instance_id); | ||
| 519 | int sst_hsw_module_set_param(struct sst_hsw *hsw, | ||
| 520 | u32 module_id, u32 instance_id, u32 parameter_id, | ||
| 521 | u32 param_size, char *param); | ||
| 522 | |||
| 470 | /* runtime module management */ | 523 | /* runtime module management */ |
| 471 | struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw, | 524 | struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw, |
| 472 | int mod_id, int offset); | 525 | int mod_id, int offset); |
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 7e21e8f85885..b40ec746bc19 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c | |||
| @@ -318,6 +318,97 @@ static int hsw_volume_get(struct snd_kcontrol *kcontrol, | |||
| 318 | return 0; | 318 | return 0; |
| 319 | } | 319 | } |
| 320 | 320 | ||
| 321 | static int hsw_waves_switch_get(struct snd_kcontrol *kcontrol, | ||
| 322 | struct snd_ctl_elem_value *ucontrol) | ||
| 323 | { | ||
| 324 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); | ||
| 325 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); | ||
| 326 | struct sst_hsw *hsw = pdata->hsw; | ||
| 327 | enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES; | ||
| 328 | |||
| 329 | ucontrol->value.integer.value[0] = | ||
| 330 | (sst_hsw_is_module_active(hsw, id) || | ||
| 331 | sst_hsw_is_module_enabled_rtd3(hsw, id)); | ||
| 332 | return 0; | ||
| 333 | } | ||
| 334 | |||
| 335 | static int hsw_waves_switch_put(struct snd_kcontrol *kcontrol, | ||
| 336 | struct snd_ctl_elem_value *ucontrol) | ||
| 337 | { | ||
| 338 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); | ||
| 339 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); | ||
| 340 | struct sst_hsw *hsw = pdata->hsw; | ||
| 341 | int ret = 0; | ||
| 342 | enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES; | ||
| 343 | bool switch_on = (bool)ucontrol->value.integer.value[0]; | ||
| 344 | |||
| 345 | /* if module is in RAM on the DSP, apply user settings to module through | ||
| 346 | * ipc. If module is not in RAM on the DSP, store user setting for | ||
| 347 | * track */ | ||
| 348 | if (sst_hsw_is_module_loaded(hsw, id)) { | ||
| 349 | if (switch_on == sst_hsw_is_module_active(hsw, id)) | ||
| 350 | return 0; | ||
| 351 | |||
| 352 | if (switch_on) | ||
| 353 | ret = sst_hsw_module_enable(hsw, id, 0); | ||
| 354 | else | ||
| 355 | ret = sst_hsw_module_disable(hsw, id, 0); | ||
| 356 | } else { | ||
| 357 | if (switch_on == sst_hsw_is_module_enabled_rtd3(hsw, id)) | ||
| 358 | return 0; | ||
| 359 | |||
| 360 | if (switch_on) | ||
| 361 | sst_hsw_set_module_enabled_rtd3(hsw, id); | ||
| 362 | else | ||
| 363 | sst_hsw_set_module_disabled_rtd3(hsw, id); | ||
| 364 | } | ||
| 365 | |||
| 366 | return ret; | ||
| 367 | } | ||
| 368 | |||
| 369 | static int hsw_waves_param_get(struct snd_kcontrol *kcontrol, | ||
| 370 | struct snd_ctl_elem_value *ucontrol) | ||
| 371 | { | ||
| 372 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); | ||
| 373 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); | ||
| 374 | struct sst_hsw *hsw = pdata->hsw; | ||
| 375 | |||
| 376 | /* return a matching line from param buffer */ | ||
| 377 | return sst_hsw_load_param_line(hsw, ucontrol->value.bytes.data); | ||
| 378 | } | ||
| 379 | |||
| 380 | static int hsw_waves_param_put(struct snd_kcontrol *kcontrol, | ||
| 381 | struct snd_ctl_elem_value *ucontrol) | ||
| 382 | { | ||
| 383 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); | ||
| 384 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); | ||
| 385 | struct sst_hsw *hsw = pdata->hsw; | ||
| 386 | int ret; | ||
| 387 | enum sst_hsw_module_id id = SST_HSW_MODULE_WAVES; | ||
| 388 | int param_id = ucontrol->value.bytes.data[0]; | ||
| 389 | int param_size = WAVES_PARAM_COUNT; | ||
| 390 | |||
| 391 | /* clear param buffer and reset buffer index */ | ||
| 392 | if (param_id == 0xFF) { | ||
| 393 | sst_hsw_reset_param_buf(hsw); | ||
| 394 | return 0; | ||
| 395 | } | ||
| 396 | |||
| 397 | /* store params into buffer */ | ||
| 398 | ret = sst_hsw_store_param_line(hsw, ucontrol->value.bytes.data); | ||
| 399 | if (ret < 0) | ||
| 400 | return ret; | ||
| 401 | |||
| 402 | if (sst_hsw_is_module_loaded(hsw, id)) { | ||
| 403 | if (!sst_hsw_is_module_active(hsw, id)) | ||
| 404 | return 0; | ||
| 405 | |||
| 406 | ret = sst_hsw_module_set_param(hsw, id, 0, param_id, | ||
| 407 | param_size, ucontrol->value.bytes.data); | ||
| 408 | } | ||
| 409 | return ret; | ||
| 410 | } | ||
| 411 | |||
| 321 | /* TLV used by both global and stream volumes */ | 412 | /* TLV used by both global and stream volumes */ |
| 322 | static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1); | 413 | static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1); |
| 323 | 414 | ||
| @@ -339,6 +430,12 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = { | |||
| 339 | SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8, | 430 | SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8, |
| 340 | ARRAY_SIZE(volume_map) - 1, 0, | 431 | ARRAY_SIZE(volume_map) - 1, 0, |
| 341 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | 432 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), |
| 433 | /* enable/disable module waves */ | ||
| 434 | SOC_SINGLE_BOOL_EXT("Waves Switch", 0, | ||
| 435 | hsw_waves_switch_get, hsw_waves_switch_put), | ||
| 436 | /* set parameters to module waves */ | ||
| 437 | SND_SOC_BYTES_EXT("Waves Set Param", WAVES_PARAM_COUNT, | ||
| 438 | hsw_waves_param_get, hsw_waves_param_put), | ||
| 342 | }; | 439 | }; |
| 343 | 440 | ||
| 344 | /* Create DMA buffer page table for DSP */ | 441 | /* Create DMA buffer page table for DSP */ |
| @@ -807,6 +904,17 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) | |||
| 807 | pcm_data->runtime->persistent_offset; | 904 | pcm_data->runtime->persistent_offset; |
| 808 | } | 905 | } |
| 809 | 906 | ||
| 907 | /* create runtime blocks for module waves */ | ||
| 908 | if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES)) { | ||
| 909 | pcm_data = &pdata->pcm[HSW_PCM_COUNT-1][0]; | ||
| 910 | pcm_data->runtime = sst_hsw_runtime_module_create(hsw, | ||
| 911 | SST_HSW_MODULE_WAVES, pcm_data->persistent_offset); | ||
| 912 | if (pcm_data->runtime == NULL) | ||
| 913 | goto err; | ||
| 914 | pcm_data->persistent_offset = | ||
| 915 | pcm_data->runtime->persistent_offset; | ||
| 916 | } | ||
| 917 | |||
| 810 | return 0; | 918 | return 0; |
| 811 | 919 | ||
| 812 | err: | 920 | err: |
| @@ -820,12 +928,16 @@ err: | |||
| 820 | 928 | ||
| 821 | static void hsw_pcm_free_modules(struct hsw_priv_data *pdata) | 929 | static void hsw_pcm_free_modules(struct hsw_priv_data *pdata) |
| 822 | { | 930 | { |
| 931 | struct sst_hsw *hsw = pdata->hsw; | ||
| 823 | struct hsw_pcm_data *pcm_data; | 932 | struct hsw_pcm_data *pcm_data; |
| 824 | int i; | 933 | int i; |
| 825 | 934 | ||
| 826 | for (i = 0; i < ARRAY_SIZE(mod_map); i++) { | 935 | for (i = 0; i < ARRAY_SIZE(mod_map); i++) { |
| 827 | pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; | 936 | pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream]; |
| 828 | 937 | sst_hsw_runtime_module_free(pcm_data->runtime); | |
| 938 | } | ||
| 939 | if (sst_hsw_is_module_loaded(hsw, SST_HSW_MODULE_WAVES)) { | ||
| 940 | pcm_data = &pdata->pcm[HSW_PCM_COUNT-1][0]; | ||
| 829 | sst_hsw_runtime_module_free(pcm_data->runtime); | 941 | sst_hsw_runtime_module_free(pcm_data->runtime); |
| 830 | } | 942 | } |
| 831 | } | 943 | } |
| @@ -984,7 +1096,9 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) | |||
| 984 | } | 1096 | } |
| 985 | 1097 | ||
| 986 | /* allocate runtime modules */ | 1098 | /* allocate runtime modules */ |
| 987 | hsw_pcm_create_modules(priv_data); | 1099 | ret = hsw_pcm_create_modules(priv_data); |
| 1100 | if (ret < 0) | ||
| 1101 | goto err; | ||
| 988 | 1102 | ||
| 989 | /* enable runtime PM with auto suspend */ | 1103 | /* enable runtime PM with auto suspend */ |
| 990 | pm_runtime_set_autosuspend_delay(platform->dev, | 1104 | pm_runtime_set_autosuspend_delay(platform->dev, |
| @@ -1101,10 +1215,18 @@ static int hsw_pcm_runtime_suspend(struct device *dev) | |||
| 1101 | { | 1215 | { |
| 1102 | struct hsw_priv_data *pdata = dev_get_drvdata(dev); | 1216 | struct hsw_priv_data *pdata = dev_get_drvdata(dev); |
| 1103 | struct sst_hsw *hsw = pdata->hsw; | 1217 | struct sst_hsw *hsw = pdata->hsw; |
| 1218 | int ret; | ||
| 1104 | 1219 | ||
| 1105 | if (pdata->pm_state >= HSW_PM_STATE_RTD3) | 1220 | if (pdata->pm_state >= HSW_PM_STATE_RTD3) |
| 1106 | return 0; | 1221 | return 0; |
| 1107 | 1222 | ||
| 1223 | /* fw modules will be unloaded on RTD3, set flag to track */ | ||
| 1224 | if (sst_hsw_is_module_active(hsw, SST_HSW_MODULE_WAVES)) { | ||
| 1225 | ret = sst_hsw_module_disable(hsw, SST_HSW_MODULE_WAVES, 0); | ||
| 1226 | if (ret < 0) | ||
| 1227 | return ret; | ||
| 1228 | sst_hsw_set_module_enabled_rtd3(hsw, SST_HSW_MODULE_WAVES); | ||
| 1229 | } | ||
| 1108 | sst_hsw_dsp_runtime_suspend(hsw); | 1230 | sst_hsw_dsp_runtime_suspend(hsw); |
| 1109 | sst_hsw_dsp_runtime_sleep(hsw); | 1231 | sst_hsw_dsp_runtime_sleep(hsw); |
| 1110 | pdata->pm_state = HSW_PM_STATE_RTD3; | 1232 | pdata->pm_state = HSW_PM_STATE_RTD3; |
| @@ -1139,6 +1261,19 @@ static int hsw_pcm_runtime_resume(struct device *dev) | |||
| 1139 | else if (ret == 1) /* no action required */ | 1261 | else if (ret == 1) /* no action required */ |
| 1140 | return 0; | 1262 | return 0; |
| 1141 | 1263 | ||
| 1264 | /* check flag when resume */ | ||
| 1265 | if (sst_hsw_is_module_enabled_rtd3(hsw, SST_HSW_MODULE_WAVES)) { | ||
| 1266 | ret = sst_hsw_module_enable(hsw, SST_HSW_MODULE_WAVES, 0); | ||
| 1267 | if (ret < 0) | ||
| 1268 | return ret; | ||
| 1269 | /* put parameters from buffer to dsp */ | ||
| 1270 | ret = sst_hsw_launch_param_buf(hsw); | ||
| 1271 | if (ret < 0) | ||
| 1272 | return ret; | ||
| 1273 | /* unset flag */ | ||
| 1274 | sst_hsw_set_module_disabled_rtd3(hsw, SST_HSW_MODULE_WAVES); | ||
| 1275 | } | ||
| 1276 | |||
| 1142 | pdata->pm_state = HSW_PM_STATE_D0; | 1277 | pdata->pm_state = HSW_PM_STATE_D0; |
| 1143 | return ret; | 1278 | return ret; |
| 1144 | } | 1279 | } |
diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 7523cbef8780..2fbaf2c75d17 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c | |||
| @@ -594,11 +594,13 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, | |||
| 594 | ret_val = stream->ops->stream_drop(sst->dev, str_id); | 594 | ret_val = stream->ops->stream_drop(sst->dev, str_id); |
| 595 | break; | 595 | break; |
| 596 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 596 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
| 597 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 597 | dev_dbg(rtd->dev, "sst: in pause\n"); | 598 | dev_dbg(rtd->dev, "sst: in pause\n"); |
| 598 | status = SST_PLATFORM_PAUSED; | 599 | status = SST_PLATFORM_PAUSED; |
| 599 | ret_val = stream->ops->stream_pause(sst->dev, str_id); | 600 | ret_val = stream->ops->stream_pause(sst->dev, str_id); |
| 600 | break; | 601 | break; |
| 601 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 602 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
| 603 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 602 | dev_dbg(rtd->dev, "sst: in pause release\n"); | 604 | dev_dbg(rtd->dev, "sst: in pause release\n"); |
| 603 | status = SST_PLATFORM_RUNNING; | 605 | status = SST_PLATFORM_RUNNING; |
| 604 | ret_val = stream->ops->stream_pause_release(sst->dev, str_id); | 606 | ret_val = stream->ops->stream_pause_release(sst->dev, str_id); |
| @@ -665,6 +667,9 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
| 665 | 667 | ||
| 666 | static int sst_soc_probe(struct snd_soc_platform *platform) | 668 | static int sst_soc_probe(struct snd_soc_platform *platform) |
| 667 | { | 669 | { |
| 670 | struct sst_data *drv = dev_get_drvdata(platform->dev); | ||
| 671 | |||
| 672 | drv->soc_card = platform->component.card; | ||
| 668 | return sst_dsp_init_v2_dpcm(platform); | 673 | return sst_dsp_init_v2_dpcm(platform); |
| 669 | } | 674 | } |
| 670 | 675 | ||
| @@ -727,9 +732,64 @@ static int sst_platform_remove(struct platform_device *pdev) | |||
| 727 | return 0; | 732 | return 0; |
| 728 | } | 733 | } |
| 729 | 734 | ||
| 735 | #ifdef CONFIG_PM_SLEEP | ||
| 736 | |||
| 737 | static int sst_soc_prepare(struct device *dev) | ||
| 738 | { | ||
| 739 | struct sst_data *drv = dev_get_drvdata(dev); | ||
| 740 | int i; | ||
| 741 | |||
| 742 | /* suspend all pcms first */ | ||
| 743 | snd_soc_suspend(drv->soc_card->dev); | ||
| 744 | snd_soc_poweroff(drv->soc_card->dev); | ||
| 745 | |||
| 746 | /* set the SSPs to idle */ | ||
| 747 | for (i = 0; i < drv->soc_card->num_rtd; i++) { | ||
| 748 | struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai; | ||
| 749 | |||
| 750 | if (dai->active) { | ||
| 751 | send_ssp_cmd(dai, dai->name, 0); | ||
| 752 | sst_handle_vb_timer(dai, false); | ||
| 753 | } | ||
| 754 | } | ||
| 755 | |||
| 756 | return 0; | ||
| 757 | } | ||
| 758 | |||
| 759 | static void sst_soc_complete(struct device *dev) | ||
| 760 | { | ||
| 761 | struct sst_data *drv = dev_get_drvdata(dev); | ||
| 762 | int i; | ||
| 763 | |||
| 764 | /* restart SSPs */ | ||
| 765 | for (i = 0; i < drv->soc_card->num_rtd; i++) { | ||
| 766 | struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai; | ||
| 767 | |||
| 768 | if (dai->active) { | ||
| 769 | sst_handle_vb_timer(dai, true); | ||
| 770 | send_ssp_cmd(dai, dai->name, 1); | ||
| 771 | } | ||
| 772 | } | ||
| 773 | snd_soc_resume(drv->soc_card->dev); | ||
| 774 | } | ||
| 775 | |||
| 776 | #else | ||
| 777 | |||
| 778 | #define sst_soc_prepare NULL | ||
| 779 | #define sst_soc_complete NULL | ||
| 780 | |||
| 781 | #endif | ||
| 782 | |||
| 783 | |||
| 784 | static const struct dev_pm_ops sst_platform_pm = { | ||
| 785 | .prepare = sst_soc_prepare, | ||
| 786 | .complete = sst_soc_complete, | ||
| 787 | }; | ||
| 788 | |||
| 730 | static struct platform_driver sst_platform_driver = { | 789 | static struct platform_driver sst_platform_driver = { |
| 731 | .driver = { | 790 | .driver = { |
| 732 | .name = "sst-mfld-platform", | 791 | .name = "sst-mfld-platform", |
| 792 | .pm = &sst_platform_pm, | ||
| 733 | }, | 793 | }, |
| 734 | .probe = sst_platform_probe, | 794 | .probe = sst_platform_probe, |
| 735 | .remove = sst_platform_remove, | 795 | .remove = sst_platform_remove, |
diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 79c8d1246a8f..9094314be2b0 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h | |||
| @@ -174,6 +174,7 @@ struct sst_data { | |||
| 174 | struct sst_platform_data *pdata; | 174 | struct sst_platform_data *pdata; |
| 175 | struct snd_sst_bytes_v2 *byte_stream; | 175 | struct snd_sst_bytes_v2 *byte_stream; |
| 176 | struct mutex lock; | 176 | struct mutex lock; |
| 177 | struct snd_soc_card *soc_card; | ||
| 177 | }; | 178 | }; |
| 178 | int sst_register_dsp(struct sst_device *sst); | 179 | int sst_register_dsp(struct sst_device *sst); |
| 179 | int sst_unregister_dsp(struct sst_device *sst); | 180 | int sst_unregister_dsp(struct sst_device *sst); |
diff --git a/sound/soc/intel/sst/sst.c b/sound/soc/intel/sst/sst.c index 11c578651c1c..1a7eeec444b1 100644 --- a/sound/soc/intel/sst/sst.c +++ b/sound/soc/intel/sst/sst.c | |||
| @@ -423,23 +423,135 @@ static int intel_sst_runtime_suspend(struct device *dev) | |||
| 423 | return ret; | 423 | return ret; |
| 424 | } | 424 | } |
| 425 | 425 | ||
| 426 | static int intel_sst_runtime_resume(struct device *dev) | 426 | static int intel_sst_suspend(struct device *dev) |
| 427 | { | 427 | { |
| 428 | int ret = 0; | ||
| 429 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | 428 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); |
| 429 | struct sst_fw_save *fw_save; | ||
| 430 | int i, ret = 0; | ||
| 430 | 431 | ||
| 431 | if (ctx->sst_state == SST_RESET) { | 432 | /* check first if we are already in SW reset */ |
| 432 | ret = sst_load_fw(ctx); | 433 | if (ctx->sst_state == SST_RESET) |
| 433 | if (ret) { | 434 | return 0; |
| 434 | dev_err(dev, "FW download fail %d\n", ret); | 435 | |
| 435 | sst_set_fw_state_locked(ctx, SST_RESET); | 436 | /* |
| 437 | * check if any stream is active and running | ||
| 438 | * they should already by suspend by soc_suspend | ||
| 439 | */ | ||
| 440 | for (i = 1; i <= ctx->info.max_streams; i++) { | ||
| 441 | struct stream_info *stream = &ctx->streams[i]; | ||
| 442 | |||
| 443 | if (stream->status == STREAM_RUNNING) { | ||
| 444 | dev_err(dev, "stream %d is running, cant susupend, abort\n", i); | ||
| 445 | return -EBUSY; | ||
| 436 | } | 446 | } |
| 437 | } | 447 | } |
| 448 | synchronize_irq(ctx->irq_num); | ||
| 449 | flush_workqueue(ctx->post_msg_wq); | ||
| 450 | |||
| 451 | /* Move the SST state to Reset */ | ||
| 452 | sst_set_fw_state_locked(ctx, SST_RESET); | ||
| 453 | |||
| 454 | /* tell DSP we are suspending */ | ||
| 455 | if (ctx->ops->save_dsp_context(ctx)) | ||
| 456 | return -EBUSY; | ||
| 457 | |||
| 458 | /* save the memories */ | ||
| 459 | fw_save = kzalloc(sizeof(*fw_save), GFP_KERNEL); | ||
| 460 | if (!fw_save) | ||
| 461 | return -ENOMEM; | ||
| 462 | fw_save->iram = kzalloc(ctx->iram_end - ctx->iram_base, GFP_KERNEL); | ||
| 463 | if (!fw_save->iram) { | ||
| 464 | ret = -ENOMEM; | ||
| 465 | goto iram; | ||
| 466 | } | ||
| 467 | fw_save->dram = kzalloc(ctx->dram_end - ctx->dram_base, GFP_KERNEL); | ||
| 468 | if (!fw_save->dram) { | ||
| 469 | ret = -ENOMEM; | ||
| 470 | goto dram; | ||
| 471 | } | ||
| 472 | fw_save->sram = kzalloc(SST_MAILBOX_SIZE, GFP_KERNEL); | ||
| 473 | if (!fw_save->sram) { | ||
| 474 | ret = -ENOMEM; | ||
| 475 | goto sram; | ||
| 476 | } | ||
| 477 | |||
| 478 | fw_save->ddr = kzalloc(ctx->ddr_end - ctx->ddr_base, GFP_KERNEL); | ||
| 479 | if (!fw_save->ddr) { | ||
| 480 | ret = -ENOMEM; | ||
| 481 | goto ddr; | ||
| 482 | } | ||
| 483 | |||
| 484 | memcpy32_fromio(fw_save->iram, ctx->iram, ctx->iram_end - ctx->iram_base); | ||
| 485 | memcpy32_fromio(fw_save->dram, ctx->dram, ctx->dram_end - ctx->dram_base); | ||
| 486 | memcpy32_fromio(fw_save->sram, ctx->mailbox, SST_MAILBOX_SIZE); | ||
| 487 | memcpy32_fromio(fw_save->ddr, ctx->ddr, ctx->ddr_end - ctx->ddr_base); | ||
| 488 | |||
| 489 | ctx->fw_save = fw_save; | ||
| 490 | ctx->ops->reset(ctx); | ||
| 491 | return 0; | ||
| 492 | ddr: | ||
| 493 | kfree(fw_save->sram); | ||
| 494 | sram: | ||
| 495 | kfree(fw_save->dram); | ||
| 496 | dram: | ||
| 497 | kfree(fw_save->iram); | ||
| 498 | iram: | ||
| 499 | kfree(fw_save); | ||
| 500 | return ret; | ||
| 501 | } | ||
| 502 | |||
| 503 | static int intel_sst_resume(struct device *dev) | ||
| 504 | { | ||
| 505 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
| 506 | struct sst_fw_save *fw_save = ctx->fw_save; | ||
| 507 | int ret = 0; | ||
| 508 | struct sst_block *block; | ||
| 509 | |||
| 510 | if (!fw_save) | ||
| 511 | return 0; | ||
| 512 | |||
| 513 | sst_set_fw_state_locked(ctx, SST_FW_LOADING); | ||
| 514 | |||
| 515 | /* we have to restore the memory saved */ | ||
| 516 | ctx->ops->reset(ctx); | ||
| 517 | |||
| 518 | ctx->fw_save = NULL; | ||
| 519 | |||
| 520 | memcpy32_toio(ctx->iram, fw_save->iram, ctx->iram_end - ctx->iram_base); | ||
| 521 | memcpy32_toio(ctx->dram, fw_save->dram, ctx->dram_end - ctx->dram_base); | ||
| 522 | memcpy32_toio(ctx->mailbox, fw_save->sram, SST_MAILBOX_SIZE); | ||
| 523 | memcpy32_toio(ctx->ddr, fw_save->ddr, ctx->ddr_end - ctx->ddr_base); | ||
| 524 | |||
| 525 | kfree(fw_save->sram); | ||
| 526 | kfree(fw_save->dram); | ||
| 527 | kfree(fw_save->iram); | ||
| 528 | kfree(fw_save->ddr); | ||
| 529 | kfree(fw_save); | ||
| 530 | |||
| 531 | block = sst_create_block(ctx, 0, FW_DWNL_ID); | ||
| 532 | if (block == NULL) | ||
| 533 | return -ENOMEM; | ||
| 534 | |||
| 535 | |||
| 536 | /* start and wait for ack */ | ||
| 537 | ctx->ops->start(ctx); | ||
| 538 | ret = sst_wait_timeout(ctx, block); | ||
| 539 | if (ret) { | ||
| 540 | dev_err(ctx->dev, "fw download failed %d\n", ret); | ||
| 541 | /* FW download failed due to timeout */ | ||
| 542 | ret = -EBUSY; | ||
| 543 | |||
| 544 | } else { | ||
| 545 | sst_set_fw_state_locked(ctx, SST_FW_RUNNING); | ||
| 546 | } | ||
| 547 | |||
| 548 | sst_free_block(ctx, block); | ||
| 438 | return ret; | 549 | return ret; |
| 439 | } | 550 | } |
| 440 | 551 | ||
| 441 | const struct dev_pm_ops intel_sst_pm = { | 552 | const struct dev_pm_ops intel_sst_pm = { |
| 553 | .suspend = intel_sst_suspend, | ||
| 554 | .resume = intel_sst_resume, | ||
| 442 | .runtime_suspend = intel_sst_runtime_suspend, | 555 | .runtime_suspend = intel_sst_runtime_suspend, |
| 443 | .runtime_resume = intel_sst_runtime_resume, | ||
| 444 | }; | 556 | }; |
| 445 | EXPORT_SYMBOL_GPL(intel_sst_pm); | 557 | EXPORT_SYMBOL_GPL(intel_sst_pm); |
diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/sst/sst.h index 562bc483d6b7..3f493862e98d 100644 --- a/sound/soc/intel/sst/sst.h +++ b/sound/soc/intel/sst/sst.h | |||
| @@ -337,6 +337,13 @@ struct sst_shim_regs64 { | |||
| 337 | u64 csr2; | 337 | u64 csr2; |
| 338 | }; | 338 | }; |
| 339 | 339 | ||
| 340 | struct sst_fw_save { | ||
| 341 | void *iram; | ||
| 342 | void *dram; | ||
| 343 | void *sram; | ||
| 344 | void *ddr; | ||
| 345 | }; | ||
| 346 | |||
| 340 | /** | 347 | /** |
| 341 | * struct intel_sst_drv - driver ops | 348 | * struct intel_sst_drv - driver ops |
| 342 | * | 349 | * |
| @@ -428,6 +435,8 @@ struct intel_sst_drv { | |||
| 428 | * persistent till worker thread gets called | 435 | * persistent till worker thread gets called |
| 429 | */ | 436 | */ |
| 430 | char firmware_name[FW_NAME_SIZE]; | 437 | char firmware_name[FW_NAME_SIZE]; |
| 438 | |||
| 439 | struct sst_fw_save *fw_save; | ||
| 431 | }; | 440 | }; |
| 432 | 441 | ||
| 433 | /* misc definitions */ | 442 | /* misc definitions */ |
| @@ -544,4 +553,7 @@ int sst_alloc_drv_context(struct intel_sst_drv **ctx, | |||
| 544 | int sst_context_init(struct intel_sst_drv *ctx); | 553 | int sst_context_init(struct intel_sst_drv *ctx); |
| 545 | void sst_context_cleanup(struct intel_sst_drv *ctx); | 554 | void sst_context_cleanup(struct intel_sst_drv *ctx); |
| 546 | void sst_configure_runtime_pm(struct intel_sst_drv *ctx); | 555 | void sst_configure_runtime_pm(struct intel_sst_drv *ctx); |
| 556 | void memcpy32_toio(void __iomem *dst, const void *src, int count); | ||
| 557 | void memcpy32_fromio(void *dst, const void __iomem *src, int count); | ||
| 558 | |||
| 547 | #endif | 559 | #endif |
diff --git a/sound/soc/intel/sst/sst_drv_interface.c b/sound/soc/intel/sst/sst_drv_interface.c index 5f75ef3cdd22..f0e4b99b3aeb 100644 --- a/sound/soc/intel/sst/sst_drv_interface.c +++ b/sound/soc/intel/sst/sst_drv_interface.c | |||
| @@ -138,12 +138,36 @@ int sst_get_stream(struct intel_sst_drv *ctx, | |||
| 138 | static int sst_power_control(struct device *dev, bool state) | 138 | static int sst_power_control(struct device *dev, bool state) |
| 139 | { | 139 | { |
| 140 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | 140 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); |
| 141 | 141 | int ret = 0; | |
| 142 | dev_dbg(ctx->dev, "state:%d", state); | 142 | int usage_count = 0; |
| 143 | if (state == true) | 143 | |
| 144 | return pm_runtime_get_sync(dev); | 144 | #ifdef CONFIG_PM |
| 145 | else | 145 | usage_count = atomic_read(&dev->power.usage_count); |
| 146 | #else | ||
| 147 | usage_count = 1; | ||
| 148 | #endif | ||
| 149 | |||
| 150 | if (state == true) { | ||
| 151 | ret = pm_runtime_get_sync(dev); | ||
| 152 | |||
| 153 | dev_dbg(ctx->dev, "Enable: pm usage count: %d\n", usage_count); | ||
| 154 | if (ret < 0) { | ||
| 155 | dev_err(ctx->dev, "Runtime get failed with err: %d\n", ret); | ||
| 156 | return ret; | ||
| 157 | } | ||
| 158 | if ((ctx->sst_state == SST_RESET) && (usage_count == 1)) { | ||
| 159 | ret = sst_load_fw(ctx); | ||
| 160 | if (ret) { | ||
| 161 | dev_err(dev, "FW download fail %d\n", ret); | ||
| 162 | sst_set_fw_state_locked(ctx, SST_RESET); | ||
| 163 | ret = sst_pm_runtime_put(ctx); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | } else { | ||
| 167 | dev_dbg(ctx->dev, "Disable: pm usage count: %d\n", usage_count); | ||
| 146 | return sst_pm_runtime_put(ctx); | 168 | return sst_pm_runtime_put(ctx); |
| 169 | } | ||
| 170 | return ret; | ||
| 147 | } | 171 | } |
| 148 | 172 | ||
| 149 | /* | 173 | /* |
| @@ -572,6 +596,35 @@ static int sst_stream_drop(struct device *dev, int str_id) | |||
| 572 | return sst_drop_stream(ctx, str_id); | 596 | return sst_drop_stream(ctx, str_id); |
| 573 | } | 597 | } |
| 574 | 598 | ||
| 599 | static int sst_stream_pause(struct device *dev, int str_id) | ||
| 600 | { | ||
| 601 | struct stream_info *str_info; | ||
| 602 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
| 603 | |||
| 604 | if (ctx->sst_state != SST_FW_RUNNING) | ||
| 605 | return 0; | ||
| 606 | |||
| 607 | str_info = get_stream_info(ctx, str_id); | ||
| 608 | if (!str_info) | ||
| 609 | return -EINVAL; | ||
| 610 | |||
| 611 | return sst_pause_stream(ctx, str_id); | ||
| 612 | } | ||
| 613 | |||
| 614 | static int sst_stream_resume(struct device *dev, int str_id) | ||
| 615 | { | ||
| 616 | struct stream_info *str_info; | ||
| 617 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
| 618 | |||
| 619 | if (ctx->sst_state != SST_FW_RUNNING) | ||
| 620 | return 0; | ||
| 621 | |||
| 622 | str_info = get_stream_info(ctx, str_id); | ||
| 623 | if (!str_info) | ||
| 624 | return -EINVAL; | ||
| 625 | return sst_resume_stream(ctx, str_id); | ||
| 626 | } | ||
| 627 | |||
| 575 | static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info) | 628 | static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info) |
| 576 | { | 629 | { |
| 577 | int str_id = 0; | 630 | int str_id = 0; |
| @@ -633,6 +686,8 @@ static struct sst_ops pcm_ops = { | |||
| 633 | .stream_init = sst_stream_init, | 686 | .stream_init = sst_stream_init, |
| 634 | .stream_start = sst_stream_start, | 687 | .stream_start = sst_stream_start, |
| 635 | .stream_drop = sst_stream_drop, | 688 | .stream_drop = sst_stream_drop, |
| 689 | .stream_pause = sst_stream_pause, | ||
| 690 | .stream_pause_release = sst_stream_resume, | ||
| 636 | .stream_read_tstamp = sst_read_timestamp, | 691 | .stream_read_tstamp = sst_read_timestamp, |
| 637 | .send_byte_stream = sst_send_byte_stream, | 692 | .send_byte_stream = sst_send_byte_stream, |
| 638 | .close = sst_close_pcm_stream, | 693 | .close = sst_close_pcm_stream, |
diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/sst/sst_loader.c index 7888cd707853..e88907ae8b15 100644 --- a/sound/soc/intel/sst/sst_loader.c +++ b/sound/soc/intel/sst/sst_loader.c | |||
| @@ -39,7 +39,15 @@ | |||
| 39 | #include "sst.h" | 39 | #include "sst.h" |
| 40 | #include "../sst-dsp.h" | 40 | #include "../sst-dsp.h" |
| 41 | 41 | ||
| 42 | static inline void memcpy32_toio(void __iomem *dst, const void *src, int count) | 42 | void memcpy32_toio(void __iomem *dst, const void *src, int count) |
| 43 | { | ||
| 44 | /* __iowrite32_copy uses 32-bit count values so divide by 4 for | ||
| 45 | * right count in words | ||
| 46 | */ | ||
| 47 | __iowrite32_copy(dst, src, count/4); | ||
| 48 | } | ||
| 49 | |||
| 50 | void memcpy32_fromio(void *dst, const void __iomem *src, int count) | ||
| 43 | { | 51 | { |
| 44 | /* __iowrite32_copy uses 32-bit count values so divide by 4 for | 52 | /* __iowrite32_copy uses 32-bit count values so divide by 4 for |
| 45 | * right count in words | 53 | * right count in words |
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 6b0136e7cb88..6e3781e88f9a 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
| @@ -2511,6 +2511,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | |||
| 2511 | /* DAPM dai link stream work */ | 2511 | /* DAPM dai link stream work */ |
| 2512 | INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); | 2512 | INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); |
| 2513 | 2513 | ||
| 2514 | pcm->nonatomic = rtd->dai_link->nonatomic; | ||
| 2514 | rtd->pcm = pcm; | 2515 | rtd->pcm = pcm; |
| 2515 | pcm->private_data = rtd; | 2516 | pcm->private_data = rtd; |
| 2516 | 2517 | ||
