1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) STMicroelectronics SA 2015
4 * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
7 #include <linux/rpmsg.h>
10 #include "delta-ipc.h"
11 #include "delta-mem.h"
13 #define IPC_TIMEOUT 100
14 #define IPC_SANITY_TAG 0xDEADBEEF
16 enum delta_ipc_fw_command
{
23 #define to_rpmsg_driver(__drv) container_of(__drv, struct rpmsg_driver, drv)
24 #define to_delta(__d) container_of(__d, struct delta_dev, rpmsg_driver)
26 #define to_ctx(hdl) ((struct delta_ipc_ctx *)hdl)
27 #define to_pctx(ctx) container_of(ctx, struct delta_ctx, ipc_ctx)
29 struct delta_ipc_header_msg
{
36 #define to_host_hdl(ctx) ((void *)ctx)
38 #define msg_to_ctx(msg) ((struct delta_ipc_ctx *)(msg)->header.host_hdl)
39 #define msg_to_copro_hdl(msg) ((msg)->header.copro_hdl)
41 static inline dma_addr_t
to_paddr(struct delta_ipc_ctx
*ctx
, void *vaddr
)
43 return (ctx
->ipc_buf
->paddr
+ (vaddr
- ctx
->ipc_buf
->vaddr
));
46 static inline bool is_valid_data(struct delta_ipc_ctx
*ctx
,
49 return ((data
>= ctx
->ipc_buf
->vaddr
) &&
50 ((data
+ size
) <= (ctx
->ipc_buf
->vaddr
+ ctx
->ipc_buf
->size
)));
54 * IPC shared memory (@ipc_buf_size, @ipc_buf_paddr) is sent to copro
55 * at each instance opening. This memory is allocated by IPC client
56 * and given through delta_ipc_open(). All messages parameters
57 * (open, set_stream, decode) will have their phy address within
58 * this IPC shared memory, avoiding de-facto recopies inside delta-ipc.
59 * All the below messages structures are used on both host and firmware
60 * side and are packed (use only of 32 bits size fields in messages
61 * structures to ensure packing):
62 * - struct delta_ipc_open_msg
63 * - struct delta_ipc_set_stream_msg
64 * - struct delta_ipc_decode_msg
65 * - struct delta_ipc_close_msg
66 * - struct delta_ipc_cb_msg
68 struct delta_ipc_open_msg
{
69 struct delta_ipc_header_msg header
;
71 dma_addr_t ipc_buf_paddr
;
74 dma_addr_t param_paddr
;
77 struct delta_ipc_set_stream_msg
{
78 struct delta_ipc_header_msg header
;
80 dma_addr_t param_paddr
;
83 struct delta_ipc_decode_msg
{
84 struct delta_ipc_header_msg header
;
86 dma_addr_t param_paddr
;
88 dma_addr_t status_paddr
;
91 struct delta_ipc_close_msg
{
92 struct delta_ipc_header_msg header
;
95 struct delta_ipc_cb_msg
{
96 struct delta_ipc_header_msg header
;
100 static void build_msg_header(struct delta_ipc_ctx
*ctx
,
101 enum delta_ipc_fw_command command
,
102 struct delta_ipc_header_msg
*header
)
104 header
->tag
= IPC_SANITY_TAG
;
105 header
->host_hdl
= to_host_hdl(ctx
);
106 header
->copro_hdl
= ctx
->copro_hdl
;
107 header
->command
= command
;
110 int delta_ipc_open(struct delta_ctx
*pctx
, const char *name
,
111 struct delta_ipc_param
*param
, u32 ipc_buf_size
,
112 struct delta_buf
**ipc_buf
, void **hdl
)
114 struct delta_dev
*delta
= pctx
->dev
;
115 struct rpmsg_device
*rpmsg_device
= delta
->rpmsg_device
;
116 struct delta_ipc_ctx
*ctx
= &pctx
->ipc_ctx
;
117 struct delta_ipc_open_msg msg
;
118 struct delta_buf
*buf
= &ctx
->ipc_buf_struct
;
123 "%s ipc: failed to open, rpmsg is not initialized\n",
131 "%s ipc: failed to open, no name given\n",
136 if (!param
|| !param
->data
|| !param
->size
) {
138 "%s ipc: failed to open, empty parameter\n",
145 "%s ipc: failed to open, no size given for ipc buffer\n",
150 if (param
->size
> ipc_buf_size
) {
152 "%s ipc: failed to open, too large ipc parameter (%d bytes while max %d expected)\n",
154 param
->size
, ctx
->ipc_buf
->size
);
159 init_completion(&ctx
->done
);
162 * allocation of contiguous buffer for
163 * data of commands exchanged between
164 * host and firmware coprocessor
166 ret
= hw_alloc(pctx
, ipc_buf_size
,
167 "ipc data buffer", buf
);
172 /* build rpmsg message */
173 build_msg_header(ctx
, DELTA_IPC_OPEN
, &msg
.header
);
175 msg
.ipc_buf_size
= ipc_buf_size
;
176 msg
.ipc_buf_paddr
= ctx
->ipc_buf
->paddr
;
178 memcpy(msg
.name
, name
, sizeof(msg
.name
));
179 msg
.name
[sizeof(msg
.name
) - 1] = 0;
181 msg
.param_size
= param
->size
;
182 memcpy(ctx
->ipc_buf
->vaddr
, param
->data
, msg
.param_size
);
183 msg
.param_paddr
= ctx
->ipc_buf
->paddr
;
186 ret
= rpmsg_send(rpmsg_device
->ept
, &msg
, sizeof(msg
));
189 "%s ipc: failed to open, rpmsg_send failed (%d) for DELTA_IPC_OPEN (name=%s, size=%d, data=%p)\n",
191 ret
, name
, param
->size
, param
->data
);
195 /* wait for acknowledge */
196 if (!wait_for_completion_timeout
197 (&ctx
->done
, msecs_to_jiffies(IPC_TIMEOUT
))) {
199 "%s ipc: failed to open, timeout waiting for DELTA_IPC_OPEN callback (name=%s, size=%d, data=%p)\n",
201 name
, param
->size
, param
->data
);
206 /* command completed, check error */
209 "%s ipc: failed to open, DELTA_IPC_OPEN completed but with error (%d) (name=%s, size=%d, data=%p)\n",
211 ctx
->cb_err
, name
, param
->size
, param
->data
);
216 *ipc_buf
= ctx
->ipc_buf
;
223 hw_free(pctx
, ctx
->ipc_buf
);
229 int delta_ipc_set_stream(void *hdl
, struct delta_ipc_param
*param
)
231 struct delta_ipc_ctx
*ctx
= to_ctx(hdl
);
232 struct delta_ctx
*pctx
= to_pctx(ctx
);
233 struct delta_dev
*delta
= pctx
->dev
;
234 struct rpmsg_device
*rpmsg_device
= delta
->rpmsg_device
;
235 struct delta_ipc_set_stream_msg msg
;
240 "%s ipc: failed to set stream, invalid ipc handle\n",
247 "%s ipc: failed to set stream, rpmsg is not initialized\n",
252 if (!param
|| !param
->data
|| !param
->size
) {
254 "%s ipc: failed to set stream, empty parameter\n",
259 if (param
->size
> ctx
->ipc_buf
->size
) {
261 "%s ipc: failed to set stream, too large ipc parameter(%d bytes while max %d expected)\n",
263 param
->size
, ctx
->ipc_buf
->size
);
267 if (!is_valid_data(ctx
, param
->data
, param
->size
)) {
269 "%s ipc: failed to set stream, parameter is not in expected address range (size=%d, data=%p not in %p..%p)\n",
274 ctx
->ipc_buf
->vaddr
+ ctx
->ipc_buf
->size
- 1);
278 /* build rpmsg message */
279 build_msg_header(ctx
, DELTA_IPC_SET_STREAM
, &msg
.header
);
281 msg
.param_size
= param
->size
;
282 msg
.param_paddr
= to_paddr(ctx
, param
->data
);
285 ret
= rpmsg_send(rpmsg_device
->ept
, &msg
, sizeof(msg
));
288 "%s ipc: failed to set stream, rpmsg_send failed (%d) for DELTA_IPC_SET_STREAM (size=%d, data=%p)\n",
290 ret
, param
->size
, param
->data
);
295 /* wait for acknowledge */
296 if (!wait_for_completion_timeout
297 (&ctx
->done
, msecs_to_jiffies(IPC_TIMEOUT
))) {
299 "%s ipc: failed to set stream, timeout waiting for DELTA_IPC_SET_STREAM callback (size=%d, data=%p)\n",
301 param
->size
, param
->data
);
306 /* command completed, check status */
309 "%s ipc: failed to set stream, DELTA_IPC_SET_STREAM completed but with error (%d) (size=%d, data=%p)\n",
311 ctx
->cb_err
, param
->size
, param
->data
);
319 int delta_ipc_decode(void *hdl
, struct delta_ipc_param
*param
,
320 struct delta_ipc_param
*status
)
322 struct delta_ipc_ctx
*ctx
= to_ctx(hdl
);
323 struct delta_ctx
*pctx
= to_pctx(ctx
);
324 struct delta_dev
*delta
= pctx
->dev
;
325 struct rpmsg_device
*rpmsg_device
= delta
->rpmsg_device
;
326 struct delta_ipc_decode_msg msg
;
331 "%s ipc: failed to decode, invalid ipc handle\n",
338 "%s ipc: failed to decode, rpmsg is not initialized\n",
343 if (!param
|| !param
->data
|| !param
->size
) {
345 "%s ipc: failed to decode, empty parameter\n",
350 if (!status
|| !status
->data
|| !status
->size
) {
352 "%s ipc: failed to decode, empty status\n",
357 if (param
->size
+ status
->size
> ctx
->ipc_buf
->size
) {
359 "%s ipc: failed to decode, too large ipc parameter (%d bytes (param) + %d bytes (status) while max %d expected)\n",
367 if (!is_valid_data(ctx
, param
->data
, param
->size
)) {
369 "%s ipc: failed to decode, parameter is not in expected address range (size=%d, data=%p not in %p..%p)\n",
374 ctx
->ipc_buf
->vaddr
+ ctx
->ipc_buf
->size
- 1);
378 if (!is_valid_data(ctx
, status
->data
, status
->size
)) {
380 "%s ipc: failed to decode, status is not in expected address range (size=%d, data=%p not in %p..%p)\n",
385 ctx
->ipc_buf
->vaddr
+ ctx
->ipc_buf
->size
- 1);
389 /* build rpmsg message */
390 build_msg_header(ctx
, DELTA_IPC_DECODE
, &msg
.header
);
392 msg
.param_size
= param
->size
;
393 msg
.param_paddr
= to_paddr(ctx
, param
->data
);
395 msg
.status_size
= status
->size
;
396 msg
.status_paddr
= to_paddr(ctx
, status
->data
);
399 ret
= rpmsg_send(rpmsg_device
->ept
, &msg
, sizeof(msg
));
402 "%s ipc: failed to decode, rpmsg_send failed (%d) for DELTA_IPC_DECODE (size=%d, data=%p)\n",
404 ret
, param
->size
, param
->data
);
409 /* wait for acknowledge */
410 if (!wait_for_completion_timeout
411 (&ctx
->done
, msecs_to_jiffies(IPC_TIMEOUT
))) {
413 "%s ipc: failed to decode, timeout waiting for DELTA_IPC_DECODE callback (size=%d, data=%p)\n",
415 param
->size
, param
->data
);
420 /* command completed, check status */
423 "%s ipc: failed to decode, DELTA_IPC_DECODE completed but with error (%d) (size=%d, data=%p)\n",
425 ctx
->cb_err
, param
->size
, param
->data
);
433 void delta_ipc_close(void *hdl
)
435 struct delta_ipc_ctx
*ctx
= to_ctx(hdl
);
436 struct delta_ctx
*pctx
= to_pctx(ctx
);
437 struct delta_dev
*delta
= pctx
->dev
;
438 struct rpmsg_device
*rpmsg_device
= delta
->rpmsg_device
;
439 struct delta_ipc_close_msg msg
;
444 "%s ipc: failed to close, invalid ipc handle\n",
450 hw_free(pctx
, ctx
->ipc_buf
);
456 "%s ipc: failed to close, rpmsg is not initialized\n",
461 /* build rpmsg message */
462 build_msg_header(ctx
, DELTA_IPC_CLOSE
, &msg
.header
);
465 ret
= rpmsg_send(rpmsg_device
->ept
, &msg
, sizeof(msg
));
468 "%s ipc: failed to close, rpmsg_send failed (%d) for DELTA_IPC_CLOSE\n",
474 /* wait for acknowledge */
475 if (!wait_for_completion_timeout
476 (&ctx
->done
, msecs_to_jiffies(IPC_TIMEOUT
))) {
478 "%s ipc: failed to close, timeout waiting for DELTA_IPC_CLOSE callback\n",
484 /* command completed, check status */
487 "%s ipc: failed to close, DELTA_IPC_CLOSE completed but with error (%d)\n",
488 pctx
->name
, ctx
->cb_err
);
493 static int delta_ipc_cb(struct rpmsg_device
*rpdev
, void *data
,
494 int len
, void *priv
, u32 src
)
496 struct delta_ipc_ctx
*ctx
;
497 struct delta_ipc_cb_msg
*msg
;
501 dev_err(NULL
, "rpdev is NULL\n");
507 "unexpected empty message received from src=%d\n", src
);
511 if (len
!= sizeof(*msg
)) {
513 "unexpected message length received from src=%d (received %d bytes while %zu bytes expected)\n",
514 len
, src
, sizeof(*msg
));
518 msg
= (struct delta_ipc_cb_msg
*)data
;
519 if (msg
->header
.tag
!= IPC_SANITY_TAG
) {
521 "unexpected message tag received from src=%d (received %x tag while %x expected)\n",
522 src
, msg
->header
.tag
, IPC_SANITY_TAG
);
526 ctx
= msg_to_ctx(msg
);
529 "unexpected message with NULL host_hdl received from src=%d\n",
535 * if not already known, save copro instance context
536 * to ensure re-entrance on copro side
539 ctx
->copro_hdl
= msg_to_copro_hdl(msg
);
543 * update status & complete command
545 ctx
->cb_err
= msg
->err
;
546 complete(&ctx
->done
);
551 static int delta_ipc_probe(struct rpmsg_device
*rpmsg_device
)
553 struct rpmsg_driver
*rpdrv
= to_rpmsg_driver(rpmsg_device
->dev
.driver
);
554 struct delta_dev
*delta
= to_delta(rpdrv
);
556 delta
->rpmsg_device
= rpmsg_device
;
561 static void delta_ipc_remove(struct rpmsg_device
*rpmsg_device
)
563 struct rpmsg_driver
*rpdrv
= to_rpmsg_driver(rpmsg_device
->dev
.driver
);
564 struct delta_dev
*delta
= to_delta(rpdrv
);
566 delta
->rpmsg_device
= NULL
;
569 static struct rpmsg_device_id delta_ipc_device_id_table
[] = {
570 {.name
= "rpmsg-delta"},
574 static struct rpmsg_driver delta_rpmsg_driver
= {
575 .drv
= {.name
= KBUILD_MODNAME
},
576 .id_table
= delta_ipc_device_id_table
,
577 .probe
= delta_ipc_probe
,
578 .callback
= delta_ipc_cb
,
579 .remove
= delta_ipc_remove
,
582 int delta_ipc_init(struct delta_dev
*delta
)
584 delta
->rpmsg_driver
= delta_rpmsg_driver
;
586 return register_rpmsg_driver(&delta
->rpmsg_driver
);
589 void delta_ipc_exit(struct delta_dev
*delta
)
591 unregister_rpmsg_driver(&delta
->rpmsg_driver
);