diff options
author | Mauro Carvalho Chehab <mchehab@kernel.org> | 2022-03-13 13:18:16 +0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@kernel.org> | 2022-03-18 07:56:51 +0300 |
commit | 238c84f71120f41c45301359902a912a19370f3d (patch) | |
tree | c16ced196c926c08b0c1e9513a19710bbbfc9bfa /drivers/media/platform/exynos4-is/fimc-isp-video.c | |
parent | 9b18ef7c9ff408df170ac339c57a759145c055d2 (diff) | |
download | linux-238c84f71120f41c45301359902a912a19370f3d.tar.xz |
media: platform: rename exynos4-is/ to samsung/exynos4-is/
As the end goal is to have platform drivers split by vendor,
rename exynos4-is/ to samsung/exynos4-is/.
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
Diffstat (limited to 'drivers/media/platform/exynos4-is/fimc-isp-video.c')
-rw-r--r-- | drivers/media/platform/exynos4-is/fimc-isp-video.c | 656 |
1 files changed, 0 insertions, 656 deletions
diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c deleted file mode 100644 index 83688a7982f7..000000000000 --- a/drivers/media/platform/exynos4-is/fimc-isp-video.c +++ /dev/null @@ -1,656 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver - * - * FIMC-IS ISP video input and video output DMA interface driver - * - * Copyright (C) 2013 Samsung Electronics Co., Ltd. - * Author: Sylwester Nawrocki <s.nawrocki@samsung.com> - * - * The hardware handling code derived from a driver written by - * Younghwan Joo <yhwan.joo@samsung.com>. - */ - -#include <linux/bitops.h> -#include <linux/device.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/printk.h> -#include <linux/pm_runtime.h> -#include <linux/slab.h> -#include <linux/videodev2.h> - -#include <media/v4l2-device.h> -#include <media/v4l2-ioctl.h> -#include <media/videobuf2-v4l2.h> -#include <media/videobuf2-dma-contig.h> -#include <media/drv-intf/exynos-fimc.h> - -#include "common.h" -#include "media-dev.h" -#include "fimc-is.h" -#include "fimc-isp-video.h" -#include "fimc-is-param.h" - -static int isp_video_capture_queue_setup(struct vb2_queue *vq, - unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], struct device *alloc_devs[]) -{ - struct fimc_isp *isp = vb2_get_drv_priv(vq); - struct v4l2_pix_format_mplane *vid_fmt = &isp->video_capture.pixfmt; - const struct fimc_fmt *fmt = isp->video_capture.format; - unsigned int wh, i; - - wh = vid_fmt->width * vid_fmt->height; - - if (fmt == NULL) - return -EINVAL; - - *num_buffers = clamp_t(u32, *num_buffers, FIMC_ISP_REQ_BUFS_MIN, - FIMC_ISP_REQ_BUFS_MAX); - if (*num_planes) { - if (*num_planes != fmt->memplanes) - return -EINVAL; - for (i = 0; i < *num_planes; i++) - if (sizes[i] < (wh * fmt->depth[i]) / 8) - return -EINVAL; - return 0; - } - - *num_planes = fmt->memplanes; - - for (i = 0; i < fmt->memplanes; i++) - sizes[i] = (wh * fmt->depth[i]) / 8; - - return 0; -} - -static inline struct param_dma_output *__get_isp_dma2(struct fimc_is *is) -{ - return &__get_curr_is_config(is)->isp.dma2_output; -} - -static int isp_video_capture_start_streaming(struct vb2_queue *q, - unsigned int count) -{ - struct fimc_isp *isp = vb2_get_drv_priv(q); - struct fimc_is *is = fimc_isp_to_is(isp); - struct param_dma_output *dma = __get_isp_dma2(is); - struct fimc_is_video *video = &isp->video_capture; - int ret; - - if (!test_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state) || - test_bit(ST_ISP_VID_CAP_STREAMING, &isp->state)) - return 0; - - - dma->cmd = DMA_OUTPUT_COMMAND_ENABLE; - dma->notify_dma_done = DMA_OUTPUT_NOTIFY_DMA_DONE_ENABLE; - dma->buffer_address = is->is_dma_p_region + - DMA2_OUTPUT_ADDR_ARRAY_OFFS; - dma->buffer_number = video->reqbufs_count; - dma->dma_out_mask = video->buf_mask; - - isp_dbg(2, &video->ve.vdev, - "buf_count: %d, planes: %d, dma addr table: %#x\n", - video->buf_count, video->format->memplanes, - dma->buffer_address); - - fimc_is_mem_barrier(); - - fimc_is_set_param_bit(is, PARAM_ISP_DMA2_OUTPUT); - __fimc_is_hw_update_param(is, PARAM_ISP_DMA2_OUTPUT); - - ret = fimc_is_itf_s_param(is, false); - if (ret < 0) - return ret; - - ret = fimc_pipeline_call(&video->ve, set_stream, 1); - if (ret < 0) - return ret; - - set_bit(ST_ISP_VID_CAP_STREAMING, &isp->state); - return ret; -} - -static void isp_video_capture_stop_streaming(struct vb2_queue *q) -{ - struct fimc_isp *isp = vb2_get_drv_priv(q); - struct fimc_is *is = fimc_isp_to_is(isp); - struct param_dma_output *dma = __get_isp_dma2(is); - int ret; - - ret = fimc_pipeline_call(&isp->video_capture.ve, set_stream, 0); - if (ret < 0) - return; - - dma->cmd = DMA_OUTPUT_COMMAND_DISABLE; - dma->notify_dma_done = DMA_OUTPUT_NOTIFY_DMA_DONE_DISABLE; - dma->buffer_number = 0; - dma->buffer_address = 0; - dma->dma_out_mask = 0; - - fimc_is_set_param_bit(is, PARAM_ISP_DMA2_OUTPUT); - __fimc_is_hw_update_param(is, PARAM_ISP_DMA2_OUTPUT); - - ret = fimc_is_itf_s_param(is, false); - if (ret < 0) - dev_warn(&is->pdev->dev, "%s: DMA stop failed\n", __func__); - - fimc_is_hw_set_isp_buf_mask(is, 0); - - clear_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state); - clear_bit(ST_ISP_VID_CAP_STREAMING, &isp->state); - - isp->video_capture.buf_count = 0; -} - -static int isp_video_capture_buffer_prepare(struct vb2_buffer *vb) -{ - struct fimc_isp *isp = vb2_get_drv_priv(vb->vb2_queue); - struct fimc_is_video *video = &isp->video_capture; - int i; - - if (video->format == NULL) - return -EINVAL; - - for (i = 0; i < video->format->memplanes; i++) { - unsigned long size = video->pixfmt.plane_fmt[i].sizeimage; - - if (vb2_plane_size(vb, i) < size) { - v4l2_err(&video->ve.vdev, - "User buffer too small (%ld < %ld)\n", - vb2_plane_size(vb, i), size); - return -EINVAL; - } - vb2_set_plane_payload(vb, i, size); - } - - /* Check if we get one of the already known buffers. */ - if (test_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state)) { - dma_addr_t dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); - int i; - - for (i = 0; i < video->buf_count; i++) - if (video->buffers[i]->dma_addr[0] == dma_addr) - return 0; - return -ENXIO; - } - - return 0; -} - -static void isp_video_capture_buffer_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct fimc_isp *isp = vb2_get_drv_priv(vb->vb2_queue); - struct fimc_is_video *video = &isp->video_capture; - struct fimc_is *is = fimc_isp_to_is(isp); - struct isp_video_buf *ivb = to_isp_video_buf(vbuf); - unsigned long flags; - unsigned int i; - - if (test_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state)) { - spin_lock_irqsave(&is->slock, flags); - video->buf_mask |= BIT(ivb->index); - spin_unlock_irqrestore(&is->slock, flags); - } else { - unsigned int num_planes = video->format->memplanes; - - ivb->index = video->buf_count; - video->buffers[ivb->index] = ivb; - - for (i = 0; i < num_planes; i++) { - int buf_index = ivb->index * num_planes + i; - - ivb->dma_addr[i] = vb2_dma_contig_plane_dma_addr(vb, i); - is->is_p_region->shared[32 + buf_index] = - ivb->dma_addr[i]; - - isp_dbg(2, &video->ve.vdev, - "dma_buf %d (%d/%d/%d) addr: %pad\n", - buf_index, ivb->index, i, vb->index, - &ivb->dma_addr[i]); - } - - if (++video->buf_count < video->reqbufs_count) - return; - - video->buf_mask = (1UL << video->buf_count) - 1; - set_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state); - } - - if (!test_bit(ST_ISP_VID_CAP_STREAMING, &isp->state)) - isp_video_capture_start_streaming(vb->vb2_queue, 0); -} - -/* - * FIMC-IS ISP input and output DMA interface interrupt handler. - * Locking: called with is->slock spinlock held. - */ -void fimc_isp_video_irq_handler(struct fimc_is *is) -{ - struct fimc_is_video *video = &is->isp.video_capture; - struct vb2_v4l2_buffer *vbuf; - int buf_index; - - /* TODO: Ensure the DMA is really stopped in stop_streaming callback */ - if (!test_bit(ST_ISP_VID_CAP_STREAMING, &is->isp.state)) - return; - - buf_index = (is->i2h_cmd.args[1] - 1) % video->buf_count; - vbuf = &video->buffers[buf_index]->vb; - - vbuf->vb2_buf.timestamp = ktime_get_ns(); - vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); - - video->buf_mask &= ~BIT(buf_index); - fimc_is_hw_set_isp_buf_mask(is, video->buf_mask); -} - -static const struct vb2_ops isp_video_capture_qops = { - .queue_setup = isp_video_capture_queue_setup, - .buf_prepare = isp_video_capture_buffer_prepare, - .buf_queue = isp_video_capture_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .start_streaming = isp_video_capture_start_streaming, - .stop_streaming = isp_video_capture_stop_streaming, -}; - -static int isp_video_open(struct file *file) -{ - struct fimc_isp *isp = video_drvdata(file); - struct exynos_video_entity *ve = &isp->video_capture.ve; - struct media_entity *me = &ve->vdev.entity; - int ret; - - if (mutex_lock_interruptible(&isp->video_lock)) - return -ERESTARTSYS; - - ret = v4l2_fh_open(file); - if (ret < 0) - goto unlock; - - ret = pm_runtime_resume_and_get(&isp->pdev->dev); - if (ret < 0) - goto rel_fh; - - if (v4l2_fh_is_singular_file(file)) { - mutex_lock(&me->graph_obj.mdev->graph_mutex); - - ret = fimc_pipeline_call(ve, open, me, true); - - /* Mark the video pipeline as in use. */ - if (ret == 0) - me->use_count++; - - mutex_unlock(&me->graph_obj.mdev->graph_mutex); - } - if (!ret) - goto unlock; -rel_fh: - v4l2_fh_release(file); -unlock: - mutex_unlock(&isp->video_lock); - return ret; -} - -static int isp_video_release(struct file *file) -{ - struct fimc_isp *isp = video_drvdata(file); - struct fimc_is_video *ivc = &isp->video_capture; - struct media_entity *entity = &ivc->ve.vdev.entity; - struct media_device *mdev = entity->graph_obj.mdev; - bool is_singular_file; - - mutex_lock(&isp->video_lock); - - is_singular_file = v4l2_fh_is_singular_file(file); - - if (is_singular_file && ivc->streaming) { - media_pipeline_stop(entity); - ivc->streaming = 0; - } - - _vb2_fop_release(file, NULL); - - if (is_singular_file) { - fimc_pipeline_call(&ivc->ve, close); - - mutex_lock(&mdev->graph_mutex); - entity->use_count--; - mutex_unlock(&mdev->graph_mutex); - } - - pm_runtime_put(&isp->pdev->dev); - mutex_unlock(&isp->video_lock); - - return 0; -} - -static const struct v4l2_file_operations isp_video_fops = { - .owner = THIS_MODULE, - .open = isp_video_open, - .release = isp_video_release, - .poll = vb2_fop_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = vb2_fop_mmap, -}; - -/* - * Video node ioctl operations - */ -static int isp_video_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct fimc_isp *isp = video_drvdata(file); - - __fimc_vidioc_querycap(&isp->pdev->dev, cap); - return 0; -} - -static int isp_video_enum_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - const struct fimc_fmt *fmt; - - if (f->index >= FIMC_ISP_NUM_FORMATS) - return -EINVAL; - - fmt = fimc_isp_find_format(NULL, NULL, f->index); - if (WARN_ON(fmt == NULL)) - return -EINVAL; - - f->pixelformat = fmt->fourcc; - - return 0; -} - -static int isp_video_g_fmt_mplane(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct fimc_isp *isp = video_drvdata(file); - - f->fmt.pix_mp = isp->video_capture.pixfmt; - return 0; -} - -static void __isp_video_try_fmt(struct fimc_isp *isp, - struct v4l2_pix_format_mplane *pixm, - const struct fimc_fmt **fmt) -{ - const struct fimc_fmt *__fmt; - - __fmt = fimc_isp_find_format(&pixm->pixelformat, NULL, 2); - - if (fmt) - *fmt = __fmt; - - pixm->colorspace = V4L2_COLORSPACE_SRGB; - pixm->field = V4L2_FIELD_NONE; - pixm->num_planes = __fmt->memplanes; - pixm->pixelformat = __fmt->fourcc; - /* - * TODO: double check with the docmentation these width/height - * constraints are correct. - */ - v4l_bound_align_image(&pixm->width, FIMC_ISP_SOURCE_WIDTH_MIN, - FIMC_ISP_SOURCE_WIDTH_MAX, 3, - &pixm->height, FIMC_ISP_SOURCE_HEIGHT_MIN, - FIMC_ISP_SOURCE_HEIGHT_MAX, 0, 0); -} - -static int isp_video_try_fmt_mplane(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct fimc_isp *isp = video_drvdata(file); - - __isp_video_try_fmt(isp, &f->fmt.pix_mp, NULL); - return 0; -} - -static int isp_video_s_fmt_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct fimc_isp *isp = video_drvdata(file); - struct fimc_is *is = fimc_isp_to_is(isp); - struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; - const struct fimc_fmt *ifmt = NULL; - struct param_dma_output *dma = __get_isp_dma2(is); - - __isp_video_try_fmt(isp, pixm, &ifmt); - - if (WARN_ON(ifmt == NULL)) - return -EINVAL; - - dma->format = DMA_OUTPUT_FORMAT_BAYER; - dma->order = DMA_OUTPUT_ORDER_GB_BG; - dma->plane = ifmt->memplanes; - dma->bitwidth = ifmt->depth[0]; - dma->width = pixm->width; - dma->height = pixm->height; - - fimc_is_mem_barrier(); - - isp->video_capture.format = ifmt; - isp->video_capture.pixfmt = *pixm; - - return 0; -} - -/* - * Check for source/sink format differences at each link. - * Return 0 if the formats match or -EPIPE otherwise. - */ -static int isp_video_pipeline_validate(struct fimc_isp *isp) -{ - struct v4l2_subdev *sd = &isp->subdev; - struct v4l2_subdev_format sink_fmt, src_fmt; - struct media_pad *pad; - int ret; - - while (1) { - /* Retrieve format at the sink pad */ - pad = &sd->entity.pads[0]; - if (!(pad->flags & MEDIA_PAD_FL_SINK)) - break; - sink_fmt.pad = pad->index; - sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sink_fmt); - if (ret < 0 && ret != -ENOIOCTLCMD) - return -EPIPE; - - /* Retrieve format at the source pad */ - pad = media_entity_remote_pad(pad); - if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) - break; - - sd = media_entity_to_v4l2_subdev(pad->entity); - src_fmt.pad = pad->index; - src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt); - if (ret < 0 && ret != -ENOIOCTLCMD) - return -EPIPE; - - if (src_fmt.format.width != sink_fmt.format.width || - src_fmt.format.height != sink_fmt.format.height || - src_fmt.format.code != sink_fmt.format.code) - return -EPIPE; - } - - return 0; -} - -static int isp_video_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct fimc_isp *isp = video_drvdata(file); - struct exynos_video_entity *ve = &isp->video_capture.ve; - struct media_entity *me = &ve->vdev.entity; - int ret; - - ret = media_pipeline_start(me, &ve->pipe->mp); - if (ret < 0) - return ret; - - ret = isp_video_pipeline_validate(isp); - if (ret < 0) - goto p_stop; - - ret = vb2_ioctl_streamon(file, priv, type); - if (ret < 0) - goto p_stop; - - isp->video_capture.streaming = 1; - return 0; -p_stop: - media_pipeline_stop(me); - return ret; -} - -static int isp_video_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct fimc_isp *isp = video_drvdata(file); - struct fimc_is_video *video = &isp->video_capture; - int ret; - - ret = vb2_ioctl_streamoff(file, priv, type); - if (ret < 0) - return ret; - - media_pipeline_stop(&video->ve.vdev.entity); - video->streaming = 0; - return 0; -} - -static int isp_video_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb) -{ - struct fimc_isp *isp = video_drvdata(file); - int ret; - - ret = vb2_ioctl_reqbufs(file, priv, rb); - if (ret < 0) - return ret; - - if (rb->count && rb->count < FIMC_ISP_REQ_BUFS_MIN) { - rb->count = 0; - vb2_ioctl_reqbufs(file, priv, rb); - ret = -ENOMEM; - } - - isp->video_capture.reqbufs_count = rb->count; - return ret; -} - -static const struct v4l2_ioctl_ops isp_video_ioctl_ops = { - .vidioc_querycap = isp_video_querycap, - .vidioc_enum_fmt_vid_cap = isp_video_enum_fmt, - .vidioc_try_fmt_vid_cap_mplane = isp_video_try_fmt_mplane, - .vidioc_s_fmt_vid_cap_mplane = isp_video_s_fmt_mplane, - .vidioc_g_fmt_vid_cap_mplane = isp_video_g_fmt_mplane, - .vidioc_reqbufs = isp_video_reqbufs, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_streamon = isp_video_streamon, - .vidioc_streamoff = isp_video_streamoff, -}; - -int fimc_isp_video_device_register(struct fimc_isp *isp, - struct v4l2_device *v4l2_dev, - enum v4l2_buf_type type) -{ - struct vb2_queue *q = &isp->video_capture.vb_queue; - struct fimc_is_video *iv; - struct video_device *vdev; - int ret; - - if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - iv = &isp->video_capture; - else - return -ENOSYS; - - mutex_init(&isp->video_lock); - INIT_LIST_HEAD(&iv->pending_buf_q); - INIT_LIST_HEAD(&iv->active_buf_q); - iv->format = fimc_isp_find_format(NULL, NULL, 0); - iv->pixfmt.width = IS_DEFAULT_WIDTH; - iv->pixfmt.height = IS_DEFAULT_HEIGHT; - iv->pixfmt.pixelformat = iv->format->fourcc; - iv->pixfmt.colorspace = V4L2_COLORSPACE_SRGB; - iv->reqbufs_count = 0; - - memset(q, 0, sizeof(*q)); - q->type = type; - q->io_modes = VB2_MMAP | VB2_USERPTR; - q->ops = &isp_video_capture_qops; - q->mem_ops = &vb2_dma_contig_memops; - q->buf_struct_size = sizeof(struct isp_video_buf); - q->drv_priv = isp; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->lock = &isp->video_lock; - q->dev = &isp->pdev->dev; - - ret = vb2_queue_init(q); - if (ret < 0) - return ret; - - vdev = &iv->ve.vdev; - memset(vdev, 0, sizeof(*vdev)); - strscpy(vdev->name, "fimc-is-isp.capture", sizeof(vdev->name)); - vdev->queue = q; - vdev->fops = &isp_video_fops; - vdev->ioctl_ops = &isp_video_ioctl_ops; - vdev->v4l2_dev = v4l2_dev; - vdev->minor = -1; - vdev->release = video_device_release_empty; - vdev->lock = &isp->video_lock; - vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE; - - iv->pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_pads_init(&vdev->entity, 1, &iv->pad); - if (ret < 0) - return ret; - - video_set_drvdata(vdev, isp); - - ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); - if (ret < 0) { - media_entity_cleanup(&vdev->entity); - return ret; - } - - v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n", - vdev->name, video_device_node_name(vdev)); - - return 0; -} - -void fimc_isp_video_device_unregister(struct fimc_isp *isp, - enum v4l2_buf_type type) -{ - struct exynos_video_entity *ve; - - if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - ve = &isp->video_capture.ve; - else - return; - - mutex_lock(&isp->video_lock); - - if (video_is_registered(&ve->vdev)) { - video_unregister_device(&ve->vdev); - media_entity_cleanup(&ve->vdev.entity); - ve->pipe = NULL; - } - - mutex_unlock(&isp->video_lock); -} |