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/build_bug.h> 7 #include <linux/cleanup.h> 8 #include <linux/media/amlogic/c3-isp-config.h> 9 #include <linux/pm_runtime.h> 10 11 #include <media/v4l2-ioctl.h> 12 #include <media/v4l2-isp.h> 13 #include <media/v4l2-mc.h> 14 #include <media/videobuf2-vmalloc.h> 15 16 #include "c3-isp-common.h" 17 #include "c3-isp-regs.h" 18 19 /* 20 * union c3_isp_params_block - Generalisation of a parameter block 21 * 22 * This union allows the driver to treat a block as a generic struct to this 23 * union and safely access the header and block-specific struct without having 24 * to resort to casting. The header member is accessed first, and the type field 25 * checked which allows the driver to determine which of the other members 26 * should be used. 27 * 28 * @header: The shared header struct embedded as the first member 29 * of all the possible other members. This member would be 30 * accessed first and the type field checked to determine 31 * which of the other members should be accessed. 32 * @awb_gains: For header.type == C3_ISP_PARAMS_BLOCK_AWB_GAINS 33 * @awb_cfg: For header.type == C3_ISP_PARAMS_BLOCK_AWB_CONFIG 34 * @ae_cfg: For header.type == C3_ISP_PARAMS_BLOCK_AE_CONFIG 35 * @af_cfg: For header.type == C3_ISP_PARAMS_BLOCK_AF_CONFIG 36 * @pst_gamma: For header.type == C3_ISP_PARAMS_BLOCK_PST_GAMMA 37 * @ccm: For header.type == C3_ISP_PARAMS_BLOCK_CCM 38 * @csc: For header.type == C3_ISP_PARAMS_BLOCK_CSC 39 * @blc: For header.type == C3_ISP_PARAMS_BLOCK_BLC 40 */ 41 union c3_isp_params_block { 42 struct c3_isp_params_block_header header; 43 struct c3_isp_params_awb_gains awb_gains; 44 struct c3_isp_params_awb_config awb_cfg; 45 struct c3_isp_params_ae_config ae_cfg; 46 struct c3_isp_params_af_config af_cfg; 47 struct c3_isp_params_pst_gamma pst_gamma; 48 struct c3_isp_params_ccm ccm; 49 struct c3_isp_params_csc csc; 50 struct c3_isp_params_blc blc; 51 }; 52 53 typedef void (*c3_isp_block_handler)(struct c3_isp_device *isp, 54 const union c3_isp_params_block *block); 55 56 #define to_c3_isp_params_buffer(vbuf) \ 57 container_of(vbuf, struct c3_isp_params_buffer, vb) 58 59 /* Hardware configuration */ 60 61 static void c3_isp_params_cfg_awb_gains(struct c3_isp_device *isp, 62 const union c3_isp_params_block *block) 63 { 64 const struct c3_isp_params_awb_gains *awb_gains = &block->awb_gains; 65 66 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) { 67 c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL, 68 ISP_TOP_BEO_CTRL_WB_EN_MASK, 69 ISP_TOP_BEO_CTRL_WB_DIS); 70 return; 71 } 72 73 c3_isp_update_bits(isp, ISP_LSWB_WB_GAIN0, 74 ISP_LSWB_WB_GAIN0_GR_GAIN_MASK, 75 ISP_LSWB_WB_GAIN0_GR_GAIN(awb_gains->gr_gain)); 76 c3_isp_update_bits(isp, ISP_LSWB_WB_GAIN0, 77 ISP_LSWB_WB_GAIN0_R_GAIN_MASK, 78 ISP_LSWB_WB_GAIN0_R_GAIN(awb_gains->r_gain)); 79 c3_isp_update_bits(isp, ISP_LSWB_WB_GAIN1, 80 ISP_LSWB_WB_GAIN1_B_GAIN_MASK, 81 ISP_LSWB_WB_GAIN1_B_GAIN(awb_gains->b_gain)); 82 c3_isp_update_bits(isp, ISP_LSWB_WB_GAIN1, 83 ISP_LSWB_WB_GAIN1_GB_GAIN_MASK, 84 ISP_LSWB_WB_GAIN1_GB_GAIN(awb_gains->gb_gain)); 85 c3_isp_update_bits(isp, ISP_LSWB_WB_GAIN2, 86 ISP_LSWB_WB_GAIN2_IR_GAIN_MASK, 87 ISP_LSWB_WB_GAIN2_IR_GAIN(awb_gains->gb_gain)); 88 89 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE) 90 c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL, 91 ISP_TOP_BEO_CTRL_WB_EN_MASK, 92 ISP_TOP_BEO_CTRL_WB_EN); 93 } 94 95 static void c3_isp_params_awb_wt(struct c3_isp_device *isp, 96 const struct c3_isp_params_awb_config *cfg) 97 { 98 unsigned int zones_num; 99 unsigned int base; 100 unsigned int data; 101 unsigned int i; 102 103 /* Set the weight address to 0 position */ 104 c3_isp_write(isp, ISP_AWB_BLK_WT_ADDR, 0); 105 106 zones_num = cfg->horiz_zones_num * cfg->vert_zones_num; 107 if (zones_num > C3_ISP_AWB_MAX_ZONES) 108 zones_num = C3_ISP_AWB_MAX_ZONES; 109 110 /* Need to write 8 weights at once */ 111 for (i = 0; i < zones_num / 8; i++) { 112 base = i * 8; 113 data = ISP_AWB_BLK_WT_DATA_WT(0, cfg->zone_weight[base + 0]) | 114 ISP_AWB_BLK_WT_DATA_WT(1, cfg->zone_weight[base + 1]) | 115 ISP_AWB_BLK_WT_DATA_WT(2, cfg->zone_weight[base + 2]) | 116 ISP_AWB_BLK_WT_DATA_WT(3, cfg->zone_weight[base + 3]) | 117 ISP_AWB_BLK_WT_DATA_WT(4, cfg->zone_weight[base + 4]) | 118 ISP_AWB_BLK_WT_DATA_WT(5, cfg->zone_weight[base + 5]) | 119 ISP_AWB_BLK_WT_DATA_WT(6, cfg->zone_weight[base + 6]) | 120 ISP_AWB_BLK_WT_DATA_WT(7, cfg->zone_weight[base + 7]); 121 c3_isp_write(isp, ISP_AWB_BLK_WT_DATA, data); 122 } 123 124 if (zones_num % 8 == 0) 125 return; 126 127 data = 0; 128 base = i * 8; 129 130 for (i = 0; i < zones_num % 8; i++) 131 data |= ISP_AWB_BLK_WT_DATA_WT(i, cfg->zone_weight[base + i]); 132 133 c3_isp_write(isp, ISP_AWB_BLK_WT_DATA, data); 134 } 135 136 static void c3_isp_params_awb_cood(struct c3_isp_device *isp, 137 const struct c3_isp_params_awb_config *cfg) 138 { 139 unsigned int max_point_num; 140 141 /* The number of points is one more than the number of edges */ 142 max_point_num = max(cfg->horiz_zones_num, cfg->vert_zones_num) + 1; 143 144 /* Set the index address to 0 position */ 145 c3_isp_write(isp, ISP_AWB_IDX_ADDR, 0); 146 147 for (unsigned int i = 0; i < max_point_num; i++) 148 c3_isp_write(isp, ISP_AWB_IDX_DATA, 149 ISP_AWB_IDX_DATA_HIDX_DATA(cfg->horiz_coord[i]) | 150 ISP_AWB_IDX_DATA_VIDX_DATA(cfg->vert_coord[i])); 151 } 152 153 static void c3_isp_params_cfg_awb_config(struct c3_isp_device *isp, 154 const union c3_isp_params_block *block) 155 { 156 const struct c3_isp_params_awb_config *awb_cfg = &block->awb_cfg; 157 158 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) { 159 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 160 ISP_TOP_3A_STAT_CRTL_AWB_STAT_EN_MASK, 161 ISP_TOP_3A_STAT_CRTL_AWB_STAT_DIS); 162 return; 163 } 164 165 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 166 ISP_TOP_3A_STAT_CRTL_AWB_POINT_MASK, 167 ISP_TOP_3A_STAT_CRTL_AWB_POINT(awb_cfg->tap_point)); 168 169 c3_isp_update_bits(isp, ISP_AWB_STAT_CTRL2, 170 ISP_AWB_STAT_CTRL2_SATUR_CTRL_MASK, 171 ISP_AWB_STAT_CTRL2_SATUR_CTRL(awb_cfg->satur_vald)); 172 173 c3_isp_update_bits(isp, ISP_AWB_HV_BLKNUM, 174 ISP_AWB_HV_BLKNUM_H_NUM_MASK, 175 ISP_AWB_HV_BLKNUM_H_NUM(awb_cfg->horiz_zones_num)); 176 c3_isp_update_bits(isp, ISP_AWB_HV_BLKNUM, 177 ISP_AWB_HV_BLKNUM_V_NUM_MASK, 178 ISP_AWB_HV_BLKNUM_V_NUM(awb_cfg->vert_zones_num)); 179 180 c3_isp_update_bits(isp, ISP_AWB_STAT_RG, ISP_AWB_STAT_RG_MIN_VALUE_MASK, 181 ISP_AWB_STAT_RG_MIN_VALUE(awb_cfg->rg_min)); 182 c3_isp_update_bits(isp, ISP_AWB_STAT_RG, ISP_AWB_STAT_RG_MAX_VALUE_MASK, 183 ISP_AWB_STAT_RG_MAX_VALUE(awb_cfg->rg_max)); 184 185 c3_isp_update_bits(isp, ISP_AWB_STAT_BG, ISP_AWB_STAT_BG_MIN_VALUE_MASK, 186 ISP_AWB_STAT_BG_MIN_VALUE(awb_cfg->bg_min)); 187 c3_isp_update_bits(isp, ISP_AWB_STAT_BG, ISP_AWB_STAT_BG_MAX_VALUE_MASK, 188 ISP_AWB_STAT_BG_MAX_VALUE(awb_cfg->bg_max)); 189 190 c3_isp_update_bits(isp, ISP_AWB_STAT_RG_HL, 191 ISP_AWB_STAT_RG_HL_LOW_VALUE_MASK, 192 ISP_AWB_STAT_RG_HL_LOW_VALUE(awb_cfg->rg_low)); 193 c3_isp_update_bits(isp, ISP_AWB_STAT_RG_HL, 194 ISP_AWB_STAT_RG_HL_HIGH_VALUE_MASK, 195 ISP_AWB_STAT_RG_HL_HIGH_VALUE(awb_cfg->rg_high)); 196 197 c3_isp_update_bits(isp, ISP_AWB_STAT_BG_HL, 198 ISP_AWB_STAT_BG_HL_LOW_VALUE_MASK, 199 ISP_AWB_STAT_BG_HL_LOW_VALUE(awb_cfg->bg_low)); 200 c3_isp_update_bits(isp, ISP_AWB_STAT_BG_HL, 201 ISP_AWB_STAT_BG_HL_HIGH_VALUE_MASK, 202 ISP_AWB_STAT_BG_HL_HIGH_VALUE(awb_cfg->bg_high)); 203 204 c3_isp_params_awb_wt(isp, awb_cfg); 205 c3_isp_params_awb_cood(isp, awb_cfg); 206 207 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE) 208 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 209 ISP_TOP_3A_STAT_CRTL_AWB_STAT_EN_MASK, 210 ISP_TOP_3A_STAT_CRTL_AWB_STAT_EN); 211 } 212 213 static void c3_isp_params_ae_wt(struct c3_isp_device *isp, 214 const struct c3_isp_params_ae_config *cfg) 215 { 216 unsigned int zones_num; 217 unsigned int base; 218 unsigned int data; 219 unsigned int i; 220 221 /* Set the weight address to 0 position */ 222 c3_isp_write(isp, ISP_AE_BLK_WT_ADDR, 0); 223 224 zones_num = cfg->horiz_zones_num * cfg->vert_zones_num; 225 if (zones_num > C3_ISP_AE_MAX_ZONES) 226 zones_num = C3_ISP_AE_MAX_ZONES; 227 228 /* Need to write 8 weights at once */ 229 for (i = 0; i < zones_num / 8; i++) { 230 base = i * 8; 231 data = ISP_AE_BLK_WT_DATA_WT(0, cfg->zone_weight[base + 0]) | 232 ISP_AE_BLK_WT_DATA_WT(1, cfg->zone_weight[base + 1]) | 233 ISP_AE_BLK_WT_DATA_WT(2, cfg->zone_weight[base + 2]) | 234 ISP_AE_BLK_WT_DATA_WT(3, cfg->zone_weight[base + 3]) | 235 ISP_AE_BLK_WT_DATA_WT(4, cfg->zone_weight[base + 4]) | 236 ISP_AE_BLK_WT_DATA_WT(5, cfg->zone_weight[base + 5]) | 237 ISP_AE_BLK_WT_DATA_WT(6, cfg->zone_weight[base + 6]) | 238 ISP_AE_BLK_WT_DATA_WT(7, cfg->zone_weight[base + 7]); 239 c3_isp_write(isp, ISP_AE_BLK_WT_DATA, data); 240 } 241 242 if (zones_num % 8 == 0) 243 return; 244 245 data = 0; 246 base = i * 8; 247 248 /* Write the last weights data */ 249 for (i = 0; i < zones_num % 8; i++) 250 data |= ISP_AE_BLK_WT_DATA_WT(i, cfg->zone_weight[base + i]); 251 252 c3_isp_write(isp, ISP_AE_BLK_WT_DATA, data); 253 } 254 255 static void c3_isp_params_ae_cood(struct c3_isp_device *isp, 256 const struct c3_isp_params_ae_config *cfg) 257 { 258 unsigned int max_point_num; 259 260 /* The number of points is one more than the number of edges */ 261 max_point_num = max(cfg->horiz_zones_num, cfg->vert_zones_num) + 1; 262 263 /* Set the index address to 0 position */ 264 c3_isp_write(isp, ISP_AE_IDX_ADDR, 0); 265 266 for (unsigned int i = 0; i < max_point_num; i++) 267 c3_isp_write(isp, ISP_AE_IDX_DATA, 268 ISP_AE_IDX_DATA_HIDX_DATA(cfg->horiz_coord[i]) | 269 ISP_AE_IDX_DATA_VIDX_DATA(cfg->vert_coord[i])); 270 } 271 272 static void c3_isp_params_cfg_ae_config(struct c3_isp_device *isp, 273 const union c3_isp_params_block *block) 274 { 275 const struct c3_isp_params_ae_config *ae_cfg = &block->ae_cfg; 276 277 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) { 278 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 279 ISP_TOP_3A_STAT_CRTL_AE_STAT_EN_MASK, 280 ISP_TOP_3A_STAT_CRTL_AE_STAT_DIS); 281 return; 282 } 283 284 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 285 ISP_TOP_3A_STAT_CRTL_AE_POINT_MASK, 286 ISP_TOP_3A_STAT_CRTL_AE_POINT(ae_cfg->tap_point)); 287 288 if (ae_cfg->tap_point == C3_ISP_AE_STATS_TAP_GE) 289 c3_isp_update_bits(isp, ISP_AE_CTRL, 290 ISP_AE_CTRL_INPUT_2LINE_MASK, 291 ISP_AE_CTRL_INPUT_2LINE_EN); 292 else 293 c3_isp_update_bits(isp, ISP_AE_CTRL, 294 ISP_AE_CTRL_INPUT_2LINE_MASK, 295 ISP_AE_CTRL_INPUT_2LINE_DIS); 296 297 c3_isp_update_bits(isp, ISP_AE_HV_BLKNUM, 298 ISP_AE_HV_BLKNUM_H_NUM_MASK, 299 ISP_AE_HV_BLKNUM_H_NUM(ae_cfg->horiz_zones_num)); 300 c3_isp_update_bits(isp, ISP_AE_HV_BLKNUM, 301 ISP_AE_HV_BLKNUM_V_NUM_MASK, 302 ISP_AE_HV_BLKNUM_V_NUM(ae_cfg->vert_zones_num)); 303 304 c3_isp_params_ae_wt(isp, ae_cfg); 305 c3_isp_params_ae_cood(isp, ae_cfg); 306 307 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE) 308 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 309 ISP_TOP_3A_STAT_CRTL_AE_STAT_EN_MASK, 310 ISP_TOP_3A_STAT_CRTL_AE_STAT_EN); 311 } 312 313 static void c3_isp_params_af_cood(struct c3_isp_device *isp, 314 const struct c3_isp_params_af_config *cfg) 315 { 316 unsigned int max_point_num; 317 318 /* The number of points is one more than the number of edges */ 319 max_point_num = max(cfg->horiz_zones_num, cfg->vert_zones_num) + 1; 320 321 /* Set the index address to 0 position */ 322 c3_isp_write(isp, ISP_AF_IDX_ADDR, 0); 323 324 for (unsigned int i = 0; i < max_point_num; i++) 325 c3_isp_write(isp, ISP_AF_IDX_DATA, 326 ISP_AF_IDX_DATA_HIDX_DATA(cfg->horiz_coord[i]) | 327 ISP_AF_IDX_DATA_VIDX_DATA(cfg->vert_coord[i])); 328 } 329 330 static void c3_isp_params_cfg_af_config(struct c3_isp_device *isp, 331 const union c3_isp_params_block *block) 332 { 333 const struct c3_isp_params_af_config *af_cfg = &block->af_cfg; 334 335 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) { 336 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 337 ISP_TOP_3A_STAT_CRTL_AF_STAT_EN_MASK, 338 ISP_TOP_3A_STAT_CRTL_AF_STAT_DIS); 339 return; 340 } 341 342 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 343 ISP_TOP_3A_STAT_CRTL_AF_POINT_MASK, 344 ISP_TOP_3A_STAT_CRTL_AF_POINT(af_cfg->tap_point)); 345 346 c3_isp_update_bits(isp, ISP_AF_HV_BLKNUM, 347 ISP_AF_HV_BLKNUM_H_NUM_MASK, 348 ISP_AF_HV_BLKNUM_H_NUM(af_cfg->horiz_zones_num)); 349 c3_isp_update_bits(isp, ISP_AF_HV_BLKNUM, 350 ISP_AF_HV_BLKNUM_V_NUM_MASK, 351 ISP_AF_HV_BLKNUM_V_NUM(af_cfg->vert_zones_num)); 352 353 c3_isp_params_af_cood(isp, af_cfg); 354 355 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE) 356 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 357 ISP_TOP_3A_STAT_CRTL_AF_STAT_EN_MASK, 358 ISP_TOP_3A_STAT_CRTL_AF_STAT_EN); 359 } 360 361 static void c3_isp_params_cfg_pst_gamma(struct c3_isp_device *isp, 362 const union c3_isp_params_block *block) 363 { 364 const struct c3_isp_params_pst_gamma *gm = &block->pst_gamma; 365 unsigned int base; 366 unsigned int i; 367 368 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) { 369 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 370 ISP_TOP_BED_CTRL_PST_GAMMA_EN_MASK, 371 ISP_TOP_BED_CTRL_PST_GAMMA_DIS); 372 return; 373 } 374 375 /* R, G and B channels use the same gamma lut */ 376 for (unsigned int j = 0; j < 3; j++) { 377 /* Set the channel lut address */ 378 c3_isp_write(isp, ISP_PST_GAMMA_LUT_ADDR, 379 ISP_PST_GAMMA_LUT_ADDR_IDX_ADDR(j)); 380 381 /* Need to write 2 lut values at once */ 382 for (i = 0; i < ARRAY_SIZE(gm->lut) / 2; i++) { 383 base = i * 2; 384 c3_isp_write(isp, ISP_PST_GAMMA_LUT_DATA, 385 ISP_PST_GM_LUT_DATA0(gm->lut[base]) | 386 ISP_PST_GM_LUT_DATA1(gm->lut[base + 1])); 387 } 388 389 /* Write the last one */ 390 if (ARRAY_SIZE(gm->lut) % 2) { 391 base = i * 2; 392 c3_isp_write(isp, ISP_PST_GAMMA_LUT_DATA, 393 ISP_PST_GM_LUT_DATA0(gm->lut[base])); 394 } 395 } 396 397 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE) 398 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 399 ISP_TOP_BED_CTRL_PST_GAMMA_EN_MASK, 400 ISP_TOP_BED_CTRL_PST_GAMMA_EN); 401 } 402 403 /* Configure 3 x 3 ccm matrix */ 404 static void c3_isp_params_cfg_ccm(struct c3_isp_device *isp, 405 const union c3_isp_params_block *block) 406 { 407 const struct c3_isp_params_ccm *ccm = &block->ccm; 408 409 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) { 410 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 411 ISP_TOP_BED_CTRL_CCM_EN_MASK, 412 ISP_TOP_BED_CTRL_CCM_DIS); 413 return; 414 } 415 416 c3_isp_update_bits(isp, ISP_CCM_MTX_00_01, 417 ISP_CCM_MTX_00_01_MTX_00_MASK, 418 ISP_CCM_MTX_00_01_MTX_00(ccm->matrix[0][0])); 419 c3_isp_update_bits(isp, ISP_CCM_MTX_00_01, 420 ISP_CCM_MTX_00_01_MTX_01_MASK, 421 ISP_CCM_MTX_00_01_MTX_01(ccm->matrix[0][1])); 422 c3_isp_update_bits(isp, ISP_CCM_MTX_02_03, 423 ISP_CCM_MTX_02_03_MTX_02_MASK, 424 ISP_CCM_MTX_02_03_MTX_02(ccm->matrix[0][2])); 425 426 c3_isp_update_bits(isp, ISP_CCM_MTX_10_11, 427 ISP_CCM_MTX_10_11_MTX_10_MASK, 428 ISP_CCM_MTX_10_11_MTX_10(ccm->matrix[1][0])); 429 c3_isp_update_bits(isp, ISP_CCM_MTX_10_11, 430 ISP_CCM_MTX_10_11_MTX_11_MASK, 431 ISP_CCM_MTX_10_11_MTX_11(ccm->matrix[1][1])); 432 c3_isp_update_bits(isp, ISP_CCM_MTX_12_13, 433 ISP_CCM_MTX_12_13_MTX_12_MASK, 434 ISP_CCM_MTX_12_13_MTX_12(ccm->matrix[1][2])); 435 436 c3_isp_update_bits(isp, ISP_CCM_MTX_20_21, 437 ISP_CCM_MTX_20_21_MTX_20_MASK, 438 ISP_CCM_MTX_20_21_MTX_20(ccm->matrix[2][0])); 439 c3_isp_update_bits(isp, ISP_CCM_MTX_20_21, 440 ISP_CCM_MTX_20_21_MTX_21_MASK, 441 ISP_CCM_MTX_20_21_MTX_21(ccm->matrix[2][1])); 442 c3_isp_update_bits(isp, ISP_CCM_MTX_22_23_RS, 443 ISP_CCM_MTX_22_23_RS_MTX_22_MASK, 444 ISP_CCM_MTX_22_23_RS_MTX_22(ccm->matrix[2][2])); 445 446 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE) 447 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 448 ISP_TOP_BED_CTRL_CCM_EN_MASK, 449 ISP_TOP_BED_CTRL_CCM_EN); 450 } 451 452 /* Configure color space conversion matrix parameters */ 453 static void c3_isp_params_cfg_csc(struct c3_isp_device *isp, 454 const union c3_isp_params_block *block) 455 { 456 const struct c3_isp_params_csc *csc = &block->csc; 457 458 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) { 459 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 460 ISP_TOP_BED_CTRL_CM0_EN_MASK, 461 ISP_TOP_BED_CTRL_CM0_DIS); 462 return; 463 } 464 465 c3_isp_update_bits(isp, ISP_CM0_COEF00_01, 466 ISP_CM0_COEF00_01_MTX_00_MASK, 467 ISP_CM0_COEF00_01_MTX_00(csc->matrix[0][0])); 468 c3_isp_update_bits(isp, ISP_CM0_COEF00_01, 469 ISP_CM0_COEF00_01_MTX_01_MASK, 470 ISP_CM0_COEF00_01_MTX_01(csc->matrix[0][1])); 471 c3_isp_update_bits(isp, ISP_CM0_COEF02_10, 472 ISP_CM0_COEF02_10_MTX_02_MASK, 473 ISP_CM0_COEF02_10_MTX_02(csc->matrix[0][2])); 474 475 c3_isp_update_bits(isp, ISP_CM0_COEF02_10, 476 ISP_CM0_COEF02_10_MTX_10_MASK, 477 ISP_CM0_COEF02_10_MTX_10(csc->matrix[1][0])); 478 c3_isp_update_bits(isp, ISP_CM0_COEF11_12, 479 ISP_CM0_COEF11_12_MTX_11_MASK, 480 ISP_CM0_COEF11_12_MTX_11(csc->matrix[1][1])); 481 c3_isp_update_bits(isp, ISP_CM0_COEF11_12, 482 ISP_CM0_COEF11_12_MTX_12_MASK, 483 ISP_CM0_COEF11_12_MTX_12(csc->matrix[1][2])); 484 485 c3_isp_update_bits(isp, ISP_CM0_COEF20_21, 486 ISP_CM0_COEF20_21_MTX_20_MASK, 487 ISP_CM0_COEF20_21_MTX_20(csc->matrix[2][0])); 488 c3_isp_update_bits(isp, ISP_CM0_COEF20_21, 489 ISP_CM0_COEF20_21_MTX_21_MASK, 490 ISP_CM0_COEF20_21_MTX_21(csc->matrix[2][1])); 491 c3_isp_update_bits(isp, ISP_CM0_COEF22_OUP_OFST0, 492 ISP_CM0_COEF22_OUP_OFST0_MTX_22_MASK, 493 ISP_CM0_COEF22_OUP_OFST0_MTX_22(csc->matrix[2][2])); 494 495 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE) 496 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 497 ISP_TOP_BED_CTRL_CM0_EN_MASK, 498 ISP_TOP_BED_CTRL_CM0_EN); 499 } 500 501 /* Set blc offset of each color channel */ 502 static void c3_isp_params_cfg_blc(struct c3_isp_device *isp, 503 const union c3_isp_params_block *block) 504 { 505 const struct c3_isp_params_blc *blc = &block->blc; 506 507 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_DISABLE) { 508 c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL, 509 ISP_TOP_BEO_CTRL_BLC_EN_MASK, 510 ISP_TOP_BEO_CTRL_BLC_DIS); 511 return; 512 } 513 514 c3_isp_write(isp, ISP_LSWB_BLC_OFST0, 515 ISP_LSWB_BLC_OFST0_R_OFST(blc->r_ofst) | 516 ISP_LSWB_BLC_OFST0_GR_OFST(blc->gr_ofst)); 517 c3_isp_write(isp, ISP_LSWB_BLC_OFST1, 518 ISP_LSWB_BLC_OFST1_GB_OFST(blc->gb_ofst) | 519 ISP_LSWB_BLC_OFST1_B_OFST(blc->b_ofst)); 520 521 if (block->header.flags & C3_ISP_PARAMS_BLOCK_FL_ENABLE) 522 c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL, 523 ISP_TOP_BEO_CTRL_BLC_EN_MASK, 524 ISP_TOP_BEO_CTRL_BLC_EN); 525 } 526 527 static const c3_isp_block_handler c3_isp_params_handlers[] = { 528 [C3_ISP_PARAMS_BLOCK_AWB_GAINS] = c3_isp_params_cfg_awb_gains, 529 [C3_ISP_PARAMS_BLOCK_AWB_CONFIG] = c3_isp_params_cfg_awb_config, 530 [C3_ISP_PARAMS_BLOCK_AE_CONFIG] = c3_isp_params_cfg_ae_config, 531 [C3_ISP_PARAMS_BLOCK_AF_CONFIG] = c3_isp_params_cfg_af_config, 532 [C3_ISP_PARAMS_BLOCK_PST_GAMMA] = c3_isp_params_cfg_pst_gamma, 533 [C3_ISP_PARAMS_BLOCK_CCM] = c3_isp_params_cfg_ccm, 534 [C3_ISP_PARAMS_BLOCK_CSC] = c3_isp_params_cfg_csc, 535 [C3_ISP_PARAMS_BLOCK_BLC] = c3_isp_params_cfg_blc, 536 }; 537 538 static int 539 c3_isp_params_awb_config_validate(struct device *dev, 540 const struct v4l2_isp_block_header *block) 541 { 542 const struct c3_isp_params_awb_config *cfg = 543 (const struct c3_isp_params_awb_config *)block; 544 545 if (cfg->horiz_zones_num * cfg->vert_zones_num > C3_ISP_AWB_MAX_ZONES) { 546 dev_dbg(dev, "Invalid number of AWB measurement zones\n"); 547 return -EINVAL; 548 } 549 550 return 0; 551 } 552 553 static int 554 c3_isp_params_ae_config_validate(struct device *dev, 555 const struct v4l2_isp_block_header *block) 556 { 557 const struct c3_isp_params_ae_config *cfg = 558 (const struct c3_isp_params_ae_config *)block; 559 560 if (cfg->horiz_zones_num * cfg->vert_zones_num > C3_ISP_AE_MAX_ZONES) { 561 dev_dbg(dev, "Invalid number of AE measurement zones\n"); 562 return -EINVAL; 563 } 564 565 return 0; 566 } 567 568 #define C3_ISP_PARAMS_BLOCK_INFO_CBK(block, data, cbk) \ 569 [C3_ISP_PARAMS_BLOCK_ ## block] = { \ 570 .size = sizeof(struct c3_isp_params_ ## data), \ 571 .block_validate = (cbk)\ 572 } 573 574 #define C3_ISP_PARAMS_BLOCK_INFO(block, data) \ 575 C3_ISP_PARAMS_BLOCK_INFO_CBK(block, data, NULL) 576 577 static const struct v4l2_isp_params_block_type_info 578 c3_isp_params_block_types_info[] = { 579 C3_ISP_PARAMS_BLOCK_INFO(AWB_GAINS, awb_gains), 580 C3_ISP_PARAMS_BLOCK_INFO_CBK(AWB_CONFIG, awb_config, 581 &c3_isp_params_awb_config_validate), 582 C3_ISP_PARAMS_BLOCK_INFO_CBK(AE_CONFIG, ae_config, 583 &c3_isp_params_ae_config_validate), 584 C3_ISP_PARAMS_BLOCK_INFO(AF_CONFIG, af_config), 585 C3_ISP_PARAMS_BLOCK_INFO(PST_GAMMA, pst_gamma), 586 C3_ISP_PARAMS_BLOCK_INFO(CCM, ccm), 587 C3_ISP_PARAMS_BLOCK_INFO(CSC, csc), 588 C3_ISP_PARAMS_BLOCK_INFO(BLC, blc), 589 }; 590 591 static_assert(ARRAY_SIZE(c3_isp_params_handlers) == 592 ARRAY_SIZE(c3_isp_params_block_types_info)); 593 594 static void c3_isp_params_cfg_blocks(struct c3_isp_params *params) 595 { 596 struct c3_isp_params_cfg *config = params->buff->cfg; 597 size_t block_offset = 0; 598 599 if (WARN_ON(!config)) 600 return; 601 602 /* Walk the list of parameter blocks and process them */ 603 while (block_offset < config->data_size) { 604 const union c3_isp_params_block *block; 605 c3_isp_block_handler block_handler; 606 607 block = (const union c3_isp_params_block *) 608 &config->data[block_offset]; 609 610 block_handler = c3_isp_params_handlers[block->header.type]; 611 block_handler(params->isp, block); 612 613 block_offset += block->header.size; 614 } 615 } 616 617 void c3_isp_params_pre_cfg(struct c3_isp_device *isp) 618 { 619 struct c3_isp_params *params = &isp->params; 620 621 /* Disable some unused modules */ 622 c3_isp_update_bits(isp, ISP_TOP_FEO_CTRL0, 623 ISP_TOP_FEO_CTRL0_INPUT_FMT_EN_MASK, 624 ISP_TOP_FEO_CTRL0_INPUT_FMT_DIS); 625 626 c3_isp_update_bits(isp, ISP_TOP_FEO_CTRL1_0, 627 ISP_TOP_FEO_CTRL1_0_DPC_EN_MASK, 628 ISP_TOP_FEO_CTRL1_0_DPC_DIS); 629 c3_isp_update_bits(isp, ISP_TOP_FEO_CTRL1_0, 630 ISP_TOP_FEO_CTRL1_0_OG_EN_MASK, 631 ISP_TOP_FEO_CTRL1_0_OG_DIS); 632 633 c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, ISP_TOP_FED_CTRL_PDPC_EN_MASK, 634 ISP_TOP_FED_CTRL_PDPC_DIS); 635 c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, 636 ISP_TOP_FED_CTRL_RAWCNR_EN_MASK, 637 ISP_TOP_FED_CTRL_RAWCNR_DIS); 638 c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, ISP_TOP_FED_CTRL_SNR1_EN_MASK, 639 ISP_TOP_FED_CTRL_SNR1_DIS); 640 c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, ISP_TOP_FED_CTRL_TNR0_EN_MASK, 641 ISP_TOP_FED_CTRL_TNR0_DIS); 642 c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, 643 ISP_TOP_FED_CTRL_CUBIC_CS_EN_MASK, 644 ISP_TOP_FED_CTRL_CUBIC_CS_DIS); 645 c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, ISP_TOP_FED_CTRL_SQRT_EN_MASK, 646 ISP_TOP_FED_CTRL_SQRT_DIS); 647 c3_isp_update_bits(isp, ISP_TOP_FED_CTRL, 648 ISP_TOP_FED_CTRL_DGAIN_EN_MASK, 649 ISP_TOP_FED_CTRL_DGAIN_DIS); 650 651 c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL, 652 ISP_TOP_BEO_CTRL_INV_DGAIN_EN_MASK, 653 ISP_TOP_BEO_CTRL_INV_DGAIN_DIS); 654 c3_isp_update_bits(isp, ISP_TOP_BEO_CTRL, ISP_TOP_BEO_CTRL_EOTF_EN_MASK, 655 ISP_TOP_BEO_CTRL_EOTF_DIS); 656 657 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 658 ISP_TOP_BED_CTRL_YHS_STAT_EN_MASK, 659 ISP_TOP_BED_CTRL_YHS_STAT_DIS); 660 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 661 ISP_TOP_BED_CTRL_GRPH_STAT_EN_MASK, 662 ISP_TOP_BED_CTRL_GRPH_STAT_DIS); 663 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 664 ISP_TOP_BED_CTRL_FMETER_EN_MASK, 665 ISP_TOP_BED_CTRL_FMETER_DIS); 666 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, ISP_TOP_BED_CTRL_BSC_EN_MASK, 667 ISP_TOP_BED_CTRL_BSC_DIS); 668 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, ISP_TOP_BED_CTRL_CNR2_EN_MASK, 669 ISP_TOP_BED_CTRL_CNR2_DIS); 670 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, ISP_TOP_BED_CTRL_CM1_EN_MASK, 671 ISP_TOP_BED_CTRL_CM1_DIS); 672 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 673 ISP_TOP_BED_CTRL_LUT3D_EN_MASK, 674 ISP_TOP_BED_CTRL_LUT3D_DIS); 675 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, 676 ISP_TOP_BED_CTRL_PST_TNR_LITE_EN_MASK, 677 ISP_TOP_BED_CTRL_PST_TNR_LITE_DIS); 678 c3_isp_update_bits(isp, ISP_TOP_BED_CTRL, ISP_TOP_BED_CTRL_AMCM_EN_MASK, 679 ISP_TOP_BED_CTRL_AMCM_DIS); 680 681 /* 682 * Disable AE, AF and AWB stat module. Please configure the parameters 683 * in userspace algorithm if need to enable these switch. 684 */ 685 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 686 ISP_TOP_3A_STAT_CRTL_AE_STAT_EN_MASK, 687 ISP_TOP_3A_STAT_CRTL_AE_STAT_DIS); 688 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 689 ISP_TOP_3A_STAT_CRTL_AWB_STAT_EN_MASK, 690 ISP_TOP_3A_STAT_CRTL_AWB_STAT_DIS); 691 c3_isp_update_bits(isp, ISP_TOP_3A_STAT_CRTL, 692 ISP_TOP_3A_STAT_CRTL_AF_STAT_EN_MASK, 693 ISP_TOP_3A_STAT_CRTL_AF_STAT_DIS); 694 695 c3_isp_write(isp, ISP_LSWB_WB_LIMIT0, 696 ISP_LSWB_WB_LIMIT0_WB_LIMIT_R_MAX | 697 ISP_LSWB_WB_LIMIT0_WB_LIMIT_GR_MAX); 698 c3_isp_write(isp, ISP_LSWB_WB_LIMIT1, 699 ISP_LSWB_WB_LIMIT1_WB_LIMIT_GB_MAX | 700 ISP_LSWB_WB_LIMIT1_WB_LIMIT_B_MAX); 701 702 guard(spinlock_irqsave)(¶ms->buff_lock); 703 704 /* Only use the first buffer to initialize ISP */ 705 params->buff = 706 list_first_entry_or_null(¶ms->pending, 707 struct c3_isp_params_buffer, list); 708 if (params->buff) 709 c3_isp_params_cfg_blocks(params); 710 } 711 712 /* V4L2 video operations */ 713 714 static int c3_isp_params_querycap(struct file *file, void *fh, 715 struct v4l2_capability *cap) 716 { 717 strscpy(cap->driver, C3_ISP_DRIVER_NAME, sizeof(cap->driver)); 718 strscpy(cap->card, "AML C3 ISP", sizeof(cap->card)); 719 720 return 0; 721 } 722 723 static int c3_isp_params_enum_fmt(struct file *file, void *fh, 724 struct v4l2_fmtdesc *f) 725 { 726 if (f->index) 727 return -EINVAL; 728 729 f->pixelformat = V4L2_META_FMT_C3ISP_PARAMS; 730 731 return 0; 732 } 733 734 static int c3_isp_params_g_fmt(struct file *file, void *fh, 735 struct v4l2_format *f) 736 { 737 struct c3_isp_params *params = video_drvdata(file); 738 739 f->fmt.meta = params->vfmt.fmt.meta; 740 741 return 0; 742 } 743 744 static const struct v4l2_ioctl_ops isp_params_v4l2_ioctl_ops = { 745 .vidioc_querycap = c3_isp_params_querycap, 746 .vidioc_enum_fmt_meta_out = c3_isp_params_enum_fmt, 747 .vidioc_g_fmt_meta_out = c3_isp_params_g_fmt, 748 .vidioc_s_fmt_meta_out = c3_isp_params_g_fmt, 749 .vidioc_try_fmt_meta_out = c3_isp_params_g_fmt, 750 .vidioc_reqbufs = vb2_ioctl_reqbufs, 751 .vidioc_querybuf = vb2_ioctl_querybuf, 752 .vidioc_qbuf = vb2_ioctl_qbuf, 753 .vidioc_expbuf = vb2_ioctl_expbuf, 754 .vidioc_dqbuf = vb2_ioctl_dqbuf, 755 .vidioc_prepare_buf = vb2_ioctl_prepare_buf, 756 .vidioc_create_bufs = vb2_ioctl_create_bufs, 757 .vidioc_streamon = vb2_ioctl_streamon, 758 .vidioc_streamoff = vb2_ioctl_streamoff, 759 }; 760 761 static const struct v4l2_file_operations isp_params_v4l2_fops = { 762 .open = v4l2_fh_open, 763 .release = vb2_fop_release, 764 .poll = vb2_fop_poll, 765 .unlocked_ioctl = video_ioctl2, 766 .mmap = vb2_fop_mmap, 767 }; 768 769 static int c3_isp_params_vb2_queue_setup(struct vb2_queue *q, 770 unsigned int *num_buffers, 771 unsigned int *num_planes, 772 unsigned int sizes[], 773 struct device *alloc_devs[]) 774 { 775 if (*num_planes) { 776 if (*num_planes != 1) 777 return -EINVAL; 778 779 if (sizes[0] < sizeof(struct c3_isp_params_cfg)) 780 return -EINVAL; 781 782 return 0; 783 } 784 785 *num_planes = 1; 786 sizes[0] = sizeof(struct c3_isp_params_cfg); 787 788 return 0; 789 } 790 791 static void c3_isp_params_vb2_buf_queue(struct vb2_buffer *vb) 792 { 793 struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); 794 struct c3_isp_params_buffer *buf = to_c3_isp_params_buffer(v4l2_buf); 795 struct c3_isp_params *params = vb2_get_drv_priv(vb->vb2_queue); 796 797 guard(spinlock_irqsave)(¶ms->buff_lock); 798 799 list_add_tail(&buf->list, ¶ms->pending); 800 } 801 802 static int c3_isp_params_vb2_buf_prepare(struct vb2_buffer *vb) 803 { 804 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 805 struct c3_isp_params_buffer *buf = to_c3_isp_params_buffer(vbuf); 806 struct c3_isp_params *params = vb2_get_drv_priv(vb->vb2_queue); 807 struct c3_isp_params_cfg *usr_cfg = vb2_plane_vaddr(vb, 0); 808 size_t payload_size = vb2_get_plane_payload(vb, 0); 809 struct c3_isp_params_cfg *cfg = buf->cfg; 810 int ret; 811 812 ret = v4l2_isp_params_validate_buffer_size(params->isp->dev, vb, 813 params->vfmt.fmt.meta.buffersize); 814 if (ret) 815 return ret; 816 817 /* 818 * Use the internal scratch buffer to avoid userspace modifying 819 * the buffer content while the driver is processing it. 820 */ 821 memcpy(cfg, usr_cfg, payload_size); 822 823 return v4l2_isp_params_validate_buffer(params->isp->dev, vb, 824 (struct v4l2_isp_params_buffer *)cfg, 825 c3_isp_params_block_types_info, 826 ARRAY_SIZE(c3_isp_params_block_types_info)); 827 } 828 829 static int c3_isp_params_vb2_buf_init(struct vb2_buffer *vb) 830 { 831 struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); 832 struct c3_isp_params *params = vb2_get_drv_priv(vb->vb2_queue); 833 struct c3_isp_params_buffer *buf = to_c3_isp_params_buffer(v4l2_buf); 834 835 buf->cfg = kvmalloc(params->vfmt.fmt.meta.buffersize, GFP_KERNEL); 836 if (!buf->cfg) 837 return -ENOMEM; 838 839 return 0; 840 } 841 842 static void c3_isp_params_vb2_buf_cleanup(struct vb2_buffer *vb) 843 { 844 struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); 845 struct c3_isp_params_buffer *buf = to_c3_isp_params_buffer(v4l2_buf); 846 847 kvfree(buf->cfg); 848 buf->cfg = NULL; 849 } 850 851 static void c3_isp_params_vb2_stop_streaming(struct vb2_queue *q) 852 { 853 struct c3_isp_params *params = vb2_get_drv_priv(q); 854 struct c3_isp_params_buffer *buff; 855 856 guard(spinlock_irqsave)(¶ms->buff_lock); 857 858 while (!list_empty(¶ms->pending)) { 859 buff = list_first_entry(¶ms->pending, 860 struct c3_isp_params_buffer, list); 861 list_del(&buff->list); 862 vb2_buffer_done(&buff->vb.vb2_buf, VB2_BUF_STATE_ERROR); 863 } 864 } 865 866 static const struct vb2_ops isp_params_vb2_ops = { 867 .queue_setup = c3_isp_params_vb2_queue_setup, 868 .buf_queue = c3_isp_params_vb2_buf_queue, 869 .buf_prepare = c3_isp_params_vb2_buf_prepare, 870 .buf_init = c3_isp_params_vb2_buf_init, 871 .buf_cleanup = c3_isp_params_vb2_buf_cleanup, 872 .stop_streaming = c3_isp_params_vb2_stop_streaming, 873 }; 874 875 int c3_isp_params_register(struct c3_isp_device *isp) 876 { 877 struct c3_isp_params *params = &isp->params; 878 struct video_device *vdev = ¶ms->vdev; 879 struct vb2_queue *vb2_q = ¶ms->vb2_q; 880 int ret; 881 882 memset(params, 0, sizeof(*params)); 883 params->vfmt.fmt.meta.dataformat = V4L2_META_FMT_C3ISP_PARAMS; 884 params->vfmt.fmt.meta.buffersize = sizeof(struct c3_isp_params_cfg); 885 params->isp = isp; 886 INIT_LIST_HEAD(¶ms->pending); 887 spin_lock_init(¶ms->buff_lock); 888 mutex_init(¶ms->lock); 889 890 snprintf(vdev->name, sizeof(vdev->name), "c3-isp-params"); 891 vdev->fops = &isp_params_v4l2_fops; 892 vdev->ioctl_ops = &isp_params_v4l2_ioctl_ops; 893 vdev->v4l2_dev = &isp->v4l2_dev; 894 vdev->lock = ¶ms->lock; 895 vdev->minor = -1; 896 vdev->queue = vb2_q; 897 vdev->release = video_device_release_empty; 898 vdev->device_caps = V4L2_CAP_META_OUTPUT | V4L2_CAP_STREAMING; 899 vdev->vfl_dir = VFL_DIR_TX; 900 video_set_drvdata(vdev, params); 901 902 vb2_q->drv_priv = params; 903 vb2_q->mem_ops = &vb2_vmalloc_memops; 904 vb2_q->ops = &isp_params_vb2_ops; 905 vb2_q->type = V4L2_BUF_TYPE_META_OUTPUT; 906 vb2_q->io_modes = VB2_DMABUF | VB2_MMAP; 907 vb2_q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 908 vb2_q->buf_struct_size = sizeof(struct c3_isp_params_buffer); 909 vb2_q->dev = isp->dev; 910 vb2_q->lock = ¶ms->lock; 911 vb2_q->min_queued_buffers = 1; 912 913 ret = vb2_queue_init(vb2_q); 914 if (ret) 915 goto err_detroy; 916 917 params->pad.flags = MEDIA_PAD_FL_SOURCE; 918 ret = media_entity_pads_init(&vdev->entity, 1, ¶ms->pad); 919 if (ret) 920 goto err_queue_release; 921 922 ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); 923 if (ret < 0) { 924 dev_err(isp->dev, 925 "Failed to register %s: %d\n", vdev->name, ret); 926 goto err_entity_cleanup; 927 } 928 929 return 0; 930 931 err_entity_cleanup: 932 media_entity_cleanup(&vdev->entity); 933 err_queue_release: 934 vb2_queue_release(vb2_q); 935 err_detroy: 936 mutex_destroy(¶ms->lock); 937 return ret; 938 } 939 940 void c3_isp_params_unregister(struct c3_isp_device *isp) 941 { 942 struct c3_isp_params *params = &isp->params; 943 944 vb2_queue_release(¶ms->vb2_q); 945 media_entity_cleanup(¶ms->vdev.entity); 946 video_unregister_device(¶ms->vdev); 947 mutex_destroy(¶ms->lock); 948 } 949 950 void c3_isp_params_isr(struct c3_isp_device *isp) 951 { 952 struct c3_isp_params *params = &isp->params; 953 954 guard(spinlock_irqsave)(¶ms->buff_lock); 955 956 params->buff = 957 list_first_entry_or_null(¶ms->pending, 958 struct c3_isp_params_buffer, list); 959 if (!params->buff) 960 return; 961 962 list_del(¶ms->buff->list); 963 964 c3_isp_params_cfg_blocks(params); 965 966 params->buff->vb.sequence = params->isp->frm_sequence; 967 params->buff->vb.vb2_buf.timestamp = ktime_get(); 968 params->buff->vb.field = V4L2_FIELD_NONE; 969 vb2_buffer_done(¶ms->buff->vb.vb2_buf, VB2_BUF_STATE_DONE); 970 } 971