Lines Matching +full:s5pv210 +full:- +full:g2d
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Samsung S5P G2D - 2D Graphics Accelerator Driver
19 #include <media/v4l2-mem2mem.h>
20 #include <media/v4l2-device.h>
21 #include <media/v4l2-ioctl.h>
22 #include <media/videobuf2-v4l2.h>
23 #include <media/videobuf2-dma-contig.h>
25 #include "g2d.h"
26 #include "g2d-regs.h"
75 if (formats[i].fourcc == f->fmt.pix.pixelformat) in find_fmt()
87 return &ctx->in; in get_frame()
89 return &ctx->out; in get_frame()
91 return ERR_PTR(-EINVAL); in get_frame()
100 struct g2d_frame *f = get_frame(ctx, vq->type); in g2d_queue_setup()
105 sizes[0] = f->size; in g2d_queue_setup()
116 struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); in g2d_buf_prepare()
117 struct g2d_frame *f = get_frame(ctx, vb->vb2_queue->type); in g2d_buf_prepare()
121 vb2_set_plane_payload(vb, 0, f->size); in g2d_buf_prepare()
128 struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); in g2d_buf_queue()
129 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); in g2d_buf_queue()
144 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; in queue_init()
145 src_vq->io_modes = VB2_MMAP | VB2_USERPTR; in queue_init()
146 src_vq->drv_priv = ctx; in queue_init()
147 src_vq->ops = &g2d_qops; in queue_init()
148 src_vq->mem_ops = &vb2_dma_contig_memops; in queue_init()
149 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); in queue_init()
150 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; in queue_init()
151 src_vq->lock = &ctx->dev->mutex; in queue_init()
152 src_vq->dev = ctx->dev->v4l2_dev.dev; in queue_init()
158 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; in queue_init()
159 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; in queue_init()
160 dst_vq->drv_priv = ctx; in queue_init()
161 dst_vq->ops = &g2d_qops; in queue_init()
162 dst_vq->mem_ops = &vb2_dma_contig_memops; in queue_init()
163 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); in queue_init()
164 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; in queue_init()
165 dst_vq->lock = &ctx->dev->mutex; in queue_init()
166 dst_vq->dev = ctx->dev->v4l2_dev.dev; in queue_init()
173 struct g2d_ctx *ctx = container_of(ctrl->handler, struct g2d_ctx, in g2d_s_ctrl()
177 spin_lock_irqsave(&ctx->dev->ctrl_lock, flags); in g2d_s_ctrl()
178 switch (ctrl->id) { in g2d_s_ctrl()
180 if (ctrl->val == V4L2_COLORFX_NEGATIVE) in g2d_s_ctrl()
181 ctx->rop = ROP4_INVERT; in g2d_s_ctrl()
183 ctx->rop = ROP4_COPY; in g2d_s_ctrl()
187 ctx->flip = ctx->ctrl_hflip->val | (ctx->ctrl_vflip->val << 1); in g2d_s_ctrl()
191 spin_unlock_irqrestore(&ctx->dev->ctrl_lock, flags); in g2d_s_ctrl()
201 struct g2d_dev *dev = ctx->dev; in g2d_setup_ctrls()
203 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); in g2d_setup_ctrls()
205 ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops, in g2d_setup_ctrls()
208 ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops, in g2d_setup_ctrls()
212 &ctx->ctrl_handler, in g2d_setup_ctrls()
219 if (ctx->ctrl_handler.error) { in g2d_setup_ctrls()
220 int err = ctx->ctrl_handler.error; in g2d_setup_ctrls()
221 v4l2_err(&dev->v4l2_dev, "g2d_setup_ctrls failed\n"); in g2d_setup_ctrls()
222 v4l2_ctrl_handler_free(&ctx->ctrl_handler); in g2d_setup_ctrls()
226 v4l2_ctrl_cluster(2, &ctx->ctrl_hflip); in g2d_setup_ctrls()
239 return -ENOMEM; in g2d_open()
240 ctx->dev = dev; in g2d_open()
242 ctx->in = def_frame; in g2d_open()
243 ctx->out = def_frame; in g2d_open()
245 if (mutex_lock_interruptible(&dev->mutex)) { in g2d_open()
247 return -ERESTARTSYS; in g2d_open()
249 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); in g2d_open()
250 if (IS_ERR(ctx->fh.m2m_ctx)) { in g2d_open()
251 ret = PTR_ERR(ctx->fh.m2m_ctx); in g2d_open()
252 mutex_unlock(&dev->mutex); in g2d_open()
256 v4l2_fh_init(&ctx->fh, video_devdata(file)); in g2d_open()
257 file->private_data = &ctx->fh; in g2d_open()
258 v4l2_fh_add(&ctx->fh); in g2d_open()
263 v4l2_ctrl_handler_setup(&ctx->ctrl_handler); in g2d_open()
265 ctx->fh.ctrl_handler = &ctx->ctrl_handler; in g2d_open()
266 mutex_unlock(&dev->mutex); in g2d_open()
268 v4l2_info(&dev->v4l2_dev, "instance opened\n"); in g2d_open()
275 struct g2d_ctx *ctx = fh2ctx(file->private_data); in g2d_release()
277 mutex_lock(&dev->mutex); in g2d_release()
278 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); in g2d_release()
279 mutex_unlock(&dev->mutex); in g2d_release()
280 v4l2_ctrl_handler_free(&ctx->ctrl_handler); in g2d_release()
281 v4l2_fh_del(&ctx->fh); in g2d_release()
282 v4l2_fh_exit(&ctx->fh); in g2d_release()
284 v4l2_info(&dev->v4l2_dev, "instance closed\n"); in g2d_release()
292 strscpy(cap->driver, G2D_NAME, sizeof(cap->driver)); in vidioc_querycap()
293 strscpy(cap->card, G2D_NAME, sizeof(cap->card)); in vidioc_querycap()
294 cap->bus_info[0] = 0; in vidioc_querycap()
300 if (f->index >= NUM_FORMATS) in vidioc_enum_fmt()
301 return -EINVAL; in vidioc_enum_fmt()
302 f->pixelformat = formats[f->index].fourcc; in vidioc_enum_fmt()
312 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); in vidioc_g_fmt()
314 return -EINVAL; in vidioc_g_fmt()
315 frm = get_frame(ctx, f->type); in vidioc_g_fmt()
319 f->fmt.pix.width = frm->width; in vidioc_g_fmt()
320 f->fmt.pix.height = frm->height; in vidioc_g_fmt()
321 f->fmt.pix.field = V4L2_FIELD_NONE; in vidioc_g_fmt()
322 f->fmt.pix.pixelformat = frm->fmt->fourcc; in vidioc_g_fmt()
323 f->fmt.pix.bytesperline = (frm->width * frm->fmt->depth) >> 3; in vidioc_g_fmt()
324 f->fmt.pix.sizeimage = frm->size; in vidioc_g_fmt()
335 return -EINVAL; in vidioc_try_fmt()
337 field = &f->fmt.pix.field; in vidioc_try_fmt()
341 return -EINVAL; in vidioc_try_fmt()
343 if (f->fmt.pix.width > MAX_WIDTH) in vidioc_try_fmt()
344 f->fmt.pix.width = MAX_WIDTH; in vidioc_try_fmt()
345 if (f->fmt.pix.height > MAX_HEIGHT) in vidioc_try_fmt()
346 f->fmt.pix.height = MAX_HEIGHT; in vidioc_try_fmt()
348 if (f->fmt.pix.width < 1) in vidioc_try_fmt()
349 f->fmt.pix.width = 1; in vidioc_try_fmt()
350 if (f->fmt.pix.height < 1) in vidioc_try_fmt()
351 f->fmt.pix.height = 1; in vidioc_try_fmt()
353 f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; in vidioc_try_fmt()
354 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; in vidioc_try_fmt()
361 struct g2d_dev *dev = ctx->dev; in vidioc_s_fmt()
372 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); in vidioc_s_fmt()
374 v4l2_err(&dev->v4l2_dev, "queue (%d) bust\n", f->type); in vidioc_s_fmt()
375 return -EBUSY; in vidioc_s_fmt()
377 frm = get_frame(ctx, f->type); in vidioc_s_fmt()
382 return -EINVAL; in vidioc_s_fmt()
383 frm->width = f->fmt.pix.width; in vidioc_s_fmt()
384 frm->height = f->fmt.pix.height; in vidioc_s_fmt()
385 frm->size = f->fmt.pix.sizeimage; in vidioc_s_fmt()
387 frm->o_width = 0; in vidioc_s_fmt()
388 frm->o_height = 0; in vidioc_s_fmt()
389 frm->c_width = frm->width; in vidioc_s_fmt()
390 frm->c_height = frm->height; in vidioc_s_fmt()
391 frm->right = frm->width; in vidioc_s_fmt()
392 frm->bottom = frm->height; in vidioc_s_fmt()
393 frm->fmt = fmt; in vidioc_s_fmt()
394 frm->stride = f->fmt.pix.bytesperline; in vidioc_s_fmt()
404 f = get_frame(ctx, s->type); in vidioc_g_selection()
408 switch (s->target) { in vidioc_g_selection()
412 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) in vidioc_g_selection()
413 return -EINVAL; in vidioc_g_selection()
418 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) in vidioc_g_selection()
419 return -EINVAL; in vidioc_g_selection()
422 return -EINVAL; in vidioc_g_selection()
425 switch (s->target) { in vidioc_g_selection()
428 s->r.left = f->o_height; in vidioc_g_selection()
429 s->r.top = f->o_width; in vidioc_g_selection()
430 s->r.width = f->c_width; in vidioc_g_selection()
431 s->r.height = f->c_height; in vidioc_g_selection()
437 s->r.left = 0; in vidioc_g_selection()
438 s->r.top = 0; in vidioc_g_selection()
439 s->r.width = f->width; in vidioc_g_selection()
440 s->r.height = f->height; in vidioc_g_selection()
443 return -EINVAL; in vidioc_g_selection()
452 struct g2d_dev *dev = ctx->dev; in vidioc_try_selection()
455 f = get_frame(ctx, s->type); in vidioc_try_selection()
459 if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { in vidioc_try_selection()
460 if (s->target != V4L2_SEL_TGT_COMPOSE) in vidioc_try_selection()
461 return -EINVAL; in vidioc_try_selection()
462 } else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { in vidioc_try_selection()
463 if (s->target != V4L2_SEL_TGT_CROP) in vidioc_try_selection()
464 return -EINVAL; in vidioc_try_selection()
467 if (s->r.top < 0 || s->r.left < 0) { in vidioc_try_selection()
468 v4l2_err(&dev->v4l2_dev, in vidioc_try_selection()
470 return -EINVAL; in vidioc_try_selection()
486 f = get_frame(ctx, s->type); in vidioc_s_selection()
490 f->c_width = s->r.width; in vidioc_s_selection()
491 f->c_height = s->r.height; in vidioc_s_selection()
492 f->o_width = s->r.left; in vidioc_s_selection()
493 f->o_height = s->r.top; in vidioc_s_selection()
494 f->bottom = f->o_height + f->c_height; in vidioc_s_selection()
495 f->right = f->o_width + f->c_width; in vidioc_s_selection()
502 struct g2d_dev *dev = ctx->dev; in device_run()
507 dev->curr = ctx; in device_run()
509 src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); in device_run()
510 dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); in device_run()
512 clk_enable(dev->gate); in device_run()
515 spin_lock_irqsave(&dev->ctrl_lock, flags); in device_run()
517 g2d_set_src_size(dev, &ctx->in); in device_run()
518 g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(&src->vb2_buf, 0)); in device_run()
520 g2d_set_dst_size(dev, &ctx->out); in device_run()
521 g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(&dst->vb2_buf, 0)); in device_run()
523 g2d_set_rop4(dev, ctx->rop); in device_run()
524 g2d_set_flip(dev, ctx->flip); in device_run()
526 if (ctx->in.c_width != ctx->out.c_width || in device_run()
527 ctx->in.c_height != ctx->out.c_height) { in device_run()
528 if (dev->variant->hw_rev == TYPE_G2D_3X) in device_run()
531 g2d_set_v41_stretch(dev, &ctx->in, &ctx->out); in device_run()
537 spin_unlock_irqrestore(&dev->ctrl_lock, flags); in device_run()
543 struct g2d_ctx *ctx = dev->curr; in g2d_isr()
547 clk_disable(dev->gate); in g2d_isr()
551 src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); in g2d_isr()
552 dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); in g2d_isr()
557 dst->timecode = src->timecode; in g2d_isr()
558 dst->vb2_buf.timestamp = src->vb2_buf.timestamp; in g2d_isr()
559 dst->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; in g2d_isr()
560 dst->flags |= in g2d_isr()
561 src->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; in g2d_isr()
565 v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx); in g2d_isr()
567 dev->curr = NULL; in g2d_isr()
609 .minor = -1,
627 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); in g2d_probe()
629 return -ENOMEM; in g2d_probe()
631 spin_lock_init(&dev->ctrl_lock); in g2d_probe()
632 mutex_init(&dev->mutex); in g2d_probe()
633 atomic_set(&dev->num_inst, 0); in g2d_probe()
635 dev->regs = devm_platform_ioremap_resource(pdev, 0); in g2d_probe()
636 if (IS_ERR(dev->regs)) in g2d_probe()
637 return PTR_ERR(dev->regs); in g2d_probe()
639 dev->clk = clk_get(&pdev->dev, "sclk_fimg2d"); in g2d_probe()
640 if (IS_ERR(dev->clk)) { in g2d_probe()
641 dev_err(&pdev->dev, "failed to get g2d clock\n"); in g2d_probe()
642 return -ENXIO; in g2d_probe()
645 ret = clk_prepare(dev->clk); in g2d_probe()
647 dev_err(&pdev->dev, "failed to prepare g2d clock\n"); in g2d_probe()
651 dev->gate = clk_get(&pdev->dev, "fimg2d"); in g2d_probe()
652 if (IS_ERR(dev->gate)) { in g2d_probe()
653 dev_err(&pdev->dev, "failed to get g2d clock gate\n"); in g2d_probe()
654 ret = -ENXIO; in g2d_probe()
658 ret = clk_prepare(dev->gate); in g2d_probe()
660 dev_err(&pdev->dev, "failed to prepare g2d clock gate\n"); in g2d_probe()
668 dev->irq = ret; in g2d_probe()
670 ret = devm_request_irq(&pdev->dev, dev->irq, g2d_isr, in g2d_probe()
671 0, pdev->name, dev); in g2d_probe()
673 dev_err(&pdev->dev, "failed to install IRQ\n"); in g2d_probe()
677 vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); in g2d_probe()
679 ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); in g2d_probe()
684 v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); in g2d_probe()
685 ret = -ENOMEM; in g2d_probe()
689 set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags); in g2d_probe()
690 vfd->lock = &dev->mutex; in g2d_probe()
691 vfd->v4l2_dev = &dev->v4l2_dev; in g2d_probe()
692 vfd->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; in g2d_probe()
695 dev->m2m_dev = v4l2_m2m_init(&g2d_m2m_ops); in g2d_probe()
696 if (IS_ERR(dev->m2m_dev)) { in g2d_probe()
697 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); in g2d_probe()
698 ret = PTR_ERR(dev->m2m_dev); in g2d_probe()
702 def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3; in g2d_probe()
704 of_id = of_match_node(exynos_g2d_match, pdev->dev.of_node); in g2d_probe()
706 ret = -ENODEV; in g2d_probe()
709 dev->variant = (struct g2d_variant *)of_id->data; in g2d_probe()
713 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); in g2d_probe()
717 dev->vfd = vfd; in g2d_probe()
718 v4l2_info(&dev->v4l2_dev, "device registered as /dev/video%d\n", in g2d_probe()
719 vfd->num); in g2d_probe()
724 v4l2_m2m_release(dev->m2m_dev); in g2d_probe()
728 v4l2_device_unregister(&dev->v4l2_dev); in g2d_probe()
730 clk_unprepare(dev->gate); in g2d_probe()
732 clk_put(dev->gate); in g2d_probe()
734 clk_unprepare(dev->clk); in g2d_probe()
736 clk_put(dev->clk); in g2d_probe()
745 v4l2_info(&dev->v4l2_dev, "Removing " G2D_NAME); in g2d_remove()
746 v4l2_m2m_release(dev->m2m_dev); in g2d_remove()
747 video_unregister_device(dev->vfd); in g2d_remove()
748 v4l2_device_unregister(&dev->v4l2_dev); in g2d_remove()
749 vb2_dma_contig_clear_max_seg_size(&pdev->dev); in g2d_remove()
750 clk_unprepare(dev->gate); in g2d_remove()
751 clk_put(dev->gate); in g2d_remove()
752 clk_unprepare(dev->clk); in g2d_remove()
753 clk_put(dev->clk); in g2d_remove()
757 .hw_rev = TYPE_G2D_3X, /* Revision 3.0 for S5PV210 and Exynos4210 */
766 .compatible = "samsung,s5pv210-g2d",
769 .compatible = "samsung,exynos4212-g2d",
788 MODULE_DESCRIPTION("S5P G2D 2d graphics accelerator driver");