diff options
Diffstat (limited to 'sound/soc/intel/atom/sst')
| -rw-r--r-- | sound/soc/intel/atom/sst/sst.c | 24 | ||||
| -rw-r--r-- | sound/soc/intel/atom/sst/sst.h | 20 | ||||
| -rw-r--r-- | sound/soc/intel/atom/sst/sst_acpi.c | 3 | ||||
| -rw-r--r-- | sound/soc/intel/atom/sst/sst_drv_interface.c | 19 | ||||
| -rw-r--r-- | sound/soc/intel/atom/sst/sst_pvt.c | 8 | ||||
| -rw-r--r-- | sound/soc/intel/atom/sst/sst_stream.c | 117 | 
6 files changed, 111 insertions, 80 deletions
diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index 8afdff457579..0962bc9adc62 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -449,6 +449,13 @@ static int intel_sst_suspend(struct device *dev)  			dev_err(dev, "stream %d is running, can't suspend, abort\n", i);  			return -EBUSY;  		} + +		if (ctx->pdata->streams_lost_on_suspend) { +			stream->resume_status = stream->status; +			stream->resume_prev = stream->prev; +			if (stream->status != STREAM_UN_INIT) +				sst_free_stream(ctx, i); +		}  	}  	synchronize_irq(ctx->irq_num);  	flush_workqueue(ctx->post_msg_wq); @@ -509,8 +516,8 @@ static int intel_sst_resume(struct device *dev)  {  	struct intel_sst_drv *ctx = dev_get_drvdata(dev);  	struct sst_fw_save *fw_save = ctx->fw_save; -	int ret = 0;  	struct sst_block *block; +	int i, ret = 0;  	if (!fw_save)  		return 0; @@ -550,6 +557,21 @@ static int intel_sst_resume(struct device *dev)  		sst_set_fw_state_locked(ctx, SST_FW_RUNNING);  	} +	if (ctx->pdata->streams_lost_on_suspend) { +		for (i = 1; i <= ctx->info.max_streams; i++) { +			struct stream_info *stream = &ctx->streams[i]; + +			if (stream->resume_status != STREAM_UN_INIT) { +				dev_dbg(ctx->dev, "Re-allocing stream %d status %d prev %d\n", +					i, stream->resume_status, +					stream->resume_prev); +				sst_realloc_stream(ctx, i); +				stream->status = stream->resume_status; +				stream->prev = stream->resume_prev; +			} +		} +	} +  	sst_free_block(ctx, block);  	return ret;  } diff --git a/sound/soc/intel/atom/sst/sst.h b/sound/soc/intel/atom/sst/sst.h index e02e2b4cc08f..b2a705dc9304 100644 --- a/sound/soc/intel/atom/sst/sst.h +++ b/sound/soc/intel/atom/sst/sst.h @@ -65,9 +65,7 @@ enum sst_stream_states {  	STREAM_UN_INIT	= 0,	/* Freed/Not used stream */  	STREAM_RUNNING	= 1,	/* Running */  	STREAM_PAUSED	= 2,	/* Paused stream */ -	STREAM_DECODE	= 3,	/* stream is in decoding only state */ -	STREAM_INIT	= 4,	/* stream init, waiting for data */ -	STREAM_RESET	= 5,	/* force reset on recovery */ +	STREAM_INIT	= 3,	/* stream init, waiting for data */  };  enum sst_ram_type { @@ -181,22 +179,22 @@ struct sst_block {   *   * @status : stream current state   * @prev : stream prev state - * @ops : stream operation pb/cp/drm... - * @bufs: stream buffer list + * @resume_status : stream current state to restore on resume + * @resume_prev : stream prev state to restore on resume   * @lock : stream mutex for protecting state + * @alloc_param : parameters used for stream (re-)allocation   * @pcm_substream : PCM substream   * @period_elapsed : PCM period elapsed callback   * @sfreq : stream sampling freq - * @str_type : stream type   * @cumm_bytes : cummulative bytes decoded - * @str_type : stream type - * @src : stream source   */  struct stream_info {  	unsigned int		status;  	unsigned int		prev; -	unsigned int		ops; +	unsigned int		resume_status; +	unsigned int		resume_prev;  	struct mutex		lock; +	struct snd_sst_alloc_mrfld alloc_param;  	void			*pcm_substream;  	void (*period_elapsed)(void *pcm_substream); @@ -212,7 +210,6 @@ struct stream_info {  	unsigned int		num_ch;  	unsigned int		pipe_id; -	unsigned int		str_id;  	unsigned int		task_id;  }; @@ -438,6 +435,7 @@ struct intel_sst_ops {  	void (*post_download)(struct intel_sst_drv *sst);  }; +int sst_realloc_stream(struct intel_sst_drv *sst_drv_ctx, int str_id);  int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int id);  int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int id);  int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int id); @@ -501,8 +499,6 @@ int sst_prepare_and_post_msg(struct intel_sst_drv *sst,  void sst_process_pending_msg(struct work_struct *work);  int sst_assign_pvt_id(struct intel_sst_drv *sst_drv_ctx); -void sst_init_stream(struct stream_info *stream, -		int codec, int sst_id, int ops, u8 slot);  int sst_validate_strid(struct intel_sst_drv *sst_drv_ctx, int str_id);  struct stream_info *get_stream_info(struct intel_sst_drv *sst_drv_ctx,  		int str_id); diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 6cd481bec275..c90b04cc071d 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -143,10 +143,11 @@ static struct sst_platform_info byt_rvp_platform_data = {  	.lib_info = &byt_lib_dnld_info,  	.res_info = &byt_rvp_res_info,  	.platform = "sst-mfld-platform", +	.streams_lost_on_suspend = true,  };  /* Cherryview (Cherrytrail and Braswell) uses same mrfld dpcm fw as Baytrail, - * so pdata is same as Baytrail. + * so pdata is same as Baytrail, minus the streams_lost_on_suspend quirk.   */  static struct sst_platform_info chv_platform_data = {  	.probe_data = &byt_fwparse_info, diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c index 71af5449be90..6a8b253c58d2 100644 --- a/sound/soc/intel/atom/sst/sst_drv_interface.c +++ b/sound/soc/intel/atom/sst/sst_drv_interface.c @@ -238,16 +238,7 @@ static int sst_cdev_close(struct device *dev, unsigned int str_id)  		return -EINVAL;  	} -	if (stream->status == STREAM_RESET) { -		dev_dbg(dev, "stream in reset state...\n"); -		stream->status = STREAM_UN_INIT; - -		retval = 0; -		goto put; -	} -  	retval = sst_free_stream(ctx, str_id); -put:  	stream->compr_cb_param = NULL;  	stream->compr_cb = NULL; @@ -256,7 +247,6 @@ put:  	dev_dbg(dev, "End\n");  	return retval; -  }  static int sst_cdev_ack(struct device *dev, unsigned int str_id, @@ -486,16 +476,7 @@ static int sst_close_pcm_stream(struct device *dev, unsigned int str_id)  		return -EINVAL;  	} -	if (stream->status == STREAM_RESET) { -		/* silently fail here as we have cleaned the stream earlier */ -		dev_dbg(ctx->dev, "stream in reset state...\n"); - -		retval = 0; -		goto put; -	} -  	retval = free_stream_context(ctx, str_id); -put:  	stream->pcm_substream = NULL;  	stream->status = STREAM_UN_INIT;  	stream->period_elapsed = NULL; diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c index b1e6b8f34a6a..af93244b4868 100644 --- a/sound/soc/intel/atom/sst/sst_pvt.c +++ b/sound/soc/intel/atom/sst/sst_pvt.c @@ -360,14 +360,6 @@ int sst_assign_pvt_id(struct intel_sst_drv *drv)  	return local;  } -void sst_init_stream(struct stream_info *stream, -		int codec, int sst_id, int ops, u8 slot) -{ -	stream->status = STREAM_INIT; -	stream->prev = STREAM_UN_INIT; -	stream->ops = ops; -} -  int sst_validate_strid(  		struct intel_sst_drv *sst_drv_ctx, int str_id)  { diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index 7ee6aeb7e0af..107271f7dd63 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -35,29 +35,31 @@  int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params)  { -	struct snd_sst_alloc_mrfld alloc_param; +	struct snd_pcm_params *pcm_params;  	struct snd_sst_params *str_params;  	struct snd_sst_tstamp fw_tstamp;  	struct stream_info *str_info; -	struct snd_sst_alloc_response *response; -	unsigned int str_id, pipe_id, task_id; -	int i, num_ch, ret = 0; -	void *data = NULL; +	int i, num_ch, str_id;  	dev_dbg(sst_drv_ctx->dev, "Enter\n");  	str_params = (struct snd_sst_params *)params; -	memset(&alloc_param, 0, sizeof(alloc_param)); -	alloc_param.operation = str_params->ops; -	alloc_param.codec_type = str_params->codec; -	alloc_param.sg_count = str_params->aparams.sg_count; -	alloc_param.ring_buf_info[0].addr = +	str_id = str_params->stream_id; +	str_info = get_stream_info(sst_drv_ctx, str_id); +	if (!str_info) +		return -EINVAL; + +	memset(&str_info->alloc_param, 0, sizeof(str_info->alloc_param)); +	str_info->alloc_param.operation = str_params->ops; +	str_info->alloc_param.codec_type = str_params->codec; +	str_info->alloc_param.sg_count = str_params->aparams.sg_count; +	str_info->alloc_param.ring_buf_info[0].addr =  		str_params->aparams.ring_buf_info[0].addr; -	alloc_param.ring_buf_info[0].size = +	str_info->alloc_param.ring_buf_info[0].size =  		str_params->aparams.ring_buf_info[0].size; -	alloc_param.frag_size = str_params->aparams.frag_size; +	str_info->alloc_param.frag_size = str_params->aparams.frag_size; -	memcpy(&alloc_param.codec_params, &str_params->sparams, +	memcpy(&str_info->alloc_param.codec_params, &str_params->sparams,  			sizeof(struct snd_sst_stream_params));  	/* @@ -67,47 +69,62 @@ int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params)  	 * Currently hardcoding as per FW reqm.  	 */  	num_ch = sst_get_num_channel(str_params); +	pcm_params = &str_info->alloc_param.codec_params.uc.pcm_params;  	for (i = 0; i < 8; i++) {  		if (i < num_ch) -			alloc_param.codec_params.uc.pcm_params.channel_map[i] = i; +			pcm_params->channel_map[i] = i;  		else -			alloc_param.codec_params.uc.pcm_params.channel_map[i] = 0xFF; +			pcm_params->channel_map[i] = 0xff;  	} -	str_id = str_params->stream_id; -	str_info = get_stream_info(sst_drv_ctx, str_id); -	if (str_info == NULL) { -		dev_err(sst_drv_ctx->dev, "get stream info returned null\n"); -		return -EINVAL; -	} - -	pipe_id = str_params->device_type; -	task_id = str_params->task; -	sst_drv_ctx->streams[str_id].pipe_id = pipe_id; -	sst_drv_ctx->streams[str_id].task_id = task_id; +	sst_drv_ctx->streams[str_id].status = STREAM_INIT; +	sst_drv_ctx->streams[str_id].prev = STREAM_UN_INIT; +	sst_drv_ctx->streams[str_id].pipe_id = str_params->device_type; +	sst_drv_ctx->streams[str_id].task_id = str_params->task;  	sst_drv_ctx->streams[str_id].num_ch = num_ch;  	if (sst_drv_ctx->info.lpe_viewpt_rqd) -		alloc_param.ts = sst_drv_ctx->info.mailbox_start + +		str_info->alloc_param.ts = sst_drv_ctx->info.mailbox_start +  			sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));  	else -		alloc_param.ts = sst_drv_ctx->mailbox_add + +		str_info->alloc_param.ts = sst_drv_ctx->mailbox_add +  			sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));  	dev_dbg(sst_drv_ctx->dev, "alloc tstamp location = 0x%x\n", -			alloc_param.ts); +			str_info->alloc_param.ts);  	dev_dbg(sst_drv_ctx->dev, "assigned pipe id 0x%x to task %d\n", -			pipe_id, task_id); +			str_info->pipe_id, str_info->task_id); + +	return sst_realloc_stream(sst_drv_ctx, str_id); +} + +/** + * sst_realloc_stream - Send msg for (re-)allocating a stream using the + * @sst_drv_ctx  intel_sst_drv context pointer + * @str_id:	 stream ID + * + * Send a msg for (re-)allocating a stream using the parameters previously + * passed to sst_alloc_stream_mrfld() for the same stream ID. + * Return: 0 or negative errno value. + */ +int sst_realloc_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) +{ +	struct snd_sst_alloc_response *response; +	struct stream_info *str_info; +	void *data = NULL; +	int ret; -	/* allocate device type context */ -	sst_init_stream(&sst_drv_ctx->streams[str_id], alloc_param.codec_type, -			str_id, alloc_param.operation, 0); +	str_info = get_stream_info(sst_drv_ctx, str_id); +	if (!str_info) +		return -EINVAL;  	dev_dbg(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n", -			str_id, pipe_id); -	ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD, -			IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param), -			&alloc_param, &data, true, true, false, true); +		str_id, str_info->pipe_id); + +	ret = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, +			IPC_IA_ALLOC_STREAM_MRFLD, str_info->pipe_id, +			sizeof(str_info->alloc_param), &str_info->alloc_param, +			&data, true, true, false, true);  	if (ret < 0) {  		dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret); @@ -253,7 +270,7 @@ int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)  		if (retval == 0) {  			str_info->prev = str_info->status;  			str_info->status = STREAM_PAUSED; -		} else if (retval == SST_ERR_INVALID_STREAM_ID) { +		} else if (retval == -SST_ERR_INVALID_STREAM_ID) {  			retval = -EINVAL;  			mutex_lock(&sst_drv_ctx->sst_lock);  			sst_clean_stream(str_info); @@ -285,7 +302,29 @@ int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)  		return -EINVAL;  	if (str_info->status == STREAM_RUNNING)  		return 0; -	if (str_info->status == STREAM_PAUSED) { + +	if (str_info->resume_status == STREAM_PAUSED && +	    str_info->resume_prev == STREAM_RUNNING) { +		/* +		 * Stream was running before suspend and re-created on resume, +		 * start it to get back to running state. +		 */ +		dev_dbg(sst_drv_ctx->dev, "restart recreated stream after resume\n"); +		str_info->status = STREAM_RUNNING; +		str_info->prev = STREAM_PAUSED; +		retval = sst_start_stream(sst_drv_ctx, str_id); +		str_info->resume_status = STREAM_UN_INIT; +	} else if (str_info->resume_status == STREAM_PAUSED && +		   str_info->resume_prev == STREAM_INIT) { +		/* +		 * Stream was idle before suspend and re-created on resume, +		 * keep it as is. +		 */ +		dev_dbg(sst_drv_ctx->dev, "leaving recreated stream idle after resume\n"); +		str_info->status = STREAM_INIT; +		str_info->prev = STREAM_PAUSED; +		str_info->resume_status = STREAM_UN_INIT; +	} else if (str_info->status == STREAM_PAUSED) {  		retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,  				IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD,  				str_info->pipe_id, 0, NULL, NULL,  | 

