diff options
Diffstat (limited to 'sound/soc/sof/intel/hda-loader.c')
| -rw-r--r-- | sound/soc/sof/intel/hda-loader.c | 122 | 
1 files changed, 62 insertions, 60 deletions
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c index b81f231abee3..b8b914eaf7e0 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -3,7 +3,7 @@  // This file is provided under a dual BSD/GPLv2 license.  When using or  // redistributing this file, you may do so under either license.  // -// Copyright(c) 2018 Intel Corporation. All rights reserved. +// Copyright(c) 2018 Intel Corporation  //  // Authors: Liam Girdwood <[email protected]>  //	    Ranjani Sridharan <[email protected]> @@ -43,13 +43,13 @@ static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev)  	}  } -struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned int format, -					      unsigned int size, struct snd_dma_buffer *dmab, -					      int direction) +struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format, +				       unsigned int size, struct snd_dma_buffer *dmab, +				       int direction, bool is_iccmax)  { +	struct snd_sof_dev *sdev = dev_get_drvdata(dev);  	struct hdac_ext_stream *hext_stream;  	struct hdac_stream *hstream; -	struct pci_dev *pci = to_pci_dev(sdev->dev);  	int ret;  	hext_stream = hda_dsp_stream_get(sdev, direction, 0); @@ -62,7 +62,7 @@ struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned  	hstream->substream = NULL;  	/* allocate DMA buffer */ -	ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab); +	ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, dev, size, dmab);  	if (ret < 0) {  		dev_err(sdev->dev, "error: memory alloc failed: %d\n", ret);  		goto out_put; @@ -72,7 +72,7 @@ struct hdac_ext_stream *hda_cl_stream_prepare(struct snd_sof_dev *sdev, unsigned  	hstream->format_val = format;  	hstream->bufsize = size; -	if (direction == SNDRV_PCM_STREAM_CAPTURE) { +	if (is_iccmax) {  		ret = hda_dsp_iccmax_stream_hw_params(sdev, hext_stream, dmab, NULL);  		if (ret < 0) {  			dev_err(sdev->dev, "error: iccmax stream prepare failed: %d\n", ret); @@ -95,6 +95,7 @@ out_put:  	hda_dsp_stream_put(sdev, direction, hstream->stream_tag);  	return ERR_PTR(ret);  } +EXPORT_SYMBOL_NS(hda_cl_prepare, SND_SOC_SOF_INTEL_HDA_COMMON);  /*   * first boot sequence has some extra steps. @@ -218,16 +219,22 @@ err:  	kfree(dump_msg);  	return ret;  } +EXPORT_SYMBOL_NS(cl_dsp_init, SND_SOC_SOF_INTEL_HDA_COMMON); -static int cl_trigger(struct snd_sof_dev *sdev, -		      struct hdac_ext_stream *hext_stream, int cmd) +int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int cmd)  { +	struct snd_sof_dev *sdev = dev_get_drvdata(dev);  	struct hdac_stream *hstream = &hext_stream->hstream;  	int sd_offset = SOF_STREAM_SD_OFFSET(hstream); +	struct sof_intel_hda_stream *hda_stream;  	/* code loader is special case that reuses stream ops */  	switch (cmd) {  	case SNDRV_PCM_TRIGGER_START: +		hda_stream = container_of(hext_stream, struct sof_intel_hda_stream, +					  hext_stream); +		reinit_completion(&hda_stream->ioc); +  		snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,  					1 << hstream->index,  					1 << hstream->index); @@ -245,10 +252,12 @@ static int cl_trigger(struct snd_sof_dev *sdev,  		return hda_dsp_stream_trigger(sdev, hext_stream, cmd);  	}  } +EXPORT_SYMBOL_NS(hda_cl_trigger, SND_SOC_SOF_INTEL_HDA_COMMON); -int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab, +int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab,  		   struct hdac_ext_stream *hext_stream)  { +	struct snd_sof_dev *sdev =  dev_get_drvdata(dev);  	struct hdac_stream *hstream = &hext_stream->hstream;  	int sd_offset = SOF_STREAM_SD_OFFSET(hstream);  	int ret = 0; @@ -277,20 +286,40 @@ int hda_cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,  	return ret;  } +EXPORT_SYMBOL_NS(hda_cl_cleanup, SND_SOC_SOF_INTEL_HDA_COMMON); + +#define HDA_CL_DMA_IOC_TIMEOUT_MS 500  int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream)  {  	struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;  	const struct sof_intel_dsp_desc *chip = hda->desc; +	struct sof_intel_hda_stream *hda_stream; +	unsigned long time_left;  	unsigned int reg;  	int ret, status; -	ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_START); +	hda_stream = container_of(hext_stream, struct sof_intel_hda_stream, +				  hext_stream); + +	dev_dbg(sdev->dev, "Code loader DMA starting\n"); + +	ret = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_START);  	if (ret < 0) {  		dev_err(sdev->dev, "error: DMA trigger start failed\n");  		return ret;  	} +	/* Wait for completion of transfer */ +	time_left = wait_for_completion_timeout(&hda_stream->ioc, +						msecs_to_jiffies(HDA_CL_DMA_IOC_TIMEOUT_MS)); + +	if (!time_left) { +		dev_err(sdev->dev, "Code loader DMA did not complete\n"); +		return -ETIMEDOUT; +	} +	dev_dbg(sdev->dev, "Code loader DMA done, waiting for FW_ENTERED status\n"); +  	status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,  					chip->rom_status_reg, reg,  					(FSR_TO_STATE_CODE(reg) == FSR_STATE_FW_ENTERED), @@ -306,13 +335,17 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream  		dev_err(sdev->dev,  			"%s: timeout with rom_status_reg (%#x) read\n",  			__func__, chip->rom_status_reg); +	} else { +		dev_dbg(sdev->dev, "Code loader FW_ENTERED status\n");  	} -	ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_STOP); +	ret = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_STOP);  	if (ret < 0) {  		dev_err(sdev->dev, "error: DMA trigger stop failed\n");  		if (!status)  			status = ret; +	} else { +		dev_dbg(sdev->dev, "Code loader DMA stopped\n");  	}  	return status; @@ -333,8 +366,8 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)  	 * Prepare capture stream for ICCMAX. We do not need to store  	 * the data, so use a buffer of PAGE_SIZE for receiving.  	 */ -	iccmax_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, PAGE_SIZE, -					      &dmab_bdl, SNDRV_PCM_STREAM_CAPTURE); +	iccmax_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT, PAGE_SIZE, +				       &dmab_bdl, SNDRV_PCM_STREAM_CAPTURE, true);  	if (IS_ERR(iccmax_stream)) {  		dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n");  		return PTR_ERR(iccmax_stream); @@ -346,7 +379,7 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)  	 * Perform iccmax stream cleanup. This should be done even if firmware loading fails.  	 * If the cleanup also fails, we return the initial error  	 */ -	ret1 = hda_cl_cleanup(sdev, &dmab_bdl, iccmax_stream); +	ret1 = hda_cl_cleanup(sdev->dev, &dmab_bdl, iccmax_stream);  	if (ret1 < 0) {  		dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n"); @@ -361,6 +394,7 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)  	return ret;  } +EXPORT_SYMBOL_NS(hda_dsp_cl_boot_firmware_iccmax, SND_SOC_SOF_INTEL_CNL);  static int hda_dsp_boot_imr(struct snd_sof_dev *sdev)  { @@ -418,9 +452,9 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)  	init_waitqueue_head(&sdev->boot_wait);  	/* prepare DMA for code loader stream */ -	hext_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, -					    stripped_firmware.size, -					    &dmab, SNDRV_PCM_STREAM_PLAYBACK); +	hext_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT, +				     stripped_firmware.size, +				     &dmab, SNDRV_PCM_STREAM_PLAYBACK, false);  	if (IS_ERR(hext_stream)) {  		dev_err(sdev->dev, "error: dma prepare for fw loading failed\n");  		return PTR_ERR(hext_stream); @@ -493,7 +527,7 @@ cleanup:  	 * This should be done even if firmware loading fails.  	 * If the cleanup also fails, we return the initial error  	 */ -	ret1 = hda_cl_cleanup(sdev, &dmab, hext_stream); +	ret1 = hda_cl_cleanup(sdev->dev, &dmab, hext_stream);  	if (ret1 < 0) {  		dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n"); @@ -514,6 +548,7 @@ cleanup:  	return ret;  } +EXPORT_SYMBOL_NS(hda_dsp_cl_boot_firmware, SND_SOC_SOF_INTEL_HDA_COMMON);  int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,  			      struct sof_ipc4_fw_library *fw_lib, bool reload) @@ -535,9 +570,9 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,  	stripped_firmware.size = fw_lib->sof_fw.fw->size - fw_lib->sof_fw.payload_offset;  	/* prepare DMA for code loader stream */ -	hext_stream = hda_cl_stream_prepare(sdev, HDA_CL_STREAM_FORMAT, -					    stripped_firmware.size, -					    &dmab, SNDRV_PCM_STREAM_PLAYBACK); +	hext_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT, +				     stripped_firmware.size, +				     &dmab, SNDRV_PCM_STREAM_PLAYBACK, false);  	if (IS_ERR(hext_stream)) {  		dev_err(sdev->dev, "%s: DMA prepare failed\n", __func__);  		return PTR_ERR(hext_stream); @@ -580,7 +615,7 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,  		goto cleanup;  	} -	ret = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_START); +	ret = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_START);  	if (ret < 0) {  		dev_err(sdev->dev, "%s: DMA trigger start failed\n", __func__);  		goto cleanup; @@ -597,7 +632,7 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,  	ret = sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);  	/* Stop the DMA channel */ -	ret1 = cl_trigger(sdev, hext_stream, SNDRV_PCM_TRIGGER_STOP); +	ret1 = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_STOP);  	if (ret1 < 0) {  		dev_err(sdev->dev, "%s: DMA trigger stop failed\n", __func__);  		if (!ret) @@ -606,7 +641,7 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,  cleanup:  	/* clean up even in case of error and return the first error */ -	ret1 = hda_cl_cleanup(sdev, &dmab, hext_stream); +	ret1 = hda_cl_cleanup(sdev->dev, &dmab, hext_stream);  	if (ret1 < 0) {  		dev_err(sdev->dev, "%s: Code loader DSP cleanup failed\n", __func__); @@ -617,41 +652,7 @@ cleanup:  	return ret;  } - -/* pre fw run operations */ -int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev) -{ -	/* disable clock gating and power gating */ -	return hda_dsp_ctrl_clock_power_gating(sdev, false); -} - -/* post fw run operations */ -int hda_dsp_post_fw_run(struct snd_sof_dev *sdev) -{ -	int ret; - -	if (sdev->first_boot) { -		struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; - -		ret = hda_sdw_startup(sdev); -		if (ret < 0) { -			dev_err(sdev->dev, -				"error: could not startup SoundWire links\n"); -			return ret; -		} - -		/* Check if IMR boot is usable */ -		if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT) && -		    (sdev->fw_ready.flags & SOF_IPC_INFO_D3_PERSISTENT || -		     sdev->pdata->ipc_type == SOF_IPC_TYPE_4)) -			hdev->imrboot_supported = true; -	} - -	hda_sdw_int_enable(sdev, true); - -	/* re-enable clock gating and power gating */ -	return hda_dsp_ctrl_clock_power_gating(sdev, true); -} +EXPORT_SYMBOL_NS(hda_dsp_ipc4_load_library, SND_SOC_SOF_INTEL_HDA_COMMON);  int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev,  					 const struct sof_ext_man_elem_header *hdr) @@ -690,3 +691,4 @@ int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev,  	return 0;  } +EXPORT_SYMBOL_NS(hda_dsp_ext_man_get_cavs_config_data, SND_SOC_SOF_INTEL_HDA_COMMON);  |