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