xref: /openbmc/linux/drivers/media/platform/st/sti/delta/delta-ipc.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1*e7b8153eSMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0
2*e7b8153eSMauro Carvalho Chehab /*
3*e7b8153eSMauro Carvalho Chehab  * Copyright (C) STMicroelectronics SA 2015
4*e7b8153eSMauro Carvalho Chehab  * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
5*e7b8153eSMauro Carvalho Chehab  */
6*e7b8153eSMauro Carvalho Chehab 
7*e7b8153eSMauro Carvalho Chehab #include <linux/rpmsg.h>
8*e7b8153eSMauro Carvalho Chehab 
9*e7b8153eSMauro Carvalho Chehab #include "delta.h"
10*e7b8153eSMauro Carvalho Chehab #include "delta-ipc.h"
11*e7b8153eSMauro Carvalho Chehab #include "delta-mem.h"
12*e7b8153eSMauro Carvalho Chehab 
13*e7b8153eSMauro Carvalho Chehab #define IPC_TIMEOUT 100
14*e7b8153eSMauro Carvalho Chehab #define IPC_SANITY_TAG 0xDEADBEEF
15*e7b8153eSMauro Carvalho Chehab 
16*e7b8153eSMauro Carvalho Chehab enum delta_ipc_fw_command {
17*e7b8153eSMauro Carvalho Chehab 	DELTA_IPC_OPEN,
18*e7b8153eSMauro Carvalho Chehab 	DELTA_IPC_SET_STREAM,
19*e7b8153eSMauro Carvalho Chehab 	DELTA_IPC_DECODE,
20*e7b8153eSMauro Carvalho Chehab 	DELTA_IPC_CLOSE
21*e7b8153eSMauro Carvalho Chehab };
22*e7b8153eSMauro Carvalho Chehab 
23*e7b8153eSMauro Carvalho Chehab #define to_rpmsg_driver(__drv) container_of(__drv, struct rpmsg_driver, drv)
24*e7b8153eSMauro Carvalho Chehab #define to_delta(__d) container_of(__d, struct delta_dev, rpmsg_driver)
25*e7b8153eSMauro Carvalho Chehab 
26*e7b8153eSMauro Carvalho Chehab #define to_ctx(hdl) ((struct delta_ipc_ctx *)hdl)
27*e7b8153eSMauro Carvalho Chehab #define to_pctx(ctx) container_of(ctx, struct delta_ctx, ipc_ctx)
28*e7b8153eSMauro Carvalho Chehab 
29*e7b8153eSMauro Carvalho Chehab struct delta_ipc_header_msg {
30*e7b8153eSMauro Carvalho Chehab 	u32 tag;
31*e7b8153eSMauro Carvalho Chehab 	void *host_hdl;
32*e7b8153eSMauro Carvalho Chehab 	u32 copro_hdl;
33*e7b8153eSMauro Carvalho Chehab 	u32 command;
34*e7b8153eSMauro Carvalho Chehab };
35*e7b8153eSMauro Carvalho Chehab 
36*e7b8153eSMauro Carvalho Chehab #define to_host_hdl(ctx) ((void *)ctx)
37*e7b8153eSMauro Carvalho Chehab 
38*e7b8153eSMauro Carvalho Chehab #define msg_to_ctx(msg) ((struct delta_ipc_ctx *)(msg)->header.host_hdl)
39*e7b8153eSMauro Carvalho Chehab #define msg_to_copro_hdl(msg) ((msg)->header.copro_hdl)
40*e7b8153eSMauro Carvalho Chehab 
to_paddr(struct delta_ipc_ctx * ctx,void * vaddr)41*e7b8153eSMauro Carvalho Chehab static inline dma_addr_t to_paddr(struct delta_ipc_ctx *ctx, void *vaddr)
42*e7b8153eSMauro Carvalho Chehab {
43*e7b8153eSMauro Carvalho Chehab 	return (ctx->ipc_buf->paddr + (vaddr - ctx->ipc_buf->vaddr));
44*e7b8153eSMauro Carvalho Chehab }
45*e7b8153eSMauro Carvalho Chehab 
is_valid_data(struct delta_ipc_ctx * ctx,void * data,u32 size)46*e7b8153eSMauro Carvalho Chehab static inline bool is_valid_data(struct delta_ipc_ctx *ctx,
47*e7b8153eSMauro Carvalho Chehab 				 void *data, u32 size)
48*e7b8153eSMauro Carvalho Chehab {
49*e7b8153eSMauro Carvalho Chehab 	return ((data >= ctx->ipc_buf->vaddr) &&
50*e7b8153eSMauro Carvalho Chehab 		((data + size) <= (ctx->ipc_buf->vaddr + ctx->ipc_buf->size)));
51*e7b8153eSMauro Carvalho Chehab }
52*e7b8153eSMauro Carvalho Chehab 
53*e7b8153eSMauro Carvalho Chehab /*
54*e7b8153eSMauro Carvalho Chehab  * IPC shared memory (@ipc_buf_size, @ipc_buf_paddr) is sent to copro
55*e7b8153eSMauro Carvalho Chehab  * at each instance opening. This memory is allocated by IPC client
56*e7b8153eSMauro Carvalho Chehab  * and given through delta_ipc_open(). All messages parameters
57*e7b8153eSMauro Carvalho Chehab  * (open, set_stream, decode) will have their phy address within
58*e7b8153eSMauro Carvalho Chehab  * this IPC shared memory, avoiding de-facto recopies inside delta-ipc.
59*e7b8153eSMauro Carvalho Chehab  * All the below messages structures are used on both host and firmware
60*e7b8153eSMauro Carvalho Chehab  * side and are packed (use only of 32 bits size fields in messages
61*e7b8153eSMauro Carvalho Chehab  * structures to ensure packing):
62*e7b8153eSMauro Carvalho Chehab  * - struct delta_ipc_open_msg
63*e7b8153eSMauro Carvalho Chehab  * - struct delta_ipc_set_stream_msg
64*e7b8153eSMauro Carvalho Chehab  * - struct delta_ipc_decode_msg
65*e7b8153eSMauro Carvalho Chehab  * - struct delta_ipc_close_msg
66*e7b8153eSMauro Carvalho Chehab  * - struct delta_ipc_cb_msg
67*e7b8153eSMauro Carvalho Chehab  */
68*e7b8153eSMauro Carvalho Chehab struct delta_ipc_open_msg {
69*e7b8153eSMauro Carvalho Chehab 	struct delta_ipc_header_msg header;
70*e7b8153eSMauro Carvalho Chehab 	u32 ipc_buf_size;
71*e7b8153eSMauro Carvalho Chehab 	dma_addr_t ipc_buf_paddr;
72*e7b8153eSMauro Carvalho Chehab 	char name[32];
73*e7b8153eSMauro Carvalho Chehab 	u32 param_size;
74*e7b8153eSMauro Carvalho Chehab 	dma_addr_t param_paddr;
75*e7b8153eSMauro Carvalho Chehab };
76*e7b8153eSMauro Carvalho Chehab 
77*e7b8153eSMauro Carvalho Chehab struct delta_ipc_set_stream_msg {
78*e7b8153eSMauro Carvalho Chehab 	struct delta_ipc_header_msg header;
79*e7b8153eSMauro Carvalho Chehab 	u32 param_size;
80*e7b8153eSMauro Carvalho Chehab 	dma_addr_t param_paddr;
81*e7b8153eSMauro Carvalho Chehab };
82*e7b8153eSMauro Carvalho Chehab 
83*e7b8153eSMauro Carvalho Chehab struct delta_ipc_decode_msg {
84*e7b8153eSMauro Carvalho Chehab 	struct delta_ipc_header_msg header;
85*e7b8153eSMauro Carvalho Chehab 	u32 param_size;
86*e7b8153eSMauro Carvalho Chehab 	dma_addr_t param_paddr;
87*e7b8153eSMauro Carvalho Chehab 	u32 status_size;
88*e7b8153eSMauro Carvalho Chehab 	dma_addr_t status_paddr;
89*e7b8153eSMauro Carvalho Chehab };
90*e7b8153eSMauro Carvalho Chehab 
91*e7b8153eSMauro Carvalho Chehab struct delta_ipc_close_msg {
92*e7b8153eSMauro Carvalho Chehab 	struct delta_ipc_header_msg header;
93*e7b8153eSMauro Carvalho Chehab };
94*e7b8153eSMauro Carvalho Chehab 
95*e7b8153eSMauro Carvalho Chehab struct delta_ipc_cb_msg {
96*e7b8153eSMauro Carvalho Chehab 	struct delta_ipc_header_msg header;
97*e7b8153eSMauro Carvalho Chehab 	int err;
98*e7b8153eSMauro Carvalho Chehab };
99*e7b8153eSMauro Carvalho Chehab 
build_msg_header(struct delta_ipc_ctx * ctx,enum delta_ipc_fw_command command,struct delta_ipc_header_msg * header)100*e7b8153eSMauro Carvalho Chehab static void build_msg_header(struct delta_ipc_ctx *ctx,
101*e7b8153eSMauro Carvalho Chehab 			     enum delta_ipc_fw_command command,
102*e7b8153eSMauro Carvalho Chehab 			     struct delta_ipc_header_msg *header)
103*e7b8153eSMauro Carvalho Chehab {
104*e7b8153eSMauro Carvalho Chehab 	header->tag = IPC_SANITY_TAG;
105*e7b8153eSMauro Carvalho Chehab 	header->host_hdl = to_host_hdl(ctx);
106*e7b8153eSMauro Carvalho Chehab 	header->copro_hdl = ctx->copro_hdl;
107*e7b8153eSMauro Carvalho Chehab 	header->command = command;
108*e7b8153eSMauro Carvalho Chehab }
109*e7b8153eSMauro Carvalho Chehab 
delta_ipc_open(struct delta_ctx * pctx,const char * name,struct delta_ipc_param * param,u32 ipc_buf_size,struct delta_buf ** ipc_buf,void ** hdl)110*e7b8153eSMauro Carvalho Chehab int delta_ipc_open(struct delta_ctx *pctx, const char *name,
111*e7b8153eSMauro Carvalho Chehab 		   struct delta_ipc_param *param, u32 ipc_buf_size,
112*e7b8153eSMauro Carvalho Chehab 		   struct delta_buf **ipc_buf, void **hdl)
113*e7b8153eSMauro Carvalho Chehab {
114*e7b8153eSMauro Carvalho Chehab 	struct delta_dev *delta = pctx->dev;
115*e7b8153eSMauro Carvalho Chehab 	struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
116*e7b8153eSMauro Carvalho Chehab 	struct delta_ipc_ctx *ctx = &pctx->ipc_ctx;
117*e7b8153eSMauro Carvalho Chehab 	struct delta_ipc_open_msg msg;
118*e7b8153eSMauro Carvalho Chehab 	struct delta_buf *buf = &ctx->ipc_buf_struct;
119*e7b8153eSMauro Carvalho Chehab 	int ret;
120*e7b8153eSMauro Carvalho Chehab 
121*e7b8153eSMauro Carvalho Chehab 	if (!rpmsg_device) {
122*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
123*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to open, rpmsg is not initialized\n",
124*e7b8153eSMauro Carvalho Chehab 			pctx->name);
125*e7b8153eSMauro Carvalho Chehab 		pctx->sys_errors++;
126*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
127*e7b8153eSMauro Carvalho Chehab 	}
128*e7b8153eSMauro Carvalho Chehab 
129*e7b8153eSMauro Carvalho Chehab 	if (!name) {
130*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
131*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to open, no name given\n",
132*e7b8153eSMauro Carvalho Chehab 			pctx->name);
133*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
134*e7b8153eSMauro Carvalho Chehab 	}
135*e7b8153eSMauro Carvalho Chehab 
136*e7b8153eSMauro Carvalho Chehab 	if (!param || !param->data || !param->size) {
137*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
138*e7b8153eSMauro Carvalho Chehab 			"%s  ipc: failed to open, empty parameter\n",
139*e7b8153eSMauro Carvalho Chehab 			pctx->name);
140*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
141*e7b8153eSMauro Carvalho Chehab 	}
142*e7b8153eSMauro Carvalho Chehab 
143*e7b8153eSMauro Carvalho Chehab 	if (!ipc_buf_size) {
144*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
145*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to open, no size given for ipc buffer\n",
146*e7b8153eSMauro Carvalho Chehab 			pctx->name);
147*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
148*e7b8153eSMauro Carvalho Chehab 	}
149*e7b8153eSMauro Carvalho Chehab 
150*e7b8153eSMauro Carvalho Chehab 	if (param->size > ipc_buf_size) {
151*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
152*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to open, too large ipc parameter (%d bytes while max %d expected)\n",
153*e7b8153eSMauro Carvalho Chehab 			pctx->name,
154*e7b8153eSMauro Carvalho Chehab 			param->size, ctx->ipc_buf->size);
155*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
156*e7b8153eSMauro Carvalho Chehab 	}
157*e7b8153eSMauro Carvalho Chehab 
158*e7b8153eSMauro Carvalho Chehab 	/* init */
159*e7b8153eSMauro Carvalho Chehab 	init_completion(&ctx->done);
160*e7b8153eSMauro Carvalho Chehab 
161*e7b8153eSMauro Carvalho Chehab 	/*
162*e7b8153eSMauro Carvalho Chehab 	 * allocation of contiguous buffer for
163*e7b8153eSMauro Carvalho Chehab 	 * data of commands exchanged between
164*e7b8153eSMauro Carvalho Chehab 	 * host and firmware coprocessor
165*e7b8153eSMauro Carvalho Chehab 	 */
166*e7b8153eSMauro Carvalho Chehab 	ret = hw_alloc(pctx, ipc_buf_size,
167*e7b8153eSMauro Carvalho Chehab 		       "ipc data buffer", buf);
168*e7b8153eSMauro Carvalho Chehab 	if (ret)
169*e7b8153eSMauro Carvalho Chehab 		return ret;
170*e7b8153eSMauro Carvalho Chehab 	ctx->ipc_buf = buf;
171*e7b8153eSMauro Carvalho Chehab 
172*e7b8153eSMauro Carvalho Chehab 	/* build rpmsg message */
173*e7b8153eSMauro Carvalho Chehab 	build_msg_header(ctx, DELTA_IPC_OPEN, &msg.header);
174*e7b8153eSMauro Carvalho Chehab 
175*e7b8153eSMauro Carvalho Chehab 	msg.ipc_buf_size = ipc_buf_size;
176*e7b8153eSMauro Carvalho Chehab 	msg.ipc_buf_paddr = ctx->ipc_buf->paddr;
177*e7b8153eSMauro Carvalho Chehab 
178*e7b8153eSMauro Carvalho Chehab 	strscpy(msg.name, name, sizeof(msg.name));
179*e7b8153eSMauro Carvalho Chehab 
180*e7b8153eSMauro Carvalho Chehab 	msg.param_size = param->size;
181*e7b8153eSMauro Carvalho Chehab 	memcpy(ctx->ipc_buf->vaddr, param->data, msg.param_size);
182*e7b8153eSMauro Carvalho Chehab 	msg.param_paddr = ctx->ipc_buf->paddr;
183*e7b8153eSMauro Carvalho Chehab 
184*e7b8153eSMauro Carvalho Chehab 	/* send it */
185*e7b8153eSMauro Carvalho Chehab 	ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
186*e7b8153eSMauro Carvalho Chehab 	if (ret) {
187*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
188*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to open, rpmsg_send failed (%d) for DELTA_IPC_OPEN (name=%s, size=%d, data=%p)\n",
189*e7b8153eSMauro Carvalho Chehab 			pctx->name,
190*e7b8153eSMauro Carvalho Chehab 			ret, name, param->size, param->data);
191*e7b8153eSMauro Carvalho Chehab 		goto err;
192*e7b8153eSMauro Carvalho Chehab 	}
193*e7b8153eSMauro Carvalho Chehab 
194*e7b8153eSMauro Carvalho Chehab 	/* wait for acknowledge */
195*e7b8153eSMauro Carvalho Chehab 	if (!wait_for_completion_timeout
196*e7b8153eSMauro Carvalho Chehab 	    (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
197*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
198*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to open, timeout waiting for DELTA_IPC_OPEN callback (name=%s, size=%d, data=%p)\n",
199*e7b8153eSMauro Carvalho Chehab 			pctx->name,
200*e7b8153eSMauro Carvalho Chehab 			name, param->size, param->data);
201*e7b8153eSMauro Carvalho Chehab 		ret = -ETIMEDOUT;
202*e7b8153eSMauro Carvalho Chehab 		goto err;
203*e7b8153eSMauro Carvalho Chehab 	}
204*e7b8153eSMauro Carvalho Chehab 
205*e7b8153eSMauro Carvalho Chehab 	/* command completed, check error */
206*e7b8153eSMauro Carvalho Chehab 	if (ctx->cb_err) {
207*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
208*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to open, DELTA_IPC_OPEN completed but with error (%d) (name=%s, size=%d, data=%p)\n",
209*e7b8153eSMauro Carvalho Chehab 			pctx->name,
210*e7b8153eSMauro Carvalho Chehab 			ctx->cb_err, name, param->size, param->data);
211*e7b8153eSMauro Carvalho Chehab 		ret = -EIO;
212*e7b8153eSMauro Carvalho Chehab 		goto err;
213*e7b8153eSMauro Carvalho Chehab 	}
214*e7b8153eSMauro Carvalho Chehab 
215*e7b8153eSMauro Carvalho Chehab 	*ipc_buf = ctx->ipc_buf;
216*e7b8153eSMauro Carvalho Chehab 	*hdl = (void *)ctx;
217*e7b8153eSMauro Carvalho Chehab 
218*e7b8153eSMauro Carvalho Chehab 	return 0;
219*e7b8153eSMauro Carvalho Chehab 
220*e7b8153eSMauro Carvalho Chehab err:
221*e7b8153eSMauro Carvalho Chehab 	pctx->sys_errors++;
222*e7b8153eSMauro Carvalho Chehab 	hw_free(pctx, ctx->ipc_buf);
223*e7b8153eSMauro Carvalho Chehab 	ctx->ipc_buf = NULL;
224*e7b8153eSMauro Carvalho Chehab 
225*e7b8153eSMauro Carvalho Chehab 	return ret;
226*e7b8153eSMauro Carvalho Chehab };
227*e7b8153eSMauro Carvalho Chehab 
delta_ipc_set_stream(void * hdl,struct delta_ipc_param * param)228*e7b8153eSMauro Carvalho Chehab int delta_ipc_set_stream(void *hdl, struct delta_ipc_param *param)
229*e7b8153eSMauro Carvalho Chehab {
230*e7b8153eSMauro Carvalho Chehab 	struct delta_ipc_ctx *ctx = to_ctx(hdl);
231*e7b8153eSMauro Carvalho Chehab 	struct delta_ctx *pctx = to_pctx(ctx);
232*e7b8153eSMauro Carvalho Chehab 	struct delta_dev *delta = pctx->dev;
233*e7b8153eSMauro Carvalho Chehab 	struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
234*e7b8153eSMauro Carvalho Chehab 	struct delta_ipc_set_stream_msg msg;
235*e7b8153eSMauro Carvalho Chehab 	int ret;
236*e7b8153eSMauro Carvalho Chehab 
237*e7b8153eSMauro Carvalho Chehab 	if (!hdl) {
238*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
239*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to set stream, invalid ipc handle\n",
240*e7b8153eSMauro Carvalho Chehab 			pctx->name);
241*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
242*e7b8153eSMauro Carvalho Chehab 	}
243*e7b8153eSMauro Carvalho Chehab 
244*e7b8153eSMauro Carvalho Chehab 	if (!rpmsg_device) {
245*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
246*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to set stream, rpmsg is not initialized\n",
247*e7b8153eSMauro Carvalho Chehab 			pctx->name);
248*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
249*e7b8153eSMauro Carvalho Chehab 	}
250*e7b8153eSMauro Carvalho Chehab 
251*e7b8153eSMauro Carvalho Chehab 	if (!param || !param->data || !param->size) {
252*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
253*e7b8153eSMauro Carvalho Chehab 			"%s  ipc: failed to set stream, empty parameter\n",
254*e7b8153eSMauro Carvalho Chehab 			pctx->name);
255*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
256*e7b8153eSMauro Carvalho Chehab 	}
257*e7b8153eSMauro Carvalho Chehab 
258*e7b8153eSMauro Carvalho Chehab 	if (param->size > ctx->ipc_buf->size) {
259*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
260*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to set stream, too large ipc parameter(%d bytes while max %d expected)\n",
261*e7b8153eSMauro Carvalho Chehab 			pctx->name,
262*e7b8153eSMauro Carvalho Chehab 			param->size, ctx->ipc_buf->size);
263*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
264*e7b8153eSMauro Carvalho Chehab 	}
265*e7b8153eSMauro Carvalho Chehab 
266*e7b8153eSMauro Carvalho Chehab 	if (!is_valid_data(ctx, param->data, param->size)) {
267*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
268*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to set stream, parameter is not in expected address range (size=%d, data=%p not in %p..%p)\n",
269*e7b8153eSMauro Carvalho Chehab 			pctx->name,
270*e7b8153eSMauro Carvalho Chehab 			param->size,
271*e7b8153eSMauro Carvalho Chehab 			param->data,
272*e7b8153eSMauro Carvalho Chehab 			ctx->ipc_buf->vaddr,
273*e7b8153eSMauro Carvalho Chehab 			ctx->ipc_buf->vaddr + ctx->ipc_buf->size - 1);
274*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
275*e7b8153eSMauro Carvalho Chehab 	}
276*e7b8153eSMauro Carvalho Chehab 
277*e7b8153eSMauro Carvalho Chehab 	/* build rpmsg message */
278*e7b8153eSMauro Carvalho Chehab 	build_msg_header(ctx, DELTA_IPC_SET_STREAM, &msg.header);
279*e7b8153eSMauro Carvalho Chehab 
280*e7b8153eSMauro Carvalho Chehab 	msg.param_size = param->size;
281*e7b8153eSMauro Carvalho Chehab 	msg.param_paddr = to_paddr(ctx, param->data);
282*e7b8153eSMauro Carvalho Chehab 
283*e7b8153eSMauro Carvalho Chehab 	/* send it */
284*e7b8153eSMauro Carvalho Chehab 	ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
285*e7b8153eSMauro Carvalho Chehab 	if (ret) {
286*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
287*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to set stream, rpmsg_send failed (%d) for DELTA_IPC_SET_STREAM (size=%d, data=%p)\n",
288*e7b8153eSMauro Carvalho Chehab 			pctx->name,
289*e7b8153eSMauro Carvalho Chehab 			ret, param->size, param->data);
290*e7b8153eSMauro Carvalho Chehab 		pctx->sys_errors++;
291*e7b8153eSMauro Carvalho Chehab 		return ret;
292*e7b8153eSMauro Carvalho Chehab 	}
293*e7b8153eSMauro Carvalho Chehab 
294*e7b8153eSMauro Carvalho Chehab 	/* wait for acknowledge */
295*e7b8153eSMauro Carvalho Chehab 	if (!wait_for_completion_timeout
296*e7b8153eSMauro Carvalho Chehab 	    (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
297*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
298*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to set stream, timeout waiting for DELTA_IPC_SET_STREAM callback (size=%d, data=%p)\n",
299*e7b8153eSMauro Carvalho Chehab 			pctx->name,
300*e7b8153eSMauro Carvalho Chehab 			param->size, param->data);
301*e7b8153eSMauro Carvalho Chehab 		pctx->sys_errors++;
302*e7b8153eSMauro Carvalho Chehab 		return -ETIMEDOUT;
303*e7b8153eSMauro Carvalho Chehab 	}
304*e7b8153eSMauro Carvalho Chehab 
305*e7b8153eSMauro Carvalho Chehab 	/* command completed, check status */
306*e7b8153eSMauro Carvalho Chehab 	if (ctx->cb_err) {
307*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
308*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to set stream, DELTA_IPC_SET_STREAM completed but with error (%d) (size=%d, data=%p)\n",
309*e7b8153eSMauro Carvalho Chehab 			pctx->name,
310*e7b8153eSMauro Carvalho Chehab 			ctx->cb_err, param->size, param->data);
311*e7b8153eSMauro Carvalho Chehab 		pctx->sys_errors++;
312*e7b8153eSMauro Carvalho Chehab 		return -EIO;
313*e7b8153eSMauro Carvalho Chehab 	}
314*e7b8153eSMauro Carvalho Chehab 
315*e7b8153eSMauro Carvalho Chehab 	return 0;
316*e7b8153eSMauro Carvalho Chehab }
317*e7b8153eSMauro Carvalho Chehab 
delta_ipc_decode(void * hdl,struct delta_ipc_param * param,struct delta_ipc_param * status)318*e7b8153eSMauro Carvalho Chehab int delta_ipc_decode(void *hdl, struct delta_ipc_param *param,
319*e7b8153eSMauro Carvalho Chehab 		     struct delta_ipc_param *status)
320*e7b8153eSMauro Carvalho Chehab {
321*e7b8153eSMauro Carvalho Chehab 	struct delta_ipc_ctx *ctx = to_ctx(hdl);
322*e7b8153eSMauro Carvalho Chehab 	struct delta_ctx *pctx = to_pctx(ctx);
323*e7b8153eSMauro Carvalho Chehab 	struct delta_dev *delta = pctx->dev;
324*e7b8153eSMauro Carvalho Chehab 	struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
325*e7b8153eSMauro Carvalho Chehab 	struct delta_ipc_decode_msg msg;
326*e7b8153eSMauro Carvalho Chehab 	int ret;
327*e7b8153eSMauro Carvalho Chehab 
328*e7b8153eSMauro Carvalho Chehab 	if (!hdl) {
329*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
330*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to decode, invalid ipc handle\n",
331*e7b8153eSMauro Carvalho Chehab 			pctx->name);
332*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
333*e7b8153eSMauro Carvalho Chehab 	}
334*e7b8153eSMauro Carvalho Chehab 
335*e7b8153eSMauro Carvalho Chehab 	if (!rpmsg_device) {
336*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
337*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to decode, rpmsg is not initialized\n",
338*e7b8153eSMauro Carvalho Chehab 			pctx->name);
339*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
340*e7b8153eSMauro Carvalho Chehab 	}
341*e7b8153eSMauro Carvalho Chehab 
342*e7b8153eSMauro Carvalho Chehab 	if (!param || !param->data || !param->size) {
343*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
344*e7b8153eSMauro Carvalho Chehab 			"%s  ipc: failed to decode, empty parameter\n",
345*e7b8153eSMauro Carvalho Chehab 			pctx->name);
346*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
347*e7b8153eSMauro Carvalho Chehab 	}
348*e7b8153eSMauro Carvalho Chehab 
349*e7b8153eSMauro Carvalho Chehab 	if (!status || !status->data || !status->size) {
350*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
351*e7b8153eSMauro Carvalho Chehab 			"%s  ipc: failed to decode, empty status\n",
352*e7b8153eSMauro Carvalho Chehab 			pctx->name);
353*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
354*e7b8153eSMauro Carvalho Chehab 	}
355*e7b8153eSMauro Carvalho Chehab 
356*e7b8153eSMauro Carvalho Chehab 	if (param->size + status->size > ctx->ipc_buf->size) {
357*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
358*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to decode, too large ipc parameter (%d bytes (param) + %d bytes (status) while max %d expected)\n",
359*e7b8153eSMauro Carvalho Chehab 			pctx->name,
360*e7b8153eSMauro Carvalho Chehab 			param->size,
361*e7b8153eSMauro Carvalho Chehab 			status->size,
362*e7b8153eSMauro Carvalho Chehab 			ctx->ipc_buf->size);
363*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
364*e7b8153eSMauro Carvalho Chehab 	}
365*e7b8153eSMauro Carvalho Chehab 
366*e7b8153eSMauro Carvalho Chehab 	if (!is_valid_data(ctx, param->data, param->size)) {
367*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
368*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to decode, parameter is not in expected address range (size=%d, data=%p not in %p..%p)\n",
369*e7b8153eSMauro Carvalho Chehab 			pctx->name,
370*e7b8153eSMauro Carvalho Chehab 			param->size,
371*e7b8153eSMauro Carvalho Chehab 			param->data,
372*e7b8153eSMauro Carvalho Chehab 			ctx->ipc_buf->vaddr,
373*e7b8153eSMauro Carvalho Chehab 			ctx->ipc_buf->vaddr + ctx->ipc_buf->size - 1);
374*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
375*e7b8153eSMauro Carvalho Chehab 	}
376*e7b8153eSMauro Carvalho Chehab 
377*e7b8153eSMauro Carvalho Chehab 	if (!is_valid_data(ctx, status->data, status->size)) {
378*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
379*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to decode, status is not in expected address range (size=%d, data=%p not in %p..%p)\n",
380*e7b8153eSMauro Carvalho Chehab 			pctx->name,
381*e7b8153eSMauro Carvalho Chehab 			status->size,
382*e7b8153eSMauro Carvalho Chehab 			status->data,
383*e7b8153eSMauro Carvalho Chehab 			ctx->ipc_buf->vaddr,
384*e7b8153eSMauro Carvalho Chehab 			ctx->ipc_buf->vaddr + ctx->ipc_buf->size - 1);
385*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
386*e7b8153eSMauro Carvalho Chehab 	}
387*e7b8153eSMauro Carvalho Chehab 
388*e7b8153eSMauro Carvalho Chehab 	/* build rpmsg message */
389*e7b8153eSMauro Carvalho Chehab 	build_msg_header(ctx, DELTA_IPC_DECODE, &msg.header);
390*e7b8153eSMauro Carvalho Chehab 
391*e7b8153eSMauro Carvalho Chehab 	msg.param_size = param->size;
392*e7b8153eSMauro Carvalho Chehab 	msg.param_paddr = to_paddr(ctx, param->data);
393*e7b8153eSMauro Carvalho Chehab 
394*e7b8153eSMauro Carvalho Chehab 	msg.status_size = status->size;
395*e7b8153eSMauro Carvalho Chehab 	msg.status_paddr = to_paddr(ctx, status->data);
396*e7b8153eSMauro Carvalho Chehab 
397*e7b8153eSMauro Carvalho Chehab 	/* send it */
398*e7b8153eSMauro Carvalho Chehab 	ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
399*e7b8153eSMauro Carvalho Chehab 	if (ret) {
400*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
401*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to decode, rpmsg_send failed (%d) for DELTA_IPC_DECODE (size=%d, data=%p)\n",
402*e7b8153eSMauro Carvalho Chehab 			pctx->name,
403*e7b8153eSMauro Carvalho Chehab 			ret, param->size, param->data);
404*e7b8153eSMauro Carvalho Chehab 		pctx->sys_errors++;
405*e7b8153eSMauro Carvalho Chehab 		return ret;
406*e7b8153eSMauro Carvalho Chehab 	}
407*e7b8153eSMauro Carvalho Chehab 
408*e7b8153eSMauro Carvalho Chehab 	/* wait for acknowledge */
409*e7b8153eSMauro Carvalho Chehab 	if (!wait_for_completion_timeout
410*e7b8153eSMauro Carvalho Chehab 	    (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
411*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
412*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to decode, timeout waiting for DELTA_IPC_DECODE callback (size=%d, data=%p)\n",
413*e7b8153eSMauro Carvalho Chehab 			pctx->name,
414*e7b8153eSMauro Carvalho Chehab 			param->size, param->data);
415*e7b8153eSMauro Carvalho Chehab 		pctx->sys_errors++;
416*e7b8153eSMauro Carvalho Chehab 		return -ETIMEDOUT;
417*e7b8153eSMauro Carvalho Chehab 	}
418*e7b8153eSMauro Carvalho Chehab 
419*e7b8153eSMauro Carvalho Chehab 	/* command completed, check status */
420*e7b8153eSMauro Carvalho Chehab 	if (ctx->cb_err) {
421*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
422*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to decode, DELTA_IPC_DECODE completed but with error (%d) (size=%d, data=%p)\n",
423*e7b8153eSMauro Carvalho Chehab 			pctx->name,
424*e7b8153eSMauro Carvalho Chehab 			ctx->cb_err, param->size, param->data);
425*e7b8153eSMauro Carvalho Chehab 		pctx->sys_errors++;
426*e7b8153eSMauro Carvalho Chehab 		return -EIO;
427*e7b8153eSMauro Carvalho Chehab 	}
428*e7b8153eSMauro Carvalho Chehab 
429*e7b8153eSMauro Carvalho Chehab 	return 0;
430*e7b8153eSMauro Carvalho Chehab };
431*e7b8153eSMauro Carvalho Chehab 
delta_ipc_close(void * hdl)432*e7b8153eSMauro Carvalho Chehab void delta_ipc_close(void *hdl)
433*e7b8153eSMauro Carvalho Chehab {
434*e7b8153eSMauro Carvalho Chehab 	struct delta_ipc_ctx *ctx = to_ctx(hdl);
435*e7b8153eSMauro Carvalho Chehab 	struct delta_ctx *pctx = to_pctx(ctx);
436*e7b8153eSMauro Carvalho Chehab 	struct delta_dev *delta = pctx->dev;
437*e7b8153eSMauro Carvalho Chehab 	struct rpmsg_device *rpmsg_device = delta->rpmsg_device;
438*e7b8153eSMauro Carvalho Chehab 	struct delta_ipc_close_msg msg;
439*e7b8153eSMauro Carvalho Chehab 	int ret;
440*e7b8153eSMauro Carvalho Chehab 
441*e7b8153eSMauro Carvalho Chehab 	if (!hdl) {
442*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
443*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to close, invalid ipc handle\n",
444*e7b8153eSMauro Carvalho Chehab 			pctx->name);
445*e7b8153eSMauro Carvalho Chehab 		return;
446*e7b8153eSMauro Carvalho Chehab 	}
447*e7b8153eSMauro Carvalho Chehab 
448*e7b8153eSMauro Carvalho Chehab 	if (ctx->ipc_buf) {
449*e7b8153eSMauro Carvalho Chehab 		hw_free(pctx, ctx->ipc_buf);
450*e7b8153eSMauro Carvalho Chehab 		ctx->ipc_buf = NULL;
451*e7b8153eSMauro Carvalho Chehab 	}
452*e7b8153eSMauro Carvalho Chehab 
453*e7b8153eSMauro Carvalho Chehab 	if (!rpmsg_device) {
454*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
455*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to close, rpmsg is not initialized\n",
456*e7b8153eSMauro Carvalho Chehab 			pctx->name);
457*e7b8153eSMauro Carvalho Chehab 		return;
458*e7b8153eSMauro Carvalho Chehab 	}
459*e7b8153eSMauro Carvalho Chehab 
460*e7b8153eSMauro Carvalho Chehab 	/* build rpmsg message */
461*e7b8153eSMauro Carvalho Chehab 	build_msg_header(ctx, DELTA_IPC_CLOSE, &msg.header);
462*e7b8153eSMauro Carvalho Chehab 
463*e7b8153eSMauro Carvalho Chehab 	/* send it */
464*e7b8153eSMauro Carvalho Chehab 	ret = rpmsg_send(rpmsg_device->ept, &msg, sizeof(msg));
465*e7b8153eSMauro Carvalho Chehab 	if (ret) {
466*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
467*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to close, rpmsg_send failed (%d) for DELTA_IPC_CLOSE\n",
468*e7b8153eSMauro Carvalho Chehab 			pctx->name, ret);
469*e7b8153eSMauro Carvalho Chehab 		pctx->sys_errors++;
470*e7b8153eSMauro Carvalho Chehab 		return;
471*e7b8153eSMauro Carvalho Chehab 	}
472*e7b8153eSMauro Carvalho Chehab 
473*e7b8153eSMauro Carvalho Chehab 	/* wait for acknowledge */
474*e7b8153eSMauro Carvalho Chehab 	if (!wait_for_completion_timeout
475*e7b8153eSMauro Carvalho Chehab 	    (&ctx->done, msecs_to_jiffies(IPC_TIMEOUT))) {
476*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
477*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to close, timeout waiting for DELTA_IPC_CLOSE callback\n",
478*e7b8153eSMauro Carvalho Chehab 			pctx->name);
479*e7b8153eSMauro Carvalho Chehab 		pctx->sys_errors++;
480*e7b8153eSMauro Carvalho Chehab 		return;
481*e7b8153eSMauro Carvalho Chehab 	}
482*e7b8153eSMauro Carvalho Chehab 
483*e7b8153eSMauro Carvalho Chehab 	/* command completed, check status */
484*e7b8153eSMauro Carvalho Chehab 	if (ctx->cb_err) {
485*e7b8153eSMauro Carvalho Chehab 		dev_err(delta->dev,
486*e7b8153eSMauro Carvalho Chehab 			"%s   ipc: failed to close, DELTA_IPC_CLOSE completed but with error (%d)\n",
487*e7b8153eSMauro Carvalho Chehab 			pctx->name, ctx->cb_err);
488*e7b8153eSMauro Carvalho Chehab 		pctx->sys_errors++;
489*e7b8153eSMauro Carvalho Chehab 	}
490*e7b8153eSMauro Carvalho Chehab };
491*e7b8153eSMauro Carvalho Chehab 
delta_ipc_cb(struct rpmsg_device * rpdev,void * data,int len,void * priv,u32 src)492*e7b8153eSMauro Carvalho Chehab static int delta_ipc_cb(struct rpmsg_device *rpdev, void *data,
493*e7b8153eSMauro Carvalho Chehab 			int len, void *priv, u32 src)
494*e7b8153eSMauro Carvalho Chehab {
495*e7b8153eSMauro Carvalho Chehab 	struct delta_ipc_ctx *ctx;
496*e7b8153eSMauro Carvalho Chehab 	struct delta_ipc_cb_msg *msg;
497*e7b8153eSMauro Carvalho Chehab 
498*e7b8153eSMauro Carvalho Chehab 	/* sanity check */
499*e7b8153eSMauro Carvalho Chehab 	if (!rpdev) {
500*e7b8153eSMauro Carvalho Chehab 		dev_err(NULL, "rpdev is NULL\n");
501*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
502*e7b8153eSMauro Carvalho Chehab 	}
503*e7b8153eSMauro Carvalho Chehab 
504*e7b8153eSMauro Carvalho Chehab 	if (!data || !len) {
505*e7b8153eSMauro Carvalho Chehab 		dev_err(&rpdev->dev,
506*e7b8153eSMauro Carvalho Chehab 			"unexpected empty message received from src=%d\n", src);
507*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
508*e7b8153eSMauro Carvalho Chehab 	}
509*e7b8153eSMauro Carvalho Chehab 
510*e7b8153eSMauro Carvalho Chehab 	if (len != sizeof(*msg)) {
511*e7b8153eSMauro Carvalho Chehab 		dev_err(&rpdev->dev,
512*e7b8153eSMauro Carvalho Chehab 			"unexpected message length received from src=%d (received %d bytes while %zu bytes expected)\n",
513*e7b8153eSMauro Carvalho Chehab 			len, src, sizeof(*msg));
514*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
515*e7b8153eSMauro Carvalho Chehab 	}
516*e7b8153eSMauro Carvalho Chehab 
517*e7b8153eSMauro Carvalho Chehab 	msg = (struct delta_ipc_cb_msg *)data;
518*e7b8153eSMauro Carvalho Chehab 	if (msg->header.tag != IPC_SANITY_TAG) {
519*e7b8153eSMauro Carvalho Chehab 		dev_err(&rpdev->dev,
520*e7b8153eSMauro Carvalho Chehab 			"unexpected message tag received from src=%d (received %x tag while %x expected)\n",
521*e7b8153eSMauro Carvalho Chehab 			src, msg->header.tag, IPC_SANITY_TAG);
522*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
523*e7b8153eSMauro Carvalho Chehab 	}
524*e7b8153eSMauro Carvalho Chehab 
525*e7b8153eSMauro Carvalho Chehab 	ctx = msg_to_ctx(msg);
526*e7b8153eSMauro Carvalho Chehab 	if (!ctx) {
527*e7b8153eSMauro Carvalho Chehab 		dev_err(&rpdev->dev,
528*e7b8153eSMauro Carvalho Chehab 			"unexpected message with NULL host_hdl received from src=%d\n",
529*e7b8153eSMauro Carvalho Chehab 			src);
530*e7b8153eSMauro Carvalho Chehab 		return -EINVAL;
531*e7b8153eSMauro Carvalho Chehab 	}
532*e7b8153eSMauro Carvalho Chehab 
533*e7b8153eSMauro Carvalho Chehab 	/*
534*e7b8153eSMauro Carvalho Chehab 	 * if not already known, save copro instance context
535*e7b8153eSMauro Carvalho Chehab 	 * to ensure re-entrance on copro side
536*e7b8153eSMauro Carvalho Chehab 	 */
537*e7b8153eSMauro Carvalho Chehab 	if (!ctx->copro_hdl)
538*e7b8153eSMauro Carvalho Chehab 		ctx->copro_hdl = msg_to_copro_hdl(msg);
539*e7b8153eSMauro Carvalho Chehab 
540*e7b8153eSMauro Carvalho Chehab 	/*
541*e7b8153eSMauro Carvalho Chehab 	 * all is fine,
542*e7b8153eSMauro Carvalho Chehab 	 * update status & complete command
543*e7b8153eSMauro Carvalho Chehab 	 */
544*e7b8153eSMauro Carvalho Chehab 	ctx->cb_err = msg->err;
545*e7b8153eSMauro Carvalho Chehab 	complete(&ctx->done);
546*e7b8153eSMauro Carvalho Chehab 
547*e7b8153eSMauro Carvalho Chehab 	return 0;
548*e7b8153eSMauro Carvalho Chehab }
549*e7b8153eSMauro Carvalho Chehab 
delta_ipc_probe(struct rpmsg_device * rpmsg_device)550*e7b8153eSMauro Carvalho Chehab static int delta_ipc_probe(struct rpmsg_device *rpmsg_device)
551*e7b8153eSMauro Carvalho Chehab {
552*e7b8153eSMauro Carvalho Chehab 	struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpmsg_device->dev.driver);
553*e7b8153eSMauro Carvalho Chehab 	struct delta_dev *delta = to_delta(rpdrv);
554*e7b8153eSMauro Carvalho Chehab 
555*e7b8153eSMauro Carvalho Chehab 	delta->rpmsg_device = rpmsg_device;
556*e7b8153eSMauro Carvalho Chehab 
557*e7b8153eSMauro Carvalho Chehab 	return 0;
558*e7b8153eSMauro Carvalho Chehab }
559*e7b8153eSMauro Carvalho Chehab 
delta_ipc_remove(struct rpmsg_device * rpmsg_device)560*e7b8153eSMauro Carvalho Chehab static void delta_ipc_remove(struct rpmsg_device *rpmsg_device)
561*e7b8153eSMauro Carvalho Chehab {
562*e7b8153eSMauro Carvalho Chehab 	struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpmsg_device->dev.driver);
563*e7b8153eSMauro Carvalho Chehab 	struct delta_dev *delta = to_delta(rpdrv);
564*e7b8153eSMauro Carvalho Chehab 
565*e7b8153eSMauro Carvalho Chehab 	delta->rpmsg_device = NULL;
566*e7b8153eSMauro Carvalho Chehab }
567*e7b8153eSMauro Carvalho Chehab 
568*e7b8153eSMauro Carvalho Chehab static struct rpmsg_device_id delta_ipc_device_id_table[] = {
569*e7b8153eSMauro Carvalho Chehab 	{.name = "rpmsg-delta"},
570*e7b8153eSMauro Carvalho Chehab 	{},
571*e7b8153eSMauro Carvalho Chehab };
572*e7b8153eSMauro Carvalho Chehab 
573*e7b8153eSMauro Carvalho Chehab static struct rpmsg_driver delta_rpmsg_driver = {
574*e7b8153eSMauro Carvalho Chehab 	.drv = {.name = KBUILD_MODNAME},
575*e7b8153eSMauro Carvalho Chehab 	.id_table = delta_ipc_device_id_table,
576*e7b8153eSMauro Carvalho Chehab 	.probe = delta_ipc_probe,
577*e7b8153eSMauro Carvalho Chehab 	.callback = delta_ipc_cb,
578*e7b8153eSMauro Carvalho Chehab 	.remove = delta_ipc_remove,
579*e7b8153eSMauro Carvalho Chehab };
580*e7b8153eSMauro Carvalho Chehab 
delta_ipc_init(struct delta_dev * delta)581*e7b8153eSMauro Carvalho Chehab int delta_ipc_init(struct delta_dev *delta)
582*e7b8153eSMauro Carvalho Chehab {
583*e7b8153eSMauro Carvalho Chehab 	delta->rpmsg_driver = delta_rpmsg_driver;
584*e7b8153eSMauro Carvalho Chehab 
585*e7b8153eSMauro Carvalho Chehab 	return register_rpmsg_driver(&delta->rpmsg_driver);
586*e7b8153eSMauro Carvalho Chehab }
587*e7b8153eSMauro Carvalho Chehab 
delta_ipc_exit(struct delta_dev * delta)588*e7b8153eSMauro Carvalho Chehab void delta_ipc_exit(struct delta_dev *delta)
589*e7b8153eSMauro Carvalho Chehab {
590*e7b8153eSMauro Carvalho Chehab 	unregister_rpmsg_driver(&delta->rpmsg_driver);
591*e7b8153eSMauro Carvalho Chehab }
592