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()
146 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; in queue_init()
147 src_vq->io_modes = VB2_MMAP | VB2_USERPTR; in queue_init()
148 src_vq->drv_priv = ctx; in queue_init()
149 src_vq->ops = &g2d_qops; in queue_init()
150 src_vq->mem_ops = &vb2_dma_contig_memops; in queue_init()
151 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); in queue_init()
152 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; in queue_init()
153 src_vq->lock = &ctx->dev->mutex; in queue_init()
154 src_vq->dev = ctx->dev->v4l2_dev.dev; in queue_init()
160 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; in queue_init()
161 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; in queue_init()
162 dst_vq->drv_priv = ctx; in queue_init()
163 dst_vq->ops = &g2d_qops; in queue_init()
164 dst_vq->mem_ops = &vb2_dma_contig_memops; in queue_init()
165 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); in queue_init()
166 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; in queue_init()
167 dst_vq->lock = &ctx->dev->mutex; in queue_init()
168 dst_vq->dev = ctx->dev->v4l2_dev.dev; in queue_init()
175 struct g2d_ctx *ctx = container_of(ctrl->handler, struct g2d_ctx, in g2d_s_ctrl()
179 spin_lock_irqsave(&ctx->dev->ctrl_lock, flags); in g2d_s_ctrl()
180 switch (ctrl->id) { in g2d_s_ctrl()
182 if (ctrl->val == V4L2_COLORFX_NEGATIVE) in g2d_s_ctrl()
183 ctx->rop = ROP4_INVERT; in g2d_s_ctrl()
185 ctx->rop = ROP4_COPY; in g2d_s_ctrl()
189 ctx->flip = ctx->ctrl_hflip->val | (ctx->ctrl_vflip->val << 1); in g2d_s_ctrl()
193 spin_unlock_irqrestore(&ctx->dev->ctrl_lock, flags); in g2d_s_ctrl()
203 struct g2d_dev *dev = ctx->dev; in g2d_setup_ctrls()
205 v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); in g2d_setup_ctrls()
207 ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops, in g2d_setup_ctrls()
210 ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &g2d_ctrl_ops, in g2d_setup_ctrls()
214 &ctx->ctrl_handler, in g2d_setup_ctrls()
221 if (ctx->ctrl_handler.error) { in g2d_setup_ctrls()
222 int err = ctx->ctrl_handler.error; in g2d_setup_ctrls()
223 v4l2_err(&dev->v4l2_dev, "g2d_setup_ctrls failed\n"); in g2d_setup_ctrls()
224 v4l2_ctrl_handler_free(&ctx->ctrl_handler); in g2d_setup_ctrls()
228 v4l2_ctrl_cluster(2, &ctx->ctrl_hflip); in g2d_setup_ctrls()
241 return -ENOMEM; in g2d_open()
242 ctx->dev = dev; in g2d_open()
244 ctx->in = def_frame; in g2d_open()
245 ctx->out = def_frame; in g2d_open()
247 if (mutex_lock_interruptible(&dev->mutex)) { in g2d_open()
249 return -ERESTARTSYS; in g2d_open()
251 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); in g2d_open()
252 if (IS_ERR(ctx->fh.m2m_ctx)) { in g2d_open()
253 ret = PTR_ERR(ctx->fh.m2m_ctx); in g2d_open()
254 mutex_unlock(&dev->mutex); in g2d_open()
258 v4l2_fh_init(&ctx->fh, video_devdata(file)); in g2d_open()
259 file->private_data = &ctx->fh; in g2d_open()
260 v4l2_fh_add(&ctx->fh); in g2d_open()
265 v4l2_ctrl_handler_setup(&ctx->ctrl_handler); in g2d_open()
267 ctx->fh.ctrl_handler = &ctx->ctrl_handler; in g2d_open()
268 mutex_unlock(&dev->mutex); in g2d_open()
270 v4l2_info(&dev->v4l2_dev, "instance opened\n"); in g2d_open()
277 struct g2d_ctx *ctx = fh2ctx(file->private_data); in g2d_release()
279 mutex_lock(&dev->mutex); in g2d_release()
280 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); in g2d_release()
281 mutex_unlock(&dev->mutex); in g2d_release()
282 v4l2_ctrl_handler_free(&ctx->ctrl_handler); in g2d_release()
283 v4l2_fh_del(&ctx->fh); in g2d_release()
284 v4l2_fh_exit(&ctx->fh); in g2d_release()
286 v4l2_info(&dev->v4l2_dev, "instance closed\n"); in g2d_release()
294 strscpy(cap->driver, G2D_NAME, sizeof(cap->driver)); in vidioc_querycap()
295 strscpy(cap->card, G2D_NAME, sizeof(cap->card)); in vidioc_querycap()
296 cap->bus_info[0] = 0; in vidioc_querycap()
302 if (f->index >= NUM_FORMATS) in vidioc_enum_fmt()
303 return -EINVAL; in vidioc_enum_fmt()
304 f->pixelformat = formats[f->index].fourcc; in vidioc_enum_fmt()
314 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); in vidioc_g_fmt()
316 return -EINVAL; in vidioc_g_fmt()
317 frm = get_frame(ctx, f->type); in vidioc_g_fmt()
321 f->fmt.pix.width = frm->width; in vidioc_g_fmt()
322 f->fmt.pix.height = frm->height; in vidioc_g_fmt()
323 f->fmt.pix.field = V4L2_FIELD_NONE; in vidioc_g_fmt()
324 f->fmt.pix.pixelformat = frm->fmt->fourcc; in vidioc_g_fmt()
325 f->fmt.pix.bytesperline = (frm->width * frm->fmt->depth) >> 3; in vidioc_g_fmt()
326 f->fmt.pix.sizeimage = frm->size; in vidioc_g_fmt()
337 return -EINVAL; in vidioc_try_fmt()
339 field = &f->fmt.pix.field; in vidioc_try_fmt()
343 return -EINVAL; in vidioc_try_fmt()
345 if (f->fmt.pix.width > MAX_WIDTH) in vidioc_try_fmt()
346 f->fmt.pix.width = MAX_WIDTH; in vidioc_try_fmt()
347 if (f->fmt.pix.height > MAX_HEIGHT) in vidioc_try_fmt()
348 f->fmt.pix.height = MAX_HEIGHT; in vidioc_try_fmt()
350 if (f->fmt.pix.width < 1) in vidioc_try_fmt()
351 f->fmt.pix.width = 1; in vidioc_try_fmt()
352 if (f->fmt.pix.height < 1) in vidioc_try_fmt()
353 f->fmt.pix.height = 1; in vidioc_try_fmt()
355 f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; in vidioc_try_fmt()
356 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; in vidioc_try_fmt()
363 struct g2d_dev *dev = ctx->dev; in vidioc_s_fmt()
374 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); in vidioc_s_fmt()
376 v4l2_err(&dev->v4l2_dev, "queue (%d) bust\n", f->type); in vidioc_s_fmt()
377 return -EBUSY; in vidioc_s_fmt()
379 frm = get_frame(ctx, f->type); in vidioc_s_fmt()
384 return -EINVAL; in vidioc_s_fmt()
385 frm->width = f->fmt.pix.width; in vidioc_s_fmt()
386 frm->height = f->fmt.pix.height; in vidioc_s_fmt()
387 frm->size = f->fmt.pix.sizeimage; in vidioc_s_fmt()
389 frm->o_width = 0; in vidioc_s_fmt()
390 frm->o_height = 0; in vidioc_s_fmt()
391 frm->c_width = frm->width; in vidioc_s_fmt()
392 frm->c_height = frm->height; in vidioc_s_fmt()
393 frm->right = frm->width; in vidioc_s_fmt()
394 frm->bottom = frm->height; in vidioc_s_fmt()
395 frm->fmt = fmt; in vidioc_s_fmt()
396 frm->stride = f->fmt.pix.bytesperline; in vidioc_s_fmt()
406 f = get_frame(ctx, s->type); in vidioc_g_selection()
410 switch (s->target) { in vidioc_g_selection()
414 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) in vidioc_g_selection()
415 return -EINVAL; in vidioc_g_selection()
420 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) in vidioc_g_selection()
421 return -EINVAL; in vidioc_g_selection()
424 return -EINVAL; in vidioc_g_selection()
427 switch (s->target) { in vidioc_g_selection()
430 s->r.left = f->o_height; in vidioc_g_selection()
431 s->r.top = f->o_width; in vidioc_g_selection()
432 s->r.width = f->c_width; in vidioc_g_selection()
433 s->r.height = f->c_height; in vidioc_g_selection()
439 s->r.left = 0; in vidioc_g_selection()
440 s->r.top = 0; in vidioc_g_selection()
441 s->r.width = f->width; in vidioc_g_selection()
442 s->r.height = f->height; in vidioc_g_selection()
445 return -EINVAL; in vidioc_g_selection()
454 struct g2d_dev *dev = ctx->dev; in vidioc_try_selection()
457 f = get_frame(ctx, s->type); in vidioc_try_selection()
461 if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { in vidioc_try_selection()
462 if (s->target != V4L2_SEL_TGT_COMPOSE) in vidioc_try_selection()
463 return -EINVAL; in vidioc_try_selection()
464 } else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { in vidioc_try_selection()
465 if (s->target != V4L2_SEL_TGT_CROP) in vidioc_try_selection()
466 return -EINVAL; in vidioc_try_selection()
469 if (s->r.top < 0 || s->r.left < 0) { in vidioc_try_selection()
470 v4l2_err(&dev->v4l2_dev, in vidioc_try_selection()
472 return -EINVAL; in vidioc_try_selection()
488 f = get_frame(ctx, s->type); in vidioc_s_selection()
492 f->c_width = s->r.width; in vidioc_s_selection()
493 f->c_height = s->r.height; in vidioc_s_selection()
494 f->o_width = s->r.left; in vidioc_s_selection()
495 f->o_height = s->r.top; in vidioc_s_selection()
496 f->bottom = f->o_height + f->c_height; in vidioc_s_selection()
497 f->right = f->o_width + f->c_width; in vidioc_s_selection()
504 struct g2d_dev *dev = ctx->dev; in device_run()
509 dev->curr = ctx; in device_run()
511 src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); in device_run()
512 dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); in device_run()
514 clk_enable(dev->gate); in device_run()
517 spin_lock_irqsave(&dev->ctrl_lock, flags); in device_run()
519 g2d_set_src_size(dev, &ctx->in); in device_run()
520 g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(&src->vb2_buf, 0)); in device_run()
522 g2d_set_dst_size(dev, &ctx->out); in device_run()
523 g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(&dst->vb2_buf, 0)); in device_run()
525 g2d_set_rop4(dev, ctx->rop); in device_run()
526 g2d_set_flip(dev, ctx->flip); in device_run()
528 if (ctx->in.c_width != ctx->out.c_width || in device_run()
529 ctx->in.c_height != ctx->out.c_height) { in device_run()
530 if (dev->variant->hw_rev == TYPE_G2D_3X) in device_run()
533 g2d_set_v41_stretch(dev, &ctx->in, &ctx->out); in device_run()
539 spin_unlock_irqrestore(&dev->ctrl_lock, flags); in device_run()
545 struct g2d_ctx *ctx = dev->curr; in g2d_isr()
549 clk_disable(dev->gate); in g2d_isr()
553 src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); in g2d_isr()
554 dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); in g2d_isr()
559 dst->timecode = src->timecode; in g2d_isr()
560 dst->vb2_buf.timestamp = src->vb2_buf.timestamp; in g2d_isr()
561 dst->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; in g2d_isr()
562 dst->flags |= in g2d_isr()
563 src->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; in g2d_isr()
567 v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx); in g2d_isr()
569 dev->curr = NULL; in g2d_isr()
611 .minor = -1,
630 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); in g2d_probe()
632 return -ENOMEM; in g2d_probe()
634 spin_lock_init(&dev->ctrl_lock); in g2d_probe()
635 mutex_init(&dev->mutex); in g2d_probe()
636 atomic_set(&dev->num_inst, 0); in g2d_probe()
640 dev->regs = devm_ioremap_resource(&pdev->dev, res); in g2d_probe()
641 if (IS_ERR(dev->regs)) in g2d_probe()
642 return PTR_ERR(dev->regs); in g2d_probe()
644 dev->clk = clk_get(&pdev->dev, "sclk_fimg2d"); in g2d_probe()
645 if (IS_ERR(dev->clk)) { in g2d_probe()
646 dev_err(&pdev->dev, "failed to get g2d clock\n"); in g2d_probe()
647 return -ENXIO; in g2d_probe()
650 ret = clk_prepare(dev->clk); in g2d_probe()
652 dev_err(&pdev->dev, "failed to prepare g2d clock\n"); in g2d_probe()
656 dev->gate = clk_get(&pdev->dev, "fimg2d"); in g2d_probe()
657 if (IS_ERR(dev->gate)) { in g2d_probe()
658 dev_err(&pdev->dev, "failed to get g2d clock gate\n"); in g2d_probe()
659 ret = -ENXIO; in g2d_probe()
663 ret = clk_prepare(dev->gate); in g2d_probe()
665 dev_err(&pdev->dev, "failed to prepare g2d clock gate\n"); in g2d_probe()
671 dev_err(&pdev->dev, "failed to find IRQ\n"); in g2d_probe()
672 ret = -ENXIO; in g2d_probe()
676 dev->irq = res->start; in g2d_probe()
678 ret = devm_request_irq(&pdev->dev, dev->irq, g2d_isr, in g2d_probe()
679 0, pdev->name, dev); in g2d_probe()
681 dev_err(&pdev->dev, "failed to install IRQ\n"); in g2d_probe()
685 vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); in g2d_probe()
687 ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); in g2d_probe()
692 v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); in g2d_probe()
693 ret = -ENOMEM; in g2d_probe()
697 set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags); in g2d_probe()
698 vfd->lock = &dev->mutex; in g2d_probe()
699 vfd->v4l2_dev = &dev->v4l2_dev; in g2d_probe()
700 vfd->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; in g2d_probe()
703 dev->m2m_dev = v4l2_m2m_init(&g2d_m2m_ops); in g2d_probe()
704 if (IS_ERR(dev->m2m_dev)) { in g2d_probe()
705 v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); in g2d_probe()
706 ret = PTR_ERR(dev->m2m_dev); in g2d_probe()
710 def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3; in g2d_probe()
712 of_id = of_match_node(exynos_g2d_match, pdev->dev.of_node); in g2d_probe()
714 ret = -ENODEV; in g2d_probe()
717 dev->variant = (struct g2d_variant *)of_id->data; in g2d_probe()
721 v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); in g2d_probe()
725 dev->vfd = vfd; in g2d_probe()
726 v4l2_info(&dev->v4l2_dev, "device registered as /dev/video%d\n", in g2d_probe()
727 vfd->num); in g2d_probe()
732 v4l2_m2m_release(dev->m2m_dev); in g2d_probe()
736 v4l2_device_unregister(&dev->v4l2_dev); in g2d_probe()
738 clk_unprepare(dev->gate); in g2d_probe()
740 clk_put(dev->gate); in g2d_probe()
742 clk_unprepare(dev->clk); in g2d_probe()
744 clk_put(dev->clk); in g2d_probe()
753 v4l2_info(&dev->v4l2_dev, "Removing " G2D_NAME); in g2d_remove()
754 v4l2_m2m_release(dev->m2m_dev); in g2d_remove()
755 video_unregister_device(dev->vfd); in g2d_remove()
756 v4l2_device_unregister(&dev->v4l2_dev); in g2d_remove()
757 vb2_dma_contig_clear_max_seg_size(&pdev->dev); in g2d_remove()
758 clk_unprepare(dev->gate); in g2d_remove()
759 clk_put(dev->gate); in g2d_remove()
760 clk_unprepare(dev->clk); in g2d_remove()
761 clk_put(dev->clk); in g2d_remove()
766 .hw_rev = TYPE_G2D_3X, /* Revision 3.0 for S5PV210 and Exynos4210 */
775 .compatible = "samsung,s5pv210-g2d",
778 .compatible = "samsung,exynos4212-g2d",
797 MODULE_DESCRIPTION("S5P G2D 2d graphics accelerator driver");