1898 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Samsung S5P/EXYNOS4 SoC series camera interface (camera capture) driver4 *5 * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.6 * Sylwester Nawrocki <s.nawrocki@samsung.com>7 */8 9#include <linux/module.h>10#include <linux/kernel.h>11#include <linux/types.h>12#include <linux/errno.h>13#include <linux/bug.h>14#include <linux/interrupt.h>15#include <linux/device.h>16#include <linux/pm_runtime.h>17#include <linux/list.h>18#include <linux/slab.h>19 20#include <linux/videodev2.h>21#include <media/v4l2-device.h>22#include <media/v4l2-ioctl.h>23#include <media/v4l2-mem2mem.h>24#include <media/v4l2-rect.h>25#include <media/videobuf2-v4l2.h>26#include <media/videobuf2-dma-contig.h>27 28#include "common.h"29#include "fimc-core.h"30#include "fimc-reg.h"31#include "media-dev.h"32 33static int fimc_capture_hw_init(struct fimc_dev *fimc)34{35 struct fimc_source_info *si = &fimc->vid_cap.source_config;36 struct fimc_ctx *ctx = fimc->vid_cap.ctx;37 int ret;38 unsigned long flags;39 40 if (ctx == NULL || ctx->s_frame.fmt == NULL)41 return -EINVAL;42 43 if (si->fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK) {44 ret = fimc_hw_camblk_cfg_writeback(fimc);45 if (ret < 0)46 return ret;47 }48 49 spin_lock_irqsave(&fimc->slock, flags);50 fimc_prepare_dma_offset(ctx, &ctx->d_frame);51 fimc_set_yuv_order(ctx);52 53 fimc_hw_set_camera_polarity(fimc, si);54 fimc_hw_set_camera_type(fimc, si);55 fimc_hw_set_camera_source(fimc, si);56 fimc_hw_set_camera_offset(fimc, &ctx->s_frame);57 58 ret = fimc_set_scaler_info(ctx);59 if (!ret) {60 fimc_hw_set_input_path(ctx);61 fimc_hw_set_prescaler(ctx);62 fimc_hw_set_mainscaler(ctx);63 fimc_hw_set_target_format(ctx);64 fimc_hw_set_rotation(ctx);65 fimc_hw_set_effect(ctx);66 fimc_hw_set_output_path(ctx);67 fimc_hw_set_out_dma(ctx);68 if (fimc->drv_data->alpha_color)69 fimc_hw_set_rgb_alpha(ctx);70 clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);71 }72 spin_unlock_irqrestore(&fimc->slock, flags);73 return ret;74}75 76/*77 * Reinitialize the driver so it is ready to start the streaming again.78 * Set fimc->state to indicate stream off and the hardware shut down state.79 * If not suspending (@suspend is false), return any buffers to videobuf2.80 * Otherwise put any owned buffers onto the pending buffers queue, so they81 * can be re-spun when the device is being resumed. Also perform FIMC82 * software reset and disable streaming on the whole pipeline if required.83 */84static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend)85{86 struct fimc_vid_cap *cap = &fimc->vid_cap;87 struct fimc_vid_buffer *buf;88 unsigned long flags;89 bool streaming;90 91 spin_lock_irqsave(&fimc->slock, flags);92 streaming = fimc->state & (1 << ST_CAPT_ISP_STREAM);93 94 fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_SHUT |95 1 << ST_CAPT_STREAM | 1 << ST_CAPT_ISP_STREAM);96 if (suspend)97 fimc->state |= (1 << ST_CAPT_SUSPENDED);98 else99 fimc->state &= ~(1 << ST_CAPT_PEND | 1 << ST_CAPT_SUSPENDED);100 101 /* Release unused buffers */102 while (!suspend && !list_empty(&cap->pending_buf_q)) {103 buf = fimc_pending_queue_pop(cap);104 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);105 }106 /* If suspending put unused buffers onto pending queue */107 while (!list_empty(&cap->active_buf_q)) {108 buf = fimc_active_queue_pop(cap);109 if (suspend)110 fimc_pending_queue_add(cap, buf);111 else112 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);113 }114 115 fimc_hw_reset(fimc);116 cap->buf_index = 0;117 118 spin_unlock_irqrestore(&fimc->slock, flags);119 120 if (streaming)121 return fimc_pipeline_call(&cap->ve, set_stream, 0);122 else123 return 0;124}125 126static int fimc_stop_capture(struct fimc_dev *fimc, bool suspend)127{128 unsigned long flags;129 130 if (!fimc_capture_active(fimc))131 return 0;132 133 spin_lock_irqsave(&fimc->slock, flags);134 set_bit(ST_CAPT_SHUT, &fimc->state);135 fimc_deactivate_capture(fimc);136 spin_unlock_irqrestore(&fimc->slock, flags);137 138 wait_event_timeout(fimc->irq_queue,139 !test_bit(ST_CAPT_SHUT, &fimc->state),140 (2*HZ/10)); /* 200 ms */141 142 return fimc_capture_state_cleanup(fimc, suspend);143}144 145/**146 * fimc_capture_config_update - apply the camera interface configuration147 * @ctx: FIMC capture context148 *149 * To be called from within the interrupt handler with fimc.slock150 * spinlock held. It updates the camera pixel crop, rotation and151 * image flip in H/W.152 */153static int fimc_capture_config_update(struct fimc_ctx *ctx)154{155 struct fimc_dev *fimc = ctx->fimc_dev;156 int ret;157 158 fimc_hw_set_camera_offset(fimc, &ctx->s_frame);159 160 ret = fimc_set_scaler_info(ctx);161 if (ret)162 return ret;163 164 fimc_hw_set_prescaler(ctx);165 fimc_hw_set_mainscaler(ctx);166 fimc_hw_set_target_format(ctx);167 fimc_hw_set_rotation(ctx);168 fimc_hw_set_effect(ctx);169 fimc_prepare_dma_offset(ctx, &ctx->d_frame);170 fimc_hw_set_out_dma(ctx);171 if (fimc->drv_data->alpha_color)172 fimc_hw_set_rgb_alpha(ctx);173 174 clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);175 return ret;176}177 178void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf)179{180 struct fimc_vid_cap *cap = &fimc->vid_cap;181 struct fimc_pipeline *p = to_fimc_pipeline(cap->ve.pipe);182 struct v4l2_subdev *csis = p->subdevs[IDX_CSIS];183 const struct fimc_frame *f = &cap->ctx->d_frame;184 struct fimc_vid_buffer *v_buf;185 186 if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) {187 wake_up(&fimc->irq_queue);188 goto done;189 }190 191 if (!list_empty(&cap->active_buf_q) &&192 test_bit(ST_CAPT_RUN, &fimc->state) && deq_buf) {193 v_buf = fimc_active_queue_pop(cap);194 195 v_buf->vb.vb2_buf.timestamp = ktime_get_ns();196 v_buf->vb.sequence = cap->frame_count++;197 198 vb2_buffer_done(&v_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);199 }200 201 if (!list_empty(&cap->pending_buf_q)) {202 203 v_buf = fimc_pending_queue_pop(cap);204 fimc_hw_set_output_addr(fimc, &v_buf->addr, cap->buf_index);205 v_buf->index = cap->buf_index;206 207 /* Move the buffer to the capture active queue */208 fimc_active_queue_add(cap, v_buf);209 210 dbg("next frame: %d, done frame: %d",211 fimc_hw_get_frame_index(fimc), v_buf->index);212 213 if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)214 cap->buf_index = 0;215 }216 /*217 * Set up a buffer at MIPI-CSIS if current image format218 * requires the frame embedded data capture.219 */220 if (f->fmt->mdataplanes && !list_empty(&cap->active_buf_q)) {221 unsigned int plane = ffs(f->fmt->mdataplanes) - 1;222 unsigned int size = f->payload[plane];223 s32 index = fimc_hw_get_frame_index(fimc);224 void *vaddr;225 226 list_for_each_entry(v_buf, &cap->active_buf_q, list) {227 if (v_buf->index != index)228 continue;229 vaddr = vb2_plane_vaddr(&v_buf->vb.vb2_buf, plane);230 v4l2_subdev_call(csis, video, s_rx_buffer,231 vaddr, &size);232 break;233 }234 }235 236 if (cap->active_buf_cnt == 0) {237 if (deq_buf)238 clear_bit(ST_CAPT_RUN, &fimc->state);239 240 if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)241 cap->buf_index = 0;242 } else {243 set_bit(ST_CAPT_RUN, &fimc->state);244 }245 246 if (test_bit(ST_CAPT_APPLY_CFG, &fimc->state))247 fimc_capture_config_update(cap->ctx);248done:249 if (cap->active_buf_cnt == 1) {250 fimc_deactivate_capture(fimc);251 clear_bit(ST_CAPT_STREAM, &fimc->state);252 }253 254 dbg("frame: %d, active_buf_cnt: %d",255 fimc_hw_get_frame_index(fimc), cap->active_buf_cnt);256}257 258 259static int start_streaming(struct vb2_queue *q, unsigned int count)260{261 struct fimc_ctx *ctx = q->drv_priv;262 struct fimc_dev *fimc = ctx->fimc_dev;263 struct fimc_vid_cap *vid_cap = &fimc->vid_cap;264 int min_bufs;265 int ret;266 267 vid_cap->frame_count = 0;268 269 ret = fimc_capture_hw_init(fimc);270 if (ret) {271 fimc_capture_state_cleanup(fimc, false);272 return ret;273 }274 275 set_bit(ST_CAPT_PEND, &fimc->state);276 277 min_bufs = fimc->vid_cap.reqbufs_count > 1 ? 2 : 1;278 279 if (vid_cap->active_buf_cnt >= min_bufs &&280 !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) {281 fimc_activate_capture(ctx);282 283 if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))284 return fimc_pipeline_call(&vid_cap->ve, set_stream, 1);285 }286 287 return 0;288}289 290static void stop_streaming(struct vb2_queue *q)291{292 struct fimc_ctx *ctx = q->drv_priv;293 struct fimc_dev *fimc = ctx->fimc_dev;294 295 if (!fimc_capture_active(fimc))296 return;297 298 fimc_stop_capture(fimc, false);299}300 301int fimc_capture_suspend(struct fimc_dev *fimc)302{303 bool suspend = fimc_capture_busy(fimc);304 305 int ret = fimc_stop_capture(fimc, suspend);306 if (ret)307 return ret;308 return fimc_pipeline_call(&fimc->vid_cap.ve, close);309}310 311static void buffer_queue(struct vb2_buffer *vb);312 313int fimc_capture_resume(struct fimc_dev *fimc)314{315 struct fimc_vid_cap *vid_cap = &fimc->vid_cap;316 struct exynos_video_entity *ve = &vid_cap->ve;317 struct fimc_vid_buffer *buf;318 int i;319 320 if (!test_and_clear_bit(ST_CAPT_SUSPENDED, &fimc->state))321 return 0;322 323 INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);324 vid_cap->buf_index = 0;325 fimc_pipeline_call(ve, open, &ve->vdev.entity, false);326 fimc_capture_hw_init(fimc);327 328 clear_bit(ST_CAPT_SUSPENDED, &fimc->state);329 330 for (i = 0; i < vid_cap->reqbufs_count; i++) {331 if (list_empty(&vid_cap->pending_buf_q))332 break;333 buf = fimc_pending_queue_pop(vid_cap);334 buffer_queue(&buf->vb.vb2_buf);335 }336 return 0;337 338}339 340static int queue_setup(struct vb2_queue *vq,341 unsigned int *num_buffers, unsigned int *num_planes,342 unsigned int sizes[], struct device *alloc_devs[])343{344 struct fimc_ctx *ctx = vq->drv_priv;345 const struct fimc_frame *frame = &ctx->d_frame;346 const struct fimc_fmt *fmt = frame->fmt;347 unsigned long wh = frame->f_width * frame->f_height;348 int i;349 350 if (fmt == NULL)351 return -EINVAL;352 353 if (*num_planes) {354 if (*num_planes != fmt->memplanes)355 return -EINVAL;356 for (i = 0; i < *num_planes; i++)357 if (sizes[i] < (wh * fmt->depth[i]) / 8)358 return -EINVAL;359 return 0;360 }361 362 *num_planes = fmt->memplanes;363 364 for (i = 0; i < fmt->memplanes; i++) {365 unsigned int size = (wh * fmt->depth[i]) / 8;366 367 if (fimc_fmt_is_user_defined(fmt->color))368 sizes[i] = frame->payload[i];369 else370 sizes[i] = max_t(u32, size, frame->payload[i]);371 }372 373 return 0;374}375 376static int buffer_prepare(struct vb2_buffer *vb)377{378 struct vb2_queue *vq = vb->vb2_queue;379 struct fimc_ctx *ctx = vq->drv_priv;380 int i;381 382 if (ctx->d_frame.fmt == NULL)383 return -EINVAL;384 385 for (i = 0; i < ctx->d_frame.fmt->memplanes; i++) {386 unsigned long size = ctx->d_frame.payload[i];387 388 if (vb2_plane_size(vb, i) < size) {389 v4l2_err(&ctx->fimc_dev->vid_cap.ve.vdev,390 "User buffer too small (%ld < %ld)\n",391 vb2_plane_size(vb, i), size);392 return -EINVAL;393 }394 vb2_set_plane_payload(vb, i, size);395 }396 397 return 0;398}399 400static void buffer_queue(struct vb2_buffer *vb)401{402 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);403 struct fimc_vid_buffer *buf404 = container_of(vbuf, struct fimc_vid_buffer, vb);405 struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);406 struct fimc_dev *fimc = ctx->fimc_dev;407 struct fimc_vid_cap *vid_cap = &fimc->vid_cap;408 struct exynos_video_entity *ve = &vid_cap->ve;409 unsigned long flags;410 int min_bufs;411 412 spin_lock_irqsave(&fimc->slock, flags);413 fimc_prepare_addr(ctx, &buf->vb.vb2_buf, &ctx->d_frame, &buf->addr);414 415 if (!test_bit(ST_CAPT_SUSPENDED, &fimc->state) &&416 !test_bit(ST_CAPT_STREAM, &fimc->state) &&417 vid_cap->active_buf_cnt < FIMC_MAX_OUT_BUFS) {418 /* Setup the buffer directly for processing. */419 int buf_id = (vid_cap->reqbufs_count == 1) ? -1 :420 vid_cap->buf_index;421 422 fimc_hw_set_output_addr(fimc, &buf->addr, buf_id);423 buf->index = vid_cap->buf_index;424 fimc_active_queue_add(vid_cap, buf);425 426 if (++vid_cap->buf_index >= FIMC_MAX_OUT_BUFS)427 vid_cap->buf_index = 0;428 } else {429 fimc_pending_queue_add(vid_cap, buf);430 }431 432 min_bufs = vid_cap->reqbufs_count > 1 ? 2 : 1;433 434 435 if (vb2_is_streaming(&vid_cap->vbq) &&436 vid_cap->active_buf_cnt >= min_bufs &&437 !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) {438 int ret;439 440 fimc_activate_capture(ctx);441 spin_unlock_irqrestore(&fimc->slock, flags);442 443 if (test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))444 return;445 446 ret = fimc_pipeline_call(ve, set_stream, 1);447 if (ret < 0)448 v4l2_err(&ve->vdev, "stream on failed: %d\n", ret);449 return;450 }451 spin_unlock_irqrestore(&fimc->slock, flags);452}453 454static const struct vb2_ops fimc_capture_qops = {455 .queue_setup = queue_setup,456 .buf_prepare = buffer_prepare,457 .buf_queue = buffer_queue,458 .wait_prepare = vb2_ops_wait_prepare,459 .wait_finish = vb2_ops_wait_finish,460 .start_streaming = start_streaming,461 .stop_streaming = stop_streaming,462};463 464static int fimc_capture_set_default_format(struct fimc_dev *fimc);465 466static int fimc_capture_open(struct file *file)467{468 struct fimc_dev *fimc = video_drvdata(file);469 struct fimc_vid_cap *vc = &fimc->vid_cap;470 struct exynos_video_entity *ve = &vc->ve;471 int ret = -EBUSY;472 473 dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);474 475 mutex_lock(&fimc->lock);476 477 if (fimc_m2m_active(fimc))478 goto unlock;479 480 set_bit(ST_CAPT_BUSY, &fimc->state);481 ret = pm_runtime_resume_and_get(&fimc->pdev->dev);482 if (ret < 0)483 goto unlock;484 485 ret = v4l2_fh_open(file);486 if (ret) {487 pm_runtime_put_sync(&fimc->pdev->dev);488 goto unlock;489 }490 491 if (v4l2_fh_is_singular_file(file)) {492 fimc_md_graph_lock(ve);493 494 ret = fimc_pipeline_call(ve, open, &ve->vdev.entity, true);495 496 if (ret == 0)497 ve->vdev.entity.use_count++;498 499 fimc_md_graph_unlock(ve);500 501 if (ret == 0)502 ret = fimc_capture_set_default_format(fimc);503 504 if (ret < 0) {505 clear_bit(ST_CAPT_BUSY, &fimc->state);506 pm_runtime_put_sync(&fimc->pdev->dev);507 v4l2_fh_release(file);508 }509 }510unlock:511 mutex_unlock(&fimc->lock);512 return ret;513}514 515static int fimc_capture_release(struct file *file)516{517 struct fimc_dev *fimc = video_drvdata(file);518 struct fimc_vid_cap *vc = &fimc->vid_cap;519 bool close = v4l2_fh_is_singular_file(file);520 int ret;521 522 dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);523 524 mutex_lock(&fimc->lock);525 526 if (close && vc->streaming) {527 video_device_pipeline_stop(&vc->ve.vdev);528 vc->streaming = false;529 }530 531 ret = _vb2_fop_release(file, NULL);532 533 if (close) {534 clear_bit(ST_CAPT_BUSY, &fimc->state);535 fimc_pipeline_call(&vc->ve, close);536 clear_bit(ST_CAPT_SUSPENDED, &fimc->state);537 538 fimc_md_graph_lock(&vc->ve);539 vc->ve.vdev.entity.use_count--;540 fimc_md_graph_unlock(&vc->ve);541 }542 543 pm_runtime_put_sync(&fimc->pdev->dev);544 mutex_unlock(&fimc->lock);545 546 return ret;547}548 549static const struct v4l2_file_operations fimc_capture_fops = {550 .owner = THIS_MODULE,551 .open = fimc_capture_open,552 .release = fimc_capture_release,553 .poll = vb2_fop_poll,554 .unlocked_ioctl = video_ioctl2,555 .mmap = vb2_fop_mmap,556};557 558/*559 * Format and crop negotiation helpers560 */561 562static const struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx,563 u32 *width, u32 *height,564 u32 *code, u32 *fourcc, int pad)565{566 bool rotation = ctx->rotation == 90 || ctx->rotation == 270;567 struct fimc_dev *fimc = ctx->fimc_dev;568 const struct fimc_variant *var = fimc->variant;569 const struct fimc_pix_limit *pl = var->pix_limit;570 const struct fimc_frame *dst = &ctx->d_frame;571 u32 depth, min_w, max_w, min_h, align_h = 3;572 const struct fimc_fmt *ffmt;573 u32 mask = FMT_FLAGS_CAM;574 575 /* Conversion from/to JPEG or User Defined format is not supported */576 if (code && ctx->s_frame.fmt && pad == FIMC_SD_PAD_SOURCE &&577 fimc_fmt_is_user_defined(ctx->s_frame.fmt->color))578 *code = ctx->s_frame.fmt->mbus_code;579 580 if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad == FIMC_SD_PAD_SOURCE)581 mask |= FMT_FLAGS_M2M;582 583 if (pad == FIMC_SD_PAD_SINK_FIFO)584 mask = FMT_FLAGS_WRITEBACK;585 586 ffmt = fimc_find_format(fourcc, code, mask, 0);587 if (WARN_ON(!ffmt))588 return NULL;589 590 if (code)591 *code = ffmt->mbus_code;592 if (fourcc)593 *fourcc = ffmt->fourcc;594 595 if (pad != FIMC_SD_PAD_SOURCE) {596 max_w = fimc_fmt_is_user_defined(ffmt->color) ?597 pl->scaler_dis_w : pl->scaler_en_w;598 /* Apply the camera input interface pixel constraints */599 v4l_bound_align_image(width, max_t(u32, *width, 32), max_w, 4,600 height, max_t(u32, *height, 32),601 FIMC_CAMIF_MAX_HEIGHT,602 fimc_fmt_is_user_defined(ffmt->color) ?603 3 : 1,604 0);605 return ffmt;606 }607 /* Can't scale or crop in transparent (JPEG) transfer mode */608 if (fimc_fmt_is_user_defined(ffmt->color)) {609 *width = ctx->s_frame.f_width;610 *height = ctx->s_frame.f_height;611 return ffmt;612 }613 /* Apply the scaler and the output DMA constraints */614 max_w = rotation ? pl->out_rot_en_w : pl->out_rot_dis_w;615 if (ctx->state & FIMC_COMPOSE) {616 min_w = dst->offs_h + dst->width;617 min_h = dst->offs_v + dst->height;618 } else {619 min_w = var->min_out_pixsize;620 min_h = var->min_out_pixsize;621 }622 if (var->min_vsize_align == 1 && !rotation)623 align_h = fimc_fmt_is_rgb(ffmt->color) ? 0 : 1;624 625 depth = fimc_get_format_depth(ffmt);626 v4l_bound_align_image(width, min_w, max_w,627 ffs(var->min_out_pixsize) - 1,628 height, min_h, FIMC_CAMIF_MAX_HEIGHT,629 align_h,630 64/(ALIGN(depth, 8)));631 632 dbg("pad%d: code: 0x%x, %dx%d. dst fmt: %dx%d",633 pad, code ? *code : 0, *width, *height,634 dst->f_width, dst->f_height);635 636 return ffmt;637}638 639static void fimc_capture_try_selection(struct fimc_ctx *ctx,640 struct v4l2_rect *r,641 int target)642{643 bool rotate = ctx->rotation == 90 || ctx->rotation == 270;644 struct fimc_dev *fimc = ctx->fimc_dev;645 const struct fimc_variant *var = fimc->variant;646 const struct fimc_pix_limit *pl = var->pix_limit;647 const struct fimc_frame *sink = &ctx->s_frame;648 u32 max_w, max_h, min_w = 0, min_h = 0, min_sz;649 u32 align_sz = 0, align_h = 4;650 u32 max_sc_h, max_sc_v;651 652 /* In JPEG transparent transfer mode cropping is not supported */653 if (fimc_fmt_is_user_defined(ctx->d_frame.fmt->color)) {654 r->width = sink->f_width;655 r->height = sink->f_height;656 r->left = r->top = 0;657 return;658 }659 if (target == V4L2_SEL_TGT_COMPOSE) {660 u32 tmp_min_h = ffs(sink->width) - 3;661 u32 tmp_min_v = ffs(sink->height) - 1;662 663 if (ctx->rotation != 90 && ctx->rotation != 270)664 align_h = 1;665 max_sc_h = min(SCALER_MAX_HRATIO, 1 << tmp_min_h);666 max_sc_v = min(SCALER_MAX_VRATIO, 1 << tmp_min_v);667 min_sz = var->min_out_pixsize;668 } else {669 u32 depth = fimc_get_format_depth(sink->fmt);670 align_sz = 64/ALIGN(depth, 8);671 min_sz = var->min_inp_pixsize;672 min_w = min_h = min_sz;673 max_sc_h = max_sc_v = 1;674 }675 /*676 * For the compose rectangle the following constraints must be met:677 * - it must fit in the sink pad format rectangle (f_width/f_height);678 * - maximum downscaling ratio is 64;679 * - maximum crop size depends if the rotator is used or not;680 * - the sink pad format width/height must be 4 multiple of the681 * prescaler ratios determined by sink pad size and source pad crop,682 * the prescaler ratio is returned by fimc_get_scaler_factor().683 */684 max_w = min_t(u32,685 rotate ? pl->out_rot_en_w : pl->out_rot_dis_w,686 rotate ? sink->f_height : sink->f_width);687 max_h = min_t(u32, FIMC_CAMIF_MAX_HEIGHT, sink->f_height);688 689 if (target == V4L2_SEL_TGT_COMPOSE) {690 min_w = min_t(u32, max_w, sink->f_width / max_sc_h);691 min_h = min_t(u32, max_h, sink->f_height / max_sc_v);692 if (rotate) {693 swap(max_sc_h, max_sc_v);694 swap(min_w, min_h);695 }696 }697 v4l_bound_align_image(&r->width, min_w, max_w, ffs(min_sz) - 1,698 &r->height, min_h, max_h, align_h,699 align_sz);700 /* Adjust left/top if crop/compose rectangle is out of bounds */701 r->left = clamp_t(u32, r->left, 0, sink->f_width - r->width);702 r->top = clamp_t(u32, r->top, 0, sink->f_height - r->height);703 r->left = round_down(r->left, var->hor_offs_align);704 705 dbg("target %#x: (%d,%d)/%dx%d, sink fmt: %dx%d",706 target, r->left, r->top, r->width, r->height,707 sink->f_width, sink->f_height);708}709 710/*711 * The video node ioctl operations712 */713static int fimc_cap_querycap(struct file *file, void *priv,714 struct v4l2_capability *cap)715{716 struct fimc_dev *fimc = video_drvdata(file);717 718 __fimc_vidioc_querycap(&fimc->pdev->dev, cap);719 return 0;720}721 722static int fimc_cap_enum_fmt(struct file *file, void *priv,723 struct v4l2_fmtdesc *f)724{725 const struct fimc_fmt *fmt;726 727 fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM | FMT_FLAGS_M2M,728 f->index);729 if (!fmt)730 return -EINVAL;731 f->pixelformat = fmt->fourcc;732 return 0;733}734 735static struct media_entity *fimc_pipeline_get_head(struct media_entity *me)736{737 struct media_pad *pad = &me->pads[0];738 739 while (!(pad->flags & MEDIA_PAD_FL_SOURCE)) {740 pad = media_pad_remote_pad_first(pad);741 if (!pad)742 break;743 me = pad->entity;744 pad = &me->pads[0];745 }746 747 return me;748}749 750/**751 * fimc_pipeline_try_format - negotiate and/or set formats at pipeline752 * elements753 * @ctx: FIMC capture context754 * @tfmt: media bus format to try/set on subdevs755 * @fmt_id: fimc pixel format id corresponding to returned @tfmt (output)756 * @set: true to set format on subdevs, false to try only757 */758static int fimc_pipeline_try_format(struct fimc_ctx *ctx,759 struct v4l2_mbus_framefmt *tfmt,760 const struct fimc_fmt **fmt_id,761 bool set)762{763 struct fimc_dev *fimc = ctx->fimc_dev;764 struct fimc_pipeline *p = to_fimc_pipeline(fimc->vid_cap.ve.pipe);765 struct v4l2_subdev *sd = p->subdevs[IDX_SENSOR];766 struct v4l2_subdev_format sfmt = {767 .which = set ? V4L2_SUBDEV_FORMAT_ACTIVE768 : V4L2_SUBDEV_FORMAT_TRY,769 };770 struct v4l2_mbus_framefmt *mf = &sfmt.format;771 const struct fimc_fmt *ffmt;772 struct media_entity *me;773 struct media_pad *pad;774 int ret, i = 1;775 u32 fcc;776 777 if (WARN_ON(!sd || !tfmt))778 return -EINVAL;779 780 sfmt.format = *tfmt;781 782 me = fimc_pipeline_get_head(&sd->entity);783 784 while (1) {785 ffmt = fimc_find_format(NULL, mf->code != 0 ? &mf->code : NULL,786 FMT_FLAGS_CAM, i++);787 if (ffmt == NULL) {788 /*789 * Notify user-space if common pixel code for790 * host and sensor does not exist.791 */792 return -EINVAL;793 }794 mf->code = tfmt->code = ffmt->mbus_code;795 796 /* set format on all pipeline subdevs */797 while (me != &fimc->vid_cap.subdev.entity) {798 sd = media_entity_to_v4l2_subdev(me);799 800 sfmt.pad = 0;801 ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &sfmt);802 if (ret)803 return ret;804 805 if (me->pads[0].flags & MEDIA_PAD_FL_SINK) {806 sfmt.pad = me->num_pads - 1;807 mf->code = tfmt->code;808 ret = v4l2_subdev_call(sd, pad, set_fmt, NULL,809 &sfmt);810 if (ret)811 return ret;812 }813 814 pad = media_pad_remote_pad_first(&me->pads[sfmt.pad]);815 if (!pad)816 return -EINVAL;817 me = pad->entity;818 }819 820 if (mf->code != tfmt->code)821 continue;822 823 fcc = ffmt->fourcc;824 tfmt->width = mf->width;825 tfmt->height = mf->height;826 ffmt = fimc_capture_try_format(ctx, &tfmt->width, &tfmt->height,827 NULL, &fcc, FIMC_SD_PAD_SINK_CAM);828 ffmt = fimc_capture_try_format(ctx, &tfmt->width, &tfmt->height,829 NULL, &fcc, FIMC_SD_PAD_SOURCE);830 if (ffmt && ffmt->mbus_code)831 mf->code = ffmt->mbus_code;832 if (mf->width != tfmt->width || mf->height != tfmt->height)833 continue;834 tfmt->code = mf->code;835 break;836 }837 838 if (fmt_id && ffmt)839 *fmt_id = ffmt;840 *tfmt = *mf;841 842 return 0;843}844 845/**846 * fimc_get_sensor_frame_desc - query the sensor for media bus frame parameters847 * @sensor: pointer to the sensor subdev848 * @plane_fmt: provides plane sizes corresponding to the frame layout entries849 * @num_planes: number of planes850 * @try: true to set the frame parameters, false to query only851 *852 * This function is used by this driver only for compressed/blob data formats.853 */854static int fimc_get_sensor_frame_desc(struct v4l2_subdev *sensor,855 struct v4l2_plane_pix_format *plane_fmt,856 unsigned int num_planes, bool try)857{858 struct v4l2_mbus_frame_desc fd = { };859 int i, ret;860 int pad;861 862 for (i = 0; i < num_planes; i++)863 fd.entry[i].length = plane_fmt[i].sizeimage;864 865 pad = sensor->entity.num_pads - 1;866 if (try)867 ret = v4l2_subdev_call(sensor, pad, set_frame_desc, pad, &fd);868 else869 ret = v4l2_subdev_call(sensor, pad, get_frame_desc, pad, &fd);870 871 if (ret < 0)872 return ret;873 874 if (num_planes != fd.num_entries)875 return -EINVAL;876 877 for (i = 0; i < num_planes; i++)878 plane_fmt[i].sizeimage = fd.entry[i].length;879 880 if (fd.entry[0].length > FIMC_MAX_JPEG_BUF_SIZE) {881 v4l2_err(sensor->v4l2_dev, "Unsupported buffer size: %u\n",882 fd.entry[0].length);883 884 return -EINVAL;885 }886 887 return 0;888}889 890static int fimc_cap_g_fmt_mplane(struct file *file, void *fh,891 struct v4l2_format *f)892{893 struct fimc_dev *fimc = video_drvdata(file);894 895 __fimc_get_format(&fimc->vid_cap.ctx->d_frame, f);896 return 0;897}898 899/*900 * Try or set format on the fimc.X.capture video node and additionally901 * on the whole pipeline if @try is false.902 * Locking: the caller must _not_ hold the graph mutex.903 */904static int __video_try_or_set_format(struct fimc_dev *fimc,905 struct v4l2_format *f, bool try,906 const struct fimc_fmt **inp_fmt,907 const struct fimc_fmt **out_fmt)908{909 struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;910 struct fimc_vid_cap *vc = &fimc->vid_cap;911 struct exynos_video_entity *ve = &vc->ve;912 struct fimc_ctx *ctx = vc->ctx;913 unsigned int width = 0, height = 0;914 int ret = 0;915 916 /* Pre-configure format at the camera input interface, for JPEG only */917 if (fimc_jpeg_fourcc(pix->pixelformat)) {918 fimc_capture_try_format(ctx, &pix->width, &pix->height,919 NULL, &pix->pixelformat,920 FIMC_SD_PAD_SINK_CAM);921 if (try) {922 width = pix->width;923 height = pix->height;924 } else {925 ctx->s_frame.f_width = pix->width;926 ctx->s_frame.f_height = pix->height;927 }928 }929 930 /* Try the format at the scaler and the DMA output */931 *out_fmt = fimc_capture_try_format(ctx, &pix->width, &pix->height,932 NULL, &pix->pixelformat,933 FIMC_SD_PAD_SOURCE);934 if (*out_fmt == NULL)935 return -EINVAL;936 937 /* Restore image width/height for JPEG (no resizing supported). */938 if (try && fimc_jpeg_fourcc(pix->pixelformat)) {939 pix->width = width;940 pix->height = height;941 }942 943 /* Try to match format at the host and the sensor */944 if (!vc->user_subdev_api) {945 struct v4l2_mbus_framefmt mbus_fmt;946 struct v4l2_mbus_framefmt *mf;947 948 mf = try ? &mbus_fmt : &fimc->vid_cap.ci_fmt;949 950 mf->code = (*out_fmt)->mbus_code;951 mf->width = pix->width;952 mf->height = pix->height;953 954 fimc_md_graph_lock(ve);955 ret = fimc_pipeline_try_format(ctx, mf, inp_fmt, try);956 fimc_md_graph_unlock(ve);957 958 if (ret < 0)959 return ret;960 961 pix->width = mf->width;962 pix->height = mf->height;963 }964 965 fimc_adjust_mplane_format(*out_fmt, pix->width, pix->height, pix);966 967 if ((*out_fmt)->flags & FMT_FLAGS_COMPRESSED) {968 struct v4l2_subdev *sensor;969 970 fimc_md_graph_lock(ve);971 972 sensor = __fimc_md_get_subdev(ve->pipe, IDX_SENSOR);973 if (sensor)974 fimc_get_sensor_frame_desc(sensor, pix->plane_fmt,975 (*out_fmt)->memplanes, try);976 else977 ret = -EPIPE;978 979 fimc_md_graph_unlock(ve);980 }981 982 return ret;983}984 985static int fimc_cap_try_fmt_mplane(struct file *file, void *fh,986 struct v4l2_format *f)987{988 struct fimc_dev *fimc = video_drvdata(file);989 const struct fimc_fmt *out_fmt = NULL, *inp_fmt = NULL;990 991 return __video_try_or_set_format(fimc, f, true, &inp_fmt, &out_fmt);992}993 994static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx,995 enum fimc_color_fmt color)996{997 bool jpeg = fimc_fmt_is_user_defined(color);998 999 ctx->scaler.enabled = !jpeg;1000 fimc_ctrls_activate(ctx, !jpeg);1001 1002 if (jpeg)1003 set_bit(ST_CAPT_JPEG, &ctx->fimc_dev->state);1004 else1005 clear_bit(ST_CAPT_JPEG, &ctx->fimc_dev->state);1006}1007 1008static int __fimc_capture_set_format(struct fimc_dev *fimc,1009 struct v4l2_format *f)1010{1011 struct fimc_vid_cap *vc = &fimc->vid_cap;1012 struct fimc_ctx *ctx = vc->ctx;1013 const struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;1014 struct fimc_frame *ff = &ctx->d_frame;1015 const struct fimc_fmt *inp_fmt = NULL;1016 int ret, i;1017 1018 if (vb2_is_busy(&fimc->vid_cap.vbq))1019 return -EBUSY;1020 1021 ret = __video_try_or_set_format(fimc, f, false, &inp_fmt, &ff->fmt);1022 if (ret < 0)1023 return ret;1024 1025 /* Update RGB Alpha control state and value range */1026 fimc_alpha_ctrl_update(ctx);1027 1028 for (i = 0; i < ff->fmt->memplanes; i++) {1029 ff->bytesperline[i] = pix->plane_fmt[i].bytesperline;1030 ff->payload[i] = pix->plane_fmt[i].sizeimage;1031 }1032 1033 set_frame_bounds(ff, pix->width, pix->height);1034 /* Reset the composition rectangle if not yet configured */1035 if (!(ctx->state & FIMC_COMPOSE))1036 set_frame_crop(ff, 0, 0, pix->width, pix->height);1037 1038 fimc_capture_mark_jpeg_xfer(ctx, ff->fmt->color);1039 1040 /* Reset cropping and set format at the camera interface input */1041 if (!vc->user_subdev_api) {1042 ctx->s_frame.fmt = inp_fmt;1043 set_frame_bounds(&ctx->s_frame, pix->width, pix->height);1044 set_frame_crop(&ctx->s_frame, 0, 0, pix->width, pix->height);1045 }1046 1047 return ret;1048}1049 1050static int fimc_cap_s_fmt_mplane(struct file *file, void *priv,1051 struct v4l2_format *f)1052{1053 struct fimc_dev *fimc = video_drvdata(file);1054 1055 return __fimc_capture_set_format(fimc, f);1056}1057 1058static int fimc_cap_enum_input(struct file *file, void *priv,1059 struct v4l2_input *i)1060{1061 struct fimc_dev *fimc = video_drvdata(file);1062 struct exynos_video_entity *ve = &fimc->vid_cap.ve;1063 struct v4l2_subdev *sd;1064 1065 if (i->index != 0)1066 return -EINVAL;1067 1068 i->type = V4L2_INPUT_TYPE_CAMERA;1069 fimc_md_graph_lock(ve);1070 sd = __fimc_md_get_subdev(ve->pipe, IDX_SENSOR);1071 fimc_md_graph_unlock(ve);1072 1073 if (sd)1074 strscpy(i->name, sd->name, sizeof(i->name));1075 1076 return 0;1077}1078 1079static int fimc_cap_s_input(struct file *file, void *priv, unsigned int i)1080{1081 return i == 0 ? i : -EINVAL;1082}1083 1084static int fimc_cap_g_input(struct file *file, void *priv, unsigned int *i)1085{1086 *i = 0;1087 return 0;1088}1089 1090/**1091 * fimc_pipeline_validate - check for formats inconsistencies1092 * between source and sink pad of each link1093 * @fimc: the FIMC device this context applies to1094 *1095 * Return 0 if all formats match or -EPIPE otherwise.1096 */1097static int fimc_pipeline_validate(struct fimc_dev *fimc)1098{1099 struct v4l2_subdev_format sink_fmt = {1100 .which = V4L2_SUBDEV_FORMAT_ACTIVE,1101 };1102 struct v4l2_subdev_format src_fmt = {1103 .which = V4L2_SUBDEV_FORMAT_ACTIVE,1104 };1105 struct fimc_vid_cap *vc = &fimc->vid_cap;1106 struct v4l2_subdev *sd = &vc->subdev;1107 struct fimc_pipeline *p = to_fimc_pipeline(vc->ve.pipe);1108 struct media_pad *sink_pad, *src_pad;1109 int i, ret;1110 1111 while (1) {1112 /*1113 * Find current entity sink pad and any remote sink pad linked1114 * to it. We stop if there is no sink pad in current entity or1115 * it is not linked to any other remote entity.1116 */1117 src_pad = NULL;1118 1119 for (i = 0; i < sd->entity.num_pads; i++) {1120 struct media_pad *p = &sd->entity.pads[i];1121 1122 if (p->flags & MEDIA_PAD_FL_SINK) {1123 sink_pad = p;1124 src_pad = media_pad_remote_pad_first(sink_pad);1125 if (src_pad)1126 break;1127 }1128 }1129 1130 if (!src_pad || !is_media_entity_v4l2_subdev(src_pad->entity))1131 break;1132 1133 /* Don't call FIMC subdev operation to avoid nested locking */1134 if (sd == &vc->subdev) {1135 const struct fimc_frame *ff = &vc->ctx->s_frame;1136 sink_fmt.format.width = ff->f_width;1137 sink_fmt.format.height = ff->f_height;1138 sink_fmt.format.code = ff->fmt ? ff->fmt->mbus_code : 0;1139 } else {1140 sink_fmt.pad = sink_pad->index;1141 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sink_fmt);1142 if (ret < 0 && ret != -ENOIOCTLCMD)1143 return -EPIPE;1144 }1145 1146 /* Retrieve format at the source pad */1147 sd = media_entity_to_v4l2_subdev(src_pad->entity);1148 src_fmt.pad = src_pad->index;1149 ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt);1150 if (ret < 0 && ret != -ENOIOCTLCMD)1151 return -EPIPE;1152 1153 if (src_fmt.format.width != sink_fmt.format.width ||1154 src_fmt.format.height != sink_fmt.format.height ||1155 src_fmt.format.code != sink_fmt.format.code)1156 return -EPIPE;1157 1158 if (sd == p->subdevs[IDX_SENSOR] &&1159 fimc_user_defined_mbus_fmt(src_fmt.format.code)) {1160 struct v4l2_plane_pix_format plane_fmt[FIMC_MAX_PLANES];1161 const struct fimc_frame *frame = &vc->ctx->d_frame;1162 unsigned int i;1163 1164 ret = fimc_get_sensor_frame_desc(sd, plane_fmt,1165 frame->fmt->memplanes,1166 false);1167 if (ret < 0)1168 return -EPIPE;1169 1170 for (i = 0; i < frame->fmt->memplanes; i++)1171 if (frame->payload[i] < plane_fmt[i].sizeimage)1172 return -EPIPE;1173 }1174 }1175 return 0;1176}1177 1178static int fimc_cap_streamon(struct file *file, void *priv,1179 enum v4l2_buf_type type)1180{1181 struct fimc_dev *fimc = video_drvdata(file);1182 struct fimc_vid_cap *vc = &fimc->vid_cap;1183 struct fimc_source_info *si = NULL;1184 struct v4l2_subdev *sd;1185 int ret;1186 1187 if (fimc_capture_active(fimc))1188 return -EBUSY;1189 1190 ret = video_device_pipeline_start(&vc->ve.vdev, &vc->ve.pipe->mp);1191 if (ret < 0)1192 return ret;1193 1194 sd = __fimc_md_get_subdev(vc->ve.pipe, IDX_SENSOR);1195 if (sd)1196 si = v4l2_get_subdev_hostdata(sd);1197 1198 if (si == NULL) {1199 ret = -EPIPE;1200 goto err_p_stop;1201 }1202 /*1203 * Save configuration data related to currently attached image1204 * sensor or other data source, e.g. FIMC-IS.1205 */1206 vc->source_config = *si;1207 1208 if (vc->input == GRP_ID_FIMC_IS)1209 vc->source_config.fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK;1210 1211 if (vc->user_subdev_api) {1212 ret = fimc_pipeline_validate(fimc);1213 if (ret < 0)1214 goto err_p_stop;1215 }1216 1217 ret = vb2_ioctl_streamon(file, priv, type);1218 if (!ret) {1219 vc->streaming = true;1220 return ret;1221 }1222 1223err_p_stop:1224 video_device_pipeline_stop(&vc->ve.vdev);1225 return ret;1226}1227 1228static int fimc_cap_streamoff(struct file *file, void *priv,1229 enum v4l2_buf_type type)1230{1231 struct fimc_dev *fimc = video_drvdata(file);1232 struct fimc_vid_cap *vc = &fimc->vid_cap;1233 int ret;1234 1235 ret = vb2_ioctl_streamoff(file, priv, type);1236 if (ret < 0)1237 return ret;1238 1239 if (vc->streaming) {1240 video_device_pipeline_stop(&vc->ve.vdev);1241 vc->streaming = false;1242 }1243 1244 return 0;1245}1246 1247static int fimc_cap_reqbufs(struct file *file, void *priv,1248 struct v4l2_requestbuffers *reqbufs)1249{1250 struct fimc_dev *fimc = video_drvdata(file);1251 int ret;1252 1253 ret = vb2_ioctl_reqbufs(file, priv, reqbufs);1254 1255 if (!ret)1256 fimc->vid_cap.reqbufs_count = reqbufs->count;1257 1258 return ret;1259}1260 1261static int fimc_cap_g_selection(struct file *file, void *fh,1262 struct v4l2_selection *s)1263{1264 struct fimc_dev *fimc = video_drvdata(file);1265 struct fimc_ctx *ctx = fimc->vid_cap.ctx;1266 const struct fimc_frame *f = &ctx->s_frame;1267 1268 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)1269 return -EINVAL;1270 1271 switch (s->target) {1272 case V4L2_SEL_TGT_COMPOSE_DEFAULT:1273 case V4L2_SEL_TGT_COMPOSE_BOUNDS:1274 f = &ctx->d_frame;1275 fallthrough;1276 case V4L2_SEL_TGT_CROP_BOUNDS:1277 case V4L2_SEL_TGT_CROP_DEFAULT:1278 s->r.left = 0;1279 s->r.top = 0;1280 s->r.width = f->o_width;1281 s->r.height = f->o_height;1282 return 0;1283 1284 case V4L2_SEL_TGT_COMPOSE:1285 f = &ctx->d_frame;1286 fallthrough;1287 case V4L2_SEL_TGT_CROP:1288 s->r.left = f->offs_h;1289 s->r.top = f->offs_v;1290 s->r.width = f->width;1291 s->r.height = f->height;1292 return 0;1293 }1294 1295 return -EINVAL;1296}1297 1298static int fimc_cap_s_selection(struct file *file, void *fh,1299 struct v4l2_selection *s)1300{1301 struct fimc_dev *fimc = video_drvdata(file);1302 struct fimc_ctx *ctx = fimc->vid_cap.ctx;1303 struct v4l2_rect rect = s->r;1304 struct fimc_frame *f;1305 unsigned long flags;1306 1307 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)1308 return -EINVAL;1309 1310 if (s->target == V4L2_SEL_TGT_COMPOSE)1311 f = &ctx->d_frame;1312 else if (s->target == V4L2_SEL_TGT_CROP)1313 f = &ctx->s_frame;1314 else1315 return -EINVAL;1316 1317 fimc_capture_try_selection(ctx, &rect, s->target);1318 1319 if (s->flags & V4L2_SEL_FLAG_LE &&1320 !v4l2_rect_enclosed(&rect, &s->r))1321 return -ERANGE;1322 1323 if (s->flags & V4L2_SEL_FLAG_GE &&1324 !v4l2_rect_enclosed(&s->r, &rect))1325 return -ERANGE;1326 1327 s->r = rect;1328 spin_lock_irqsave(&fimc->slock, flags);1329 set_frame_crop(f, s->r.left, s->r.top, s->r.width,1330 s->r.height);1331 spin_unlock_irqrestore(&fimc->slock, flags);1332 1333 set_bit(ST_CAPT_APPLY_CFG, &fimc->state);1334 return 0;1335}1336 1337static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {1338 .vidioc_querycap = fimc_cap_querycap,1339 1340 .vidioc_enum_fmt_vid_cap = fimc_cap_enum_fmt,1341 .vidioc_try_fmt_vid_cap_mplane = fimc_cap_try_fmt_mplane,1342 .vidioc_s_fmt_vid_cap_mplane = fimc_cap_s_fmt_mplane,1343 .vidioc_g_fmt_vid_cap_mplane = fimc_cap_g_fmt_mplane,1344 1345 .vidioc_reqbufs = fimc_cap_reqbufs,1346 .vidioc_querybuf = vb2_ioctl_querybuf,1347 .vidioc_qbuf = vb2_ioctl_qbuf,1348 .vidioc_dqbuf = vb2_ioctl_dqbuf,1349 .vidioc_expbuf = vb2_ioctl_expbuf,1350 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,1351 .vidioc_create_bufs = vb2_ioctl_create_bufs,1352 1353 .vidioc_streamon = fimc_cap_streamon,1354 .vidioc_streamoff = fimc_cap_streamoff,1355 1356 .vidioc_g_selection = fimc_cap_g_selection,1357 .vidioc_s_selection = fimc_cap_s_selection,1358 1359 .vidioc_enum_input = fimc_cap_enum_input,1360 .vidioc_s_input = fimc_cap_s_input,1361 .vidioc_g_input = fimc_cap_g_input,1362};1363 1364/* Capture subdev media entity operations */1365static int fimc_link_setup(struct media_entity *entity,1366 const struct media_pad *local,1367 const struct media_pad *remote, u32 flags)1368{1369 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);1370 struct fimc_dev *fimc = v4l2_get_subdevdata(sd);1371 struct fimc_vid_cap *vc = &fimc->vid_cap;1372 struct v4l2_subdev *sensor;1373 1374 if (!is_media_entity_v4l2_subdev(remote->entity))1375 return -EINVAL;1376 1377 if (WARN_ON(fimc == NULL))1378 return 0;1379 1380 dbg("%s --> %s, flags: 0x%x. input: 0x%x",1381 local->entity->name, remote->entity->name, flags,1382 fimc->vid_cap.input);1383 1384 if (!(flags & MEDIA_LNK_FL_ENABLED)) {1385 fimc->vid_cap.input = 0;1386 return 0;1387 }1388 1389 if (vc->input != 0)1390 return -EBUSY;1391 1392 vc->input = sd->grp_id;1393 1394 if (vc->user_subdev_api)1395 return 0;1396 1397 /* Inherit V4L2 controls from the image sensor subdev. */1398 sensor = fimc_find_remote_sensor(&vc->subdev.entity);1399 if (sensor == NULL)1400 return 0;1401 1402 return v4l2_ctrl_add_handler(&vc->ctx->ctrls.handler,1403 sensor->ctrl_handler, NULL, true);1404}1405 1406static const struct media_entity_operations fimc_sd_media_ops = {1407 .link_setup = fimc_link_setup,1408};1409 1410/**1411 * fimc_sensor_notify - v4l2_device notification from a sensor subdev1412 * @sd: pointer to a subdev generating the notification1413 * @notification: the notification type, must be S5P_FIMC_TX_END_NOTIFY1414 * @arg: pointer to an u32 type integer that stores the frame payload value1415 *1416 * The End Of Frame notification sent by sensor subdev in its still capture1417 * mode. If there is only a single VSYNC generated by the sensor at the1418 * beginning of a frame transmission, FIMC does not issue the LastIrq1419 * (end of frame) interrupt. And this notification is used to complete the1420 * frame capture and returning a buffer to user-space. Subdev drivers should1421 * call this notification from their last 'End of frame capture' interrupt.1422 */1423void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification,1424 void *arg)1425{1426 struct fimc_source_info *si;1427 struct fimc_vid_buffer *buf;1428 struct fimc_md *fmd;1429 struct fimc_dev *fimc;1430 unsigned long flags;1431 1432 if (sd == NULL)1433 return;1434 1435 si = v4l2_get_subdev_hostdata(sd);1436 fmd = entity_to_fimc_mdev(&sd->entity);1437 1438 spin_lock_irqsave(&fmd->slock, flags);1439 1440 fimc = si ? source_to_sensor_info(si)->host : NULL;1441 1442 if (fimc && arg && notification == S5P_FIMC_TX_END_NOTIFY &&1443 test_bit(ST_CAPT_PEND, &fimc->state)) {1444 unsigned long irq_flags;1445 spin_lock_irqsave(&fimc->slock, irq_flags);1446 if (!list_empty(&fimc->vid_cap.active_buf_q)) {1447 buf = list_entry(fimc->vid_cap.active_buf_q.next,1448 struct fimc_vid_buffer, list);1449 vb2_set_plane_payload(&buf->vb.vb2_buf, 0,1450 *((u32 *)arg));1451 }1452 fimc_capture_irq_handler(fimc, 1);1453 fimc_deactivate_capture(fimc);1454 spin_unlock_irqrestore(&fimc->slock, irq_flags);1455 }1456 spin_unlock_irqrestore(&fmd->slock, flags);1457}1458 1459static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd,1460 struct v4l2_subdev_state *sd_state,1461 struct v4l2_subdev_mbus_code_enum *code)1462{1463 const struct fimc_fmt *fmt;1464 1465 fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, code->index);1466 if (!fmt)1467 return -EINVAL;1468 code->code = fmt->mbus_code;1469 return 0;1470}1471 1472static int fimc_subdev_get_fmt(struct v4l2_subdev *sd,1473 struct v4l2_subdev_state *sd_state,1474 struct v4l2_subdev_format *fmt)1475{1476 struct fimc_dev *fimc = v4l2_get_subdevdata(sd);1477 struct fimc_ctx *ctx = fimc->vid_cap.ctx;1478 const struct fimc_frame *ff = &ctx->s_frame;1479 struct v4l2_mbus_framefmt *mf;1480 1481 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {1482 mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);1483 fmt->format = *mf;1484 return 0;1485 }1486 1487 mf = &fmt->format;1488 mutex_lock(&fimc->lock);1489 1490 switch (fmt->pad) {1491 case FIMC_SD_PAD_SOURCE:1492 if (!WARN_ON(ff->fmt == NULL))1493 mf->code = ff->fmt->mbus_code;1494 /* Sink pads crop rectangle size */1495 mf->width = ff->width;1496 mf->height = ff->height;1497 break;1498 case FIMC_SD_PAD_SINK_FIFO:1499 *mf = fimc->vid_cap.wb_fmt;1500 break;1501 case FIMC_SD_PAD_SINK_CAM:1502 default:1503 *mf = fimc->vid_cap.ci_fmt;1504 break;1505 }1506 1507 mutex_unlock(&fimc->lock);1508 mf->colorspace = V4L2_COLORSPACE_JPEG;1509 1510 return 0;1511}1512 1513static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,1514 struct v4l2_subdev_state *sd_state,1515 struct v4l2_subdev_format *fmt)1516{1517 struct fimc_dev *fimc = v4l2_get_subdevdata(sd);1518 struct v4l2_mbus_framefmt *mf = &fmt->format;1519 struct fimc_vid_cap *vc = &fimc->vid_cap;1520 struct fimc_ctx *ctx = vc->ctx;1521 struct fimc_frame *ff;1522 const struct fimc_fmt *ffmt;1523 1524 dbg("pad%d: code: 0x%x, %dx%d",1525 fmt->pad, mf->code, mf->width, mf->height);1526 1527 if (fmt->pad == FIMC_SD_PAD_SOURCE && vb2_is_busy(&vc->vbq))1528 return -EBUSY;1529 1530 mutex_lock(&fimc->lock);1531 ffmt = fimc_capture_try_format(ctx, &mf->width, &mf->height,1532 &mf->code, NULL, fmt->pad);1533 mutex_unlock(&fimc->lock);1534 mf->colorspace = V4L2_COLORSPACE_JPEG;1535 1536 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {1537 mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);1538 *mf = fmt->format;1539 return 0;1540 }1541 /* There must be a bug in the driver if this happens */1542 if (WARN_ON(ffmt == NULL))1543 return -EINVAL;1544 1545 /* Update RGB Alpha control state and value range */1546 fimc_alpha_ctrl_update(ctx);1547 1548 fimc_capture_mark_jpeg_xfer(ctx, ffmt->color);1549 if (fmt->pad == FIMC_SD_PAD_SOURCE) {1550 ff = &ctx->d_frame;1551 /* Sink pads crop rectangle size */1552 mf->width = ctx->s_frame.width;1553 mf->height = ctx->s_frame.height;1554 } else {1555 ff = &ctx->s_frame;1556 }1557 1558 mutex_lock(&fimc->lock);1559 set_frame_bounds(ff, mf->width, mf->height);1560 1561 if (fmt->pad == FIMC_SD_PAD_SINK_FIFO)1562 vc->wb_fmt = *mf;1563 else if (fmt->pad == FIMC_SD_PAD_SINK_CAM)1564 vc->ci_fmt = *mf;1565 1566 ff->fmt = ffmt;1567 1568 /* Reset the crop rectangle if required. */1569 if (!(fmt->pad == FIMC_SD_PAD_SOURCE && (ctx->state & FIMC_COMPOSE)))1570 set_frame_crop(ff, 0, 0, mf->width, mf->height);1571 1572 if (fmt->pad != FIMC_SD_PAD_SOURCE)1573 ctx->state &= ~FIMC_COMPOSE;1574 1575 mutex_unlock(&fimc->lock);1576 return 0;1577}1578 1579static int fimc_subdev_get_selection(struct v4l2_subdev *sd,1580 struct v4l2_subdev_state *sd_state,1581 struct v4l2_subdev_selection *sel)1582{1583 struct fimc_dev *fimc = v4l2_get_subdevdata(sd);1584 struct fimc_ctx *ctx = fimc->vid_cap.ctx;1585 const struct fimc_frame *f = &ctx->s_frame;1586 struct v4l2_rect *r = &sel->r;1587 struct v4l2_rect *try_sel;1588 1589 if (sel->pad == FIMC_SD_PAD_SOURCE)1590 return -EINVAL;1591 1592 mutex_lock(&fimc->lock);1593 1594 switch (sel->target) {1595 case V4L2_SEL_TGT_COMPOSE_BOUNDS:1596 f = &ctx->d_frame;1597 fallthrough;1598 case V4L2_SEL_TGT_CROP_BOUNDS:1599 r->width = f->o_width;1600 r->height = f->o_height;1601 r->left = 0;1602 r->top = 0;1603 mutex_unlock(&fimc->lock);1604 return 0;1605 1606 case V4L2_SEL_TGT_CROP:1607 try_sel = v4l2_subdev_state_get_crop(sd_state, sel->pad);1608 break;1609 case V4L2_SEL_TGT_COMPOSE:1610 try_sel = v4l2_subdev_state_get_compose(sd_state, sel->pad);1611 f = &ctx->d_frame;1612 break;1613 default:1614 mutex_unlock(&fimc->lock);1615 return -EINVAL;1616 }1617 1618 if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {1619 sel->r = *try_sel;1620 } else {1621 r->left = f->offs_h;1622 r->top = f->offs_v;1623 r->width = f->width;1624 r->height = f->height;1625 }1626 1627 dbg("target %#x: l:%d, t:%d, %dx%d, f_w: %d, f_h: %d",1628 sel->pad, r->left, r->top, r->width, r->height,1629 f->f_width, f->f_height);1630 1631 mutex_unlock(&fimc->lock);1632 return 0;1633}1634 1635static int fimc_subdev_set_selection(struct v4l2_subdev *sd,1636 struct v4l2_subdev_state *sd_state,1637 struct v4l2_subdev_selection *sel)1638{1639 struct fimc_dev *fimc = v4l2_get_subdevdata(sd);1640 struct fimc_ctx *ctx = fimc->vid_cap.ctx;1641 struct fimc_frame *f = &ctx->s_frame;1642 struct v4l2_rect *r = &sel->r;1643 struct v4l2_rect *try_sel;1644 unsigned long flags;1645 1646 if (sel->pad == FIMC_SD_PAD_SOURCE)1647 return -EINVAL;1648 1649 mutex_lock(&fimc->lock);1650 fimc_capture_try_selection(ctx, r, V4L2_SEL_TGT_CROP);1651 1652 switch (sel->target) {1653 case V4L2_SEL_TGT_CROP:1654 try_sel = v4l2_subdev_state_get_crop(sd_state, sel->pad);1655 break;1656 case V4L2_SEL_TGT_COMPOSE:1657 try_sel = v4l2_subdev_state_get_compose(sd_state, sel->pad);1658 f = &ctx->d_frame;1659 break;1660 default:1661 mutex_unlock(&fimc->lock);1662 return -EINVAL;1663 }1664 1665 if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {1666 *try_sel = sel->r;1667 } else {1668 spin_lock_irqsave(&fimc->slock, flags);1669 set_frame_crop(f, r->left, r->top, r->width, r->height);1670 set_bit(ST_CAPT_APPLY_CFG, &fimc->state);1671 if (sel->target == V4L2_SEL_TGT_COMPOSE)1672 ctx->state |= FIMC_COMPOSE;1673 spin_unlock_irqrestore(&fimc->slock, flags);1674 }1675 1676 dbg("target %#x: (%d,%d)/%dx%d", sel->target, r->left, r->top,1677 r->width, r->height);1678 1679 mutex_unlock(&fimc->lock);1680 return 0;1681}1682 1683static const struct v4l2_subdev_pad_ops fimc_subdev_pad_ops = {1684 .enum_mbus_code = fimc_subdev_enum_mbus_code,1685 .get_selection = fimc_subdev_get_selection,1686 .set_selection = fimc_subdev_set_selection,1687 .get_fmt = fimc_subdev_get_fmt,1688 .set_fmt = fimc_subdev_set_fmt,1689};1690 1691static const struct v4l2_subdev_ops fimc_subdev_ops = {1692 .pad = &fimc_subdev_pad_ops,1693};1694 1695/* Set default format at the sensor and host interface */1696static int fimc_capture_set_default_format(struct fimc_dev *fimc)1697{1698 struct v4l2_format fmt = {1699 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,1700 .fmt.pix_mp = {1701 .width = FIMC_DEFAULT_WIDTH,1702 .height = FIMC_DEFAULT_HEIGHT,1703 .pixelformat = V4L2_PIX_FMT_YUYV,1704 .field = V4L2_FIELD_NONE,1705 .colorspace = V4L2_COLORSPACE_JPEG,1706 },1707 };1708 1709 return __fimc_capture_set_format(fimc, &fmt);1710}1711 1712/* fimc->lock must be already initialized */1713static int fimc_register_capture_device(struct fimc_dev *fimc,1714 struct v4l2_device *v4l2_dev)1715{1716 struct video_device *vfd = &fimc->vid_cap.ve.vdev;1717 struct vb2_queue *q = &fimc->vid_cap.vbq;1718 struct fimc_vid_cap *vid_cap;1719 const struct fimc_fmt *fmt;1720 struct fimc_ctx *ctx;1721 int ret = -ENOMEM;1722 1723 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);1724 if (!ctx)1725 return -ENOMEM;1726 1727 ctx->fimc_dev = fimc;1728 ctx->in_path = FIMC_IO_CAMERA;1729 ctx->out_path = FIMC_IO_DMA;1730 ctx->state = FIMC_CTX_CAP;1731 ctx->s_frame.fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0);1732 ctx->d_frame.fmt = ctx->s_frame.fmt;1733 1734 memset(vfd, 0, sizeof(*vfd));1735 snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.capture", fimc->id);1736 1737 vfd->fops = &fimc_capture_fops;1738 vfd->ioctl_ops = &fimc_capture_ioctl_ops;1739 vfd->v4l2_dev = v4l2_dev;1740 vfd->minor = -1;1741 vfd->release = video_device_release_empty;1742 vfd->queue = q;1743 vfd->lock = &fimc->lock;1744 vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE;1745 1746 video_set_drvdata(vfd, fimc);1747 vid_cap = &fimc->vid_cap;1748 vid_cap->active_buf_cnt = 0;1749 vid_cap->reqbufs_count = 0;1750 vid_cap->ctx = ctx;1751 1752 INIT_LIST_HEAD(&vid_cap->pending_buf_q);1753 INIT_LIST_HEAD(&vid_cap->active_buf_q);1754 1755 memset(q, 0, sizeof(*q));1756 q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;1757 q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;1758 q->drv_priv = ctx;1759 q->ops = &fimc_capture_qops;1760 q->mem_ops = &vb2_dma_contig_memops;1761 q->buf_struct_size = sizeof(struct fimc_vid_buffer);1762 q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;1763 q->lock = &fimc->lock;1764 q->dev = &fimc->pdev->dev;1765 1766 ret = vb2_queue_init(q);1767 if (ret)1768 goto err_free_ctx;1769 1770 /* Default format configuration */1771 fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0);1772 vid_cap->ci_fmt.width = FIMC_DEFAULT_WIDTH;1773 vid_cap->ci_fmt.height = FIMC_DEFAULT_HEIGHT;1774 vid_cap->ci_fmt.code = fmt->mbus_code;1775 1776 ctx->s_frame.width = FIMC_DEFAULT_WIDTH;1777 ctx->s_frame.height = FIMC_DEFAULT_HEIGHT;1778 ctx->s_frame.fmt = fmt;1779 1780 fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_WRITEBACK, 0);1781 vid_cap->wb_fmt = vid_cap->ci_fmt;1782 vid_cap->wb_fmt.code = fmt->mbus_code;1783 1784 vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK;1785 vfd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;1786 ret = media_entity_pads_init(&vfd->entity, 1, &vid_cap->vd_pad);1787 if (ret)1788 goto err_free_ctx;1789 1790 ret = fimc_ctrls_create(ctx);1791 if (ret)1792 goto err_me_cleanup;1793 1794 ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);1795 if (ret)1796 goto err_ctrl_free;1797 1798 v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",1799 vfd->name, video_device_node_name(vfd));1800 1801 vfd->ctrl_handler = &ctx->ctrls.handler;1802 return 0;1803 1804err_ctrl_free:1805 fimc_ctrls_delete(ctx);1806err_me_cleanup:1807 media_entity_cleanup(&vfd->entity);1808err_free_ctx:1809 kfree(ctx);1810 return ret;1811}1812 1813static int fimc_capture_subdev_registered(struct v4l2_subdev *sd)1814{1815 struct fimc_dev *fimc = v4l2_get_subdevdata(sd);1816 int ret;1817 1818 if (fimc == NULL)1819 return -ENXIO;1820 1821 ret = fimc_register_m2m_device(fimc, sd->v4l2_dev);1822 if (ret)1823 return ret;1824 1825 fimc->vid_cap.ve.pipe = v4l2_get_subdev_hostdata(sd);1826 1827 ret = fimc_register_capture_device(fimc, sd->v4l2_dev);1828 if (ret) {1829 fimc_unregister_m2m_device(fimc);1830 fimc->vid_cap.ve.pipe = NULL;1831 }1832 1833 return ret;1834}1835 1836static void fimc_capture_subdev_unregistered(struct v4l2_subdev *sd)1837{1838 struct fimc_dev *fimc = v4l2_get_subdevdata(sd);1839 struct video_device *vdev;1840 1841 if (fimc == NULL)1842 return;1843 1844 mutex_lock(&fimc->lock);1845 1846 fimc_unregister_m2m_device(fimc);1847 vdev = &fimc->vid_cap.ve.vdev;1848 1849 if (video_is_registered(vdev)) {1850 video_unregister_device(vdev);1851 media_entity_cleanup(&vdev->entity);1852 fimc_ctrls_delete(fimc->vid_cap.ctx);1853 fimc->vid_cap.ve.pipe = NULL;1854 }1855 kfree(fimc->vid_cap.ctx);1856 fimc->vid_cap.ctx = NULL;1857 1858 mutex_unlock(&fimc->lock);1859}1860 1861static const struct v4l2_subdev_internal_ops fimc_capture_sd_internal_ops = {1862 .registered = fimc_capture_subdev_registered,1863 .unregistered = fimc_capture_subdev_unregistered,1864};1865 1866int fimc_initialize_capture_subdev(struct fimc_dev *fimc)1867{1868 struct v4l2_subdev *sd = &fimc->vid_cap.subdev;1869 int ret;1870 1871 v4l2_subdev_init(sd, &fimc_subdev_ops);1872 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;1873 snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->id);1874 1875 fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_CAM].flags = MEDIA_PAD_FL_SINK;1876 fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_FIFO].flags = MEDIA_PAD_FL_SINK;1877 fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;1878 ret = media_entity_pads_init(&sd->entity, FIMC_SD_PADS_NUM,1879 fimc->vid_cap.sd_pads);1880 if (ret)1881 return ret;1882 1883 sd->entity.ops = &fimc_sd_media_ops;1884 sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;1885 sd->internal_ops = &fimc_capture_sd_internal_ops;1886 v4l2_set_subdevdata(sd, fimc);1887 return 0;1888}1889 1890void fimc_unregister_capture_subdev(struct fimc_dev *fimc)1891{1892 struct v4l2_subdev *sd = &fimc->vid_cap.subdev;1893 1894 v4l2_device_unregister_subdev(sd);1895 media_entity_cleanup(&sd->entity);1896 v4l2_set_subdevdata(sd, NULL);1897}1898