1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Support for Medifield PNW Camera Imaging ISP subsystem. 4 * 5 * Copyright (c) 2010 Intel Corporation. All Rights Reserved. 6 * 7 * Copyright (c) 2010 Silicon Hive www.siliconhive.com. 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License version 11 * 2 as published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * 19 */ 20 21 #include <linux/module.h> 22 #include <linux/pm_runtime.h> 23 24 #include <media/v4l2-ioctl.h> 25 #include <media/videobuf2-vmalloc.h> 26 27 #include "atomisp_cmd.h" 28 #include "atomisp_common.h" 29 #include "atomisp_fops.h" 30 #include "atomisp_internal.h" 31 #include "atomisp_ioctl.h" 32 #include "atomisp_compat.h" 33 #include "atomisp_subdev.h" 34 #include "atomisp_v4l2.h" 35 #include "atomisp-regs.h" 36 #include "hmm/hmm.h" 37 38 #include "ia_css_frame.h" 39 #include "type_support.h" 40 #include "device_access/device_access.h" 41 42 /* 43 * Videobuf2 ops 44 */ 45 static int atomisp_queue_setup(struct vb2_queue *vq, 46 unsigned int *nbuffers, unsigned int *nplanes, 47 unsigned int sizes[], struct device *alloc_devs[]) 48 { 49 struct atomisp_video_pipe *pipe = container_of(vq, struct atomisp_video_pipe, vb_queue); 50 u16 source_pad = atomisp_subdev_source_pad(&pipe->vdev); 51 int ret; 52 53 mutex_lock(&pipe->asd->isp->mutex); /* for get_css_frame_info() / set_fmt() */ 54 55 /* 56 * When VIDIOC_S_FMT has not been called before VIDIOC_REQBUFS, then 57 * this will fail. Call atomisp_set_fmt() ourselves and try again. 58 */ 59 ret = atomisp_get_css_frame_info(pipe->asd, source_pad, &pipe->frame_info); 60 if (ret) { 61 struct v4l2_format f = { 62 .fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420, 63 .fmt.pix.width = 10000, 64 .fmt.pix.height = 10000, 65 }; 66 67 ret = atomisp_set_fmt(&pipe->vdev, &f); 68 if (ret) 69 goto out; 70 71 ret = atomisp_get_css_frame_info(pipe->asd, source_pad, &pipe->frame_info); 72 if (ret) 73 goto out; 74 } 75 76 atomisp_alloc_css_stat_bufs(pipe->asd, ATOMISP_INPUT_STREAM_GENERAL); 77 78 *nplanes = 1; 79 sizes[0] = PAGE_ALIGN(pipe->pix.sizeimage); 80 81 out: 82 mutex_unlock(&pipe->asd->isp->mutex); 83 return ret; 84 } 85 86 static int atomisp_buf_init(struct vb2_buffer *vb) 87 { 88 struct atomisp_video_pipe *pipe = vb_to_pipe(vb); 89 struct ia_css_frame *frame = vb_to_frame(vb); 90 int ret; 91 92 ret = ia_css_frame_init_from_info(frame, &pipe->frame_info); 93 if (ret) 94 return ret; 95 96 if (frame->data_bytes > vb2_plane_size(vb, 0)) { 97 dev_err(pipe->asd->isp->dev, "Internal error frame.data_bytes(%u) > vb.length(%lu)\n", 98 frame->data_bytes, vb2_plane_size(vb, 0)); 99 return -EIO; 100 } 101 102 frame->data = hmm_create_from_vmalloc_buf(vb2_plane_size(vb, 0), 103 vb2_plane_vaddr(vb, 0)); 104 if (frame->data == mmgr_NULL) 105 return -ENOMEM; 106 107 return 0; 108 } 109 110 static int atomisp_q_one_metadata_buffer(struct atomisp_sub_device *asd, 111 enum atomisp_input_stream_id stream_id, 112 enum ia_css_pipe_id css_pipe_id) 113 { 114 struct atomisp_metadata_buf *metadata_buf; 115 enum atomisp_metadata_type md_type = ATOMISP_MAIN_METADATA; 116 struct list_head *metadata_list; 117 118 if (asd->metadata_bufs_in_css[stream_id][css_pipe_id] >= 119 ATOMISP_CSS_Q_DEPTH) 120 return 0; /* we have reached CSS queue depth */ 121 122 if (!list_empty(&asd->metadata[md_type])) { 123 metadata_list = &asd->metadata[md_type]; 124 } else if (!list_empty(&asd->metadata_ready[md_type])) { 125 metadata_list = &asd->metadata_ready[md_type]; 126 } else { 127 dev_warn(asd->isp->dev, "%s: No metadata buffers available for type %d!\n", 128 __func__, md_type); 129 return -EINVAL; 130 } 131 132 metadata_buf = list_entry(metadata_list->next, 133 struct atomisp_metadata_buf, list); 134 list_del_init(&metadata_buf->list); 135 136 if (atomisp_q_metadata_buffer_to_css(asd, metadata_buf, 137 stream_id, css_pipe_id)) { 138 list_add(&metadata_buf->list, metadata_list); 139 return -EINVAL; 140 } else { 141 list_add_tail(&metadata_buf->list, 142 &asd->metadata_in_css[md_type]); 143 } 144 asd->metadata_bufs_in_css[stream_id][css_pipe_id]++; 145 146 return 0; 147 } 148 149 static int atomisp_q_one_s3a_buffer(struct atomisp_sub_device *asd, 150 enum atomisp_input_stream_id stream_id, 151 enum ia_css_pipe_id css_pipe_id) 152 { 153 struct atomisp_s3a_buf *s3a_buf; 154 struct list_head *s3a_list; 155 unsigned int exp_id; 156 157 if (asd->s3a_bufs_in_css[css_pipe_id] >= ATOMISP_CSS_Q_DEPTH) 158 return 0; /* we have reached CSS queue depth */ 159 160 if (!list_empty(&asd->s3a_stats)) { 161 s3a_list = &asd->s3a_stats; 162 } else if (!list_empty(&asd->s3a_stats_ready)) { 163 s3a_list = &asd->s3a_stats_ready; 164 } else { 165 dev_warn(asd->isp->dev, "%s: No s3a buffers available!\n", 166 __func__); 167 return -EINVAL; 168 } 169 170 s3a_buf = list_entry(s3a_list->next, struct atomisp_s3a_buf, list); 171 list_del_init(&s3a_buf->list); 172 exp_id = s3a_buf->s3a_data->exp_id; 173 174 hmm_flush_vmap(s3a_buf->s3a_data->data_ptr); 175 if (atomisp_q_s3a_buffer_to_css(asd, s3a_buf, 176 stream_id, css_pipe_id)) { 177 /* got from head, so return back to the head */ 178 list_add(&s3a_buf->list, s3a_list); 179 return -EINVAL; 180 } else { 181 list_add_tail(&s3a_buf->list, &asd->s3a_stats_in_css); 182 if (s3a_list == &asd->s3a_stats_ready) 183 dev_dbg(asd->isp->dev, "drop one s3a stat with exp_id %d\n", exp_id); 184 } 185 186 asd->s3a_bufs_in_css[css_pipe_id]++; 187 return 0; 188 } 189 190 static int atomisp_q_one_dis_buffer(struct atomisp_sub_device *asd, 191 enum atomisp_input_stream_id stream_id, 192 enum ia_css_pipe_id css_pipe_id) 193 { 194 struct atomisp_dis_buf *dis_buf; 195 unsigned long irqflags; 196 197 if (asd->dis_bufs_in_css >= ATOMISP_CSS_Q_DEPTH) 198 return 0; /* we have reached CSS queue depth */ 199 200 spin_lock_irqsave(&asd->dis_stats_lock, irqflags); 201 if (list_empty(&asd->dis_stats)) { 202 spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags); 203 dev_warn(asd->isp->dev, "%s: No dis buffers available!\n", 204 __func__); 205 return -EINVAL; 206 } 207 208 dis_buf = list_entry(asd->dis_stats.prev, 209 struct atomisp_dis_buf, list); 210 list_del_init(&dis_buf->list); 211 spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags); 212 213 hmm_flush_vmap(dis_buf->dis_data->data_ptr); 214 if (atomisp_q_dis_buffer_to_css(asd, dis_buf, 215 stream_id, css_pipe_id)) { 216 spin_lock_irqsave(&asd->dis_stats_lock, irqflags); 217 /* got from tail, so return back to the tail */ 218 list_add_tail(&dis_buf->list, &asd->dis_stats); 219 spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags); 220 return -EINVAL; 221 } else { 222 spin_lock_irqsave(&asd->dis_stats_lock, irqflags); 223 list_add_tail(&dis_buf->list, &asd->dis_stats_in_css); 224 spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags); 225 } 226 227 asd->dis_bufs_in_css++; 228 229 return 0; 230 } 231 232 static int atomisp_q_video_buffers_to_css(struct atomisp_sub_device *asd, 233 struct atomisp_video_pipe *pipe, 234 enum atomisp_input_stream_id stream_id, 235 enum ia_css_buffer_type css_buf_type, 236 enum ia_css_pipe_id css_pipe_id) 237 { 238 struct atomisp_css_params_with_list *param; 239 struct ia_css_dvs_grid_info *dvs_grid = 240 atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info); 241 unsigned long irqflags; 242 int space, err = 0; 243 244 lockdep_assert_held(&asd->isp->mutex); 245 246 if (WARN_ON(css_pipe_id >= IA_CSS_PIPE_ID_NUM)) 247 return -EINVAL; 248 249 if (pipe->stopping) 250 return -EINVAL; 251 252 space = ATOMISP_CSS_Q_DEPTH - atomisp_buffers_in_css(pipe); 253 while (space--) { 254 struct ia_css_frame *frame; 255 256 spin_lock_irqsave(&pipe->irq_lock, irqflags); 257 frame = list_first_entry_or_null(&pipe->activeq, struct ia_css_frame, queue); 258 if (frame) 259 list_move_tail(&frame->queue, &pipe->buffers_in_css); 260 spin_unlock_irqrestore(&pipe->irq_lock, irqflags); 261 262 if (!frame) 263 return -EINVAL; 264 265 /* 266 * If there is a per_frame setting to apply on the buffer, 267 * do it before buffer en-queueing. 268 */ 269 param = pipe->frame_params[frame->vb.vb2_buf.index]; 270 if (param) { 271 atomisp_makeup_css_parameters(asd, 272 &asd->params.css_param.update_flag, 273 ¶m->params); 274 atomisp_apply_css_parameters(asd, ¶m->params); 275 276 if (param->params.update_flag.dz_config && 277 asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO) { 278 err = atomisp_calculate_real_zoom_region(asd, 279 ¶m->params.dz_config, css_pipe_id); 280 if (!err) 281 asd->params.config.dz_config = ¶m->params.dz_config; 282 } 283 atomisp_css_set_isp_config_applied_frame(asd, frame); 284 atomisp_css_update_isp_params_on_pipe(asd, 285 asd->stream_env[stream_id].pipes[css_pipe_id]); 286 asd->params.dvs_6axis = (struct ia_css_dvs_6axis_config *) 287 param->params.dvs_6axis; 288 289 /* 290 * WORKAROUND: 291 * Because the camera halv3 can't ensure to set zoom 292 * region to per_frame setting and global setting at 293 * same time and only set zoom region to pre_frame 294 * setting now.so when the pre_frame setting include 295 * zoom region,I will set it to global setting. 296 */ 297 if (param->params.update_flag.dz_config && 298 asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO 299 && !err) { 300 memcpy(&asd->params.css_param.dz_config, 301 ¶m->params.dz_config, 302 sizeof(struct ia_css_dz_config)); 303 asd->params.css_param.update_flag.dz_config = 304 (struct atomisp_dz_config *) 305 &asd->params.css_param.dz_config; 306 asd->params.css_update_params_needed = true; 307 } 308 pipe->frame_params[frame->vb.vb2_buf.index] = NULL; 309 } 310 /* Enqueue buffer */ 311 err = atomisp_q_video_buffer_to_css(asd, frame, stream_id, 312 css_buf_type, css_pipe_id); 313 if (err) { 314 spin_lock_irqsave(&pipe->irq_lock, irqflags); 315 list_move_tail(&frame->queue, &pipe->activeq); 316 spin_unlock_irqrestore(&pipe->irq_lock, irqflags); 317 dev_err(asd->isp->dev, "%s, css q fails: %d\n", 318 __func__, err); 319 return -EINVAL; 320 } 321 322 /* enqueue 3A/DIS/metadata buffers */ 323 if (asd->params.curr_grid_info.s3a_grid.enable && 324 css_pipe_id == asd->params.s3a_enabled_pipe && 325 css_buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) 326 atomisp_q_one_s3a_buffer(asd, stream_id, 327 css_pipe_id); 328 329 if (asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream_info. 330 metadata_info.size && 331 css_buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) 332 atomisp_q_one_metadata_buffer(asd, stream_id, 333 css_pipe_id); 334 335 if (dvs_grid && dvs_grid->enable && 336 css_pipe_id == IA_CSS_PIPE_ID_VIDEO && 337 css_buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) 338 atomisp_q_one_dis_buffer(asd, stream_id, 339 css_pipe_id); 340 } 341 342 return 0; 343 } 344 345 static int atomisp_get_css_buf_type(struct atomisp_sub_device *asd, 346 enum ia_css_pipe_id pipe_id, 347 uint16_t source_pad) 348 { 349 if (pipe_id == IA_CSS_PIPE_ID_COPY || 350 source_pad == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE || 351 source_pad == ATOMISP_SUBDEV_PAD_SOURCE_VIDEO || 352 (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW && 353 asd->run_mode->val != ATOMISP_RUN_MODE_VIDEO)) 354 return IA_CSS_BUFFER_TYPE_OUTPUT_FRAME; 355 else 356 return IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME; 357 } 358 359 /* queue all available buffers to css */ 360 int atomisp_qbuffers_to_css(struct atomisp_sub_device *asd) 361 { 362 enum ia_css_buffer_type buf_type; 363 enum ia_css_pipe_id css_capture_pipe_id = IA_CSS_PIPE_ID_NUM; 364 enum ia_css_pipe_id css_preview_pipe_id = IA_CSS_PIPE_ID_NUM; 365 enum ia_css_pipe_id css_video_pipe_id = IA_CSS_PIPE_ID_NUM; 366 enum atomisp_input_stream_id input_stream_id; 367 struct atomisp_video_pipe *capture_pipe = NULL; 368 struct atomisp_video_pipe *vf_pipe = NULL; 369 struct atomisp_video_pipe *preview_pipe = NULL; 370 struct atomisp_video_pipe *video_pipe = NULL; 371 bool raw_mode = atomisp_is_mbuscode_raw( 372 asd->fmt[asd->capture_pad].fmt.code); 373 374 if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) { 375 video_pipe = &asd->video_out_video_capture; 376 css_video_pipe_id = IA_CSS_PIPE_ID_VIDEO; 377 } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) { 378 preview_pipe = &asd->video_out_capture; 379 css_preview_pipe_id = IA_CSS_PIPE_ID_CAPTURE; 380 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { 381 video_pipe = &asd->video_out_video_capture; 382 preview_pipe = &asd->video_out_preview; 383 css_video_pipe_id = IA_CSS_PIPE_ID_VIDEO; 384 css_preview_pipe_id = IA_CSS_PIPE_ID_VIDEO; 385 } else if (asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW) { 386 preview_pipe = &asd->video_out_preview; 387 css_preview_pipe_id = IA_CSS_PIPE_ID_PREVIEW; 388 } else { 389 /* ATOMISP_RUN_MODE_STILL_CAPTURE */ 390 capture_pipe = &asd->video_out_capture; 391 if (!raw_mode) 392 vf_pipe = &asd->video_out_vf; 393 css_capture_pipe_id = IA_CSS_PIPE_ID_CAPTURE; 394 } 395 396 if (IS_ISP2401 && asd->copy_mode) { 397 css_capture_pipe_id = IA_CSS_PIPE_ID_COPY; 398 css_preview_pipe_id = IA_CSS_PIPE_ID_COPY; 399 css_video_pipe_id = IA_CSS_PIPE_ID_COPY; 400 } 401 402 if (capture_pipe) { 403 buf_type = atomisp_get_css_buf_type( 404 asd, css_capture_pipe_id, 405 atomisp_subdev_source_pad(&capture_pipe->vdev)); 406 input_stream_id = ATOMISP_INPUT_STREAM_GENERAL; 407 408 atomisp_q_video_buffers_to_css(asd, capture_pipe, 409 input_stream_id, 410 buf_type, css_capture_pipe_id); 411 } 412 413 if (vf_pipe) { 414 buf_type = atomisp_get_css_buf_type( 415 asd, css_capture_pipe_id, 416 atomisp_subdev_source_pad(&vf_pipe->vdev)); 417 if (asd->stream_env[ATOMISP_INPUT_STREAM_POSTVIEW].stream) 418 input_stream_id = ATOMISP_INPUT_STREAM_POSTVIEW; 419 else 420 input_stream_id = ATOMISP_INPUT_STREAM_GENERAL; 421 422 atomisp_q_video_buffers_to_css(asd, vf_pipe, 423 input_stream_id, 424 buf_type, css_capture_pipe_id); 425 } 426 427 if (preview_pipe) { 428 buf_type = atomisp_get_css_buf_type( 429 asd, css_preview_pipe_id, 430 atomisp_subdev_source_pad(&preview_pipe->vdev)); 431 432 if (css_preview_pipe_id == IA_CSS_PIPE_ID_YUVPP) 433 input_stream_id = ATOMISP_INPUT_STREAM_VIDEO; 434 else if (asd->stream_env[ATOMISP_INPUT_STREAM_PREVIEW].stream) 435 input_stream_id = ATOMISP_INPUT_STREAM_PREVIEW; 436 else 437 input_stream_id = ATOMISP_INPUT_STREAM_GENERAL; 438 439 atomisp_q_video_buffers_to_css(asd, preview_pipe, 440 input_stream_id, 441 buf_type, css_preview_pipe_id); 442 } 443 444 if (video_pipe) { 445 buf_type = atomisp_get_css_buf_type( 446 asd, css_video_pipe_id, 447 atomisp_subdev_source_pad(&video_pipe->vdev)); 448 if (asd->stream_env[ATOMISP_INPUT_STREAM_VIDEO].stream) 449 input_stream_id = ATOMISP_INPUT_STREAM_VIDEO; 450 else 451 input_stream_id = ATOMISP_INPUT_STREAM_GENERAL; 452 453 atomisp_q_video_buffers_to_css(asd, video_pipe, 454 input_stream_id, 455 buf_type, css_video_pipe_id); 456 } 457 458 return 0; 459 } 460 461 static void atomisp_buf_queue(struct vb2_buffer *vb) 462 { 463 struct atomisp_video_pipe *pipe = vb_to_pipe(vb); 464 struct ia_css_frame *frame = vb_to_frame(vb); 465 struct atomisp_sub_device *asd = pipe->asd; 466 unsigned long irqflags; 467 int ret; 468 469 mutex_lock(&asd->isp->mutex); 470 471 ret = atomisp_pipe_check(pipe, false); 472 if (ret || pipe->stopping) { 473 spin_lock_irqsave(&pipe->irq_lock, irqflags); 474 atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR); 475 spin_unlock_irqrestore(&pipe->irq_lock, irqflags); 476 goto out_unlock; 477 } 478 479 /* FIXME this ugliness comes from the original atomisp buffer handling */ 480 if (!(vb->skip_cache_sync_on_finish && vb->skip_cache_sync_on_prepare)) 481 wbinvd(); 482 483 pipe->frame_params[vb->index] = NULL; 484 485 spin_lock_irqsave(&pipe->irq_lock, irqflags); 486 /* 487 * when a frame buffer meets following conditions, it should be put into 488 * the waiting list: 489 * 1. It is not a main output frame, and it has a per-frame parameter 490 * to go with it. 491 * 2. It is not a main output frame, and the waiting buffer list is not 492 * empty, to keep the FIFO sequence of frame buffer processing, it 493 * is put to waiting list until previous per-frame parameter buffers 494 * get enqueued. 495 */ 496 if (!atomisp_is_vf_pipe(pipe) && 497 (pipe->frame_request_config_id[vb->index] || 498 !list_empty(&pipe->buffers_waiting_for_param))) 499 list_add_tail(&frame->queue, &pipe->buffers_waiting_for_param); 500 else 501 list_add_tail(&frame->queue, &pipe->activeq); 502 503 spin_unlock_irqrestore(&pipe->irq_lock, irqflags); 504 505 /* TODO: do this better, not best way to queue to css */ 506 if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED) { 507 if (!list_empty(&pipe->buffers_waiting_for_param)) 508 atomisp_handle_parameter_and_buffer(pipe); 509 else 510 atomisp_qbuffers_to_css(asd); 511 } 512 513 out_unlock: 514 mutex_unlock(&asd->isp->mutex); 515 } 516 517 static void atomisp_buf_cleanup(struct vb2_buffer *vb) 518 { 519 struct atomisp_video_pipe *pipe = vb_to_pipe(vb); 520 struct ia_css_frame *frame = vb_to_frame(vb); 521 int index = frame->vb.vb2_buf.index; 522 523 pipe->frame_request_config_id[index] = 0; 524 pipe->frame_params[index] = NULL; 525 526 hmm_free(frame->data); 527 } 528 529 const struct vb2_ops atomisp_vb2_ops = { 530 .queue_setup = atomisp_queue_setup, 531 .buf_init = atomisp_buf_init, 532 .buf_cleanup = atomisp_buf_cleanup, 533 .buf_queue = atomisp_buf_queue, 534 .start_streaming = atomisp_start_streaming, 535 .stop_streaming = atomisp_stop_streaming, 536 }; 537 538 static void atomisp_dev_init_struct(struct atomisp_device *isp) 539 { 540 unsigned int i; 541 542 isp->need_gfx_throttle = true; 543 isp->isp_fatal_error = false; 544 isp->mipi_frame_size = 0; 545 546 for (i = 0; i < isp->input_cnt; i++) 547 isp->inputs[i].asd = NULL; 548 /* 549 * For Merrifield, frequency is scalable. 550 * After boot-up, the default frequency is 200MHz. 551 */ 552 isp->running_freq = ISP_FREQ_200MHZ; 553 } 554 555 static void atomisp_subdev_init_struct(struct atomisp_sub_device *asd) 556 { 557 v4l2_ctrl_s_ctrl(asd->run_mode, ATOMISP_RUN_MODE_STILL_CAPTURE); 558 memset(&asd->params.css_param, 0, sizeof(asd->params.css_param)); 559 asd->params.color_effect = V4L2_COLORFX_NONE; 560 asd->params.bad_pixel_en = true; 561 asd->params.gdc_cac_en = false; 562 asd->params.video_dis_en = false; 563 asd->params.sc_en = false; 564 asd->params.fpn_en = false; 565 asd->params.xnr_en = false; 566 asd->params.false_color = 0; 567 asd->params.yuv_ds_en = 0; 568 /* s3a grid not enabled for any pipe */ 569 asd->params.s3a_enabled_pipe = IA_CSS_PIPE_ID_NUM; 570 571 /* Add for channel */ 572 asd->input_curr = 0; 573 574 asd->mipi_frame_size = 0; 575 asd->copy_mode = false; 576 577 asd->stream_prepared = false; 578 asd->high_speed_mode = false; 579 asd->sensor_array_res.height = 0; 580 asd->sensor_array_res.width = 0; 581 atomisp_css_init_struct(asd); 582 } 583 584 /* 585 * file operation functions 586 */ 587 static unsigned int atomisp_subdev_users(struct atomisp_sub_device *asd) 588 { 589 return asd->video_out_preview.users + 590 asd->video_out_vf.users + 591 asd->video_out_capture.users + 592 asd->video_out_video_capture.users; 593 } 594 595 unsigned int atomisp_dev_users(struct atomisp_device *isp) 596 { 597 return atomisp_subdev_users(&isp->asd); 598 } 599 600 static int atomisp_open(struct file *file) 601 { 602 struct video_device *vdev = video_devdata(file); 603 struct atomisp_device *isp = video_get_drvdata(vdev); 604 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); 605 struct atomisp_sub_device *asd = pipe->asd; 606 int ret; 607 608 dev_dbg(isp->dev, "open device %s\n", vdev->name); 609 610 ret = v4l2_fh_open(file); 611 if (ret) 612 return ret; 613 614 mutex_lock(&isp->mutex); 615 616 asd->subdev.devnode = vdev; 617 618 if (!isp->input_cnt) { 619 dev_err(isp->dev, "no camera attached\n"); 620 ret = -EINVAL; 621 goto error; 622 } 623 624 /* 625 * atomisp does not allow multiple open 626 */ 627 if (pipe->users) { 628 dev_dbg(isp->dev, "video node already opened\n"); 629 mutex_unlock(&isp->mutex); 630 return -EBUSY; 631 } 632 633 if (atomisp_dev_users(isp)) { 634 dev_dbg(isp->dev, "skip init isp in open\n"); 635 goto init_subdev; 636 } 637 638 /* runtime power management, turn on ISP */ 639 ret = pm_runtime_resume_and_get(vdev->v4l2_dev->dev); 640 if (ret < 0) { 641 dev_err(isp->dev, "Failed to power on device\n"); 642 goto error; 643 } 644 645 atomisp_dev_init_struct(isp); 646 647 ret = v4l2_subdev_call(isp->flash, core, s_power, 1); 648 if (ret < 0 && ret != -ENODEV && ret != -ENOIOCTLCMD) { 649 dev_err(isp->dev, "Failed to power-on flash\n"); 650 goto css_error; 651 } 652 653 init_subdev: 654 if (atomisp_subdev_users(asd)) 655 goto done; 656 657 atomisp_subdev_init_struct(asd); 658 /* Ensure that a mode is set */ 659 v4l2_ctrl_s_ctrl(asd->run_mode, pipe->default_run_mode); 660 661 done: 662 pipe->users++; 663 mutex_unlock(&isp->mutex); 664 665 666 return 0; 667 668 css_error: 669 pm_runtime_put(vdev->v4l2_dev->dev); 670 error: 671 mutex_unlock(&isp->mutex); 672 v4l2_fh_release(file); 673 return ret; 674 } 675 676 static int atomisp_release(struct file *file) 677 { 678 struct video_device *vdev = video_devdata(file); 679 struct atomisp_device *isp = video_get_drvdata(vdev); 680 struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); 681 struct atomisp_sub_device *asd = pipe->asd; 682 struct v4l2_subdev_fh fh; 683 struct v4l2_rect clear_compose = {0}; 684 unsigned long flags; 685 int ret; 686 687 v4l2_fh_init(&fh.vfh, vdev); 688 689 dev_dbg(isp->dev, "release device %s\n", vdev->name); 690 691 asd->subdev.devnode = vdev; 692 693 /* Note file must not be used after this! */ 694 vb2_fop_release(file); 695 696 mutex_lock(&isp->mutex); 697 698 pipe->users--; 699 if (pipe->users) 700 goto done; 701 702 /* 703 * A little trick here: 704 * file injection input resolution is recorded in the sink pad, 705 * therefore can not be cleared when releaseing one device node. 706 * The sink pad setting can only be cleared when all device nodes 707 * get released. 708 */ 709 { 710 struct v4l2_mbus_framefmt isp_sink_fmt = { 0 }; 711 712 atomisp_subdev_set_ffmt(&asd->subdev, fh.state, 713 V4L2_SUBDEV_FORMAT_ACTIVE, 714 ATOMISP_SUBDEV_PAD_SINK, &isp_sink_fmt); 715 } 716 717 if (atomisp_subdev_users(asd)) 718 goto done; 719 720 atomisp_css_free_stat_buffers(asd); 721 atomisp_free_internal_buffers(asd); 722 723 if (isp->inputs[asd->input_curr].asd == asd) { 724 ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, 725 core, s_power, 0); 726 if (ret && ret != -ENOIOCTLCMD) 727 dev_warn(isp->dev, "Failed to power-off sensor\n"); 728 729 /* clear the asd field to show this camera is not used */ 730 isp->inputs[asd->input_curr].asd = NULL; 731 } 732 733 spin_lock_irqsave(&isp->lock, flags); 734 asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED; 735 spin_unlock_irqrestore(&isp->lock, flags); 736 737 if (atomisp_dev_users(isp)) 738 goto done; 739 740 atomisp_destroy_pipes_stream_force(asd); 741 742 ret = v4l2_subdev_call(isp->flash, core, s_power, 0); 743 if (ret < 0 && ret != -ENODEV && ret != -ENOIOCTLCMD) 744 dev_warn(isp->dev, "Failed to power-off flash\n"); 745 746 if (pm_runtime_put_sync(vdev->v4l2_dev->dev) < 0) 747 dev_err(isp->dev, "Failed to power off device\n"); 748 749 done: 750 atomisp_subdev_set_selection(&asd->subdev, fh.state, 751 V4L2_SUBDEV_FORMAT_ACTIVE, 752 atomisp_subdev_source_pad(vdev), 753 V4L2_SEL_TGT_COMPOSE, 0, 754 &clear_compose); 755 mutex_unlock(&isp->mutex); 756 return 0; 757 } 758 759 const struct v4l2_file_operations atomisp_fops = { 760 .owner = THIS_MODULE, 761 .open = atomisp_open, 762 .release = atomisp_release, 763 .mmap = vb2_fop_mmap, 764 .poll = vb2_fop_poll, 765 .unlocked_ioctl = video_ioctl2, 766 #ifdef CONFIG_COMPAT 767 /* 768 * this was removed because of bugs, the interface 769 * needs to be made safe for compat tasks instead. 770 .compat_ioctl32 = atomisp_compat_ioctl32, 771 */ 772 #endif 773 }; 774