Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: SOF: Intel: hda: Define FW boot sequence with ICCMAX

Define the FW boot sequence for platforms that are recommended
to use ICCMAX. This function uses the existing prepare and cleanup
functions for creating a specially crafted capture stream before
powering up the DSP cores.

Reviewed-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Link: https://lore.kernel.org/r/20200826184532.1612070-7-ranjani.sridharan@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Ranjani Sridharan and committed by
Mark Brown
acf705a4 d43e3813

+78 -15
+77 -15
sound/soc/sof/intel/hda-loader.c
··· 17 17 18 18 #include <linux/firmware.h> 19 19 #include <sound/hdaudio_ext.h> 20 + #include <sound/hda_register.h> 20 21 #include <sound/sof.h> 21 22 #include "../ops.h" 22 23 #include "hda.h" ··· 33 32 struct hdac_stream *hstream; 34 33 struct pci_dev *pci = to_pci_dev(sdev->dev); 35 34 int ret; 36 - 37 - if (direction != SNDRV_PCM_STREAM_PLAYBACK) { 38 - dev_err(sdev->dev, "error: code loading DMA is playback only\n"); 39 - return -EINVAL; 40 - } 41 35 42 36 dsp_stream = hda_dsp_stream_get(sdev, direction); 43 37 ··· 54 58 hstream->format_val = format; 55 59 hstream->bufsize = size; 56 60 57 - ret = hda_dsp_stream_hw_params(sdev, dsp_stream, dmab, NULL); 58 - if (ret < 0) { 59 - dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret); 60 - goto error; 61 + if (direction == SNDRV_PCM_STREAM_CAPTURE) { 62 + ret = hda_dsp_iccmax_stream_hw_params(sdev, dsp_stream, dmab, NULL); 63 + if (ret < 0) { 64 + dev_err(sdev->dev, "error: iccmax stream prepare failed: %x\n", ret); 65 + goto error; 66 + } 67 + } else { 68 + ret = hda_dsp_stream_hw_params(sdev, dsp_stream, dmab, NULL); 69 + if (ret < 0) { 70 + dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret); 71 + goto error; 72 + } 73 + hda_dsp_stream_spib_config(sdev, dsp_stream, HDA_DSP_SPIB_ENABLE, size); 61 74 } 62 - 63 - hda_dsp_stream_spib_config(sdev, dsp_stream, HDA_DSP_SPIB_ENABLE, size); 64 75 65 76 return hstream->stream_tag; 66 77 ··· 227 224 { 228 225 struct hdac_stream *hstream = &stream->hstream; 229 226 int sd_offset = SOF_STREAM_SD_OFFSET(hstream); 230 - int ret; 227 + int ret = 0; 231 228 232 - ret = hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); 229 + if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK) 230 + ret = hda_dsp_stream_spib_config(sdev, stream, HDA_DSP_SPIB_DISABLE, 0); 231 + else 232 + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, 233 + SOF_HDA_SD_CTL_DMA_START, 0); 233 234 234 - hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_PLAYBACK, 235 - hstream->stream_tag); 235 + hda_dsp_stream_put(sdev, hstream->direction, hstream->stream_tag); 236 236 hstream->running = 0; 237 237 hstream->substream = NULL; 238 238 ··· 291 285 } 292 286 293 287 return status; 288 + } 289 + 290 + int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev) 291 + { 292 + struct snd_sof_pdata *plat_data = sdev->pdata; 293 + struct hdac_ext_stream *iccmax_stream; 294 + struct hdac_bus *bus = sof_to_bus(sdev); 295 + struct firmware stripped_firmware; 296 + int ret, ret1; 297 + int iccmax_tag; 298 + u8 original_gb; 299 + 300 + /* save the original LTRP guardband value */ 301 + original_gb = snd_hdac_chip_readb(bus, VS_LTRP) & HDA_VS_INTEL_LTRP_GB_MASK; 302 + 303 + if (plat_data->fw->size <= plat_data->fw_offset) { 304 + dev_err(sdev->dev, "error: firmware size must be greater than firmware offset\n"); 305 + return -EINVAL; 306 + } 307 + 308 + stripped_firmware.size = plat_data->fw->size - plat_data->fw_offset; 309 + 310 + /* prepare capture stream for ICCMAX */ 311 + iccmax_tag = cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, stripped_firmware.size, 312 + &sdev->dmab_bdl, SNDRV_PCM_STREAM_CAPTURE); 313 + if (iccmax_tag < 0) { 314 + dev_err(sdev->dev, "error: dma prepare for ICCMAX %x\n", iccmax_tag); 315 + return iccmax_tag; 316 + } 317 + 318 + /* get stream with tag */ 319 + iccmax_stream = get_stream_with_tag(sdev, iccmax_tag, SNDRV_PCM_STREAM_CAPTURE); 320 + if (!iccmax_stream) { 321 + dev_err(sdev->dev, "error: could not get stream with stream tag %d\n", iccmax_tag); 322 + ret = -ENODEV; 323 + } else { 324 + ret = hda_dsp_cl_boot_firmware(sdev); 325 + } 326 + 327 + /* 328 + * Perform iccmax stream cleanup. This should be done even if firmware loading fails. 329 + * If the cleanup also fails, we return the initial error 330 + */ 331 + ret1 = cl_cleanup(sdev, &sdev->dmab_bdl, iccmax_stream); 332 + if (ret1 < 0) { 333 + dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n"); 334 + 335 + /* set return value to indicate cleanup failure */ 336 + if (!ret) 337 + ret = ret1; 338 + } 339 + 340 + /* restore the original guardband value after FW boot */ 341 + snd_hdac_chip_updateb(bus, VS_LTRP, HDA_VS_INTEL_LTRP_GB_MASK, original_gb); 342 + 343 + return ret; 294 344 } 295 345 296 346 int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
+1
sound/soc/sof/intel/hda.h
··· 612 612 * DSP Code loader. 613 613 */ 614 614 int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev); 615 + int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev); 615 616 int hda_dsp_cl_boot_firmware_skl(struct snd_sof_dev *sdev); 616 617 617 618 /* pre and post fw run ops */