cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

imx-pcm-rpmsg.c (23412B)


      1// SPDX-License-Identifier: GPL-2.0+
      2// Copyright 2017-2021 NXP
      3
      4#include <linux/dma-mapping.h>
      5#include <linux/slab.h>
      6#include <linux/module.h>
      7#include <linux/delay.h>
      8#include <linux/rpmsg.h>
      9#include <sound/core.h>
     10#include <sound/pcm.h>
     11#include <sound/pcm_params.h>
     12#include <sound/dmaengine_pcm.h>
     13#include <sound/soc.h>
     14
     15#include "imx-pcm.h"
     16#include "fsl_rpmsg.h"
     17#include "imx-pcm-rpmsg.h"
     18
     19static struct snd_pcm_hardware imx_rpmsg_pcm_hardware = {
     20	.info = SNDRV_PCM_INFO_INTERLEAVED |
     21		SNDRV_PCM_INFO_BLOCK_TRANSFER |
     22		SNDRV_PCM_INFO_MMAP |
     23		SNDRV_PCM_INFO_MMAP_VALID |
     24		SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
     25		SNDRV_PCM_INFO_PAUSE |
     26		SNDRV_PCM_INFO_RESUME,
     27	.buffer_bytes_max = IMX_DEFAULT_DMABUF_SIZE,
     28	.period_bytes_min = 512,
     29	.period_bytes_max = 65536,
     30	.periods_min = 2,
     31	.periods_max = 6000,
     32	.fifo_size = 0,
     33};
     34
     35static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg,
     36				      struct rpmsg_info *info)
     37{
     38	struct rpmsg_device *rpdev = info->rpdev;
     39	int ret = 0;
     40
     41	mutex_lock(&info->msg_lock);
     42	if (!rpdev) {
     43		dev_err(info->dev, "rpmsg channel not ready\n");
     44		mutex_unlock(&info->msg_lock);
     45		return -EINVAL;
     46	}
     47
     48	dev_dbg(&rpdev->dev, "send cmd %d\n", msg->s_msg.header.cmd);
     49
     50	if (!(msg->s_msg.header.type == MSG_TYPE_C))
     51		reinit_completion(&info->cmd_complete);
     52
     53	ret = rpmsg_send(rpdev->ept, (void *)&msg->s_msg,
     54			 sizeof(struct rpmsg_s_msg));
     55	if (ret) {
     56		dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
     57		mutex_unlock(&info->msg_lock);
     58		return ret;
     59	}
     60
     61	/* No receive msg for TYPE_C command */
     62	if (msg->s_msg.header.type == MSG_TYPE_C) {
     63		mutex_unlock(&info->msg_lock);
     64		return 0;
     65	}
     66
     67	/* wait response from rpmsg */
     68	ret = wait_for_completion_timeout(&info->cmd_complete,
     69					  msecs_to_jiffies(RPMSG_TIMEOUT));
     70	if (!ret) {
     71		dev_err(&rpdev->dev, "rpmsg_send cmd %d timeout!\n",
     72			msg->s_msg.header.cmd);
     73		mutex_unlock(&info->msg_lock);
     74		return -ETIMEDOUT;
     75	}
     76
     77	memcpy(&msg->r_msg, &info->r_msg, sizeof(struct rpmsg_r_msg));
     78	memcpy(&info->msg[msg->r_msg.header.cmd].r_msg,
     79	       &msg->r_msg, sizeof(struct rpmsg_r_msg));
     80
     81	/*
     82	 * Reset the buffer pointer to be zero, actully we have
     83	 * set the buffer pointer to be zero in imx_rpmsg_terminate_all
     84	 * But if there is timer task queued in queue, after it is
     85	 * executed the buffer pointer will be changed, so need to
     86	 * reset it again with TERMINATE command.
     87	 */
     88	switch (msg->s_msg.header.cmd) {
     89	case TX_TERMINATE:
     90		info->msg[TX_POINTER].r_msg.param.buffer_offset = 0;
     91		break;
     92	case RX_TERMINATE:
     93		info->msg[RX_POINTER].r_msg.param.buffer_offset = 0;
     94		break;
     95	default:
     96		break;
     97	}
     98
     99	dev_dbg(&rpdev->dev, "cmd:%d, resp %d\n", msg->s_msg.header.cmd,
    100		info->r_msg.param.resp);
    101
    102	mutex_unlock(&info->msg_lock);
    103
    104	return 0;
    105}
    106
    107static int imx_rpmsg_insert_workqueue(struct snd_pcm_substream *substream,
    108				      struct rpmsg_msg *msg,
    109				      struct rpmsg_info *info)
    110{
    111	unsigned long flags;
    112	int ret = 0;
    113
    114	/*
    115	 * Queue the work to workqueue.
    116	 * If the queue is full, drop the message.
    117	 */
    118	spin_lock_irqsave(&info->wq_lock, flags);
    119	if (info->work_write_index != info->work_read_index) {
    120		int index = info->work_write_index;
    121
    122		memcpy(&info->work_list[index].msg, msg,
    123		       sizeof(struct rpmsg_s_msg));
    124
    125		queue_work(info->rpmsg_wq, &info->work_list[index].work);
    126		info->work_write_index++;
    127		info->work_write_index %= WORK_MAX_NUM;
    128	} else {
    129		info->msg_drop_count[substream->stream]++;
    130		ret = -EPIPE;
    131	}
    132	spin_unlock_irqrestore(&info->wq_lock, flags);
    133
    134	return ret;
    135}
    136
    137static int imx_rpmsg_pcm_hw_params(struct snd_soc_component *component,
    138				   struct snd_pcm_substream *substream,
    139				   struct snd_pcm_hw_params *params)
    140{
    141	struct rpmsg_info *info = dev_get_drvdata(component->dev);
    142	struct rpmsg_msg *msg;
    143	int ret = 0;
    144
    145	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
    146		msg = &info->msg[TX_HW_PARAM];
    147		msg->s_msg.header.cmd = TX_HW_PARAM;
    148	} else {
    149		msg = &info->msg[RX_HW_PARAM];
    150		msg->s_msg.header.cmd = RX_HW_PARAM;
    151	}
    152
    153	msg->s_msg.param.rate = params_rate(params);
    154
    155	switch (params_format(params)) {
    156	case SNDRV_PCM_FORMAT_S16_LE:
    157		msg->s_msg.param.format   = RPMSG_S16_LE;
    158		break;
    159	case SNDRV_PCM_FORMAT_S24_LE:
    160		msg->s_msg.param.format   = RPMSG_S24_LE;
    161		break;
    162	case SNDRV_PCM_FORMAT_DSD_U16_LE:
    163		msg->s_msg.param.format   = RPMSG_DSD_U16_LE;
    164		break;
    165	case SNDRV_PCM_FORMAT_DSD_U32_LE:
    166		msg->s_msg.param.format   = RPMSG_DSD_U32_LE;
    167		break;
    168	default:
    169		msg->s_msg.param.format   = RPMSG_S32_LE;
    170		break;
    171	}
    172
    173	switch (params_channels(params)) {
    174	case 1:
    175		msg->s_msg.param.channels = RPMSG_CH_LEFT;
    176		break;
    177	case 2:
    178		msg->s_msg.param.channels = RPMSG_CH_STEREO;
    179		break;
    180	default:
    181		ret = -EINVAL;
    182		break;
    183	}
    184
    185	info->send_message(msg, info);
    186
    187	return ret;
    188}
    189
    190static snd_pcm_uframes_t imx_rpmsg_pcm_pointer(struct snd_soc_component *component,
    191					       struct snd_pcm_substream *substream)
    192{
    193	struct rpmsg_info *info = dev_get_drvdata(component->dev);
    194	struct rpmsg_msg *msg;
    195	unsigned int pos = 0;
    196	int buffer_tail = 0;
    197
    198	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
    199		msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
    200	else
    201		msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
    202
    203	buffer_tail = msg->r_msg.param.buffer_tail;
    204	pos = buffer_tail * snd_pcm_lib_period_bytes(substream);
    205
    206	return bytes_to_frames(substream->runtime, pos);
    207}
    208
    209static void imx_rpmsg_timer_callback(struct timer_list *t)
    210{
    211	struct stream_timer  *stream_timer =
    212			from_timer(stream_timer, t, timer);
    213	struct snd_pcm_substream *substream = stream_timer->substream;
    214	struct rpmsg_info *info = stream_timer->info;
    215	struct rpmsg_msg *msg;
    216
    217	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
    218		msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
    219		msg->s_msg.header.cmd = TX_PERIOD_DONE;
    220	} else {
    221		msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
    222		msg->s_msg.header.cmd = RX_PERIOD_DONE;
    223	}
    224
    225	imx_rpmsg_insert_workqueue(substream, msg, info);
    226}
    227
    228static int imx_rpmsg_pcm_open(struct snd_soc_component *component,
    229			      struct snd_pcm_substream *substream)
    230{
    231	struct rpmsg_info *info = dev_get_drvdata(component->dev);
    232	struct rpmsg_msg *msg;
    233	int ret = 0;
    234	int cmd;
    235
    236	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
    237		msg = &info->msg[TX_OPEN];
    238		msg->s_msg.header.cmd = TX_OPEN;
    239
    240		/* reinitialize buffer counter*/
    241		cmd = TX_PERIOD_DONE + MSG_TYPE_A_NUM;
    242		info->msg[cmd].s_msg.param.buffer_tail = 0;
    243		info->msg[cmd].r_msg.param.buffer_tail = 0;
    244		info->msg[TX_POINTER].r_msg.param.buffer_offset = 0;
    245
    246	} else {
    247		msg = &info->msg[RX_OPEN];
    248		msg->s_msg.header.cmd = RX_OPEN;
    249
    250		/* reinitialize buffer counter*/
    251		cmd = RX_PERIOD_DONE + MSG_TYPE_A_NUM;
    252		info->msg[cmd].s_msg.param.buffer_tail = 0;
    253		info->msg[cmd].r_msg.param.buffer_tail = 0;
    254		info->msg[RX_POINTER].r_msg.param.buffer_offset = 0;
    255	}
    256
    257	info->send_message(msg, info);
    258
    259	imx_rpmsg_pcm_hardware.period_bytes_max =
    260			imx_rpmsg_pcm_hardware.buffer_bytes_max / 2;
    261
    262	snd_soc_set_runtime_hwparams(substream, &imx_rpmsg_pcm_hardware);
    263
    264	ret = snd_pcm_hw_constraint_integer(substream->runtime,
    265					    SNDRV_PCM_HW_PARAM_PERIODS);
    266	if (ret < 0)
    267		return ret;
    268
    269	info->msg_drop_count[substream->stream] = 0;
    270
    271	/* Create timer*/
    272	info->stream_timer[substream->stream].info = info;
    273	info->stream_timer[substream->stream].substream = substream;
    274	timer_setup(&info->stream_timer[substream->stream].timer,
    275		    imx_rpmsg_timer_callback, 0);
    276	return ret;
    277}
    278
    279static int imx_rpmsg_pcm_close(struct snd_soc_component *component,
    280			       struct snd_pcm_substream *substream)
    281{
    282	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    283	struct rpmsg_info *info = dev_get_drvdata(component->dev);
    284	struct rpmsg_msg *msg;
    285	int ret = 0;
    286
    287	/* Flush work in workqueue to make TX_CLOSE is the last message */
    288	flush_workqueue(info->rpmsg_wq);
    289
    290	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
    291		msg = &info->msg[TX_CLOSE];
    292		msg->s_msg.header.cmd = TX_CLOSE;
    293	} else {
    294		msg = &info->msg[RX_CLOSE];
    295		msg->s_msg.header.cmd = RX_CLOSE;
    296	}
    297
    298	info->send_message(msg, info);
    299
    300	del_timer(&info->stream_timer[substream->stream].timer);
    301
    302	rtd->dai_link->ignore_suspend = 0;
    303
    304	if (info->msg_drop_count[substream->stream])
    305		dev_warn(rtd->dev, "Msg is dropped!, number is %d\n",
    306			 info->msg_drop_count[substream->stream]);
    307
    308	return ret;
    309}
    310
    311static int imx_rpmsg_pcm_prepare(struct snd_soc_component *component,
    312				 struct snd_pcm_substream *substream)
    313{
    314	struct snd_pcm_runtime *runtime = substream->runtime;
    315	struct snd_soc_pcm_runtime *rtd = substream->private_data;
    316	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    317	struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
    318
    319	/*
    320	 * NON-MMAP mode, NONBLOCK, Version 2, enable lpa in dts
    321	 * four conditions to determine the lpa is enabled.
    322	 */
    323	if ((runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
    324	     runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) &&
    325	     rpmsg->enable_lpa) {
    326		/*
    327		 * Ignore suspend operation in low power mode
    328		 * M core will continue playback music on A core suspend.
    329		 */
    330		rtd->dai_link->ignore_suspend = 1;
    331		rpmsg->force_lpa = 1;
    332	} else {
    333		rpmsg->force_lpa = 0;
    334	}
    335
    336	return 0;
    337}
    338
    339static void imx_rpmsg_pcm_dma_complete(void *arg)
    340{
    341	struct snd_pcm_substream *substream = arg;
    342
    343	snd_pcm_period_elapsed(substream);
    344}
    345
    346static int imx_rpmsg_prepare_and_submit(struct snd_soc_component *component,
    347					struct snd_pcm_substream *substream)
    348{
    349	struct rpmsg_info *info = dev_get_drvdata(component->dev);
    350	struct rpmsg_msg *msg;
    351
    352	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
    353		msg = &info->msg[TX_BUFFER];
    354		msg->s_msg.header.cmd = TX_BUFFER;
    355	} else {
    356		msg = &info->msg[RX_BUFFER];
    357		msg->s_msg.header.cmd = RX_BUFFER;
    358	}
    359
    360	/* Send buffer address and buffer size */
    361	msg->s_msg.param.buffer_addr = substream->runtime->dma_addr;
    362	msg->s_msg.param.buffer_size = snd_pcm_lib_buffer_bytes(substream);
    363	msg->s_msg.param.period_size = snd_pcm_lib_period_bytes(substream);
    364	msg->s_msg.param.buffer_tail = 0;
    365
    366	info->num_period[substream->stream] = msg->s_msg.param.buffer_size /
    367					      msg->s_msg.param.period_size;
    368
    369	info->callback[substream->stream] = imx_rpmsg_pcm_dma_complete;
    370	info->callback_param[substream->stream] = substream;
    371
    372	return imx_rpmsg_insert_workqueue(substream, msg, info);
    373}
    374
    375static int imx_rpmsg_async_issue_pending(struct snd_soc_component *component,
    376					 struct snd_pcm_substream *substream)
    377{
    378	struct rpmsg_info *info = dev_get_drvdata(component->dev);
    379	struct rpmsg_msg *msg;
    380
    381	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
    382		msg = &info->msg[TX_START];
    383		msg->s_msg.header.cmd = TX_START;
    384	} else {
    385		msg = &info->msg[RX_START];
    386		msg->s_msg.header.cmd = RX_START;
    387	}
    388
    389	return imx_rpmsg_insert_workqueue(substream, msg, info);
    390}
    391
    392static int imx_rpmsg_restart(struct snd_soc_component *component,
    393			     struct snd_pcm_substream *substream)
    394{
    395	struct rpmsg_info *info = dev_get_drvdata(component->dev);
    396	struct rpmsg_msg *msg;
    397
    398	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
    399		msg = &info->msg[TX_RESTART];
    400		msg->s_msg.header.cmd = TX_RESTART;
    401	} else {
    402		msg = &info->msg[RX_RESTART];
    403		msg->s_msg.header.cmd = RX_RESTART;
    404	}
    405
    406	return imx_rpmsg_insert_workqueue(substream, msg, info);
    407}
    408
    409static int imx_rpmsg_pause(struct snd_soc_component *component,
    410			   struct snd_pcm_substream *substream)
    411{
    412	struct rpmsg_info *info = dev_get_drvdata(component->dev);
    413	struct rpmsg_msg *msg;
    414
    415	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
    416		msg = &info->msg[TX_PAUSE];
    417		msg->s_msg.header.cmd = TX_PAUSE;
    418	} else {
    419		msg = &info->msg[RX_PAUSE];
    420		msg->s_msg.header.cmd = RX_PAUSE;
    421	}
    422
    423	return imx_rpmsg_insert_workqueue(substream, msg, info);
    424}
    425
    426static int imx_rpmsg_terminate_all(struct snd_soc_component *component,
    427				   struct snd_pcm_substream *substream)
    428{
    429	struct rpmsg_info *info = dev_get_drvdata(component->dev);
    430	struct rpmsg_msg *msg;
    431	int cmd;
    432
    433	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
    434		msg = &info->msg[TX_TERMINATE];
    435		msg->s_msg.header.cmd = TX_TERMINATE;
    436		/* Clear buffer count*/
    437		cmd = TX_PERIOD_DONE + MSG_TYPE_A_NUM;
    438		info->msg[cmd].s_msg.param.buffer_tail = 0;
    439		info->msg[cmd].r_msg.param.buffer_tail = 0;
    440		info->msg[TX_POINTER].r_msg.param.buffer_offset = 0;
    441	} else {
    442		msg = &info->msg[RX_TERMINATE];
    443		msg->s_msg.header.cmd = RX_TERMINATE;
    444		/* Clear buffer count*/
    445		cmd = RX_PERIOD_DONE + MSG_TYPE_A_NUM;
    446		info->msg[cmd].s_msg.param.buffer_tail = 0;
    447		info->msg[cmd].r_msg.param.buffer_tail = 0;
    448		info->msg[RX_POINTER].r_msg.param.buffer_offset = 0;
    449	}
    450
    451	del_timer(&info->stream_timer[substream->stream].timer);
    452
    453	return imx_rpmsg_insert_workqueue(substream, msg, info);
    454}
    455
    456static int imx_rpmsg_pcm_trigger(struct snd_soc_component *component,
    457				 struct snd_pcm_substream *substream, int cmd)
    458{
    459	struct snd_pcm_runtime *runtime = substream->runtime;
    460	struct snd_soc_pcm_runtime *rtd = substream->private_data;
    461	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    462	struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
    463	int ret = 0;
    464
    465	switch (cmd) {
    466	case SNDRV_PCM_TRIGGER_START:
    467		ret = imx_rpmsg_prepare_and_submit(component, substream);
    468		if (ret)
    469			return ret;
    470		ret = imx_rpmsg_async_issue_pending(component, substream);
    471		break;
    472	case SNDRV_PCM_TRIGGER_RESUME:
    473		if (rpmsg->force_lpa)
    474			break;
    475		fallthrough;
    476	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
    477		ret = imx_rpmsg_restart(component, substream);
    478		break;
    479	case SNDRV_PCM_TRIGGER_SUSPEND:
    480		if (!rpmsg->force_lpa) {
    481			if (runtime->info & SNDRV_PCM_INFO_PAUSE)
    482				ret = imx_rpmsg_pause(component, substream);
    483			else
    484				ret = imx_rpmsg_terminate_all(component, substream);
    485		}
    486		break;
    487	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
    488		ret = imx_rpmsg_pause(component, substream);
    489		break;
    490	case SNDRV_PCM_TRIGGER_STOP:
    491		ret = imx_rpmsg_terminate_all(component, substream);
    492		break;
    493	default:
    494		return -EINVAL;
    495	}
    496
    497	if (ret)
    498		return ret;
    499
    500	return 0;
    501}
    502
    503/*
    504 * imx_rpmsg_pcm_ack
    505 *
    506 * Send the period index to M core through rpmsg, but not send
    507 * all the period index to M core, reduce some unnessesary msg
    508 * to reduce the pressure of rpmsg bandwidth.
    509 */
    510static int imx_rpmsg_pcm_ack(struct snd_soc_component *component,
    511			     struct snd_pcm_substream *substream)
    512{
    513	struct snd_pcm_runtime *runtime = substream->runtime;
    514	struct snd_soc_pcm_runtime *rtd = substream->private_data;
    515	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    516	struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
    517	struct rpmsg_info *info = dev_get_drvdata(component->dev);
    518	snd_pcm_uframes_t period_size = runtime->period_size;
    519	snd_pcm_sframes_t avail;
    520	struct timer_list *timer;
    521	struct rpmsg_msg *msg;
    522	unsigned long flags;
    523	int buffer_tail = 0;
    524	int written_num;
    525
    526	if (!rpmsg->force_lpa)
    527		return 0;
    528
    529	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
    530		msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
    531		msg->s_msg.header.cmd = TX_PERIOD_DONE;
    532	} else {
    533		msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
    534		msg->s_msg.header.cmd = RX_PERIOD_DONE;
    535	}
    536
    537	msg->s_msg.header.type = MSG_TYPE_C;
    538
    539	buffer_tail = (frames_to_bytes(runtime, runtime->control->appl_ptr) %
    540		       snd_pcm_lib_buffer_bytes(substream));
    541	buffer_tail = buffer_tail / snd_pcm_lib_period_bytes(substream);
    542
    543	/* There is update for period index */
    544	if (buffer_tail != msg->s_msg.param.buffer_tail) {
    545		written_num = buffer_tail - msg->s_msg.param.buffer_tail;
    546		if (written_num < 0)
    547			written_num += runtime->periods;
    548
    549		msg->s_msg.param.buffer_tail = buffer_tail;
    550
    551		/* The notification message is updated to latest */
    552		spin_lock_irqsave(&info->lock[substream->stream], flags);
    553		memcpy(&info->notify[substream->stream], msg,
    554		       sizeof(struct rpmsg_s_msg));
    555		info->notify_updated[substream->stream] = true;
    556		spin_unlock_irqrestore(&info->lock[substream->stream], flags);
    557
    558		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
    559			avail = snd_pcm_playback_hw_avail(runtime);
    560		else
    561			avail = snd_pcm_capture_hw_avail(runtime);
    562
    563		timer = &info->stream_timer[substream->stream].timer;
    564		/*
    565		 * If the data in the buffer is less than one period before
    566		 * this fill, which means the data may not enough on M
    567		 * core side, we need to send message immediately to let
    568		 * M core know the pointer is updated.
    569		 * if there is more than one period data in the buffer before
    570		 * this fill, which means the data is enough on M core side,
    571		 * we can delay one period (using timer) to send the message
    572		 * for reduce the message number in workqueue, because the
    573		 * pointer may be updated by ack function later, we can
    574		 * send latest pointer to M core side.
    575		 */
    576		if ((avail - written_num * period_size) <= period_size) {
    577			imx_rpmsg_insert_workqueue(substream, msg, info);
    578		} else if (rpmsg->force_lpa && !timer_pending(timer)) {
    579			int time_msec;
    580
    581			time_msec = (int)(runtime->period_size * 1000 / runtime->rate);
    582			mod_timer(timer, jiffies + msecs_to_jiffies(time_msec));
    583		}
    584	}
    585
    586	return 0;
    587}
    588
    589static int imx_rpmsg_pcm_new(struct snd_soc_component *component,
    590			     struct snd_soc_pcm_runtime *rtd)
    591{
    592	struct snd_card *card = rtd->card->snd_card;
    593	struct snd_pcm *pcm = rtd->pcm;
    594	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    595	struct fsl_rpmsg *rpmsg = dev_get_drvdata(cpu_dai->dev);
    596	int ret;
    597
    598	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
    599	if (ret)
    600		return ret;
    601
    602	imx_rpmsg_pcm_hardware.buffer_bytes_max = rpmsg->buffer_size;
    603	return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_WC,
    604					    pcm->card->dev, rpmsg->buffer_size);
    605}
    606
    607static const struct snd_soc_component_driver imx_rpmsg_soc_component = {
    608	.name		= IMX_PCM_DRV_NAME,
    609	.pcm_construct	= imx_rpmsg_pcm_new,
    610	.open		= imx_rpmsg_pcm_open,
    611	.close		= imx_rpmsg_pcm_close,
    612	.hw_params	= imx_rpmsg_pcm_hw_params,
    613	.trigger	= imx_rpmsg_pcm_trigger,
    614	.pointer	= imx_rpmsg_pcm_pointer,
    615	.ack		= imx_rpmsg_pcm_ack,
    616	.prepare	= imx_rpmsg_pcm_prepare,
    617};
    618
    619static void imx_rpmsg_pcm_work(struct work_struct *work)
    620{
    621	struct work_of_rpmsg *work_of_rpmsg;
    622	bool is_notification = false;
    623	struct rpmsg_info *info;
    624	struct rpmsg_msg msg;
    625	unsigned long flags;
    626
    627	work_of_rpmsg = container_of(work, struct work_of_rpmsg, work);
    628	info = work_of_rpmsg->info;
    629
    630	/*
    631	 * Every work in the work queue, first we check if there
    632	 * is update for period is filled, because there may be not
    633	 * enough data in M core side, need to let M core know
    634	 * data is updated immediately.
    635	 */
    636	spin_lock_irqsave(&info->lock[TX], flags);
    637	if (info->notify_updated[TX]) {
    638		memcpy(&msg, &info->notify[TX], sizeof(struct rpmsg_s_msg));
    639		info->notify_updated[TX] = false;
    640		spin_unlock_irqrestore(&info->lock[TX], flags);
    641		info->send_message(&msg, info);
    642	} else {
    643		spin_unlock_irqrestore(&info->lock[TX], flags);
    644	}
    645
    646	spin_lock_irqsave(&info->lock[RX], flags);
    647	if (info->notify_updated[RX]) {
    648		memcpy(&msg, &info->notify[RX], sizeof(struct rpmsg_s_msg));
    649		info->notify_updated[RX] = false;
    650		spin_unlock_irqrestore(&info->lock[RX], flags);
    651		info->send_message(&msg, info);
    652	} else {
    653		spin_unlock_irqrestore(&info->lock[RX], flags);
    654	}
    655
    656	/* Skip the notification message for it has been processed above */
    657	if (work_of_rpmsg->msg.s_msg.header.type == MSG_TYPE_C &&
    658	    (work_of_rpmsg->msg.s_msg.header.cmd == TX_PERIOD_DONE ||
    659	     work_of_rpmsg->msg.s_msg.header.cmd == RX_PERIOD_DONE))
    660		is_notification = true;
    661
    662	if (!is_notification)
    663		info->send_message(&work_of_rpmsg->msg, info);
    664
    665	/* update read index */
    666	spin_lock_irqsave(&info->wq_lock, flags);
    667	info->work_read_index++;
    668	info->work_read_index %= WORK_MAX_NUM;
    669	spin_unlock_irqrestore(&info->wq_lock, flags);
    670}
    671
    672static int imx_rpmsg_pcm_probe(struct platform_device *pdev)
    673{
    674	struct snd_soc_component *component;
    675	struct rpmsg_info *info;
    676	int ret, i;
    677
    678	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
    679	if (!info)
    680		return -ENOMEM;
    681
    682	platform_set_drvdata(pdev, info);
    683
    684	info->rpdev = container_of(pdev->dev.parent, struct rpmsg_device, dev);
    685	info->dev = &pdev->dev;
    686	/* Setup work queue */
    687	info->rpmsg_wq = alloc_ordered_workqueue("rpmsg_audio",
    688						 WQ_HIGHPRI |
    689						 WQ_UNBOUND |
    690						 WQ_FREEZABLE);
    691	if (!info->rpmsg_wq) {
    692		dev_err(&pdev->dev, "workqueue create failed\n");
    693		return -ENOMEM;
    694	}
    695
    696	/* Write index initialize 1, make it differ with the read index */
    697	info->work_write_index = 1;
    698	info->send_message = imx_rpmsg_pcm_send_message;
    699
    700	for (i = 0; i < WORK_MAX_NUM; i++) {
    701		INIT_WORK(&info->work_list[i].work, imx_rpmsg_pcm_work);
    702		info->work_list[i].info = info;
    703	}
    704
    705	/* Initialize msg */
    706	for (i = 0; i < MSG_MAX_NUM; i++) {
    707		info->msg[i].s_msg.header.cate  = IMX_RPMSG_AUDIO;
    708		info->msg[i].s_msg.header.major = IMX_RMPSG_MAJOR;
    709		info->msg[i].s_msg.header.minor = IMX_RMPSG_MINOR;
    710		info->msg[i].s_msg.header.type  = MSG_TYPE_A;
    711		info->msg[i].s_msg.param.audioindex = 0;
    712	}
    713
    714	init_completion(&info->cmd_complete);
    715	mutex_init(&info->msg_lock);
    716	spin_lock_init(&info->lock[TX]);
    717	spin_lock_init(&info->lock[RX]);
    718	spin_lock_init(&info->wq_lock);
    719
    720	ret = devm_snd_soc_register_component(&pdev->dev,
    721					      &imx_rpmsg_soc_component,
    722					      NULL, 0);
    723	if (ret)
    724		goto fail;
    725
    726	component = snd_soc_lookup_component(&pdev->dev, IMX_PCM_DRV_NAME);
    727	if (!component) {
    728		ret = -EINVAL;
    729		goto fail;
    730	}
    731#ifdef CONFIG_DEBUG_FS
    732	component->debugfs_prefix = "rpmsg";
    733#endif
    734
    735	return 0;
    736
    737fail:
    738	if (info->rpmsg_wq)
    739		destroy_workqueue(info->rpmsg_wq);
    740
    741	return ret;
    742}
    743
    744static int imx_rpmsg_pcm_remove(struct platform_device *pdev)
    745{
    746	struct rpmsg_info *info = platform_get_drvdata(pdev);
    747
    748	if (info->rpmsg_wq)
    749		destroy_workqueue(info->rpmsg_wq);
    750
    751	return 0;
    752}
    753
    754#ifdef CONFIG_PM
    755static int imx_rpmsg_pcm_runtime_resume(struct device *dev)
    756{
    757	struct rpmsg_info *info = dev_get_drvdata(dev);
    758
    759	cpu_latency_qos_add_request(&info->pm_qos_req, 0);
    760
    761	return 0;
    762}
    763
    764static int imx_rpmsg_pcm_runtime_suspend(struct device *dev)
    765{
    766	struct rpmsg_info *info = dev_get_drvdata(dev);
    767
    768	cpu_latency_qos_remove_request(&info->pm_qos_req);
    769
    770	return 0;
    771}
    772#endif
    773
    774#ifdef CONFIG_PM_SLEEP
    775static int imx_rpmsg_pcm_suspend(struct device *dev)
    776{
    777	struct rpmsg_info *info = dev_get_drvdata(dev);
    778	struct rpmsg_msg *rpmsg_tx;
    779	struct rpmsg_msg *rpmsg_rx;
    780
    781	rpmsg_tx = &info->msg[TX_SUSPEND];
    782	rpmsg_rx = &info->msg[RX_SUSPEND];
    783
    784	rpmsg_tx->s_msg.header.cmd = TX_SUSPEND;
    785	info->send_message(rpmsg_tx, info);
    786
    787	rpmsg_rx->s_msg.header.cmd = RX_SUSPEND;
    788	info->send_message(rpmsg_rx, info);
    789
    790	return 0;
    791}
    792
    793static int imx_rpmsg_pcm_resume(struct device *dev)
    794{
    795	struct rpmsg_info *info = dev_get_drvdata(dev);
    796	struct rpmsg_msg *rpmsg_tx;
    797	struct rpmsg_msg *rpmsg_rx;
    798
    799	rpmsg_tx = &info->msg[TX_RESUME];
    800	rpmsg_rx = &info->msg[RX_RESUME];
    801
    802	rpmsg_tx->s_msg.header.cmd = TX_RESUME;
    803	info->send_message(rpmsg_tx, info);
    804
    805	rpmsg_rx->s_msg.header.cmd = RX_RESUME;
    806	info->send_message(rpmsg_rx, info);
    807
    808	return 0;
    809}
    810#endif /* CONFIG_PM_SLEEP */
    811
    812static const struct dev_pm_ops imx_rpmsg_pcm_pm_ops = {
    813	SET_RUNTIME_PM_OPS(imx_rpmsg_pcm_runtime_suspend,
    814			   imx_rpmsg_pcm_runtime_resume,
    815			   NULL)
    816	SET_SYSTEM_SLEEP_PM_OPS(imx_rpmsg_pcm_suspend,
    817				imx_rpmsg_pcm_resume)
    818};
    819
    820static struct platform_driver imx_pcm_rpmsg_driver = {
    821	.probe  = imx_rpmsg_pcm_probe,
    822	.remove	= imx_rpmsg_pcm_remove,
    823	.driver = {
    824		.name = IMX_PCM_DRV_NAME,
    825		.pm = &imx_rpmsg_pcm_pm_ops,
    826	},
    827};
    828module_platform_driver(imx_pcm_rpmsg_driver);
    829
    830MODULE_DESCRIPTION("Freescale SoC Audio RPMSG PCM interface");
    831MODULE_AUTHOR("Shengjiu Wang <shengjiu.wang@nxp.com>");
    832MODULE_ALIAS("platform:" IMX_PCM_DRV_NAME);
    833MODULE_LICENSE("GPL v2");