2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
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 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
[], void *allocators
[])
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");
456 allocators
[0] = ctx
->bdisp_dev
->alloc_ctx
;
459 return sizes
[0] < frame
->sizeimage
? -EINVAL
: 0;
462 sizes
[0] = frame
->sizeimage
;
467 static int bdisp_buf_prepare(struct vb2_buffer
*vb
)
469 struct bdisp_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
470 struct bdisp_frame
*frame
= ctx_get_frame(ctx
, vb
->vb2_queue
->type
);
473 dev_err(ctx
->bdisp_dev
->dev
, "Invalid frame (%p)\n", frame
);
474 return PTR_ERR(frame
);
477 if (vb
->vb2_queue
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
)
478 vb2_set_plane_payload(vb
, 0, frame
->sizeimage
);
483 static void bdisp_buf_queue(struct vb2_buffer
*vb
)
485 struct vb2_v4l2_buffer
*vbuf
= to_vb2_v4l2_buffer(vb
);
486 struct bdisp_ctx
*ctx
= vb2_get_drv_priv(vb
->vb2_queue
);
488 /* return to V4L2 any 0-size buffer so it can be dequeued by user */
489 if (!vb2_get_plane_payload(vb
, 0)) {
490 dev_dbg(ctx
->bdisp_dev
->dev
, "0 data buffer, skip it\n");
491 vb2_buffer_done(vb
, VB2_BUF_STATE_DONE
);
496 v4l2_m2m_buf_queue(ctx
->fh
.m2m_ctx
, vbuf
);
499 static int bdisp_start_streaming(struct vb2_queue
*q
, unsigned int count
)
501 struct bdisp_ctx
*ctx
= q
->drv_priv
;
502 struct vb2_v4l2_buffer
*buf
;
503 int ret
= pm_runtime_get_sync(ctx
->bdisp_dev
->dev
);
506 dev_err(ctx
->bdisp_dev
->dev
, "failed to set runtime PM\n");
508 if (q
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
) {
509 while ((buf
= v4l2_m2m_src_buf_remove(ctx
->fh
.m2m_ctx
)))
510 v4l2_m2m_buf_done(buf
, VB2_BUF_STATE_QUEUED
);
512 while ((buf
= v4l2_m2m_dst_buf_remove(ctx
->fh
.m2m_ctx
)))
513 v4l2_m2m_buf_done(buf
, VB2_BUF_STATE_QUEUED
);
522 static void bdisp_stop_streaming(struct vb2_queue
*q
)
524 struct bdisp_ctx
*ctx
= q
->drv_priv
;
526 __bdisp_job_abort(ctx
);
528 pm_runtime_put(ctx
->bdisp_dev
->dev
);
531 static struct vb2_ops bdisp_qops
= {
532 .queue_setup
= bdisp_queue_setup
,
533 .buf_prepare
= bdisp_buf_prepare
,
534 .buf_queue
= bdisp_buf_queue
,
535 .wait_prepare
= vb2_ops_wait_prepare
,
536 .wait_finish
= vb2_ops_wait_finish
,
537 .stop_streaming
= bdisp_stop_streaming
,
538 .start_streaming
= bdisp_start_streaming
,
541 static int queue_init(void *priv
,
542 struct vb2_queue
*src_vq
, struct vb2_queue
*dst_vq
)
544 struct bdisp_ctx
*ctx
= priv
;
547 memset(src_vq
, 0, sizeof(*src_vq
));
548 src_vq
->type
= V4L2_BUF_TYPE_VIDEO_OUTPUT
;
549 src_vq
->io_modes
= VB2_MMAP
| VB2_DMABUF
;
550 src_vq
->drv_priv
= ctx
;
551 src_vq
->ops
= &bdisp_qops
;
552 src_vq
->mem_ops
= &vb2_dma_contig_memops
;
553 src_vq
->buf_struct_size
= sizeof(struct v4l2_m2m_buffer
);
554 src_vq
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
555 src_vq
->lock
= &ctx
->bdisp_dev
->lock
;
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
;
571 return vb2_queue_init(dst_vq
);
574 static int bdisp_open(struct file
*file
)
576 struct bdisp_dev
*bdisp
= video_drvdata(file
);
577 struct bdisp_ctx
*ctx
= NULL
;
580 if (mutex_lock_interruptible(&bdisp
->lock
))
583 /* Allocate memory for both context and node */
584 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
589 ctx
->bdisp_dev
= bdisp
;
591 if (bdisp_hw_alloc_nodes(ctx
)) {
592 dev_err(bdisp
->dev
, "no memory for nodes\n");
597 v4l2_fh_init(&ctx
->fh
, bdisp
->m2m
.vdev
);
599 ret
= bdisp_ctrls_create(ctx
);
601 dev_err(bdisp
->dev
, "Failed to create control\n");
605 /* Use separate control handler per file handle */
606 ctx
->fh
.ctrl_handler
= &ctx
->ctrl_handler
;
607 file
->private_data
= &ctx
->fh
;
608 v4l2_fh_add(&ctx
->fh
);
611 ctx
->src
= bdisp_dflt_fmt
;
612 ctx
->dst
= bdisp_dflt_fmt
;
614 /* Setup the device context for mem2mem mode. */
615 ctx
->fh
.m2m_ctx
= v4l2_m2m_ctx_init(bdisp
->m2m
.m2m_dev
, ctx
,
617 if (IS_ERR(ctx
->fh
.m2m_ctx
)) {
618 dev_err(bdisp
->dev
, "Failed to initialize m2m context\n");
619 ret
= PTR_ERR(ctx
->fh
.m2m_ctx
);
624 set_bit(ST_M2M_OPEN
, &bdisp
->state
);
626 dev_dbg(bdisp
->dev
, "driver opened, ctx = 0x%p\n", ctx
);
628 mutex_unlock(&bdisp
->lock
);
633 bdisp_ctrls_delete(ctx
);
635 v4l2_fh_del(&ctx
->fh
);
636 v4l2_fh_exit(&ctx
->fh
);
637 bdisp_hw_free_nodes(ctx
);
641 mutex_unlock(&bdisp
->lock
);
646 static int bdisp_release(struct file
*file
)
648 struct bdisp_ctx
*ctx
= fh_to_ctx(file
->private_data
);
649 struct bdisp_dev
*bdisp
= ctx
->bdisp_dev
;
651 dev_dbg(bdisp
->dev
, "%s\n", __func__
);
653 if (mutex_lock_interruptible(&bdisp
->lock
))
656 v4l2_m2m_ctx_release(ctx
->fh
.m2m_ctx
);
658 bdisp_ctrls_delete(ctx
);
660 v4l2_fh_del(&ctx
->fh
);
661 v4l2_fh_exit(&ctx
->fh
);
663 if (--bdisp
->m2m
.refcnt
<= 0)
664 clear_bit(ST_M2M_OPEN
, &bdisp
->state
);
666 bdisp_hw_free_nodes(ctx
);
670 mutex_unlock(&bdisp
->lock
);
675 static const struct v4l2_file_operations bdisp_fops
= {
676 .owner
= THIS_MODULE
,
678 .release
= bdisp_release
,
679 .poll
= v4l2_m2m_fop_poll
,
680 .unlocked_ioctl
= video_ioctl2
,
681 .mmap
= v4l2_m2m_fop_mmap
,
684 static int bdisp_querycap(struct file
*file
, void *fh
,
685 struct v4l2_capability
*cap
)
687 struct bdisp_ctx
*ctx
= fh_to_ctx(fh
);
688 struct bdisp_dev
*bdisp
= ctx
->bdisp_dev
;
690 strlcpy(cap
->driver
, bdisp
->pdev
->name
, sizeof(cap
->driver
));
691 strlcpy(cap
->card
, bdisp
->pdev
->name
, sizeof(cap
->card
));
692 snprintf(cap
->bus_info
, sizeof(cap
->bus_info
), "platform:%s%d",
693 BDISP_NAME
, bdisp
->id
);
695 cap
->device_caps
= V4L2_CAP_STREAMING
| V4L2_CAP_VIDEO_M2M
;
697 cap
->capabilities
= cap
->device_caps
| V4L2_CAP_DEVICE_CAPS
;
702 static int bdisp_enum_fmt(struct file
*file
, void *fh
, struct v4l2_fmtdesc
*f
)
704 struct bdisp_ctx
*ctx
= fh_to_ctx(fh
);
705 const struct bdisp_fmt
*fmt
;
707 if (f
->index
>= ARRAY_SIZE(bdisp_formats
))
710 fmt
= &bdisp_formats
[f
->index
];
712 if ((fmt
->pixelformat
== V4L2_PIX_FMT_YUV420
) &&
713 (f
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
)) {
714 dev_dbg(ctx
->bdisp_dev
->dev
, "No YU12 on capture\n");
717 f
->pixelformat
= fmt
->pixelformat
;
722 static int bdisp_g_fmt(struct file
*file
, void *fh
, struct v4l2_format
*f
)
724 struct bdisp_ctx
*ctx
= fh_to_ctx(fh
);
725 struct v4l2_pix_format
*pix
= &f
->fmt
.pix
;
726 struct bdisp_frame
*frame
= ctx_get_frame(ctx
, f
->type
);
729 dev_err(ctx
->bdisp_dev
->dev
, "Invalid frame (%p)\n", frame
);
730 return PTR_ERR(frame
);
734 pix
->width
= frame
->width
;
735 pix
->height
= frame
->height
;
736 pix
->pixelformat
= frame
->fmt
->pixelformat
;
737 pix
->field
= frame
->field
;
738 pix
->bytesperline
= frame
->bytesperline
;
739 pix
->sizeimage
= frame
->sizeimage
;
740 pix
->colorspace
= (f
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
) ?
741 frame
->colorspace
: bdisp_dflt_fmt
.colorspace
;
746 static int bdisp_try_fmt(struct file
*file
, void *fh
, struct v4l2_format
*f
)
748 struct bdisp_ctx
*ctx
= fh_to_ctx(fh
);
749 struct v4l2_pix_format
*pix
= &f
->fmt
.pix
;
750 const struct bdisp_fmt
*format
;
753 format
= bdisp_find_fmt(pix
->pixelformat
);
755 dev_dbg(ctx
->bdisp_dev
->dev
, "Unknown format 0x%x\n",
760 /* YUV420P only supported for VIDEO_OUTPUT */
761 if ((format
->pixelformat
== V4L2_PIX_FMT_YUV420
) &&
762 (f
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
)) {
763 dev_dbg(ctx
->bdisp_dev
->dev
, "No YU12 on capture\n");
767 /* Field (interlaced only supported on OUTPUT) */
768 if ((f
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
) ||
769 (pix
->field
!= V4L2_FIELD_INTERLACED
))
770 pix
->field
= V4L2_FIELD_NONE
;
772 /* Adjust width & height */
775 v4l_bound_align_image(&pix
->width
,
776 BDISP_MIN_W
, BDISP_MAX_W
,
777 ffs(format
->w_align
) - 1,
779 BDISP_MIN_H
, BDISP_MAX_H
,
780 ffs(format
->h_align
) - 1,
782 if ((pix
->width
!= in_w
) || (pix
->height
!= in_h
))
783 dev_dbg(ctx
->bdisp_dev
->dev
,
784 "%s size updated: %dx%d -> %dx%d\n", __func__
,
785 in_w
, in_h
, pix
->width
, pix
->height
);
787 pix
->bytesperline
= (pix
->width
* format
->bpp_plane0
) / 8;
788 pix
->sizeimage
= (pix
->width
* pix
->height
* format
->bpp
) / 8;
790 if (f
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
)
791 pix
->colorspace
= bdisp_dflt_fmt
.colorspace
;
796 static int bdisp_s_fmt(struct file
*file
, void *fh
, struct v4l2_format
*f
)
798 struct bdisp_ctx
*ctx
= fh_to_ctx(fh
);
799 struct vb2_queue
*vq
;
800 struct bdisp_frame
*frame
;
801 struct v4l2_pix_format
*pix
;
805 ret
= bdisp_try_fmt(file
, fh
, f
);
807 dev_err(ctx
->bdisp_dev
->dev
, "Cannot set format\n");
811 vq
= v4l2_m2m_get_vq(ctx
->fh
.m2m_ctx
, f
->type
);
812 if (vb2_is_streaming(vq
)) {
813 dev_err(ctx
->bdisp_dev
->dev
, "queue (%d) busy\n", f
->type
);
817 frame
= (f
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
) ?
818 &ctx
->src
: &ctx
->dst
;
820 frame
->fmt
= bdisp_find_fmt(pix
->pixelformat
);
822 dev_err(ctx
->bdisp_dev
->dev
, "Unknown format 0x%x\n",
827 frame
->width
= pix
->width
;
828 frame
->height
= pix
->height
;
829 frame
->bytesperline
= pix
->bytesperline
;
830 frame
->sizeimage
= pix
->sizeimage
;
831 frame
->field
= pix
->field
;
832 if (f
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
)
833 frame
->colorspace
= pix
->colorspace
;
835 frame
->crop
.width
= frame
->width
;
836 frame
->crop
.height
= frame
->height
;
837 frame
->crop
.left
= 0;
840 state
= BDISP_PARAMS
;
841 state
|= (f
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
) ?
842 BDISP_DST_FMT
: BDISP_SRC_FMT
;
843 bdisp_ctx_state_lock_set(state
, ctx
);
848 static int bdisp_g_selection(struct file
*file
, void *fh
,
849 struct v4l2_selection
*s
)
851 struct bdisp_frame
*frame
;
852 struct bdisp_ctx
*ctx
= fh_to_ctx(fh
);
854 frame
= ctx_get_frame(ctx
, s
->type
);
856 dev_err(ctx
->bdisp_dev
->dev
, "Invalid frame (%p)\n", frame
);
857 return PTR_ERR(frame
);
861 case V4L2_BUF_TYPE_VIDEO_OUTPUT
:
863 case V4L2_SEL_TGT_CROP
:
867 case V4L2_SEL_TGT_CROP_DEFAULT
:
868 case V4L2_SEL_TGT_CROP_BOUNDS
:
872 s
->r
.width
= frame
->width
;
873 s
->r
.height
= frame
->height
;
876 dev_err(ctx
->bdisp_dev
->dev
, "Invalid target\n");
881 case V4L2_BUF_TYPE_VIDEO_CAPTURE
:
883 case V4L2_SEL_TGT_COMPOSE
:
884 case V4L2_SEL_TGT_COMPOSE_PADDED
:
885 /* composed (cropped) frame */
888 case V4L2_SEL_TGT_COMPOSE_DEFAULT
:
889 case V4L2_SEL_TGT_COMPOSE_BOUNDS
:
893 s
->r
.width
= frame
->width
;
894 s
->r
.height
= frame
->height
;
897 dev_err(ctx
->bdisp_dev
->dev
, "Invalid target\n");
903 dev_err(ctx
->bdisp_dev
->dev
, "Invalid type\n");
910 static int is_rect_enclosed(struct v4l2_rect
*a
, struct v4l2_rect
*b
)
912 /* Return 1 if a is enclosed in b, or 0 otherwise. */
914 if (a
->left
< b
->left
|| a
->top
< b
->top
)
917 if (a
->left
+ a
->width
> b
->left
+ b
->width
)
920 if (a
->top
+ a
->height
> b
->top
+ b
->height
)
926 static int bdisp_s_selection(struct file
*file
, void *fh
,
927 struct v4l2_selection
*s
)
929 struct bdisp_frame
*frame
;
930 struct bdisp_ctx
*ctx
= fh_to_ctx(fh
);
931 struct v4l2_rect
*in
, out
;
934 if ((s
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
) &&
935 (s
->target
== V4L2_SEL_TGT_CROP
))
938 if ((s
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
) &&
939 (s
->target
== V4L2_SEL_TGT_COMPOSE
))
943 dev_err(ctx
->bdisp_dev
->dev
, "Invalid type / target\n");
947 frame
= ctx_get_frame(ctx
, s
->type
);
949 dev_err(ctx
->bdisp_dev
->dev
, "Invalid frame (%p)\n", frame
);
950 return PTR_ERR(frame
);
956 /* Align and check origin */
957 out
.left
= ALIGN(in
->left
, frame
->fmt
->w_align
);
958 out
.top
= ALIGN(in
->top
, frame
->fmt
->h_align
);
960 if ((out
.left
< 0) || (out
.left
>= frame
->width
) ||
961 (out
.top
< 0) || (out
.top
>= frame
->height
)) {
962 dev_err(ctx
->bdisp_dev
->dev
,
963 "Invalid crop: %dx%d@(%d,%d) vs frame: %dx%d\n",
964 out
.width
, out
.height
, out
.left
, out
.top
,
965 frame
->width
, frame
->height
);
969 /* Align and check size */
970 out
.width
= ALIGN(in
->width
, frame
->fmt
->w_align
);
971 out
.height
= ALIGN(in
->height
, frame
->fmt
->w_align
);
973 if (((out
.left
+ out
.width
) > frame
->width
) ||
974 ((out
.top
+ out
.height
) > frame
->height
)) {
975 dev_err(ctx
->bdisp_dev
->dev
,
976 "Invalid crop: %dx%d@(%d,%d) vs frame: %dx%d\n",
977 out
.width
, out
.height
, out
.left
, out
.top
,
978 frame
->width
, frame
->height
);
982 /* Checks adjust constraints flags */
983 if (s
->flags
& V4L2_SEL_FLAG_LE
&& !is_rect_enclosed(&out
, in
))
986 if (s
->flags
& V4L2_SEL_FLAG_GE
&& !is_rect_enclosed(in
, &out
))
989 if ((out
.left
!= in
->left
) || (out
.top
!= in
->top
) ||
990 (out
.width
!= in
->width
) || (out
.height
!= in
->height
)) {
991 dev_dbg(ctx
->bdisp_dev
->dev
,
992 "%s crop updated: %dx%d@(%d,%d) -> %dx%d@(%d,%d)\n",
993 __func__
, in
->width
, in
->height
, in
->left
, in
->top
,
994 out
.width
, out
.height
, out
.left
, out
.top
);
1000 bdisp_ctx_state_lock_set(BDISP_PARAMS
, ctx
);
1005 static int bdisp_streamon(struct file
*file
, void *fh
, enum v4l2_buf_type type
)
1007 struct bdisp_ctx
*ctx
= fh_to_ctx(fh
);
1009 if ((type
== V4L2_BUF_TYPE_VIDEO_OUTPUT
) &&
1010 !bdisp_ctx_state_is_set(BDISP_SRC_FMT
, ctx
)) {
1011 dev_err(ctx
->bdisp_dev
->dev
, "src not defined\n");
1015 if ((type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
) &&
1016 !bdisp_ctx_state_is_set(BDISP_DST_FMT
, ctx
)) {
1017 dev_err(ctx
->bdisp_dev
->dev
, "dst not defined\n");
1021 return v4l2_m2m_streamon(file
, ctx
->fh
.m2m_ctx
, type
);
1024 static const struct v4l2_ioctl_ops bdisp_ioctl_ops
= {
1025 .vidioc_querycap
= bdisp_querycap
,
1026 .vidioc_enum_fmt_vid_cap
= bdisp_enum_fmt
,
1027 .vidioc_enum_fmt_vid_out
= bdisp_enum_fmt
,
1028 .vidioc_g_fmt_vid_cap
= bdisp_g_fmt
,
1029 .vidioc_g_fmt_vid_out
= bdisp_g_fmt
,
1030 .vidioc_try_fmt_vid_cap
= bdisp_try_fmt
,
1031 .vidioc_try_fmt_vid_out
= bdisp_try_fmt
,
1032 .vidioc_s_fmt_vid_cap
= bdisp_s_fmt
,
1033 .vidioc_s_fmt_vid_out
= bdisp_s_fmt
,
1034 .vidioc_g_selection
= bdisp_g_selection
,
1035 .vidioc_s_selection
= bdisp_s_selection
,
1036 .vidioc_reqbufs
= v4l2_m2m_ioctl_reqbufs
,
1037 .vidioc_create_bufs
= v4l2_m2m_ioctl_create_bufs
,
1038 .vidioc_expbuf
= v4l2_m2m_ioctl_expbuf
,
1039 .vidioc_querybuf
= v4l2_m2m_ioctl_querybuf
,
1040 .vidioc_qbuf
= v4l2_m2m_ioctl_qbuf
,
1041 .vidioc_dqbuf
= v4l2_m2m_ioctl_dqbuf
,
1042 .vidioc_streamon
= bdisp_streamon
,
1043 .vidioc_streamoff
= v4l2_m2m_ioctl_streamoff
,
1044 .vidioc_subscribe_event
= v4l2_ctrl_subscribe_event
,
1045 .vidioc_unsubscribe_event
= v4l2_event_unsubscribe
,
1048 static int bdisp_register_device(struct bdisp_dev
*bdisp
)
1055 bdisp
->vdev
.fops
= &bdisp_fops
;
1056 bdisp
->vdev
.ioctl_ops
= &bdisp_ioctl_ops
;
1057 bdisp
->vdev
.release
= video_device_release_empty
;
1058 bdisp
->vdev
.lock
= &bdisp
->lock
;
1059 bdisp
->vdev
.vfl_dir
= VFL_DIR_M2M
;
1060 bdisp
->vdev
.v4l2_dev
= &bdisp
->v4l2_dev
;
1061 snprintf(bdisp
->vdev
.name
, sizeof(bdisp
->vdev
.name
), "%s.%d",
1062 BDISP_NAME
, bdisp
->id
);
1064 video_set_drvdata(&bdisp
->vdev
, bdisp
);
1066 bdisp
->m2m
.vdev
= &bdisp
->vdev
;
1067 bdisp
->m2m
.m2m_dev
= v4l2_m2m_init(&bdisp_m2m_ops
);
1068 if (IS_ERR(bdisp
->m2m
.m2m_dev
)) {
1069 dev_err(bdisp
->dev
, "failed to initialize v4l2-m2m device\n");
1070 return PTR_ERR(bdisp
->m2m
.m2m_dev
);
1073 ret
= video_register_device(&bdisp
->vdev
, VFL_TYPE_GRABBER
, -1);
1076 "%s(): failed to register video device\n", __func__
);
1077 v4l2_m2m_release(bdisp
->m2m
.m2m_dev
);
1084 static void bdisp_unregister_device(struct bdisp_dev
*bdisp
)
1089 if (bdisp
->m2m
.m2m_dev
)
1090 v4l2_m2m_release(bdisp
->m2m
.m2m_dev
);
1092 video_unregister_device(bdisp
->m2m
.vdev
);
1095 static irqreturn_t
bdisp_irq_thread(int irq
, void *priv
)
1097 struct bdisp_dev
*bdisp
= priv
;
1098 struct bdisp_ctx
*ctx
;
1100 spin_lock(&bdisp
->slock
);
1102 bdisp_dbg_perf_end(bdisp
);
1104 cancel_delayed_work(&bdisp
->timeout_work
);
1106 if (!test_and_clear_bit(ST_M2M_RUNNING
, &bdisp
->state
))
1109 if (test_and_clear_bit(ST_M2M_SUSPENDING
, &bdisp
->state
)) {
1110 set_bit(ST_M2M_SUSPENDED
, &bdisp
->state
);
1111 wake_up(&bdisp
->irq_queue
);
1115 ctx
= v4l2_m2m_get_curr_priv(bdisp
->m2m
.m2m_dev
);
1116 if (!ctx
|| !ctx
->fh
.m2m_ctx
)
1119 spin_unlock(&bdisp
->slock
);
1121 bdisp_job_finish(ctx
, VB2_BUF_STATE_DONE
);
1123 if (bdisp_ctx_state_is_set(BDISP_CTX_STOP_REQ
, ctx
)) {
1124 bdisp_ctx_state_lock_clear(BDISP_CTX_STOP_REQ
, ctx
);
1125 wake_up(&bdisp
->irq_queue
);
1131 spin_unlock(&bdisp
->slock
);
1136 static irqreturn_t
bdisp_irq_handler(int irq
, void *priv
)
1138 if (bdisp_hw_get_and_clear_irq((struct bdisp_dev
*)priv
))
1141 return IRQ_WAKE_THREAD
;
1144 static void bdisp_irq_timeout(struct work_struct
*ptr
)
1146 struct delayed_work
*twork
= to_delayed_work(ptr
);
1147 struct bdisp_dev
*bdisp
= container_of(twork
, struct bdisp_dev
,
1149 struct bdisp_ctx
*ctx
;
1151 ctx
= v4l2_m2m_get_curr_priv(bdisp
->m2m
.m2m_dev
);
1153 dev_err(ctx
->bdisp_dev
->dev
, "Device work timeout\n");
1155 spin_lock(&bdisp
->slock
);
1156 clear_bit(ST_M2M_RUNNING
, &bdisp
->state
);
1157 spin_unlock(&bdisp
->slock
);
1159 bdisp_hw_reset(bdisp
);
1161 bdisp_job_finish(ctx
, VB2_BUF_STATE_ERROR
);
1164 static int bdisp_m2m_suspend(struct bdisp_dev
*bdisp
)
1166 unsigned long flags
;
1169 spin_lock_irqsave(&bdisp
->slock
, flags
);
1170 if (!test_bit(ST_M2M_RUNNING
, &bdisp
->state
)) {
1171 spin_unlock_irqrestore(&bdisp
->slock
, flags
);
1174 clear_bit(ST_M2M_SUSPENDED
, &bdisp
->state
);
1175 set_bit(ST_M2M_SUSPENDING
, &bdisp
->state
);
1176 spin_unlock_irqrestore(&bdisp
->slock
, flags
);
1178 timeout
= wait_event_timeout(bdisp
->irq_queue
,
1179 test_bit(ST_M2M_SUSPENDED
, &bdisp
->state
),
1180 BDISP_WORK_TIMEOUT
);
1182 clear_bit(ST_M2M_SUSPENDING
, &bdisp
->state
);
1185 dev_err(bdisp
->dev
, "%s IRQ timeout\n", __func__
);
1192 static int bdisp_m2m_resume(struct bdisp_dev
*bdisp
)
1194 struct bdisp_ctx
*ctx
;
1195 unsigned long flags
;
1197 spin_lock_irqsave(&bdisp
->slock
, flags
);
1198 ctx
= bdisp
->m2m
.ctx
;
1199 bdisp
->m2m
.ctx
= NULL
;
1200 spin_unlock_irqrestore(&bdisp
->slock
, flags
);
1202 if (test_and_clear_bit(ST_M2M_SUSPENDED
, &bdisp
->state
))
1203 bdisp_job_finish(ctx
, VB2_BUF_STATE_ERROR
);
1208 static int bdisp_runtime_resume(struct device
*dev
)
1210 struct bdisp_dev
*bdisp
= dev_get_drvdata(dev
);
1211 int ret
= clk_enable(bdisp
->clock
);
1216 return bdisp_m2m_resume(bdisp
);
1219 static int bdisp_runtime_suspend(struct device
*dev
)
1221 struct bdisp_dev
*bdisp
= dev_get_drvdata(dev
);
1222 int ret
= bdisp_m2m_suspend(bdisp
);
1225 clk_disable(bdisp
->clock
);
1230 static int bdisp_resume(struct device
*dev
)
1232 struct bdisp_dev
*bdisp
= dev_get_drvdata(dev
);
1233 unsigned long flags
;
1236 spin_lock_irqsave(&bdisp
->slock
, flags
);
1237 opened
= test_bit(ST_M2M_OPEN
, &bdisp
->state
);
1238 spin_unlock_irqrestore(&bdisp
->slock
, flags
);
1243 if (!pm_runtime_suspended(dev
))
1244 return bdisp_runtime_resume(dev
);
1249 static int bdisp_suspend(struct device
*dev
)
1251 if (!pm_runtime_suspended(dev
))
1252 return bdisp_runtime_suspend(dev
);
1257 static const struct dev_pm_ops bdisp_pm_ops
= {
1258 .suspend
= bdisp_suspend
,
1259 .resume
= bdisp_resume
,
1260 .runtime_suspend
= bdisp_runtime_suspend
,
1261 .runtime_resume
= bdisp_runtime_resume
,
1264 static int bdisp_remove(struct platform_device
*pdev
)
1266 struct bdisp_dev
*bdisp
= platform_get_drvdata(pdev
);
1268 bdisp_unregister_device(bdisp
);
1270 bdisp_hw_free_filters(bdisp
->dev
);
1272 vb2_dma_contig_cleanup_ctx(bdisp
->alloc_ctx
);
1274 pm_runtime_disable(&pdev
->dev
);
1276 bdisp_debugfs_remove(bdisp
);
1278 v4l2_device_unregister(&bdisp
->v4l2_dev
);
1280 if (!IS_ERR(bdisp
->clock
))
1281 clk_unprepare(bdisp
->clock
);
1283 dev_dbg(&pdev
->dev
, "%s driver unloaded\n", pdev
->name
);
1288 static int bdisp_probe(struct platform_device
*pdev
)
1290 struct bdisp_dev
*bdisp
;
1291 struct resource
*res
;
1292 struct device
*dev
= &pdev
->dev
;
1295 dev_dbg(dev
, "%s\n", __func__
);
1297 bdisp
= devm_kzalloc(dev
, sizeof(struct bdisp_dev
), GFP_KERNEL
);
1303 platform_set_drvdata(pdev
, bdisp
);
1306 bdisp
->id
= of_alias_get_id(pdev
->dev
.of_node
, BDISP_NAME
);
1308 bdisp
->id
= pdev
->id
;
1310 init_waitqueue_head(&bdisp
->irq_queue
);
1311 INIT_DELAYED_WORK(&bdisp
->timeout_work
, bdisp_irq_timeout
);
1312 bdisp
->work_queue
= create_workqueue(BDISP_NAME
);
1314 spin_lock_init(&bdisp
->slock
);
1315 mutex_init(&bdisp
->lock
);
1318 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
1319 bdisp
->regs
= devm_ioremap_resource(dev
, res
);
1320 if (IS_ERR(bdisp
->regs
)) {
1321 dev_err(dev
, "failed to get regs\n");
1322 return PTR_ERR(bdisp
->regs
);
1325 bdisp
->clock
= devm_clk_get(dev
, BDISP_NAME
);
1326 if (IS_ERR(bdisp
->clock
)) {
1327 dev_err(dev
, "failed to get clock\n");
1328 return PTR_ERR(bdisp
->clock
);
1331 ret
= clk_prepare(bdisp
->clock
);
1333 dev_err(dev
, "clock prepare failed\n");
1334 bdisp
->clock
= ERR_PTR(-EINVAL
);
1338 res
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 0);
1340 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");
1374 /* Continuous memory allocator */
1375 bdisp
->alloc_ctx
= vb2_dma_contig_init_ctx(dev
);
1376 if (IS_ERR(bdisp
->alloc_ctx
)) {
1377 ret
= PTR_ERR(bdisp
->alloc_ctx
);
1382 if (bdisp_hw_alloc_filters(bdisp
->dev
)) {
1383 dev_err(bdisp
->dev
, "no memory for filters\n");
1389 ret
= bdisp_register_device(bdisp
);
1391 dev_err(dev
, "failed to register\n");
1395 dev_info(dev
, "%s%d registered as /dev/video%d\n", BDISP_NAME
,
1396 bdisp
->id
, bdisp
->vdev
.num
);
1398 pm_runtime_put(dev
);
1403 bdisp_hw_free_filters(bdisp
->dev
);
1405 vb2_dma_contig_cleanup_ctx(bdisp
->alloc_ctx
);
1407 pm_runtime_put(dev
);
1409 bdisp_debugfs_remove(bdisp
);
1411 v4l2_device_unregister(&bdisp
->v4l2_dev
);
1413 if (!IS_ERR(bdisp
->clock
))
1414 clk_unprepare(bdisp
->clock
);
1419 static const struct of_device_id bdisp_match_types
[] = {
1421 .compatible
= "st,stih407-bdisp",
1426 MODULE_DEVICE_TABLE(of
, bdisp_match_types
);
1428 static struct platform_driver bdisp_driver
= {
1429 .probe
= bdisp_probe
,
1430 .remove
= bdisp_remove
,
1433 .of_match_table
= bdisp_match_types
,
1434 .pm
= &bdisp_pm_ops
,
1438 module_platform_driver(bdisp_driver
);
1440 MODULE_DESCRIPTION("2D blitter for STMicroelectronics SoC");
1441 MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>");
1442 MODULE_LICENSE("GPL");