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