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