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