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 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License version 9 * 2 as published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * 17 */ 18#include <linux/module.h> 19#include <linux/uaccess.h> 20#include <linux/delay.h> 21#include <linux/device.h> 22#include <linux/mm.h> 23#include <linux/sched.h> 24#include <linux/slab.h> 25 26#include <media/v4l2-event.h> 27#include <media/v4l2-mediabus.h> 28#include <media/videobuf2-vmalloc.h> 29#include "atomisp_cmd.h" 30#include "atomisp_common.h" 31#include "atomisp_compat.h" 32#include "atomisp_fops.h" 33#include "atomisp_internal.h" 34 35const struct atomisp_in_fmt_conv atomisp_in_fmt_conv[] = { 36 { MEDIA_BUS_FMT_SBGGR8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_BGGR }, 37 { MEDIA_BUS_FMT_SGBRG8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_GBRG }, 38 { MEDIA_BUS_FMT_SGRBG8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_GRBG }, 39 { MEDIA_BUS_FMT_SRGGB8_1X8, 8, 8, ATOMISP_INPUT_FORMAT_RAW_8, IA_CSS_BAYER_ORDER_RGGB }, 40 { MEDIA_BUS_FMT_SBGGR10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_BGGR }, 41 { MEDIA_BUS_FMT_SGBRG10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_GBRG }, 42 { MEDIA_BUS_FMT_SGRBG10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_GRBG }, 43 { MEDIA_BUS_FMT_SRGGB10_1X10, 10, 10, ATOMISP_INPUT_FORMAT_RAW_10, IA_CSS_BAYER_ORDER_RGGB }, 44 { MEDIA_BUS_FMT_SBGGR12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_BGGR }, 45 { MEDIA_BUS_FMT_SGBRG12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_GBRG }, 46 { MEDIA_BUS_FMT_SGRBG12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_GRBG }, 47 { MEDIA_BUS_FMT_SRGGB12_1X12, 12, 12, ATOMISP_INPUT_FORMAT_RAW_12, IA_CSS_BAYER_ORDER_RGGB }, 48 { MEDIA_BUS_FMT_UYVY8_1X16, 8, 8, ATOMISP_INPUT_FORMAT_YUV422_8, 0 }, 49 { MEDIA_BUS_FMT_YUYV8_1X16, 8, 8, ATOMISP_INPUT_FORMAT_YUV422_8, 0 }, 50#if 0 // disabled due to clang warnings 51 { MEDIA_BUS_FMT_JPEG_1X8, 8, 8, IA_CSS_FRAME_FORMAT_BINARY_8, 0 }, 52 { V4L2_MBUS_FMT_CUSTOM_NV12, 12, 12, IA_CSS_FRAME_FORMAT_NV12, 0 }, 53 { V4L2_MBUS_FMT_CUSTOM_NV21, 12, 12, IA_CSS_FRAME_FORMAT_NV21, 0 }, 54#endif 55 { V4L2_MBUS_FMT_CUSTOM_YUV420, 12, 12, ATOMISP_INPUT_FORMAT_YUV420_8_LEGACY, 0 }, 56#if 0 57 { V4L2_MBUS_FMT_CUSTOM_M10MO_RAW, 8, 8, IA_CSS_FRAME_FORMAT_BINARY_8, 0 }, 58#endif 59 /* no valid V4L2 MBUS code for metadata format, so leave it 0. */ 60 { 0, 0, 0, ATOMISP_INPUT_FORMAT_EMBEDDED, 0 }, 61 {} 62}; 63 64static const struct { 65 u32 code; 66 u32 compressed; 67} compressed_codes[] = { 68 { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 }, 69 { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 }, 70 { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 }, 71 { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 }, 72}; 73 74u32 atomisp_subdev_uncompressed_code(u32 code) 75{ 76 unsigned int i; 77 78 for (i = 0; i < ARRAY_SIZE(compressed_codes); i++) 79 if (code == compressed_codes[i].compressed) 80 return compressed_codes[i].code; 81 82 return code; 83} 84 85bool atomisp_subdev_is_compressed(u32 code) 86{ 87 int i; 88 89 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++) 90 if (code == atomisp_in_fmt_conv[i].code) 91 return atomisp_in_fmt_conv[i].bpp != 92 atomisp_in_fmt_conv[i].depth; 93 94 return false; 95} 96 97const struct atomisp_in_fmt_conv *atomisp_find_in_fmt_conv(u32 code) 98{ 99 int i; 100 101 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++) 102 if (code == atomisp_in_fmt_conv[i].code) 103 return atomisp_in_fmt_conv + i; 104 105 return NULL; 106} 107 108const struct atomisp_in_fmt_conv *atomisp_find_in_fmt_conv_by_atomisp_in_fmt( 109 enum atomisp_input_format atomisp_in_fmt) 110{ 111 int i; 112 113 for (i = 0; i < ARRAY_SIZE(atomisp_in_fmt_conv) - 1; i++) 114 if (atomisp_in_fmt_conv[i].atomisp_in_fmt == atomisp_in_fmt) 115 return atomisp_in_fmt_conv + i; 116 117 return NULL; 118} 119 120bool atomisp_subdev_format_conversion(struct atomisp_sub_device *asd) 121{ 122 struct v4l2_mbus_framefmt *sink, *src; 123 124 sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL, 125 V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SINK); 126 src = atomisp_subdev_get_ffmt(&asd->subdev, NULL, 127 V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SOURCE); 128 129 return atomisp_is_mbuscode_raw(sink->code) 130 && !atomisp_is_mbuscode_raw(src->code); 131} 132 133/* 134 * V4L2 subdev operations 135 */ 136 137/* 138 * isp_subdev_ioctl - CCDC module private ioctl's 139 * @sd: ISP V4L2 subdevice 140 * @cmd: ioctl command 141 * @arg: ioctl argument 142 * 143 * Return 0 on success or a negative error code otherwise. 144 */ 145static long isp_subdev_ioctl(struct v4l2_subdev *sd, 146 unsigned int cmd, void *arg) 147{ 148 return 0; 149} 150 151/* 152 * isp_subdev_set_power - Power on/off the CCDC module 153 * @sd: ISP V4L2 subdevice 154 * @on: power on/off 155 * 156 * Return 0 on success or a negative error code otherwise. 157 */ 158static int isp_subdev_set_power(struct v4l2_subdev *sd, int on) 159{ 160 return 0; 161} 162 163static int isp_subdev_subscribe_event(struct v4l2_subdev *sd, 164 struct v4l2_fh *fh, 165 struct v4l2_event_subscription *sub) 166{ 167 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); 168 struct atomisp_device *isp = isp_sd->isp; 169 170 if (sub->type != V4L2_EVENT_FRAME_SYNC && 171 sub->type != V4L2_EVENT_FRAME_END && 172 sub->type != V4L2_EVENT_ATOMISP_3A_STATS_READY && 173 sub->type != V4L2_EVENT_ATOMISP_METADATA_READY && 174 sub->type != V4L2_EVENT_ATOMISP_PAUSE_BUFFER && 175 sub->type != V4L2_EVENT_ATOMISP_CSS_RESET && 176 sub->type != V4L2_EVENT_ATOMISP_ACC_COMPLETE) 177 return -EINVAL; 178 179 if (sub->type == V4L2_EVENT_FRAME_SYNC && 180 !atomisp_css_valid_sof(isp)) 181 return -EINVAL; 182 183 return v4l2_event_subscribe(fh, sub, 16, NULL); 184} 185 186static int isp_subdev_unsubscribe_event(struct v4l2_subdev *sd, 187 struct v4l2_fh *fh, 188 struct v4l2_event_subscription *sub) 189{ 190 return v4l2_event_unsubscribe(fh, sub); 191} 192 193/* 194 * isp_subdev_enum_mbus_code - Handle pixel format enumeration 195 * @sd: pointer to v4l2 subdev structure 196 * @fh : V4L2 subdev file handle 197 * @code: pointer to v4l2_subdev_pad_mbus_code_enum structure 198 * return -EINVAL or zero on success 199 */ 200static int isp_subdev_enum_mbus_code(struct v4l2_subdev *sd, 201 struct v4l2_subdev_state *sd_state, 202 struct v4l2_subdev_mbus_code_enum *code) 203{ 204 if (code->index >= ARRAY_SIZE(atomisp_in_fmt_conv) - 1) 205 return -EINVAL; 206 207 code->code = atomisp_in_fmt_conv[code->index].code; 208 209 return 0; 210} 211 212static int isp_subdev_validate_rect(struct v4l2_subdev *sd, uint32_t pad, 213 uint32_t target) 214{ 215 switch (pad) { 216 case ATOMISP_SUBDEV_PAD_SINK: 217 switch (target) { 218 case V4L2_SEL_TGT_CROP: 219 return 0; 220 } 221 break; 222 default: 223 switch (target) { 224 case V4L2_SEL_TGT_COMPOSE: 225 return 0; 226 } 227 break; 228 } 229 230 return -EINVAL; 231} 232 233struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd, 234 struct v4l2_subdev_state *sd_state, 235 u32 which, uint32_t pad, 236 uint32_t target) 237{ 238 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); 239 240 if (which == V4L2_SUBDEV_FORMAT_TRY) { 241 switch (target) { 242 case V4L2_SEL_TGT_CROP: 243 return v4l2_subdev_state_get_crop(sd_state, pad); 244 case V4L2_SEL_TGT_COMPOSE: 245 return v4l2_subdev_state_get_compose(sd_state, pad); 246 } 247 } 248 249 switch (target) { 250 case V4L2_SEL_TGT_CROP: 251 return &isp_sd->fmt[pad].crop; 252 case V4L2_SEL_TGT_COMPOSE: 253 return &isp_sd->fmt[pad].compose; 254 } 255 256 return NULL; 257} 258 259struct v4l2_mbus_framefmt 260*atomisp_subdev_get_ffmt(struct v4l2_subdev *sd, 261 struct v4l2_subdev_state *sd_state, uint32_t which, 262 uint32_t pad) 263{ 264 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); 265 266 if (which == V4L2_SUBDEV_FORMAT_TRY) 267 return v4l2_subdev_state_get_format(sd_state, pad); 268 269 return &isp_sd->fmt[pad].fmt; 270} 271 272static void isp_get_fmt_rect(struct v4l2_subdev *sd, 273 struct v4l2_subdev_state *sd_state, 274 uint32_t which, 275 struct v4l2_mbus_framefmt **ffmt, 276 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM], 277 struct v4l2_rect *comp[ATOMISP_SUBDEV_PADS_NUM]) 278{ 279 unsigned int i; 280 281 for (i = 0; i < ATOMISP_SUBDEV_PADS_NUM; i++) { 282 ffmt[i] = atomisp_subdev_get_ffmt(sd, sd_state, which, i); 283 crop[i] = atomisp_subdev_get_rect(sd, sd_state, which, i, 284 V4L2_SEL_TGT_CROP); 285 comp[i] = atomisp_subdev_get_rect(sd, sd_state, which, i, 286 V4L2_SEL_TGT_COMPOSE); 287 } 288} 289 290static void isp_subdev_propagate(struct v4l2_subdev *sd, 291 struct v4l2_subdev_state *sd_state, 292 u32 which, uint32_t pad, uint32_t target, 293 uint32_t flags) 294{ 295 struct v4l2_mbus_framefmt *ffmt[ATOMISP_SUBDEV_PADS_NUM]; 296 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM], 297 *comp[ATOMISP_SUBDEV_PADS_NUM]; 298 299 if (flags & V4L2_SEL_FLAG_KEEP_CONFIG) 300 return; 301 302 isp_get_fmt_rect(sd, sd_state, which, ffmt, crop, comp); 303 304 switch (pad) { 305 case ATOMISP_SUBDEV_PAD_SINK: { 306 struct v4l2_rect r = {0}; 307 308 /* Only crop target supported on sink pad. */ 309 r.width = ffmt[pad]->width; 310 r.height = ffmt[pad]->height; 311 312 atomisp_subdev_set_selection(sd, sd_state, which, pad, 313 target, flags, &r); 314 break; 315 } 316 } 317} 318 319static int isp_subdev_get_selection(struct v4l2_subdev *sd, 320 struct v4l2_subdev_state *sd_state, 321 struct v4l2_subdev_selection *sel) 322{ 323 struct v4l2_rect *rec; 324 int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target); 325 326 if (rval) 327 return rval; 328 329 rec = atomisp_subdev_get_rect(sd, sd_state, sel->which, sel->pad, 330 sel->target); 331 if (!rec) 332 return -EINVAL; 333 334 sel->r = *rec; 335 return 0; 336} 337 338static const char *atomisp_pad_str(unsigned int pad) 339{ 340 static const char *const pad_str[] = { 341 "ATOMISP_SUBDEV_PAD_SINK", 342 "ATOMISP_SUBDEV_PAD_SOURCE", 343 }; 344 345 if (pad >= ARRAY_SIZE(pad_str)) 346 return "ATOMISP_INVALID_PAD"; 347 return pad_str[pad]; 348} 349 350int atomisp_subdev_set_selection(struct v4l2_subdev *sd, 351 struct v4l2_subdev_state *sd_state, 352 u32 which, uint32_t pad, uint32_t target, 353 u32 flags, struct v4l2_rect *r) 354{ 355 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); 356 struct atomisp_device *isp = isp_sd->isp; 357 struct v4l2_mbus_framefmt *ffmt[ATOMISP_SUBDEV_PADS_NUM]; 358 struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM], 359 *comp[ATOMISP_SUBDEV_PADS_NUM]; 360 361 if ((pad == ATOMISP_SUBDEV_PAD_SINK && target != V4L2_SEL_TGT_CROP) || 362 (pad == ATOMISP_SUBDEV_PAD_SOURCE && target != V4L2_SEL_TGT_COMPOSE)) 363 return -EINVAL; 364 365 isp_get_fmt_rect(sd, sd_state, which, ffmt, crop, comp); 366 367 dev_dbg(isp->dev, 368 "sel: pad %s tgt %s l %d t %d w %d h %d which %s f 0x%8.8x\n", 369 atomisp_pad_str(pad), target == V4L2_SEL_TGT_CROP 370 ? "V4L2_SEL_TGT_CROP" : "V4L2_SEL_TGT_COMPOSE", 371 r->left, r->top, r->width, r->height, 372 which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY" 373 : "V4L2_SUBDEV_FORMAT_ACTIVE", flags); 374 375 r->width = rounddown(r->width, ATOM_ISP_STEP_WIDTH); 376 r->height = rounddown(r->height, ATOM_ISP_STEP_HEIGHT); 377 378 if (pad == ATOMISP_SUBDEV_PAD_SINK) { 379 /* Only crop target supported on sink pad. */ 380 unsigned int dvs_w, dvs_h; 381 382 crop[pad]->width = ffmt[pad]->width; 383 crop[pad]->height = ffmt[pad]->height; 384 385 if (atomisp_subdev_format_conversion(isp_sd) 386 && crop[pad]->width && crop[pad]->height) { 387 crop[pad]->width -= isp_sd->sink_pad_padding_w; 388 crop[pad]->height -= isp_sd->sink_pad_padding_h; 389 } 390 391 if (isp_sd->params.video_dis_en && 392 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { 393 /* This resolution contains 20 % of DVS slack 394 * (of the desired captured image before 395 * scaling, or 1 / 6 of what we get from the 396 * sensor) in both width and height. Remove 397 * it. */ 398 crop[pad]->width = roundup(crop[pad]->width * 5 / 6, 399 ATOM_ISP_STEP_WIDTH); 400 crop[pad]->height = roundup(crop[pad]->height * 5 / 6, 401 ATOM_ISP_STEP_HEIGHT); 402 } 403 404 crop[pad]->width = min(crop[pad]->width, r->width); 405 crop[pad]->height = min(crop[pad]->height, r->height); 406 407 if (!(flags & V4L2_SEL_FLAG_KEEP_CONFIG)) { 408 struct v4l2_rect tmp = *crop[pad]; 409 410 atomisp_subdev_set_selection(sd, sd_state, which, 411 ATOMISP_SUBDEV_PAD_SOURCE, 412 V4L2_SEL_TGT_COMPOSE, flags, &tmp); 413 } 414 415 if (which == V4L2_SUBDEV_FORMAT_TRY) 416 goto get_rect; 417 418 if (isp_sd->params.video_dis_en && 419 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { 420 dvs_w = rounddown(crop[pad]->width / 5, 421 ATOM_ISP_STEP_WIDTH); 422 dvs_h = rounddown(crop[pad]->height / 5, 423 ATOM_ISP_STEP_HEIGHT); 424 } else if (!isp_sd->params.video_dis_en && 425 isp_sd->run_mode->val == ATOMISP_RUN_MODE_VIDEO) { 426 /* 427 * For CSS2.0, digital zoom needs to set dvs envelope to 12 428 * when dvs is disabled. 429 */ 430 dvs_w = dvs_h = 12; 431 } else { 432 dvs_w = dvs_h = 0; 433 } 434 atomisp_css_video_set_dis_envelope(isp_sd, dvs_w, dvs_h); 435 atomisp_css_input_set_effective_resolution(isp_sd, 436 ATOMISP_INPUT_STREAM_GENERAL, 437 crop[pad]->width, 438 crop[pad]->height); 439 } else if (isp_sd->run_mode->val != ATOMISP_RUN_MODE_PREVIEW) { 440 /* Only compose target is supported on source pads. */ 441 if (isp_sd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) { 442 /* Scaling is disabled in this mode */ 443 r->width = crop[ATOMISP_SUBDEV_PAD_SINK]->width; 444 r->height = crop[ATOMISP_SUBDEV_PAD_SINK]->height; 445 } 446 447 if (crop[ATOMISP_SUBDEV_PAD_SINK]->width == r->width 448 && crop[ATOMISP_SUBDEV_PAD_SINK]->height == r->height) 449 isp_sd->params.yuv_ds_en = false; 450 else 451 isp_sd->params.yuv_ds_en = true; 452 453 comp[pad]->width = r->width; 454 comp[pad]->height = r->height; 455 456 if (r->width == 0 || r->height == 0 || 457 crop[ATOMISP_SUBDEV_PAD_SINK]->width == 0 || 458 crop[ATOMISP_SUBDEV_PAD_SINK]->height == 0) 459 goto get_rect; 460 /* 461 * do cropping on sensor input if ratio of required resolution 462 * is different with sensor output resolution ratio: 463 * 464 * ratio = width / height 465 * 466 * if ratio_output < ratio_sensor: 467 * effect_width = sensor_height * out_width / out_height; 468 * effect_height = sensor_height; 469 * else 470 * effect_width = sensor_width; 471 * effect_height = sensor_width * out_height / out_width; 472 * 473 */ 474 if (r->width * crop[ATOMISP_SUBDEV_PAD_SINK]->height < 475 crop[ATOMISP_SUBDEV_PAD_SINK]->width * r->height) 476 atomisp_css_input_set_effective_resolution(isp_sd, 477 ATOMISP_INPUT_STREAM_GENERAL, 478 rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]-> 479 height * r->width / r->height, 480 ATOM_ISP_STEP_WIDTH), 481 crop[ATOMISP_SUBDEV_PAD_SINK]->height); 482 else 483 atomisp_css_input_set_effective_resolution(isp_sd, 484 ATOMISP_INPUT_STREAM_GENERAL, 485 crop[ATOMISP_SUBDEV_PAD_SINK]->width, 486 rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]-> 487 width * r->height / r->width, 488 ATOM_ISP_STEP_WIDTH)); 489 } else { 490 comp[pad]->width = r->width; 491 comp[pad]->height = r->height; 492 } 493 494get_rect: 495 /* Set format dimensions on non-sink pads as well. */ 496 if (pad != ATOMISP_SUBDEV_PAD_SINK) { 497 ffmt[pad]->width = comp[pad]->width; 498 ffmt[pad]->height = comp[pad]->height; 499 } 500 501 if (!atomisp_subdev_get_rect(sd, sd_state, which, pad, target)) 502 return -EINVAL; 503 *r = *atomisp_subdev_get_rect(sd, sd_state, which, pad, target); 504 505 dev_dbg(isp->dev, "sel actual: l %d t %d w %d h %d\n", 506 r->left, r->top, r->width, r->height); 507 508 return 0; 509} 510 511static int isp_subdev_set_selection(struct v4l2_subdev *sd, 512 struct v4l2_subdev_state *sd_state, 513 struct v4l2_subdev_selection *sel) 514{ 515 int rval = isp_subdev_validate_rect(sd, sel->pad, sel->target); 516 517 if (rval) 518 return rval; 519 520 return atomisp_subdev_set_selection(sd, sd_state, sel->which, 521 sel->pad, 522 sel->target, sel->flags, &sel->r); 523} 524 525void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd, 526 struct v4l2_subdev_state *sd_state, 527 uint32_t which, 528 u32 pad, struct v4l2_mbus_framefmt *ffmt) 529{ 530 struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); 531 struct atomisp_device *isp = isp_sd->isp; 532 struct v4l2_mbus_framefmt *__ffmt = 533 atomisp_subdev_get_ffmt(sd, sd_state, which, pad); 534 535 dev_dbg(isp->dev, "ffmt: pad %s w %d h %d code 0x%8.8x which %s\n", 536 atomisp_pad_str(pad), ffmt->width, ffmt->height, ffmt->code, 537 which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY" 538 : "V4L2_SUBDEV_FORMAT_ACTIVE"); 539 540 switch (pad) { 541 case ATOMISP_SUBDEV_PAD_SINK: { 542 const struct atomisp_in_fmt_conv *fc = 543 atomisp_find_in_fmt_conv(ffmt->code); 544 545 if (!fc) { 546 fc = atomisp_in_fmt_conv; 547 ffmt->code = fc->code; 548 dev_dbg(isp->dev, "using 0x%8.8x instead\n", 549 ffmt->code); 550 } 551 552 *__ffmt = *ffmt; 553 554 isp_subdev_propagate(sd, sd_state, which, pad, 555 V4L2_SEL_TGT_CROP, 0); 556 557 if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { 558 atomisp_css_input_set_resolution(isp_sd, 559 ATOMISP_INPUT_STREAM_GENERAL, ffmt); 560 atomisp_css_input_set_binning_factor(isp_sd, 561 ATOMISP_INPUT_STREAM_GENERAL, 562 0); 563 atomisp_css_input_set_bayer_order(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, 564 fc->bayer_order); 565 atomisp_css_input_set_format(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, 566 fc->atomisp_in_fmt); 567 atomisp_css_set_default_isys_config(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, 568 ffmt); 569 } 570 571 break; 572 } 573 case ATOMISP_SUBDEV_PAD_SOURCE: 574 __ffmt->code = ffmt->code; 575 break; 576 } 577} 578 579/* 580 * isp_subdev_get_format - Retrieve the video format on a pad 581 * @sd : ISP V4L2 subdevice 582 * @fh : V4L2 subdev file handle 583 * @pad: Pad number 584 * @fmt: Format 585 * 586 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond 587 * to the format type. 588 */ 589static int isp_subdev_get_format(struct v4l2_subdev *sd, 590 struct v4l2_subdev_state *sd_state, 591 struct v4l2_subdev_format *fmt) 592{ 593 fmt->format = *atomisp_subdev_get_ffmt(sd, sd_state, fmt->which, 594 fmt->pad); 595 596 return 0; 597} 598 599/* 600 * isp_subdev_set_format - Set the video format on a pad 601 * @sd : ISP subdev V4L2 subdevice 602 * @fh : V4L2 subdev file handle 603 * @pad: Pad number 604 * @fmt: Format 605 * 606 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond 607 * to the format type. 608 */ 609static int isp_subdev_set_format(struct v4l2_subdev *sd, 610 struct v4l2_subdev_state *sd_state, 611 struct v4l2_subdev_format *fmt) 612{ 613 atomisp_subdev_set_ffmt(sd, sd_state, fmt->which, fmt->pad, 614 &fmt->format); 615 616 return 0; 617} 618 619/* V4L2 subdev core operations */ 620static const struct v4l2_subdev_core_ops isp_subdev_v4l2_core_ops = { 621 .ioctl = isp_subdev_ioctl, .s_power = isp_subdev_set_power, 622 .subscribe_event = isp_subdev_subscribe_event, 623 .unsubscribe_event = isp_subdev_unsubscribe_event, 624}; 625 626/* V4L2 subdev pad operations */ 627static const struct v4l2_subdev_pad_ops isp_subdev_v4l2_pad_ops = { 628 .enum_mbus_code = isp_subdev_enum_mbus_code, 629 .get_fmt = isp_subdev_get_format, 630 .set_fmt = isp_subdev_set_format, 631 .get_selection = isp_subdev_get_selection, 632 .set_selection = isp_subdev_set_selection, 633 .link_validate = v4l2_subdev_link_validate_default, 634}; 635 636/* V4L2 subdev operations */ 637static const struct v4l2_subdev_ops isp_subdev_v4l2_ops = { 638 .core = &isp_subdev_v4l2_core_ops, 639 .pad = &isp_subdev_v4l2_pad_ops, 640}; 641 642static void isp_subdev_init_params(struct atomisp_sub_device *asd) 643{ 644 unsigned int i; 645 646 /* parameters initialization */ 647 INIT_LIST_HEAD(&asd->s3a_stats); 648 INIT_LIST_HEAD(&asd->s3a_stats_in_css); 649 INIT_LIST_HEAD(&asd->s3a_stats_ready); 650 INIT_LIST_HEAD(&asd->dis_stats); 651 INIT_LIST_HEAD(&asd->dis_stats_in_css); 652 spin_lock_init(&asd->dis_stats_lock); 653 for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) { 654 INIT_LIST_HEAD(&asd->metadata[i]); 655 INIT_LIST_HEAD(&asd->metadata_in_css[i]); 656 INIT_LIST_HEAD(&asd->metadata_ready[i]); 657 } 658} 659 660/* media operations */ 661static const struct media_entity_operations isp_subdev_media_ops = { 662 .link_validate = v4l2_subdev_link_validate, 663 /* .set_power = v4l2_subdev_set_power, */ 664}; 665 666static const char *const ctrl_run_mode_menu[] = { 667 [ATOMISP_RUN_MODE_VIDEO] = "Video", 668 [ATOMISP_RUN_MODE_STILL_CAPTURE] = "Still capture", 669 [ATOMISP_RUN_MODE_PREVIEW] = "Preview", 670}; 671 672static const struct v4l2_ctrl_config ctrl_run_mode = { 673 .id = V4L2_CID_RUN_MODE, 674 .name = "Atomisp run mode", 675 .type = V4L2_CTRL_TYPE_MENU, 676 .min = ATOMISP_RUN_MODE_MIN, 677 .def = ATOMISP_RUN_MODE_PREVIEW, 678 .max = ATOMISP_RUN_MODE_MAX, 679 .qmenu = ctrl_run_mode_menu, 680}; 681 682static const char *const ctrl_vfpp_mode_menu[] = { 683 "Enable", /* vfpp always enabled */ 684 "Disable to scaler mode", /* CSS into video mode and disable */ 685 "Disable to low latency mode", /* CSS into still mode and disable */ 686}; 687 688static const struct v4l2_ctrl_config ctrl_vfpp = { 689 .id = V4L2_CID_VFPP, 690 .name = "Atomisp vf postprocess", 691 .type = V4L2_CTRL_TYPE_MENU, 692 .min = 0, 693 .def = 0, 694 .max = 2, 695 .qmenu = ctrl_vfpp_mode_menu, 696}; 697 698/* 699 * Control for continuous mode raw buffer size 700 * 701 * The size of the RAW ringbuffer sets limit on how much 702 * back in time application can go when requesting capture 703 * frames to be rendered, and how many frames can be rendered 704 * in a burst at full sensor rate. 705 * 706 * Note: this setting has a big impact on memory consumption of 707 * the CSS subsystem. 708 */ 709static const struct v4l2_ctrl_config ctrl_continuous_raw_buffer_size = { 710 .id = V4L2_CID_ATOMISP_CONTINUOUS_RAW_BUFFER_SIZE, 711 .type = V4L2_CTRL_TYPE_INTEGER, 712 .name = "Continuous raw ringbuffer size", 713 .min = 1, 714 .max = 100, /* depends on CSS version, runtime checked */ 715 .step = 1, 716 .def = 3, 717}; 718 719/* 720 * Control for enabling continuous viewfinder 721 * 722 * When enabled, and ISP is in continuous mode (see ctrl_continuous_mode ), 723 * preview pipeline continues concurrently with capture 724 * processing. When disabled, and continuous mode is used, 725 * preview is paused while captures are processed, but 726 * full pipeline restart is not needed. 727 * 728 * By setting this to disabled, capture processing is 729 * essentially given priority over preview, and the effective 730 * capture output rate may be higher than with continuous 731 * viewfinder enabled. 732 */ 733static const struct v4l2_ctrl_config ctrl_continuous_viewfinder = { 734 .id = V4L2_CID_ATOMISP_CONTINUOUS_VIEWFINDER, 735 .type = V4L2_CTRL_TYPE_BOOLEAN, 736 .name = "Continuous viewfinder", 737 .min = 0, 738 .max = 1, 739 .step = 1, 740 .def = 0, 741}; 742 743/* 744 * Control for enabling Lock&Unlock Raw Buffer mechanism 745 * 746 * When enabled, Raw Buffer can be locked and unlocked. 747 * Application can hold the exp_id of Raw Buffer 748 * and unlock it when no longer needed. 749 * Note: Make sure set this configuration before creating stream. 750 */ 751static const struct v4l2_ctrl_config ctrl_enable_raw_buffer_lock = { 752 .id = V4L2_CID_ENABLE_RAW_BUFFER_LOCK, 753 .type = V4L2_CTRL_TYPE_BOOLEAN, 754 .name = "Lock Unlock Raw Buffer", 755 .min = 0, 756 .max = 1, 757 .step = 1, 758 .def = 0, 759}; 760 761/* 762 * Control to disable digital zoom of the whole stream 763 * 764 * When it is true, pipe configuration enable_dz will be set to false. 765 * This can help get a better performance by disabling pp binary. 766 * 767 * Note: Make sure set this configuration before creating stream. 768 */ 769static const struct v4l2_ctrl_config ctrl_disable_dz = { 770 .id = V4L2_CID_DISABLE_DZ, 771 .type = V4L2_CTRL_TYPE_BOOLEAN, 772 .name = "Disable digital zoom", 773 .min = 0, 774 .max = 1, 775 .step = 1, 776 .def = 0, 777}; 778 779static int atomisp_init_subdev_pipe(struct atomisp_sub_device *asd, 780 struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type) 781{ 782 int ret; 783 784 pipe->type = buf_type; 785 pipe->asd = asd; 786 pipe->isp = asd->isp; 787 spin_lock_init(&pipe->irq_lock); 788 mutex_init(&pipe->vb_queue_mutex); 789 790 /* Init videobuf2 queue structure */ 791 pipe->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 792 pipe->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR; 793 pipe->vb_queue.buf_struct_size = sizeof(struct ia_css_frame); 794 pipe->vb_queue.ops = &atomisp_vb2_ops; 795 pipe->vb_queue.mem_ops = &vb2_vmalloc_memops; 796 pipe->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 797 ret = vb2_queue_init(&pipe->vb_queue); 798 if (ret) 799 return ret; 800 801 pipe->vdev.queue = &pipe->vb_queue; 802 pipe->vdev.queue->lock = &pipe->vb_queue_mutex; 803 804 INIT_LIST_HEAD(&pipe->buffers_in_css); 805 INIT_LIST_HEAD(&pipe->activeq); 806 INIT_LIST_HEAD(&pipe->buffers_waiting_for_param); 807 INIT_LIST_HEAD(&pipe->per_frame_params); 808 809 return 0; 810} 811 812/* 813 * isp_subdev_init_entities - Initialize V4L2 subdev and media entity 814 * @asd: ISP CCDC module 815 * 816 * Return 0 on success and a negative error code on failure. 817 */ 818static int isp_subdev_init_entities(struct atomisp_sub_device *asd) 819{ 820 struct v4l2_subdev *sd = &asd->subdev; 821 struct media_pad *pads = asd->pads; 822 struct media_entity *me = &sd->entity; 823 int ret; 824 825 v4l2_subdev_init(sd, &isp_subdev_v4l2_ops); 826 sprintf(sd->name, "ATOMISP_SUBDEV"); 827 v4l2_set_subdevdata(sd, asd); 828 sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; 829 sd->devnode = &asd->video_out.vdev; 830 831 pads[ATOMISP_SUBDEV_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 832 pads[ATOMISP_SUBDEV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; 833 834 asd->fmt[ATOMISP_SUBDEV_PAD_SINK].fmt.code = MEDIA_BUS_FMT_SBGGR10_1X10; 835 asd->fmt[ATOMISP_SUBDEV_PAD_SOURCE].fmt.code = MEDIA_BUS_FMT_SBGGR10_1X10; 836 837 me->ops = &isp_subdev_media_ops; 838 me->function = MEDIA_ENT_F_PROC_VIDEO_ISP; 839 ret = media_entity_pads_init(me, ATOMISP_SUBDEV_PADS_NUM, pads); 840 if (ret < 0) 841 return ret; 842 843 ret = atomisp_init_subdev_pipe(asd, &asd->video_out, V4L2_BUF_TYPE_VIDEO_CAPTURE); 844 if (ret) 845 return ret; 846 847 ret = atomisp_video_init(&asd->video_out); 848 if (ret < 0) 849 return ret; 850 851 ret = v4l2_ctrl_handler_init(&asd->ctrl_handler, 1); 852 if (ret) 853 return ret; 854 855 asd->run_mode = v4l2_ctrl_new_custom(&asd->ctrl_handler, 856 &ctrl_run_mode, NULL); 857 asd->vfpp = v4l2_ctrl_new_custom(&asd->ctrl_handler, 858 &ctrl_vfpp, NULL); 859 asd->continuous_viewfinder = v4l2_ctrl_new_custom(&asd->ctrl_handler, 860 &ctrl_continuous_viewfinder, 861 NULL); 862 asd->continuous_raw_buffer_size = 863 v4l2_ctrl_new_custom(&asd->ctrl_handler, 864 &ctrl_continuous_raw_buffer_size, 865 NULL); 866 867 asd->enable_raw_buffer_lock = 868 v4l2_ctrl_new_custom(&asd->ctrl_handler, 869 &ctrl_enable_raw_buffer_lock, 870 NULL); 871 asd->disable_dz = 872 v4l2_ctrl_new_custom(&asd->ctrl_handler, 873 &ctrl_disable_dz, 874 NULL); 875 876 /* Make controls visible on subdev as well. */ 877 asd->subdev.ctrl_handler = &asd->ctrl_handler; 878 spin_lock_init(&asd->raw_buffer_bitmap_lock); 879 return asd->ctrl_handler.error; 880} 881 882static void atomisp_subdev_cleanup_entities(struct atomisp_sub_device *asd) 883{ 884 v4l2_ctrl_handler_free(&asd->ctrl_handler); 885 886 media_entity_cleanup(&asd->subdev.entity); 887} 888 889void atomisp_subdev_cleanup_pending_events(struct atomisp_sub_device *asd) 890{ 891 struct v4l2_fh *fh, *fh_tmp; 892 struct v4l2_event event; 893 unsigned int i, pending_event; 894 895 list_for_each_entry_safe(fh, fh_tmp, 896 &asd->subdev.devnode->fh_list, list) { 897 pending_event = v4l2_event_pending(fh); 898 for (i = 0; i < pending_event; i++) 899 v4l2_event_dequeue(fh, &event, 1); 900 } 901} 902 903void atomisp_subdev_unregister_entities(struct atomisp_sub_device *asd) 904{ 905 atomisp_subdev_cleanup_entities(asd); 906 v4l2_device_unregister_subdev(&asd->subdev); 907 atomisp_video_unregister(&asd->video_out); 908} 909 910int atomisp_subdev_register_subdev(struct atomisp_sub_device *asd, 911 struct v4l2_device *vdev) 912{ 913 return v4l2_device_register_subdev(vdev, &asd->subdev); 914} 915 916/* 917 * atomisp_subdev_init - ISP Subdevice initialization. 918 * @dev: Device pointer specific to the ATOM ISP. 919 * 920 * TODO: Get the initialisation values from platform data. 921 * 922 * Return 0 on success or a negative error code otherwise. 923 */ 924int atomisp_subdev_init(struct atomisp_device *isp) 925{ 926 int ret; 927 928 isp->asd.isp = isp; 929 isp_subdev_init_params(&isp->asd); 930 ret = isp_subdev_init_entities(&isp->asd); 931 if (ret < 0) 932 atomisp_subdev_cleanup_entities(&isp->asd); 933 934 return ret; 935} 936