1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) STMicroelectronics SA 2014
4 * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
7 #include <linux/errno.h>
8 #include <linux/interrupt.h>
9 #include <linux/kernel.h>
10 #include <linux/module.h>
12 #include <linux/pm_runtime.h>
13 #include <linux/slab.h>
15 #include <media/v4l2-event.h>
16 #include <media/v4l2-ioctl.h>
20 #define BDISP_MAX_CTRL_NUM 10
22 #define BDISP_WORK_TIMEOUT ((100 * HZ) / 1000)
24 /* User configuration change */
25 #define BDISP_PARAMS BIT(0) /* Config updated */
26 #define BDISP_SRC_FMT BIT(1) /* Source set */
27 #define BDISP_DST_FMT BIT(2) /* Destination set */
28 #define BDISP_CTX_STOP_REQ BIT(3) /* Stop request */
29 #define BDISP_CTX_ABORT BIT(4) /* Abort while device run */
32 #define BDISP_MAX_W 8191
34 #define BDISP_MAX_H 8191
36 #define fh_to_ctx(__fh) container_of(__fh, struct bdisp_ctx, fh)
38 enum bdisp_dev_flags
{
39 ST_M2M_OPEN
, /* Driver opened */
40 ST_M2M_RUNNING
, /* HW device running */
41 ST_M2M_SUSPENDED
, /* Driver suspended */
42 ST_M2M_SUSPENDING
, /* Driver being suspended */
45 static const struct bdisp_fmt bdisp_formats
[] = {
46 /* ARGB888. [31:0] A:R:G:B 8:8:8:8 little endian */
48 .pixelformat
= V4L2_PIX_FMT_ABGR32
, /* is actually ARGB */
55 /* XRGB888. [31:0] x:R:G:B 8:8:8:8 little endian */
57 .pixelformat
= V4L2_PIX_FMT_XBGR32
, /* is actually xRGB */
64 /* RGB565. [15:0] R:G:B 5:6:5 little endian */
66 .pixelformat
= V4L2_PIX_FMT_RGB565
,
73 /* NV12. YUV420SP - 1 plane for Y + 1 plane for (CbCr) */
75 .pixelformat
= V4L2_PIX_FMT_NV12
,
82 /* RGB888. [23:0] B:G:R 8:8:8 little endian */
84 .pixelformat
= V4L2_PIX_FMT_RGB24
,
91 /* YU12. YUV420P - 1 plane for Y + 1 plane for Cb + 1 plane for Cr
92 * To keep as the LAST element of this table (no support on capture)
95 .pixelformat
= V4L2_PIX_FMT_YUV420
,
104 /* Default format : HD ARGB32*/
105 #define BDISP_DEF_WIDTH 1920
106 #define BDISP_DEF_HEIGHT 1080
108 static const struct bdisp_frame bdisp_dflt_fmt
= {
109 .width
= BDISP_DEF_WIDTH
,
110 .height
= BDISP_DEF_HEIGHT
,
111 .fmt
= &bdisp_formats
[0],
112 .field
= V4L2_FIELD_NONE
,
113 .bytesperline
= BDISP_DEF_WIDTH
* 4,
114 .sizeimage
= BDISP_DEF_WIDTH
* BDISP_DEF_HEIGHT
* 4,
115 .colorspace
= V4L2_COLORSPACE_REC709
,
116 .crop
= {0, 0, BDISP_DEF_WIDTH
, BDISP_DEF_HEIGHT
},
117 .paddr
= {0, 0, 0, 0}
120 static inline void bdisp_ctx_state_lock_set(u32 state
, struct bdisp_ctx
*ctx
)
124 spin_lock_irqsave(&ctx
->bdisp_dev
->slock
, flags
);
126 spin_unlock_irqrestore(&ctx
->bdisp_dev
->slock
, flags
);
129 static inline void bdisp_ctx_state_lock_clear(u32 state
, struct bdisp_ctx
*ctx
)
133 spin_lock_irqsave(&ctx
->bdisp_dev
->slock
, flags
);
134 ctx
->state
&= ~state
;
135 spin_unlock_irqrestore(&ctx
->bdisp_dev
->slock
, flags
);
138 static inline bool bdisp_ctx_state_is_set(u32 mask
, struct bdisp_ctx
*ctx
)
143 spin_lock_irqsave(&ctx
->bdisp_dev
->slock
, flags
);
144 ret
= (ctx
->state
& mask
) == mask
;
145 spin_unlock_irqrestore(&ctx
->bdisp_dev
->slock
, flags
);
150 static const struct bdisp_fmt
*bdisp_find_fmt(u32 pixelformat
)
152 const struct bdisp_fmt
*fmt
;
155 for (i
= 0; i
< ARRAY_SIZE(bdisp_formats
); i
++) {
156 fmt
= &bdisp_formats
[i
];
157 if (fmt
->pixelformat
== pixelformat
)
164 static struct bdisp_frame
*ctx_get_frame(struct bdisp_ctx
*ctx
,
165 enum v4l2_buf_type type
)
168 case V4L2_BUF_TYPE_VIDEO_OUTPUT
:
170 case V4L2_BUF_TYPE_VIDEO_CAPTURE
:
173 dev_err(ctx
->bdisp_dev
->dev
,
174 "Wrong buffer/video queue type (%d)\n", type
);
178 return ERR_PTR(-EINVAL
);
181 static void bdisp_job_finish(struct bdisp_ctx
*ctx
, int vb_state
)
183 struct vb2_v4l2_buffer
*src_vb
, *dst_vb
;
185 if (WARN(!ctx
|| !ctx
->fh
.m2m_ctx
, "Null hardware context\n"))
188 dev_dbg(ctx
->bdisp_dev
->dev
, "%s\n", __func__
);
190 src_vb
= v4l2_m2m_src_buf_remove(ctx
->fh
.m2m_ctx
);
191 dst_vb
= v4l2_m2m_dst_buf_remove(ctx
->fh
.m2m_ctx
);
193 if (src_vb
&& dst_vb
) {
194 dst_vb
->vb2_buf
.timestamp
= src_vb
->vb2_buf
.timestamp
;
195 dst_vb
->timecode
= src_vb
->timecode
;
196 dst_vb
->flags
&= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK
;
197 dst_vb
->flags
|= src_vb
->flags
&
198 V4L2_BUF_FLAG_TSTAMP_SRC_MASK
;
200 v4l2_m2m_buf_done(src_vb
, vb_state
);
201 v4l2_m2m_buf_done(dst_vb
, vb_state
);
203 v4l2_m2m_job_finish(ctx
->bdisp_dev
->m2m
.m2m_dev
,
208 static int bdisp_ctx_stop_req(struct bdisp_ctx
*ctx
)
210 struct bdisp_ctx
*curr_ctx
;
211 struct bdisp_dev
*bdisp
= ctx
->bdisp_dev
;
214 dev_dbg(ctx
->bdisp_dev
->dev
, "%s\n", __func__
);
216 cancel_delayed_work(&bdisp
->timeout_work
);
218 curr_ctx
= v4l2_m2m_get_curr_priv(bdisp
->m2m
.m2m_dev
);
219 if (!test_bit(ST_M2M_RUNNING
, &bdisp
->state
) || (curr_ctx
!= ctx
))
222 bdisp_ctx_state_lock_set(BDISP_CTX_STOP_REQ
, ctx
);
224 ret
= wait_event_timeout(bdisp
->irq_queue
,
225 !bdisp_ctx_state_is_set(BDISP_CTX_STOP_REQ
, ctx
),
229 dev_err(ctx
->bdisp_dev
->dev
, "%s IRQ timeout\n", __func__
);
236 static void __bdisp_job_abort(struct bdisp_ctx
*ctx
)
240 ret
= bdisp_ctx_stop_req(ctx
);
241 if ((ret
== -ETIMEDOUT
) || (ctx
->state
& BDISP_CTX_ABORT
)) {
242 bdisp_ctx_state_lock_clear(BDISP_CTX_STOP_REQ
| BDISP_CTX_ABORT
,
244 bdisp_job_finish(ctx
, VB2_BUF_STATE_ERROR
);
248 static void bdisp_job_abort(void *priv
)
250 __bdisp_job_abort((struct bdisp_ctx
*)priv
);
253 static int bdisp_get_addr(struct bdisp_ctx
*ctx
, struct vb2_buffer
*vb
,
254 struct bdisp_frame
*frame
, dma_addr_t
*paddr
)
259 paddr
[0] = vb2_dma_contig_plane_dma_addr(vb
, 0);
261 if (frame
->fmt
->nb_planes
> 1)
262 /* UV (NV12) or U (420P) */
263 paddr
[1] = (dma_addr_t
)(paddr
[0] +
264 frame
->bytesperline
* frame
->height
);
266 if (frame
->fmt
->nb_planes
> 2)
268 paddr
[2] = (dma_addr_t
)(paddr
[1] +
269 (frame
->bytesperline
* frame
->height
) / 4);
271 if (frame
->fmt
->nb_planes
> 3)
272 dev_dbg(ctx
->bdisp_dev
->dev
, "ignoring some planes\n");
274 dev_dbg(ctx
->bdisp_dev
->dev
,
275 "%s plane[0]=%pad plane[1]=%pad plane[2]=%pad\n",
276 __func__
, &paddr
[0], &paddr
[1], &paddr
[2]);
281 static int bdisp_get_bufs(struct bdisp_ctx
*ctx
)
283 struct bdisp_frame
*src
, *dst
;
284 struct vb2_v4l2_buffer
*src_vb
, *dst_vb
;
290 src_vb
= v4l2_m2m_next_src_buf(ctx
->fh
.m2m_ctx
);
291 ret
= bdisp_get_addr(ctx
, &src_vb
->vb2_buf
, src
, src
->paddr
);
295 dst_vb
= v4l2_m2m_next_dst_buf(ctx
->fh
.m2m_ctx
);
296 ret
= bdisp_get_addr(ctx
, &dst_vb
->vb2_buf
, dst
, dst
->paddr
);
300 dst_vb
->vb2_buf
.timestamp
= src_vb
->vb2_buf
.timestamp
;
305 static void bdisp_device_run(void *priv
)
307 struct bdisp_ctx
*ctx
= priv
;
308 struct bdisp_dev
*bdisp
;
312 if (WARN(!ctx
, "Null hardware context\n"))
315 bdisp
= ctx
->bdisp_dev
;
316 dev_dbg(bdisp
->dev
, "%s\n", __func__
);
317 spin_lock_irqsave(&bdisp
->slock
, flags
);
319 if (bdisp
->m2m
.ctx
!= ctx
) {
320 dev_dbg(bdisp
->dev
, "ctx updated: %p -> %p\n",
321 bdisp
->m2m
.ctx
, ctx
);
322 ctx
->state
|= BDISP_PARAMS
;
323 bdisp
->m2m
.ctx
= ctx
;
326 if (ctx
->state
& BDISP_CTX_STOP_REQ
) {
327 ctx
->state
&= ~BDISP_CTX_STOP_REQ
;
328 ctx
->state
|= BDISP_CTX_ABORT
;
329 wake_up(&bdisp
->irq_queue
);
333 err
= bdisp_get_bufs(ctx
);
335 dev_err(bdisp
->dev
, "cannot get address\n");
339 bdisp_dbg_perf_begin(bdisp
);
341 err
= bdisp_hw_reset(bdisp
);
343 dev_err(bdisp
->dev
, "could not get HW ready\n");
347 err
= bdisp_hw_update(ctx
);
349 dev_err(bdisp
->dev
, "could not send HW request\n");
353 queue_delayed_work(bdisp
->work_queue
, &bdisp
->timeout_work
,
355 set_bit(ST_M2M_RUNNING
, &bdisp
->state
);
357 ctx
->state
&= ~BDISP_PARAMS
;
358 spin_unlock_irqrestore(&bdisp
->slock
, flags
);
360 bdisp_job_finish(ctx
, VB2_BUF_STATE_ERROR
);
363 static const struct v4l2_m2m_ops bdisp_m2m_ops
= {
364 .device_run
= bdisp_device_run
,
365 .job_abort
= bdisp_job_abort
,
368 static int __bdisp_s_ctrl(struct bdisp_ctx
*ctx
, struct v4l2_ctrl
*ctrl
)
370 if (ctrl
->flags
& V4L2_CTRL_FLAG_INACTIVE
)
375 ctx
->hflip
= ctrl
->val
;
378 ctx
->vflip
= ctrl
->val
;
381 dev_err(ctx
->bdisp_dev
->dev
, "unknown control %d\n", ctrl
->id
);
385 ctx
->state
|= BDISP_PARAMS
;
390 static int bdisp_s_ctrl(struct v4l2_ctrl
*ctrl
)
392 struct bdisp_ctx
*ctx
= container_of(ctrl
->handler
, struct bdisp_ctx
,
397 spin_lock_irqsave(&ctx
->bdisp_dev
->slock
, flags
);
398 ret
= __bdisp_s_ctrl(ctx
, ctrl
);
399 spin_unlock_irqrestore(&ctx
->bdisp_dev
->slock
, flags
);
404 static const struct v4l2_ctrl_ops bdisp_c_ops
= {
405 .s_ctrl
= bdisp_s_ctrl
,
408 static int bdisp_ctrls_create(struct bdisp_ctx
*ctx
)
413 v4l2_ctrl_handler_init(&ctx
->ctrl_handler
, BDISP_MAX_CTRL_NUM
);
415 ctx
->bdisp_ctrls
.hflip
= v4l2_ctrl_new_std(&ctx
->ctrl_handler
,
416 &bdisp_c_ops
, V4L2_CID_HFLIP
, 0, 1, 1, 0);
417 ctx
->bdisp_ctrls
.vflip
= v4l2_ctrl_new_std(&ctx
->ctrl_handler
,
418 &bdisp_c_ops
, V4L2_CID_VFLIP
, 0, 1, 1, 0);
420 if (ctx
->ctrl_handler
.error
) {
421 int err
= ctx
->ctrl_handler
.error
;
423 v4l2_ctrl_handler_free(&ctx
->ctrl_handler
);
427 ctx
->ctrls_rdy
= true;
432 static void bdisp_ctrls_delete(struct bdisp_ctx
*ctx
)
434 if (ctx
->ctrls_rdy
) {
435 v4l2_ctrl_handler_free(&ctx
->ctrl_handler
);
436 ctx
->ctrls_rdy
= false;
440 static int bdisp_queue_setup(struct vb2_queue
*vq
,
441 unsigned int *nb_buf
, unsigned int *nb_planes
,
442 unsigned int sizes
[], struct device
*alloc_devs
[])
444 struct bdisp_ctx
*ctx
= vb2_get_drv_priv(vq
);
445 struct bdisp_frame
*frame
= ctx_get_frame(ctx
, vq
->type
);
448 dev_err(ctx
->bdisp_dev
->dev
, "Invalid frame (%p)\n", frame
);
449 return PTR_ERR(frame
);
453 dev_err(ctx
->bdisp_dev
->dev
, "Invalid format\n");
458 return sizes
[0] < frame
->sizeimage
? -EINVAL
: 0;
461 sizes
[0] = frame
->sizeimage
;
466 static int bdisp_buf_prepare(struct vb2_buffer
*vb
)
468 struct bdisp_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
469 struct bdisp_frame
*frame
= ctx_get_frame(ctx
, vb
->vb2_queue
->type
);
472 dev_err(ctx
->bdisp_dev
->dev
, "Invalid frame (%p)\n", frame
);
473 return PTR_ERR(frame
);
476 if (vb
->vb2_queue
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
)
477 vb2_set_plane_payload(vb
, 0, frame
->sizeimage
);
482 static void bdisp_buf_queue(struct vb2_buffer
*vb
)
484 struct vb2_v4l2_buffer
*vbuf
= to_vb2_v4l2_buffer(vb
);
485 struct bdisp_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
487 /* return to V4L2 any 0-size buffer so it can be dequeued by user */
488 if (!vb2_get_plane_payload(vb
, 0)) {
489 dev_dbg(ctx
->bdisp_dev
->dev
, "0 data buffer, skip it\n");
490 vb2_buffer_done(vb
, VB2_BUF_STATE_DONE
);
495 v4l2_m2m_buf_queue(ctx
->fh
.m2m_ctx
, vbuf
);
498 static int bdisp_start_streaming(struct vb2_queue
*q
, unsigned int count
)
500 struct bdisp_ctx
*ctx
= q
->drv_priv
;
501 struct vb2_v4l2_buffer
*buf
;
502 int ret
= pm_runtime_get_sync(ctx
->bdisp_dev
->dev
);
505 dev_err(ctx
->bdisp_dev
->dev
, "failed to set runtime PM\n");
507 if (q
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
) {
508 while ((buf
= v4l2_m2m_src_buf_remove(ctx
->fh
.m2m_ctx
)))
509 v4l2_m2m_buf_done(buf
, VB2_BUF_STATE_QUEUED
);
511 while ((buf
= v4l2_m2m_dst_buf_remove(ctx
->fh
.m2m_ctx
)))
512 v4l2_m2m_buf_done(buf
, VB2_BUF_STATE_QUEUED
);
521 static void bdisp_stop_streaming(struct vb2_queue
*q
)
523 struct bdisp_ctx
*ctx
= q
->drv_priv
;
525 __bdisp_job_abort(ctx
);
527 pm_runtime_put(ctx
->bdisp_dev
->dev
);
530 static const struct vb2_ops bdisp_qops
= {
531 .queue_setup
= bdisp_queue_setup
,
532 .buf_prepare
= bdisp_buf_prepare
,
533 .buf_queue
= bdisp_buf_queue
,
534 .wait_prepare
= vb2_ops_wait_prepare
,
535 .wait_finish
= vb2_ops_wait_finish
,
536 .stop_streaming
= bdisp_stop_streaming
,
537 .start_streaming
= bdisp_start_streaming
,
540 static int queue_init(void *priv
,
541 struct vb2_queue
*src_vq
, struct vb2_queue
*dst_vq
)
543 struct bdisp_ctx
*ctx
= priv
;
546 memset(src_vq
, 0, sizeof(*src_vq
));
547 src_vq
->type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
548 src_vq
->io_modes
= VB2_MMAP
| VB2_DMABUF
;
549 src_vq
->drv_priv
= ctx
;
550 src_vq
->ops
= &bdisp_qops
;
551 src_vq
->mem_ops
= &vb2_dma_contig_memops
;
552 src_vq
->buf_struct_size
= sizeof(struct v4l2_m2m_buffer
);
553 src_vq
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
554 src_vq
->lock
= &ctx
->bdisp_dev
->lock
;
555 src_vq
->dev
= ctx
->bdisp_dev
->v4l2_dev
.dev
;
557 ret
= vb2_queue_init(src_vq
);
561 memset(dst_vq
, 0, sizeof(*dst_vq
));
562 dst_vq
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
563 dst_vq
->io_modes
= VB2_MMAP
| VB2_DMABUF
;
564 dst_vq
->drv_priv
= ctx
;
565 dst_vq
->ops
= &bdisp_qops
;
566 dst_vq
->mem_ops
= &vb2_dma_contig_memops
;
567 dst_vq
->buf_struct_size
= sizeof(struct v4l2_m2m_buffer
);
568 dst_vq
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
569 dst_vq
->lock
= &ctx
->bdisp_dev
->lock
;
570 dst_vq
->dev
= ctx
->bdisp_dev
->v4l2_dev
.dev
;
572 return vb2_queue_init(dst_vq
);
575 static int bdisp_open(struct file
*file
)
577 struct bdisp_dev
*bdisp
= video_drvdata(file
);
578 struct bdisp_ctx
*ctx
= NULL
;
581 if (mutex_lock_interruptible(&bdisp
->lock
))
584 /* Allocate memory for both context and node */
585 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
590 ctx
->bdisp_dev
= bdisp
;
592 if (bdisp_hw_alloc_nodes(ctx
)) {
593 dev_err(bdisp
->dev
, "no memory for nodes\n");
598 v4l2_fh_init(&ctx
->fh
, bdisp
->m2m
.vdev
);
600 ret
= bdisp_ctrls_create(ctx
);
602 dev_err(bdisp
->dev
, "Failed to create control\n");
606 /* Use separate control handler per file handle */
607 ctx
->fh
.ctrl_handler
= &ctx
->ctrl_handler
;
608 file
->private_data
= &ctx
->fh
;
609 v4l2_fh_add(&ctx
->fh
);
612 ctx
->src
= bdisp_dflt_fmt
;
613 ctx
->dst
= bdisp_dflt_fmt
;
615 /* Setup the device context for mem2mem mode. */
616 ctx
->fh
.m2m_ctx
= v4l2_m2m_ctx_init(bdisp
->m2m
.m2m_dev
, ctx
,
618 if (IS_ERR(ctx
->fh
.m2m_ctx
)) {
619 dev_err(bdisp
->dev
, "Failed to initialize m2m context\n");
620 ret
= PTR_ERR(ctx
->fh
.m2m_ctx
);
625 set_bit(ST_M2M_OPEN
, &bdisp
->state
);
627 dev_dbg(bdisp
->dev
, "driver opened, ctx = 0x%p\n", ctx
);
629 mutex_unlock(&bdisp
->lock
);
634 bdisp_ctrls_delete(ctx
);
635 v4l2_fh_del(&ctx
->fh
);
637 v4l2_fh_exit(&ctx
->fh
);
638 bdisp_hw_free_nodes(ctx
);
642 mutex_unlock(&bdisp
->lock
);
647 static int bdisp_release(struct file
*file
)
649 struct bdisp_ctx
*ctx
= fh_to_ctx(file
->private_data
);
650 struct bdisp_dev
*bdisp
= ctx
->bdisp_dev
;
652 dev_dbg(bdisp
->dev
, "%s\n", __func__
);
654 if (mutex_lock_interruptible(&bdisp
->lock
))
657 v4l2_m2m_ctx_release(ctx
->fh
.m2m_ctx
);
659 bdisp_ctrls_delete(ctx
);
661 v4l2_fh_del(&ctx
->fh
);
662 v4l2_fh_exit(&ctx
->fh
);
664 if (--bdisp
->m2m
.refcnt
<= 0)
665 clear_bit(ST_M2M_OPEN
, &bdisp
->state
);
667 bdisp_hw_free_nodes(ctx
);
671 mutex_unlock(&bdisp
->lock
);
676 static const struct v4l2_file_operations bdisp_fops
= {
677 .owner
= THIS_MODULE
,
679 .release
= bdisp_release
,
680 .poll
= v4l2_m2m_fop_poll
,
681 .unlocked_ioctl
= video_ioctl2
,
682 .mmap
= v4l2_m2m_fop_mmap
,
685 static int bdisp_querycap(struct file
*file
, void *fh
,
686 struct v4l2_capability
*cap
)
688 struct bdisp_ctx
*ctx
= fh_to_ctx(fh
);
689 struct bdisp_dev
*bdisp
= ctx
->bdisp_dev
;
691 strlcpy(cap
->driver
, bdisp
->pdev
->name
, sizeof(cap
->driver
));
692 strlcpy(cap
->card
, bdisp
->pdev
->name
, sizeof(cap
->card
));
693 snprintf(cap
->bus_info
, sizeof(cap
->bus_info
), "platform:%s%d",
694 BDISP_NAME
, bdisp
->id
);
696 cap
->device_caps
= V4L2_CAP_STREAMING
| V4L2_CAP_VIDEO_M2M
;
698 cap
->capabilities
= cap
->device_caps
| V4L2_CAP_DEVICE_CAPS
;
703 static int bdisp_enum_fmt(struct file
*file
, void *fh
, struct v4l2_fmtdesc
*f
)
705 struct bdisp_ctx
*ctx
= fh_to_ctx(fh
);
706 const struct bdisp_fmt
*fmt
;
708 if (f
->index
>= ARRAY_SIZE(bdisp_formats
))
711 fmt
= &bdisp_formats
[f
->index
];
713 if ((fmt
->pixelformat
== V4L2_PIX_FMT_YUV420
) &&
714 (f
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
)) {
715 dev_dbg(ctx
->bdisp_dev
->dev
, "No YU12 on capture\n");
718 f
->pixelformat
= fmt
->pixelformat
;
723 static int bdisp_g_fmt(struct file
*file
, void *fh
, struct v4l2_format
*f
)
725 struct bdisp_ctx
*ctx
= fh_to_ctx(fh
);
726 struct v4l2_pix_format
*pix
;
727 struct bdisp_frame
*frame
= ctx_get_frame(ctx
, f
->type
);
730 dev_err(ctx
->bdisp_dev
->dev
, "Invalid frame (%p)\n", frame
);
731 return PTR_ERR(frame
);
735 pix
->width
= frame
->width
;
736 pix
->height
= frame
->height
;
737 pix
->pixelformat
= frame
->fmt
->pixelformat
;
738 pix
->field
= frame
->field
;
739 pix
->bytesperline
= frame
->bytesperline
;
740 pix
->sizeimage
= frame
->sizeimage
;
741 pix
->colorspace
= (f
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
) ?
742 frame
->colorspace
: bdisp_dflt_fmt
.colorspace
;
747 static int bdisp_try_fmt(struct file
*file
, void *fh
, struct v4l2_format
*f
)
749 struct bdisp_ctx
*ctx
= fh_to_ctx(fh
);
750 struct v4l2_pix_format
*pix
= &f
->fmt
.pix
;
751 const struct bdisp_fmt
*format
;
754 format
= bdisp_find_fmt(pix
->pixelformat
);
756 dev_dbg(ctx
->bdisp_dev
->dev
, "Unknown format 0x%x\n",
761 /* YUV420P only supported for VIDEO_OUTPUT */
762 if ((format
->pixelformat
== V4L2_PIX_FMT_YUV420
) &&
763 (f
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
)) {
764 dev_dbg(ctx
->bdisp_dev
->dev
, "No YU12 on capture\n");
768 /* Field (interlaced only supported on OUTPUT) */
769 if ((f
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
) ||
770 (pix
->field
!= V4L2_FIELD_INTERLACED
))
771 pix
->field
= V4L2_FIELD_NONE
;
773 /* Adjust width & height */
776 v4l_bound_align_image(&pix
->width
,
777 BDISP_MIN_W
, BDISP_MAX_W
,
778 ffs(format
->w_align
) - 1,
780 BDISP_MIN_H
, BDISP_MAX_H
,
781 ffs(format
->h_align
) - 1,
783 if ((pix
->width
!= in_w
) || (pix
->height
!= in_h
))
784 dev_dbg(ctx
->bdisp_dev
->dev
,
785 "%s size updated: %dx%d -> %dx%d\n", __func__
,
786 in_w
, in_h
, pix
->width
, pix
->height
);
788 pix
->bytesperline
= (pix
->width
* format
->bpp_plane0
) / 8;
789 pix
->sizeimage
= (pix
->width
* pix
->height
* format
->bpp
) / 8;
791 if (f
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
)
792 pix
->colorspace
= bdisp_dflt_fmt
.colorspace
;
797 static int bdisp_s_fmt(struct file
*file
, void *fh
, struct v4l2_format
*f
)
799 struct bdisp_ctx
*ctx
= fh_to_ctx(fh
);
800 struct vb2_queue
*vq
;
801 struct bdisp_frame
*frame
;
802 struct v4l2_pix_format
*pix
;
806 ret
= bdisp_try_fmt(file
, fh
, f
);
808 dev_err(ctx
->bdisp_dev
->dev
, "Cannot set format\n");
812 vq
= v4l2_m2m_get_vq(ctx
->fh
.m2m_ctx
, f
->type
);
813 if (vb2_is_streaming(vq
)) {
814 dev_err(ctx
->bdisp_dev
->dev
, "queue (%d) busy\n", f
->type
);
818 frame
= (f
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
) ?
819 &ctx
->src
: &ctx
->dst
;
821 frame
->fmt
= bdisp_find_fmt(pix
->pixelformat
);
823 dev_err(ctx
->bdisp_dev
->dev
, "Unknown format 0x%x\n",
828 frame
->width
= pix
->width
;
829 frame
->height
= pix
->height
;
830 frame
->bytesperline
= pix
->bytesperline
;
831 frame
->sizeimage
= pix
->sizeimage
;
832 frame
->field
= pix
->field
;
833 if (f
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
)
834 frame
->colorspace
= pix
->colorspace
;
836 frame
->crop
.width
= frame
->width
;
837 frame
->crop
.height
= frame
->height
;
838 frame
->crop
.left
= 0;
841 state
= BDISP_PARAMS
;
842 state
|= (f
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
) ?
843 BDISP_DST_FMT
: BDISP_SRC_FMT
;
844 bdisp_ctx_state_lock_set(state
, ctx
);
849 static int bdisp_g_selection(struct file
*file
, void *fh
,
850 struct v4l2_selection
*s
)
852 struct bdisp_frame
*frame
;
853 struct bdisp_ctx
*ctx
= fh_to_ctx(fh
);
855 frame
= ctx_get_frame(ctx
, s
->type
);
857 dev_err(ctx
->bdisp_dev
->dev
, "Invalid frame (%p)\n", frame
);
858 return PTR_ERR(frame
);
862 case V4L2_BUF_TYPE_VIDEO_OUTPUT
:
864 case V4L2_SEL_TGT_CROP
:
868 case V4L2_SEL_TGT_CROP_DEFAULT
:
869 case V4L2_SEL_TGT_CROP_BOUNDS
:
873 s
->r
.width
= frame
->width
;
874 s
->r
.height
= frame
->height
;
877 dev_err(ctx
->bdisp_dev
->dev
, "Invalid target\n");
882 case V4L2_BUF_TYPE_VIDEO_CAPTURE
:
884 case V4L2_SEL_TGT_COMPOSE
:
885 case V4L2_SEL_TGT_COMPOSE_PADDED
:
886 /* composed (cropped) frame */
889 case V4L2_SEL_TGT_COMPOSE_DEFAULT
:
890 case V4L2_SEL_TGT_COMPOSE_BOUNDS
:
894 s
->r
.width
= frame
->width
;
895 s
->r
.height
= frame
->height
;
898 dev_err(ctx
->bdisp_dev
->dev
, "Invalid target\n");
904 dev_err(ctx
->bdisp_dev
->dev
, "Invalid type\n");
911 static int is_rect_enclosed(struct v4l2_rect
*a
, struct v4l2_rect
*b
)
913 /* Return 1 if a is enclosed in b, or 0 otherwise. */
915 if (a
->left
< b
->left
|| a
->top
< b
->top
)
918 if (a
->left
+ a
->width
> b
->left
+ b
->width
)
921 if (a
->top
+ a
->height
> b
->top
+ b
->height
)
927 static int bdisp_s_selection(struct file
*file
, void *fh
,
928 struct v4l2_selection
*s
)
930 struct bdisp_frame
*frame
;
931 struct bdisp_ctx
*ctx
= fh_to_ctx(fh
);
932 struct v4l2_rect
*in
, out
;
935 if ((s
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
) &&
936 (s
->target
== V4L2_SEL_TGT_CROP
))
939 if ((s
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
) &&
940 (s
->target
== V4L2_SEL_TGT_COMPOSE
))
944 dev_err(ctx
->bdisp_dev
->dev
, "Invalid type / target\n");
948 frame
= ctx_get_frame(ctx
, s
->type
);
950 dev_err(ctx
->bdisp_dev
->dev
, "Invalid frame (%p)\n", frame
);
951 return PTR_ERR(frame
);
957 /* Align and check origin */
958 out
.left
= ALIGN(in
->left
, frame
->fmt
->w_align
);
959 out
.top
= ALIGN(in
->top
, frame
->fmt
->h_align
);
961 if ((out
.left
< 0) || (out
.left
>= frame
->width
) ||
962 (out
.top
< 0) || (out
.top
>= frame
->height
)) {
963 dev_err(ctx
->bdisp_dev
->dev
,
964 "Invalid crop: %dx%d@(%d,%d) vs frame: %dx%d\n",
965 out
.width
, out
.height
, out
.left
, out
.top
,
966 frame
->width
, frame
->height
);
970 /* Align and check size */
971 out
.width
= ALIGN(in
->width
, frame
->fmt
->w_align
);
972 out
.height
= ALIGN(in
->height
, frame
->fmt
->w_align
);
974 if (((out
.left
+ out
.width
) > frame
->width
) ||
975 ((out
.top
+ out
.height
) > frame
->height
)) {
976 dev_err(ctx
->bdisp_dev
->dev
,
977 "Invalid crop: %dx%d@(%d,%d) vs frame: %dx%d\n",
978 out
.width
, out
.height
, out
.left
, out
.top
,
979 frame
->width
, frame
->height
);
983 /* Checks adjust constraints flags */
984 if (s
->flags
& V4L2_SEL_FLAG_LE
&& !is_rect_enclosed(&out
, in
))
987 if (s
->flags
& V4L2_SEL_FLAG_GE
&& !is_rect_enclosed(in
, &out
))
990 if ((out
.left
!= in
->left
) || (out
.top
!= in
->top
) ||
991 (out
.width
!= in
->width
) || (out
.height
!= in
->height
)) {
992 dev_dbg(ctx
->bdisp_dev
->dev
,
993 "%s crop updated: %dx%d@(%d,%d) -> %dx%d@(%d,%d)\n",
994 __func__
, in
->width
, in
->height
, in
->left
, in
->top
,
995 out
.width
, out
.height
, out
.left
, out
.top
);
1001 bdisp_ctx_state_lock_set(BDISP_PARAMS
, ctx
);
1006 static int bdisp_streamon(struct file
*file
, void *fh
, enum v4l2_buf_type type
)
1008 struct bdisp_ctx
*ctx
= fh_to_ctx(fh
);
1010 if ((type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
) &&
1011 !bdisp_ctx_state_is_set(BDISP_SRC_FMT
, ctx
)) {
1012 dev_err(ctx
->bdisp_dev
->dev
, "src not defined\n");
1016 if ((type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
) &&
1017 !bdisp_ctx_state_is_set(BDISP_DST_FMT
, ctx
)) {
1018 dev_err(ctx
->bdisp_dev
->dev
, "dst not defined\n");
1022 return v4l2_m2m_streamon(file
, ctx
->fh
.m2m_ctx
, type
);
1025 static const struct v4l2_ioctl_ops bdisp_ioctl_ops
= {
1026 .vidioc_querycap
= bdisp_querycap
,
1027 .vidioc_enum_fmt_vid_cap
= bdisp_enum_fmt
,
1028 .vidioc_enum_fmt_vid_out
= bdisp_enum_fmt
,
1029 .vidioc_g_fmt_vid_cap
= bdisp_g_fmt
,
1030 .vidioc_g_fmt_vid_out
= bdisp_g_fmt
,
1031 .vidioc_try_fmt_vid_cap
= bdisp_try_fmt
,
1032 .vidioc_try_fmt_vid_out
= bdisp_try_fmt
,
1033 .vidioc_s_fmt_vid_cap
= bdisp_s_fmt
,
1034 .vidioc_s_fmt_vid_out
= bdisp_s_fmt
,
1035 .vidioc_g_selection
= bdisp_g_selection
,
1036 .vidioc_s_selection
= bdisp_s_selection
,
1037 .vidioc_reqbufs
= v4l2_m2m_ioctl_reqbufs
,
1038 .vidioc_create_bufs
= v4l2_m2m_ioctl_create_bufs
,
1039 .vidioc_expbuf
= v4l2_m2m_ioctl_expbuf
,
1040 .vidioc_querybuf
= v4l2_m2m_ioctl_querybuf
,
1041 .vidioc_qbuf
= v4l2_m2m_ioctl_qbuf
,
1042 .vidioc_dqbuf
= v4l2_m2m_ioctl_dqbuf
,
1043 .vidioc_streamon
= bdisp_streamon
,
1044 .vidioc_streamoff
= v4l2_m2m_ioctl_streamoff
,
1045 .vidioc_subscribe_event
= v4l2_ctrl_subscribe_event
,
1046 .vidioc_unsubscribe_event
= v4l2_event_unsubscribe
,
1049 static int bdisp_register_device(struct bdisp_dev
*bdisp
)
1056 bdisp
->vdev
.fops
= &bdisp_fops
;
1057 bdisp
->vdev
.ioctl_ops
= &bdisp_ioctl_ops
;
1058 bdisp
->vdev
.release
= video_device_release_empty
;
1059 bdisp
->vdev
.lock
= &bdisp
->lock
;
1060 bdisp
->vdev
.vfl_dir
= VFL_DIR_M2M
;
1061 bdisp
->vdev
.v4l2_dev
= &bdisp
->v4l2_dev
;
1062 snprintf(bdisp
->vdev
.name
, sizeof(bdisp
->vdev
.name
), "%s.%d",
1063 BDISP_NAME
, bdisp
->id
);
1065 video_set_drvdata(&bdisp
->vdev
, bdisp
);
1067 bdisp
->m2m
.vdev
= &bdisp
->vdev
;
1068 bdisp
->m2m
.m2m_dev
= v4l2_m2m_init(&bdisp_m2m_ops
);
1069 if (IS_ERR(bdisp
->m2m
.m2m_dev
)) {
1070 dev_err(bdisp
->dev
, "failed to initialize v4l2-m2m device\n");
1071 return PTR_ERR(bdisp
->m2m
.m2m_dev
);
1074 ret
= video_register_device(&bdisp
->vdev
, VFL_TYPE_GRABBER
, -1);
1077 "%s(): failed to register video device\n", __func__
);
1078 v4l2_m2m_release(bdisp
->m2m
.m2m_dev
);
1085 static void bdisp_unregister_device(struct bdisp_dev
*bdisp
)
1090 if (bdisp
->m2m
.m2m_dev
)
1091 v4l2_m2m_release(bdisp
->m2m
.m2m_dev
);
1093 video_unregister_device(bdisp
->m2m
.vdev
);
1096 static irqreturn_t
bdisp_irq_thread(int irq
, void *priv
)
1098 struct bdisp_dev
*bdisp
= priv
;
1099 struct bdisp_ctx
*ctx
;
1101 spin_lock(&bdisp
->slock
);
1103 bdisp_dbg_perf_end(bdisp
);
1105 cancel_delayed_work(&bdisp
->timeout_work
);
1107 if (!test_and_clear_bit(ST_M2M_RUNNING
, &bdisp
->state
))
1110 if (test_and_clear_bit(ST_M2M_SUSPENDING
, &bdisp
->state
)) {
1111 set_bit(ST_M2M_SUSPENDED
, &bdisp
->state
);
1112 wake_up(&bdisp
->irq_queue
);
1116 ctx
= v4l2_m2m_get_curr_priv(bdisp
->m2m
.m2m_dev
);
1117 if (!ctx
|| !ctx
->fh
.m2m_ctx
)
1120 spin_unlock(&bdisp
->slock
);
1122 bdisp_job_finish(ctx
, VB2_BUF_STATE_DONE
);
1124 if (bdisp_ctx_state_is_set(BDISP_CTX_STOP_REQ
, ctx
)) {
1125 bdisp_ctx_state_lock_clear(BDISP_CTX_STOP_REQ
, ctx
);
1126 wake_up(&bdisp
->irq_queue
);
1132 spin_unlock(&bdisp
->slock
);
1137 static irqreturn_t
bdisp_irq_handler(int irq
, void *priv
)
1139 if (bdisp_hw_get_and_clear_irq((struct bdisp_dev
*)priv
))
1142 return IRQ_WAKE_THREAD
;
1145 static void bdisp_irq_timeout(struct work_struct
*ptr
)
1147 struct delayed_work
*twork
= to_delayed_work(ptr
);
1148 struct bdisp_dev
*bdisp
= container_of(twork
, struct bdisp_dev
,
1150 struct bdisp_ctx
*ctx
;
1152 ctx
= v4l2_m2m_get_curr_priv(bdisp
->m2m
.m2m_dev
);
1154 dev_err(ctx
->bdisp_dev
->dev
, "Device work timeout\n");
1156 spin_lock(&bdisp
->slock
);
1157 clear_bit(ST_M2M_RUNNING
, &bdisp
->state
);
1158 spin_unlock(&bdisp
->slock
);
1160 bdisp_hw_reset(bdisp
);
1162 bdisp_job_finish(ctx
, VB2_BUF_STATE_ERROR
);
1165 static int bdisp_m2m_suspend(struct bdisp_dev
*bdisp
)
1167 unsigned long flags
;
1170 spin_lock_irqsave(&bdisp
->slock
, flags
);
1171 if (!test_bit(ST_M2M_RUNNING
, &bdisp
->state
)) {
1172 spin_unlock_irqrestore(&bdisp
->slock
, flags
);
1175 clear_bit(ST_M2M_SUSPENDED
, &bdisp
->state
);
1176 set_bit(ST_M2M_SUSPENDING
, &bdisp
->state
);
1177 spin_unlock_irqrestore(&bdisp
->slock
, flags
);
1179 timeout
= wait_event_timeout(bdisp
->irq_queue
,
1180 test_bit(ST_M2M_SUSPENDED
, &bdisp
->state
),
1181 BDISP_WORK_TIMEOUT
);
1183 clear_bit(ST_M2M_SUSPENDING
, &bdisp
->state
);
1186 dev_err(bdisp
->dev
, "%s IRQ timeout\n", __func__
);
1193 static int bdisp_m2m_resume(struct bdisp_dev
*bdisp
)
1195 struct bdisp_ctx
*ctx
;
1196 unsigned long flags
;
1198 spin_lock_irqsave(&bdisp
->slock
, flags
);
1199 ctx
= bdisp
->m2m
.ctx
;
1200 bdisp
->m2m
.ctx
= NULL
;
1201 spin_unlock_irqrestore(&bdisp
->slock
, flags
);
1203 if (test_and_clear_bit(ST_M2M_SUSPENDED
, &bdisp
->state
))
1204 bdisp_job_finish(ctx
, VB2_BUF_STATE_ERROR
);
1209 static int bdisp_runtime_resume(struct device
*dev
)
1211 struct bdisp_dev
*bdisp
= dev_get_drvdata(dev
);
1212 int ret
= clk_enable(bdisp
->clock
);
1217 return bdisp_m2m_resume(bdisp
);
1220 static int bdisp_runtime_suspend(struct device
*dev
)
1222 struct bdisp_dev
*bdisp
= dev_get_drvdata(dev
);
1223 int ret
= bdisp_m2m_suspend(bdisp
);
1226 clk_disable(bdisp
->clock
);
1231 static int bdisp_resume(struct device
*dev
)
1233 struct bdisp_dev
*bdisp
= dev_get_drvdata(dev
);
1234 unsigned long flags
;
1237 spin_lock_irqsave(&bdisp
->slock
, flags
);
1238 opened
= test_bit(ST_M2M_OPEN
, &bdisp
->state
);
1239 spin_unlock_irqrestore(&bdisp
->slock
, flags
);
1244 if (!pm_runtime_suspended(dev
))
1245 return bdisp_runtime_resume(dev
);
1250 static int bdisp_suspend(struct device
*dev
)
1252 if (!pm_runtime_suspended(dev
))
1253 return bdisp_runtime_suspend(dev
);
1258 static const struct dev_pm_ops bdisp_pm_ops
= {
1259 .suspend
= bdisp_suspend
,
1260 .resume
= bdisp_resume
,
1261 .runtime_suspend
= bdisp_runtime_suspend
,
1262 .runtime_resume
= bdisp_runtime_resume
,
1265 static int bdisp_remove(struct platform_device
*pdev
)
1267 struct bdisp_dev
*bdisp
= platform_get_drvdata(pdev
);
1269 bdisp_unregister_device(bdisp
);
1271 bdisp_hw_free_filters(bdisp
->dev
);
1273 pm_runtime_disable(&pdev
->dev
);
1275 bdisp_debugfs_remove(bdisp
);
1277 v4l2_device_unregister(&bdisp
->v4l2_dev
);
1279 if (!IS_ERR(bdisp
->clock
))
1280 clk_unprepare(bdisp
->clock
);
1282 dev_dbg(&pdev
->dev
, "%s driver unloaded\n", pdev
->name
);
1287 static int bdisp_probe(struct platform_device
*pdev
)
1289 struct bdisp_dev
*bdisp
;
1290 struct resource
*res
;
1291 struct device
*dev
= &pdev
->dev
;
1294 dev_dbg(dev
, "%s\n", __func__
);
1296 bdisp
= devm_kzalloc(dev
, sizeof(struct bdisp_dev
), GFP_KERNEL
);
1302 platform_set_drvdata(pdev
, bdisp
);
1305 bdisp
->id
= of_alias_get_id(pdev
->dev
.of_node
, BDISP_NAME
);
1307 bdisp
->id
= pdev
->id
;
1309 init_waitqueue_head(&bdisp
->irq_queue
);
1310 INIT_DELAYED_WORK(&bdisp
->timeout_work
, bdisp_irq_timeout
);
1311 bdisp
->work_queue
= create_workqueue(BDISP_NAME
);
1313 spin_lock_init(&bdisp
->slock
);
1314 mutex_init(&bdisp
->lock
);
1317 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
1318 bdisp
->regs
= devm_ioremap_resource(dev
, res
);
1319 if (IS_ERR(bdisp
->regs
)) {
1320 dev_err(dev
, "failed to get regs\n");
1321 return PTR_ERR(bdisp
->regs
);
1324 bdisp
->clock
= devm_clk_get(dev
, BDISP_NAME
);
1325 if (IS_ERR(bdisp
->clock
)) {
1326 dev_err(dev
, "failed to get clock\n");
1327 return PTR_ERR(bdisp
->clock
);
1330 ret
= clk_prepare(bdisp
->clock
);
1332 dev_err(dev
, "clock prepare failed\n");
1333 bdisp
->clock
= ERR_PTR(-EINVAL
);
1337 res
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 0);
1339 dev_err(dev
, "failed to get IRQ resource\n");
1344 ret
= devm_request_threaded_irq(dev
, res
->start
, bdisp_irq_handler
,
1345 bdisp_irq_thread
, IRQF_ONESHOT
,
1348 dev_err(dev
, "failed to install irq\n");
1353 ret
= v4l2_device_register(dev
, &bdisp
->v4l2_dev
);
1355 dev_err(dev
, "failed to register\n");
1360 ret
= bdisp_debugfs_create(bdisp
);
1362 dev_err(dev
, "failed to create debugfs\n");
1366 /* Power management */
1367 pm_runtime_enable(dev
);
1368 ret
= pm_runtime_get_sync(dev
);
1370 dev_err(dev
, "failed to set PM\n");
1375 if (bdisp_hw_alloc_filters(bdisp
->dev
)) {
1376 dev_err(bdisp
->dev
, "no memory for filters\n");
1382 ret
= bdisp_register_device(bdisp
);
1384 dev_err(dev
, "failed to register\n");
1388 dev_info(dev
, "%s%d registered as /dev/video%d\n", BDISP_NAME
,
1389 bdisp
->id
, bdisp
->vdev
.num
);
1391 pm_runtime_put(dev
);
1396 bdisp_hw_free_filters(bdisp
->dev
);
1398 pm_runtime_put(dev
);
1400 bdisp_debugfs_remove(bdisp
);
1402 v4l2_device_unregister(&bdisp
->v4l2_dev
);
1404 if (!IS_ERR(bdisp
->clock
))
1405 clk_unprepare(bdisp
->clock
);
1410 static const struct of_device_id bdisp_match_types
[] = {
1412 .compatible
= "st,stih407-bdisp",
1417 MODULE_DEVICE_TABLE(of
, bdisp_match_types
);
1419 static struct platform_driver bdisp_driver
= {
1420 .probe
= bdisp_probe
,
1421 .remove
= bdisp_remove
,
1424 .of_match_table
= bdisp_match_types
,
1425 .pm
= &bdisp_pm_ops
,
1429 module_platform_driver(bdisp_driver
);
1431 MODULE_DESCRIPTION("2D blitter for STMicroelectronics SoC");
1432 MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>");
1433 MODULE_LICENSE("GPL");