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