FILE
c3-isp-core.c
File preview with syntax highlighting.
linux-6.19.14/drivers/media/platform/amlogic/c3/isp/c3-isp-core.c
1// SPDX-License-Identifier: (GPL-2.0-only OR MIT) 2/* 3 * Copyright (C) 2024 Amlogic, Inc. All rights reserved 4 */ 5 6#include <linux/media/amlogic/c3-isp-config.h> 7#include <linux/pm_runtime.h> 8 9#include <media/v4l2-event.h> 10 11#include "c3-isp-common.h" 12#include "c3-isp-regs.h" 13 14#define C3_ISP_CORE_SUBDEV_NAME "c3-isp-core" 15 16#define C3_ISP_PHASE_OFFSET_0 0 17#define C3_ISP_PHASE_OFFSET_1 1 18#define C3_ISP_PHASE_OFFSET_NONE 0xff 19 20#define C3_ISP_CORE_DEF_SINK_PAD_FMT MEDIA_BUS_FMT_SRGGB10_1X10 21#define C3_ISP_CORE_DEF_SRC_PAD_FMT MEDIA_BUS_FMT_YUV10_1X30 22 23/* 24 * struct c3_isp_core_format_info - ISP core format information 25 * 26 * @mbus_code: the mbus code 27 * @pads: bitmask detailing valid pads for this mbus_code 28 * @xofst: horizontal phase offset of hardware 29 * @yofst: vertical phase offset of hardware 30 * @is_raw: the raw format flag of mbus code 31 */ 32struct c3_isp_core_format_info { 33 u32 mbus_code; 34 u32 pads; 35 u8 xofst; 36 u8 yofst; 37 bool is_raw; 38}; 39 40static const struct c3_isp_core_format_info c3_isp_core_fmts[] = { 41 /* RAW formats */ 42 { 43 .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, 44 .pads = BIT(C3_ISP_CORE_PAD_SINK_VIDEO), 45 .xofst = C3_ISP_PHASE_OFFSET_0, 46 .yofst = C3_ISP_PHASE_OFFSET_1, 47 .is_raw = true, 48 }, { 49 .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, 50 .pads = BIT(C3_ISP_CORE_PAD_SINK_VIDEO), 51 .xofst = C3_ISP_PHASE_OFFSET_1, 52 .yofst = C3_ISP_PHASE_OFFSET_1, 53 .is_raw = true, 54 }, { 55 .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, 56 .pads = BIT(C3_ISP_CORE_PAD_SINK_VIDEO), 57 .xofst = C3_ISP_PHASE_OFFSET_0, 58 .yofst = C3_ISP_PHASE_OFFSET_0, 59 .is_raw = true, 60 }, { 61 .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, 62 .pads = BIT(C3_ISP_CORE_PAD_SINK_VIDEO), 63 .xofst = C3_ISP_PHASE_OFFSET_1, 64 .yofst = C3_ISP_PHASE_OFFSET_0, 65 .is_raw = true, 66 }, { 67 .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, 68 .pads = BIT(C3_ISP_CORE_PAD_SINK_VIDEO), 69 .xofst = C3_ISP_PHASE_OFFSET_0, 70 .yofst = C3_ISP_PHASE_OFFSET_1, 71 .is_raw = true, 72 }, { 73 .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, 74 .pads = BIT(C3_ISP_CORE_PAD_SINK_VIDEO), 75 .xofst = C3_ISP_PHASE_OFFSET_1, 76 .yofst = C3_ISP_PHASE_OFFSET_1, 77 .is_raw = true, 78 }, { 79 .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, 80 .pads = BIT(C3_ISP_CORE_PAD_SINK_VIDEO), 81 .xofst = C3_ISP_PHASE_OFFSET_0, 82 .yofst = C3_ISP_PHASE_OFFSET_0, 83 .is_raw = true, 84 }, { 85 .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, 86 .pads = BIT(C3_ISP_CORE_PAD_SINK_VIDEO), 87 .xofst = C3_ISP_PHASE_OFFSET_1, 88 .yofst = C3_ISP_PHASE_OFFSET_0, 89 .is_raw = true, 90 }, { 91 .mbus_code = MEDIA_BUS_FMT_SRGGB16_1X16, 92 .pads = BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_0) 93 | BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_1) 94 | BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_2), 95 .xofst = C3_ISP_PHASE_OFFSET_NONE, 96 .yofst = C3_ISP_PHASE_OFFSET_NONE, 97 .is_raw = true, 98 }, { 99 .mbus_code = MEDIA_BUS_FMT_SBGGR16_1X16, 100 .pads = BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_0) 101 | BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_1) 102 | BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_2), 103 .xofst = C3_ISP_PHASE_OFFSET_NONE, 104 .yofst = C3_ISP_PHASE_OFFSET_NONE, 105 .is_raw = true, 106 }, { 107 .mbus_code = MEDIA_BUS_FMT_SGRBG16_1X16, 108 .pads = BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_0) 109 | BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_1) 110 | BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_2), 111 .xofst = C3_ISP_PHASE_OFFSET_NONE, 112 .yofst = C3_ISP_PHASE_OFFSET_NONE, 113 .is_raw = true, 114 }, { 115 .mbus_code = MEDIA_BUS_FMT_SGBRG16_1X16, 116 .pads = BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_0) 117 | BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_1) 118 | BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_2), 119 .xofst = C3_ISP_PHASE_OFFSET_NONE, 120 .yofst = C3_ISP_PHASE_OFFSET_NONE, 121 .is_raw = true, 122 }, 123 /* YUV formats */ 124 { 125 .mbus_code = MEDIA_BUS_FMT_YUV10_1X30, 126 .pads = BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_0) | 127 BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_1) | 128 BIT(C3_ISP_CORE_PAD_SOURCE_VIDEO_2), 129 .xofst = C3_ISP_PHASE_OFFSET_NONE, 130 .yofst = C3_ISP_PHASE_OFFSET_NONE, 131 .is_raw = false, 132 }, 133}; 134 135static const struct c3_isp_core_format_info 136*core_find_format_by_code(u32 code, u32 pad) 137{ 138 for (unsigned int i = 0; i < ARRAY_SIZE(c3_isp_core_fmts); i++) { 139 const struct c3_isp_core_format_info *info = 140 &c3_isp_core_fmts[i]; 141 142 if (info->mbus_code == code && info->pads & BIT(pad)) 143 return info; 144 } 145 146 return NULL; 147} 148 149static const struct c3_isp_core_format_info 150*core_find_format_by_index(u32 index, u32 pad) 151{ 152 for (unsigned int i = 0; i < ARRAY_SIZE(c3_isp_core_fmts); i++) { 153 const struct c3_isp_core_format_info *info = 154 &c3_isp_core_fmts[i]; 155 156 if (!(info->pads & BIT(pad))) 157 continue; 158 159 if (!index) 160 return info; 161 162 index--; 163 } 164 165 return NULL; 166} 167 168static void c3_isp_core_enable(struct c3_isp_device *isp) 169{ 170 c3_isp_update_bits(isp, ISP_TOP_IRQ_EN, ISP_TOP_IRQ_EN_FRM_END_MASK, 171 ISP_TOP_IRQ_EN_FRM_END_EN); 172 c3_isp_update_bits(isp, ISP_TOP_IRQ_EN, ISP_TOP_IRQ_EN_FRM_RST_MASK, 173 ISP_TOP_IRQ_EN_FRM_RST_EN); 174 175 /* Enable image data to ISP core */ 176 c3_isp_update_bits(isp, ISP_TOP_PATH_SEL, ISP_TOP_PATH_SEL_CORE_MASK, 177 ISP_TOP_PATH_SEL_CORE_MIPI_CORE); 178} 179 180static void c3_isp_core_disable(struct c3_isp_device *isp) 181{ 182 /* Disable image data to ISP core */ 183 c3_isp_update_bits(isp, ISP_TOP_PATH_SEL, ISP_TOP_PATH_SEL_CORE_MASK, 184 ISP_TOP_PATH_SEL_CORE_CORE_DIS); 185 186 c3_isp_update_bits(isp, ISP_TOP_IRQ_EN, ISP_TOP_IRQ_EN_FRM_END_MASK, 187 ISP_TOP_IRQ_EN_FRM_END_DIS); 188 c3_isp_update_bits(isp, ISP_TOP_IRQ_EN, ISP_TOP_IRQ_EN_FRM_RST_MASK, 189 ISP_TOP_IRQ_EN_FRM_RST_DIS); 190} 191 192/* Set the phase offset of blc, wb and lns */ 193static void c3_isp_core_lswb_ofst(struct c3_isp_device *isp, 194 u8 xofst, u8 yofst) 195{ 196 c3_isp_update_bits(isp, ISP_LSWB_BLC_PHSOFST, 197 ISP_LSWB_BLC_PHSOFST_HORIZ_OFST_MASK, 198 ISP_LSWB_BLC_PHSOFST_HORIZ_OFST(xofst)); 199 c3_isp_update_bits(isp, ISP_LSWB_BLC_PHSOFST, 200 ISP_LSWB_BLC_PHSOFST_VERT_OFST_MASK, 201 ISP_LSWB_BLC_PHSOFST_VERT_OFST(yofst)); 202 203 c3_isp_update_bits(isp, ISP_LSWB_WB_PHSOFST, 204 ISP_LSWB_WB_PHSOFST_HORIZ_OFST_MASK, 205 ISP_LSWB_WB_PHSOFST_HORIZ_OFST(xofst)); 206 c3_isp_update_bits(isp, ISP_LSWB_WB_PHSOFST, 207 ISP_LSWB_WB_PHSOFST_VERT_OFST_MASK, 208 ISP_LSWB_WB_PHSOFST_VERT_OFST(yofst)); 209 210 c3_isp_update_bits(isp, ISP_LSWB_LNS_PHSOFST, 211 ISP_LSWB_LNS_PHSOFST_HORIZ_OFST_MASK, 212 ISP_LSWB_LNS_PHSOFST_HORIZ_OFST(xofst)); 213 c3_isp_update_bits(isp, ISP_LSWB_LNS_PHSOFST, 214 ISP_LSWB_LNS_PHSOFST_VERT_OFST_MASK, 215 ISP_LSWB_LNS_PHSOFST_VERT_OFST(yofst)); 216} 217 218/* Set the phase offset of af, ae and awb */ 219static void c3_isp_core_3a_ofst(struct c3_isp_device *isp, 220 u8 xofst, u8 yofst) 221{ 222 c3_isp_update_bits(isp, ISP_AF_CTRL, ISP_AF_CTRL_HORIZ_OFST_MASK, 223 ISP_AF_CTRL_HORIZ_OFST(xofst)); 224 c3_isp_update_bits(isp, ISP_AF_CTRL, ISP_AF_CTRL_VERT_OFST_MASK, 225 ISP_AF_CTRL_VERT_OFST(yofst)); 226 227 c3_isp_update_bits(isp, ISP_AE_CTRL, ISP_AE_CTRL_HORIZ_OFST_MASK, 228 ISP_AE_CTRL_HORIZ_OFST(xofst)); 229 c3_isp_update_bits(isp, ISP_AE_CTRL, ISP_AE_CTRL_VERT_OFST_MASK, 230 ISP_AE_CTRL_VERT_OFST(yofst)); 231 232 c3_isp_update_bits(isp, ISP_AWB_CTRL, ISP_AWB_CTRL_HORIZ_OFST_MASK, 233 ISP_AWB_CTRL_HORIZ_OFST(xofst)); 234 c3_isp_update_bits(isp, ISP_AWB_CTRL, ISP_AWB_CTRL_VERT_OFST_MASK, 235 ISP_AWB_CTRL_VERT_OFST(yofst)); 236} 237 238/* Set the phase offset of demosaic */ 239static void c3_isp_core_dms_ofst(struct c3_isp_device *isp, 240 u8 xofst, u8 yofst) 241{ 242 c3_isp_update_bits(isp, ISP_DMS_COMMON_PARAM0, 243 ISP_DMS_COMMON_PARAM0_HORIZ_PHS_OFST_MASK, 244 ISP_DMS_COMMON_PARAM0_HORIZ_PHS_OFST(xofst)); 245 c3_isp_update_bits(isp, ISP_DMS_COMMON_PARAM0, 246 ISP_DMS_COMMON_PARAM0_VERT_PHS_OFST_MASK, 247 ISP_DMS_COMMON_PARAM0_VERT_PHS_OFST(yofst)); 248} 249 250static void c3_isp_core_cfg_format(struct c3_isp_device *isp, 251 struct v4l2_subdev_state *state) 252{ 253 struct v4l2_mbus_framefmt *fmt; 254 const struct c3_isp_core_format_info *isp_fmt; 255 256 fmt = v4l2_subdev_state_get_format(state, C3_ISP_CORE_PAD_SINK_VIDEO); 257 isp_fmt = core_find_format_by_code(fmt->code, 258 C3_ISP_CORE_PAD_SINK_VIDEO); 259 260 c3_isp_write(isp, ISP_TOP_INPUT_SIZE, 261 ISP_TOP_INPUT_SIZE_HORIZ_SIZE(fmt->width) | 262 ISP_TOP_INPUT_SIZE_VERT_SIZE(fmt->height)); 263 c3_isp_write(isp, ISP_TOP_FRM_SIZE, 264 ISP_TOP_FRM_SIZE_CORE_HORIZ_SIZE(fmt->width) | 265 ISP_TOP_FRM_SIZE_CORE_VERT_SIZE(fmt->height)); 266 267 c3_isp_update_bits(isp, ISP_TOP_HOLD_SIZE, 268 ISP_TOP_HOLD_SIZE_CORE_HORIZ_SIZE_MASK, 269 ISP_TOP_HOLD_SIZE_CORE_HORIZ_SIZE(fmt->width)); 270 271 c3_isp_write(isp, ISP_AF_HV_SIZE, 272 ISP_AF_HV_SIZE_GLB_WIN_XSIZE(fmt->width) | 273 ISP_AF_HV_SIZE_GLB_WIN_YSIZE(fmt->height)); 274 c3_isp_write(isp, ISP_AE_HV_SIZE, 275 ISP_AE_HV_SIZE_HORIZ_SIZE(fmt->width) | 276 ISP_AE_HV_SIZE_VERT_SIZE(fmt->height)); 277 c3_isp_write(isp, ISP_AWB_HV_SIZE, 278 ISP_AWB_HV_SIZE_HORIZ_SIZE(fmt->width) | 279 ISP_AWB_HV_SIZE_VERT_SIZE(fmt->height)); 280 281 c3_isp_core_lswb_ofst(isp, isp_fmt->xofst, isp_fmt->yofst); 282 c3_isp_core_3a_ofst(isp, isp_fmt->xofst, isp_fmt->yofst); 283 c3_isp_core_dms_ofst(isp, isp_fmt->xofst, isp_fmt->yofst); 284} 285 286static bool c3_isp_core_streams_ready(struct c3_isp_core *core) 287{ 288 unsigned int n_links = 0; 289 struct media_link *link; 290 291 for_each_media_entity_data_link(&core->sd.entity, link) { 292 if ((link->source->index == C3_ISP_CORE_PAD_SOURCE_VIDEO_0 || 293 link->source->index == C3_ISP_CORE_PAD_SOURCE_VIDEO_1 || 294 link->source->index == C3_ISP_CORE_PAD_SOURCE_VIDEO_2) && 295 link->flags == MEDIA_LNK_FL_ENABLED) 296 n_links++; 297 } 298 299 return n_links == core->isp->pipe.start_count; 300} 301 302static int c3_isp_core_enable_streams(struct v4l2_subdev *sd, 303 struct v4l2_subdev_state *state, 304 u32 pad, u64 streams_mask) 305{ 306 struct c3_isp_core *core = v4l2_get_subdevdata(sd); 307 struct media_pad *sink_pad; 308 struct v4l2_subdev *src_sd; 309 int ret; 310 311 if (!c3_isp_core_streams_ready(core)) 312 return 0; 313 314 core->isp->frm_sequence = 0; 315 c3_isp_core_cfg_format(core->isp, state); 316 c3_isp_core_enable(core->isp); 317 318 sink_pad = &core->pads[C3_ISP_CORE_PAD_SINK_VIDEO]; 319 core->src_pad = media_pad_remote_pad_unique(sink_pad); 320 if (IS_ERR(core->src_pad)) { 321 dev_dbg(core->isp->dev, 322 "Failed to get source pad for ISP core\n"); 323 return -EPIPE; 324 } 325 326 src_sd = media_entity_to_v4l2_subdev(core->src_pad->entity); 327 328 ret = v4l2_subdev_enable_streams(src_sd, core->src_pad->index, BIT(0)); 329 if (ret) { 330 c3_isp_core_disable(core->isp); 331 return ret; 332 } 333 334 return 0; 335} 336 337static int c3_isp_core_disable_streams(struct v4l2_subdev *sd, 338 struct v4l2_subdev_state *state, 339 u32 pad, u64 streams_mask) 340{ 341 struct c3_isp_core *core = v4l2_get_subdevdata(sd); 342 struct v4l2_subdev *src_sd; 343 344 if (core->isp->pipe.start_count != 1) 345 return 0; 346 347 if (core->src_pad) { 348 src_sd = media_entity_to_v4l2_subdev(core->src_pad->entity); 349 v4l2_subdev_disable_streams(src_sd, core->src_pad->index, 350 BIT(0)); 351 } 352 core->src_pad = NULL; 353 354 c3_isp_core_disable(core->isp); 355 356 return 0; 357} 358 359static int c3_isp_core_enum_mbus_code(struct v4l2_subdev *sd, 360 struct v4l2_subdev_state *state, 361 struct v4l2_subdev_mbus_code_enum *code) 362{ 363 const struct c3_isp_core_format_info *info; 364 365 switch (code->pad) { 366 case C3_ISP_CORE_PAD_SINK_VIDEO: 367 case C3_ISP_CORE_PAD_SOURCE_VIDEO_0: 368 case C3_ISP_CORE_PAD_SOURCE_VIDEO_1: 369 case C3_ISP_CORE_PAD_SOURCE_VIDEO_2: 370 info = core_find_format_by_index(code->index, code->pad); 371 if (!info) 372 return -EINVAL; 373 374 code->code = info->mbus_code; 375 376 break; 377 case C3_ISP_CORE_PAD_SINK_PARAMS: 378 case C3_ISP_CORE_PAD_SOURCE_STATS: 379 if (code->index) 380 return -EINVAL; 381 382 code->code = MEDIA_BUS_FMT_METADATA_FIXED; 383 384 break; 385 default: 386 return -EINVAL; 387 } 388 389 return 0; 390} 391 392static void c3_isp_core_set_sink_fmt(struct v4l2_subdev_state *state, 393 struct v4l2_subdev_format *format) 394{ 395 struct v4l2_mbus_framefmt *sink_fmt; 396 struct v4l2_mbus_framefmt *src_fmt; 397 const struct c3_isp_core_format_info *isp_fmt; 398 399 sink_fmt = v4l2_subdev_state_get_format(state, format->pad); 400 401 isp_fmt = core_find_format_by_code(format->format.code, format->pad); 402 if (!isp_fmt) 403 sink_fmt->code = C3_ISP_CORE_DEF_SINK_PAD_FMT; 404 else 405 sink_fmt->code = format->format.code; 406 407 sink_fmt->width = clamp_t(u32, format->format.width, 408 C3_ISP_MIN_WIDTH, C3_ISP_MAX_WIDTH); 409 sink_fmt->height = clamp_t(u32, format->format.height, 410 C3_ISP_MIN_HEIGHT, C3_ISP_MAX_HEIGHT); 411 sink_fmt->field = V4L2_FIELD_NONE; 412 sink_fmt->colorspace = V4L2_COLORSPACE_RAW; 413 sink_fmt->xfer_func = V4L2_XFER_FUNC_NONE; 414 sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 415 sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 416 417 for (unsigned int i = C3_ISP_CORE_PAD_SOURCE_VIDEO_0; 418 i < C3_ISP_CORE_PAD_MAX; i++) { 419 src_fmt = v4l2_subdev_state_get_format(state, i); 420 421 src_fmt->width = sink_fmt->width; 422 src_fmt->height = sink_fmt->height; 423 } 424 425 format->format = *sink_fmt; 426} 427 428static void c3_isp_core_set_source_fmt(struct v4l2_subdev_state *state, 429 struct v4l2_subdev_format *format) 430{ 431 const struct c3_isp_core_format_info *isp_fmt; 432 struct v4l2_mbus_framefmt *src_fmt; 433 struct v4l2_mbus_framefmt *sink_fmt; 434 435 sink_fmt = v4l2_subdev_state_get_format(state, 436 C3_ISP_CORE_PAD_SINK_VIDEO); 437 src_fmt = v4l2_subdev_state_get_format(state, format->pad); 438 439 isp_fmt = core_find_format_by_code(format->format.code, format->pad); 440 if (!isp_fmt) 441 src_fmt->code = C3_ISP_CORE_DEF_SRC_PAD_FMT; 442 else 443 src_fmt->code = format->format.code; 444 445 src_fmt->width = sink_fmt->width; 446 src_fmt->height = sink_fmt->height; 447 src_fmt->field = V4L2_FIELD_NONE; 448 src_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 449 450 if (isp_fmt && isp_fmt->is_raw) { 451 src_fmt->colorspace = V4L2_COLORSPACE_RAW; 452 src_fmt->xfer_func = V4L2_XFER_FUNC_NONE; 453 src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 454 } else { 455 src_fmt->colorspace = V4L2_COLORSPACE_SRGB; 456 src_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; 457 src_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; 458 } 459 460 format->format = *src_fmt; 461} 462 463static int c3_isp_core_set_fmt(struct v4l2_subdev *sd, 464 struct v4l2_subdev_state *state, 465 struct v4l2_subdev_format *format) 466{ 467 if (format->pad == C3_ISP_CORE_PAD_SINK_VIDEO) 468 c3_isp_core_set_sink_fmt(state, format); 469 else if (format->pad == C3_ISP_CORE_PAD_SOURCE_VIDEO_0 || 470 format->pad == C3_ISP_CORE_PAD_SOURCE_VIDEO_1 || 471 format->pad == C3_ISP_CORE_PAD_SOURCE_VIDEO_2) 472 c3_isp_core_set_source_fmt(state, format); 473 else 474 format->format = 475 *v4l2_subdev_state_get_format(state, format->pad); 476 477 return 0; 478} 479 480static int c3_isp_core_init_state(struct v4l2_subdev *sd, 481 struct v4l2_subdev_state *state) 482{ 483 struct v4l2_mbus_framefmt *fmt; 484 485 /* Video sink pad */ 486 fmt = v4l2_subdev_state_get_format(state, C3_ISP_CORE_PAD_SINK_VIDEO); 487 fmt->width = C3_ISP_DEFAULT_WIDTH; 488 fmt->height = C3_ISP_DEFAULT_HEIGHT; 489 fmt->field = V4L2_FIELD_NONE; 490 fmt->code = C3_ISP_CORE_DEF_SINK_PAD_FMT; 491 fmt->colorspace = V4L2_COLORSPACE_RAW; 492 fmt->xfer_func = V4L2_XFER_FUNC_NONE; 493 fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 494 fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 495 496 /* Video source pad */ 497 for (unsigned int i = C3_ISP_CORE_PAD_SOURCE_VIDEO_0; 498 i < C3_ISP_CORE_PAD_MAX; i++) { 499 fmt = v4l2_subdev_state_get_format(state, i); 500 fmt->width = C3_ISP_DEFAULT_WIDTH; 501 fmt->height = C3_ISP_DEFAULT_HEIGHT; 502 fmt->field = V4L2_FIELD_NONE; 503 fmt->code = C3_ISP_CORE_DEF_SRC_PAD_FMT; 504 fmt->colorspace = V4L2_COLORSPACE_SRGB; 505 fmt->xfer_func = V4L2_XFER_FUNC_SRGB; 506 fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 507 fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; 508 } 509 510 /* Parameters pad */ 511 fmt = v4l2_subdev_state_get_format(state, C3_ISP_CORE_PAD_SINK_PARAMS); 512 fmt->width = 0; 513 fmt->height = 0; 514 fmt->field = V4L2_FIELD_NONE; 515 fmt->code = MEDIA_BUS_FMT_METADATA_FIXED; 516 517 /* Statistics pad */ 518 fmt = v4l2_subdev_state_get_format(state, C3_ISP_CORE_PAD_SOURCE_STATS); 519 fmt->width = 0; 520 fmt->height = 0; 521 fmt->field = V4L2_FIELD_NONE; 522 fmt->code = MEDIA_BUS_FMT_METADATA_FIXED; 523 524 return 0; 525} 526 527static int c3_isp_core_subscribe_event(struct v4l2_subdev *sd, 528 struct v4l2_fh *fh, 529 struct v4l2_event_subscription *sub) 530{ 531 if (sub->type != V4L2_EVENT_FRAME_SYNC) 532 return -EINVAL; 533 534 /* V4L2_EVENT_FRAME_SYNC doesn't need id, so should set 0 */ 535 if (sub->id != 0) 536 return -EINVAL; 537 538 return v4l2_event_subscribe(fh, sub, 0, NULL); 539} 540 541static const struct v4l2_subdev_pad_ops c3_isp_core_pad_ops = { 542 .enum_mbus_code = c3_isp_core_enum_mbus_code, 543 .get_fmt = v4l2_subdev_get_fmt, 544 .set_fmt = c3_isp_core_set_fmt, 545 .enable_streams = c3_isp_core_enable_streams, 546 .disable_streams = c3_isp_core_disable_streams, 547}; 548 549static const struct v4l2_subdev_core_ops c3_isp_core_core_ops = { 550 .subscribe_event = c3_isp_core_subscribe_event, 551 .unsubscribe_event = v4l2_event_subdev_unsubscribe, 552}; 553 554static const struct v4l2_subdev_ops c3_isp_core_subdev_ops = { 555 .core = &c3_isp_core_core_ops, 556 .pad = &c3_isp_core_pad_ops, 557}; 558 559static const struct v4l2_subdev_internal_ops c3_isp_core_internal_ops = { 560 .init_state = c3_isp_core_init_state, 561}; 562 563static int c3_isp_core_link_validate(struct media_link *link) 564{ 565 if (link->sink->index == C3_ISP_CORE_PAD_SINK_PARAMS) 566 return 0; 567 568 return v4l2_subdev_link_validate(link); 569} 570 571/* Media entity operations */ 572static const struct media_entity_operations c3_isp_core_entity_ops = { 573 .link_validate = c3_isp_core_link_validate, 574}; 575 576void c3_isp_core_queue_sof(struct c3_isp_device *isp) 577{ 578 struct v4l2_event event = { 579 .type = V4L2_EVENT_FRAME_SYNC, 580 }; 581 582 event.u.frame_sync.frame_sequence = isp->frm_sequence; 583 v4l2_event_queue(isp->core.sd.devnode, &event); 584} 585 586int c3_isp_core_register(struct c3_isp_device *isp) 587{ 588 struct c3_isp_core *core = &isp->core; 589 struct v4l2_subdev *sd = &core->sd; 590 int ret; 591 592 v4l2_subdev_init(sd, &c3_isp_core_subdev_ops); 593 sd->owner = THIS_MODULE; 594 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; 595 sd->internal_ops = &c3_isp_core_internal_ops; 596 snprintf(sd->name, sizeof(sd->name), "%s", C3_ISP_CORE_SUBDEV_NAME); 597 598 sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; 599 sd->entity.ops = &c3_isp_core_entity_ops; 600 601 core->isp = isp; 602 sd->dev = isp->dev; 603 v4l2_set_subdevdata(sd, core); 604 605 core->pads[C3_ISP_CORE_PAD_SINK_VIDEO].flags = MEDIA_PAD_FL_SINK; 606 core->pads[C3_ISP_CORE_PAD_SINK_PARAMS].flags = MEDIA_PAD_FL_SINK; 607 core->pads[C3_ISP_CORE_PAD_SOURCE_STATS].flags = MEDIA_PAD_FL_SOURCE; 608 core->pads[C3_ISP_CORE_PAD_SOURCE_VIDEO_0].flags = MEDIA_PAD_FL_SOURCE; 609 core->pads[C3_ISP_CORE_PAD_SOURCE_VIDEO_1].flags = MEDIA_PAD_FL_SOURCE; 610 core->pads[C3_ISP_CORE_PAD_SOURCE_VIDEO_2].flags = MEDIA_PAD_FL_SOURCE; 611 ret = media_entity_pads_init(&sd->entity, C3_ISP_CORE_PAD_MAX, 612 core->pads); 613 if (ret) 614 return ret; 615 616 ret = v4l2_subdev_init_finalize(sd); 617 if (ret) 618 goto err_entity_cleanup; 619 620 ret = v4l2_device_register_subdev(&isp->v4l2_dev, sd); 621 if (ret) 622 goto err_subdev_cleanup; 623 624 return 0; 625 626err_subdev_cleanup: 627 v4l2_subdev_cleanup(sd); 628err_entity_cleanup: 629 media_entity_cleanup(&sd->entity); 630 return ret; 631} 632 633void c3_isp_core_unregister(struct c3_isp_device *isp) 634{ 635 struct c3_isp_core *core = &isp->core; 636 struct v4l2_subdev *sd = &core->sd; 637 638 v4l2_device_unregister_subdev(sd); 639 v4l2_subdev_cleanup(sd); 640 media_entity_cleanup(&sd->entity); 641}
~/
Read-only file preview.